Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ffab4bdf56 | ||
|
|
fff40499cc | ||
|
|
0b24bf8fe8 | ||
|
|
429dd80409 | ||
|
|
bee5d36fbf | ||
|
|
8428edad37 | ||
|
|
2ba2bb8115 | ||
|
|
b8be5d3bf5 | ||
|
|
b99ba2c25e | ||
|
|
289a21156c | ||
|
|
66ca70acd2 | ||
|
|
578113d557 | ||
|
|
79c9a2781f | ||
|
|
fd7436527d | ||
|
|
20f128b9c3 | ||
|
|
e6a1370ae5 | ||
|
|
4758154014 | ||
|
|
a7ed62a108 | ||
|
|
8f8e2343a0 | ||
|
|
6d8e1705b8 | ||
|
|
a84bc49540 | ||
|
|
fe56cbb77f | ||
|
|
ac9b6af56a | ||
|
|
4ff99126d6 | ||
|
|
3e4763df68 | ||
|
|
f3fdcf327d | ||
|
|
e5dd36d807 | ||
|
|
ad03ab01e2 | ||
|
|
be72a3ff47 | ||
|
|
d8b2946fb5 | ||
|
|
aa3e049565 | ||
|
|
bf49d7b766 | ||
|
|
b9cbf8274e | ||
|
|
07ec530442 | ||
|
|
12cbbcd485 | ||
|
|
d2be23e354 | ||
|
|
ea1783504d | ||
|
|
8391f593d9 | ||
|
|
dc3ffdff08 | ||
|
|
ef6cf18aaa | ||
|
|
a31c8891ba | ||
|
|
36b65f3f30 | ||
|
|
dff2a5656f | ||
|
|
5507855bee | ||
|
|
7266821eae | ||
|
|
27e79c2222 | ||
|
|
d3f67947ef | ||
|
|
a0cd03caa4 | ||
|
|
850125b8ab | ||
|
|
6b9b9b544b | ||
|
|
45e3f776cf | ||
|
|
1a00998357 | ||
|
|
ac02592c13 | ||
|
|
52d3115ad6 | ||
|
|
97492fcb29 | ||
|
|
1d39235a45 | ||
|
|
15dc89fe2f | ||
|
|
e27e4309da | ||
|
|
7f733fdf34 | ||
|
|
e190ba82b4 | ||
|
|
f2f99833a6 | ||
|
|
5daf874f6c | ||
|
|
8beb7848a2 | ||
|
|
c7313f519f | ||
|
|
43a3e6d984 | ||
|
|
0bafdfd43a | ||
|
|
3fc7b7573d | ||
|
|
8fc213a134 | ||
|
|
eb96d48230 | ||
|
|
4ff6590e74 | ||
|
|
b8cac31e85 | ||
|
|
c3d698bcac | ||
|
|
28da8ccacf | ||
|
|
00b1d893e2 | ||
|
|
4a1630b7ba | ||
|
|
7ea048f5bd | ||
|
|
bd3895e6c1 | ||
|
|
71200ca5f3 | ||
|
|
00456fe62c | ||
|
|
269b61d6c4 | ||
|
|
b23d62190d | ||
|
|
113131a2b3 | ||
|
|
d4436acea3 | ||
|
|
fc581e3d3d | ||
|
|
83cdbec1d3 | ||
|
|
9f237c2d1a | ||
|
|
cfed10bbac | ||
|
|
67cfe69f38 | ||
|
|
94f83a92b7 | ||
|
|
738d9186a6 | ||
|
|
1b494389a6 | ||
|
|
4588d1db08 | ||
|
|
8c1f6f3014 | ||
|
|
abb49664f9 | ||
|
|
c0fc298082 | ||
|
|
32af35492d | ||
|
|
ad58952a32 | ||
|
|
e05816419e | ||
|
|
3b0feec801 | ||
|
|
688fd5725d | ||
|
|
9c7f07979b | ||
|
|
22f7985d20 | ||
|
|
675b9df44c | ||
|
|
af0b06ff28 | ||
|
|
a71a984a03 | ||
|
|
f4231dd890 | ||
|
|
cfaf2d26a5 | ||
|
|
43197b3099 | ||
|
|
3c30a2fc3d | ||
|
|
4c31b25110 | ||
|
|
a5ef85c676 | ||
|
|
b747cd339a | ||
|
|
8e7ce7c814 | ||
|
|
a4b75b0132 | ||
|
|
453845dd20 | ||
|
|
33ff286635 | ||
|
|
a45c3efa38 | ||
|
|
0925d41db6 | ||
|
|
c63f92d1ea | ||
|
|
e249937457 | ||
|
|
645affad93 | ||
|
|
77c2ab3822 | ||
|
|
6aa4940e2b | ||
|
|
78ec4046cc | ||
|
|
5604fa23a8 | ||
|
|
41f3146c47 | ||
|
|
e395d6e0e0 | ||
|
|
99c29c5e61 | ||
|
|
862af9cbae | ||
|
|
6c0a281ac2 | ||
|
|
dcec480f08 | ||
|
|
6e11a66cb0 | ||
|
|
b31abab595 | ||
|
|
ff23f320ac | ||
|
|
2d55fb3443 | ||
|
|
9f3a1f1e7e | ||
|
|
a8394baa1a | ||
|
|
0533ddcc3e | ||
|
|
2825560c1f | ||
|
|
1497944eff | ||
|
|
bda437985e | ||
|
|
4f024a0974 | ||
|
|
3d2cf3f6b4 | ||
|
|
0cd33120cf | ||
|
|
c5f4e0a268 | ||
|
|
aaafb59976 | ||
|
|
06e3221c0f | ||
|
|
120768c74b | ||
|
|
864c62b6e0 | ||
|
|
854d1c0afa | ||
|
|
ae8fd0c2d4 | ||
|
|
81d23aafab | ||
|
|
7bc26d5e40 | ||
|
|
fedf0ef7ce | ||
|
|
bfefe5e80f | ||
|
|
f76b14dd83 | ||
|
|
06947ef9d3 | ||
|
|
8dc8d6f367 | ||
|
|
31ed6254db | ||
|
|
88d8a409bb | ||
|
|
c976557346 | ||
|
|
6cd92e1278 | ||
|
|
dd41c319ee | ||
|
|
0501f12017 | ||
|
|
2176785370 | ||
|
|
ad866e44f5 | ||
|
|
b28146aa47 | ||
|
|
390cf2c16c | ||
|
|
586a1e347d | ||
|
|
08b4bdada1 | ||
|
|
0f357c24a7 | ||
|
|
f887aca66f | ||
|
|
ff6487caf3 | ||
|
|
aa146613ac | ||
|
|
dadabd899d | ||
|
|
2f790c6503 | ||
|
|
120dcdac54 | ||
|
|
a95aae22ab | ||
|
|
64010672eb | ||
|
|
f9640fb99e | ||
|
|
1614855353 | ||
|
|
f9a1fb8d3f | ||
|
|
2e32688ad6 | ||
|
|
b24011cd6c | ||
|
|
1cf40a7d7a | ||
|
|
6d8d4b59cc | ||
|
|
f4e329f5de | ||
|
|
0eb86fd4b6 | ||
|
|
a284275ffe | ||
|
|
a8317177c6 | ||
|
|
df7fab7e03 | ||
|
|
7d0d01211b | ||
|
|
8b9ae1c1b8 | ||
|
|
844919cfda | ||
|
|
d01bc09b5b | ||
|
|
e55de4bf8d | ||
|
|
b6b3e7f492 | ||
|
|
4ce0bbe1c0 | ||
|
|
d2b5a7362e | ||
|
|
66e3c90655 | ||
|
|
b508ccab08 | ||
|
|
a138e9bde4 | ||
|
|
822a4310cd | ||
|
|
d0399eb902 | ||
|
|
86b780aa2e | ||
|
|
db6c70215a | ||
|
|
c55e1ac99c | ||
|
|
a60ce80141 | ||
|
|
acb1929b49 | ||
|
|
1ab9170a9b | ||
|
|
0e8e725f59 | ||
|
|
0c63a5aba4 | ||
|
|
831bbef9e1 | ||
|
|
6b7c610676 | ||
|
|
092a6b922e | ||
|
|
f2ced978c9 | ||
|
|
213c70e00d | ||
|
|
dc014e9b1d | ||
|
|
417f5c3f0f | ||
|
|
5365d1d1fd | ||
|
|
9c0777991b | ||
|
|
c61ba5f050 | ||
|
|
e10445807c | ||
|
|
3bc50c1c3b | ||
|
|
15b383886e | ||
|
|
91d1ba6713 | ||
|
|
4cb516d8b1 | ||
|
|
ecee86cc6d | ||
|
|
5500792ed3 | ||
|
|
51b0231f68 | ||
|
|
b55140d50a | ||
|
|
43af999d41 | ||
|
|
64b41ffb8e | ||
|
|
0e8bf56284 | ||
|
|
f2c9719c23 | ||
|
|
fb3ddb035c | ||
|
|
390208d16a | ||
|
|
4963f8401a | ||
|
|
9ce20d50ac | ||
|
|
717781655f | ||
|
|
4ffed5edf2 | ||
|
|
21ab1b7e06 | ||
|
|
e07c98b418 | ||
|
|
20eaf1455d | ||
|
|
6e75a13a90 | ||
|
|
d970bd5830 | ||
|
|
2652ece827 | ||
|
|
5b95ff5ff3 | ||
|
|
50ed22c63c | ||
|
|
e0af565824 | ||
|
|
b96285a56c | ||
|
|
49accf9fc8 | ||
|
|
932aa87d87 | ||
|
|
c1c5c67b36 | ||
|
|
a5a622cf92 | ||
|
|
f04a199f4c | ||
|
|
70da3e287d | ||
|
|
57d0e12b1f | ||
|
|
e2eefe350d | ||
|
|
e5b0094f7d | ||
|
|
3fe872c125 | ||
|
|
3739710fba | ||
|
|
65593c5200 | ||
|
|
46cc218694 | ||
|
|
c08ec3e52a | ||
|
|
9420c22298 | ||
|
|
a05e116ceb | ||
|
|
99b04827d1 | ||
|
|
40027c2266 | ||
|
|
6db2aa5354 | ||
|
|
9d8a4f14e3 | ||
|
|
6b1180caa4 | ||
|
|
e5ea6b242d | ||
|
|
0638de200b | ||
|
|
8dc6500649 | ||
|
|
bb2697a1d8 | ||
|
|
65d9df9c54 | ||
|
|
14d91c6bec | ||
|
|
3bd28b28ab | ||
|
|
f1601d01ea | ||
|
|
c27cc7ddf1 | ||
|
|
f58940d92d | ||
|
|
a1b680b722 | ||
|
|
56364d187a | ||
|
|
0023c5753a | ||
|
|
436c466e2d | ||
|
|
ffe1f9c7a4 | ||
|
|
0b4701f96d | ||
|
|
93ea03972b | ||
|
|
c9fcc22875 | ||
|
|
32e302b1b6 | ||
|
|
844d8fbe08 | ||
|
|
b60a99008e | ||
|
|
4c6959191d | ||
|
|
4a50eb2e05 | ||
|
|
661fd3446d | ||
|
|
02a997e28c | ||
|
|
221b4329c6 | ||
|
|
6930357351 | ||
|
|
28ebace7c6 | ||
|
|
486d0ae25a | ||
|
|
41ba12b1d7 | ||
|
|
b525be4680 | ||
|
|
87389c7ca6 | ||
|
|
f372e7ae11 | ||
|
|
018fe182d3 | ||
|
|
d0b437bc74 | ||
|
|
50a5abe321 | ||
|
|
9dcdf84824 | ||
|
|
880e4dfb3a | ||
|
|
c6e266b08f | ||
|
|
3eed879fd2 | ||
|
|
07b6f54990 | ||
|
|
bd07c5338a | ||
|
|
31279a0cdc | ||
|
|
487bf288e5 | ||
|
|
ad93ad55cc | ||
|
|
9e7ca719d8 | ||
|
|
b7b0ca40b0 | ||
|
|
1dcc6db079 | ||
|
|
10422caa92 | ||
|
|
319127f88a | ||
|
|
b4cf1ba041 | ||
|
|
0a32d13cb0 | ||
|
|
6d34f53e43 | ||
|
|
b3cc75fe46 | ||
|
|
409fab31e6 | ||
|
|
df6ec644e9 | ||
|
|
101cf4db2c | ||
|
|
9c3c239162 | ||
|
|
b22d1837be | ||
|
|
7ed2efd584 | ||
|
|
eaa9003aea | ||
|
|
9c4d4ccb70 | ||
|
|
9f8ca93a57 | ||
|
|
3aa97c7e0f | ||
|
|
38d72bc672 | ||
|
|
229d814866 | ||
|
|
5cc1ef9609 | ||
|
|
8913ef8929 | ||
|
|
71ee5f6b4b | ||
|
|
07000fd86f | ||
|
|
19d26f148f | ||
|
|
47c20911c3 | ||
|
|
a07211253c | ||
|
|
2f85a417d6 | ||
|
|
ee3b7deb07 | ||
|
|
2664e30a8b | ||
|
|
3268081d1f | ||
|
|
88035429bb | ||
|
|
25c7d98d2c | ||
|
|
4422530fe4 | ||
|
|
17b3fc044d | ||
|
|
bbe1b58437 | ||
|
|
546c95bdf6 | ||
|
|
faac82287f | ||
|
|
0fdfd8919f | ||
|
|
55fa6024db | ||
|
|
a1e3feda4f | ||
|
|
46a975b966 | ||
|
|
0508c54799 | ||
|
|
89e776281f | ||
|
|
1188da3c21 | ||
|
|
d81c944e45 | ||
|
|
6750b90671 | ||
|
|
723c9ae556 | ||
|
|
1d38ca64c7 | ||
|
|
547ed38855 | ||
|
|
8da7b0ee91 | ||
|
|
1da9e93241 | ||
|
|
3200f1c6ca | ||
|
|
a25ffe0899 | ||
|
|
7b04023f54 | ||
|
|
1c79db2303 | ||
|
|
b1fc23af08 | ||
|
|
4280c3513a | ||
|
|
9eab840f37 | ||
|
|
ce31353a7a | ||
|
|
f22684b5e8 | ||
|
|
12459aae1e | ||
|
|
fd0a0de4b2 | ||
|
|
0e3ead62fb | ||
|
|
8b36cddd9c | ||
|
|
415e826a73 | ||
|
|
6a0958f9c1 | ||
|
|
2788af6922 | ||
|
|
49e4e8e2fd | ||
|
|
63585dfea6 | ||
|
|
27035770d7 | ||
|
|
f2a70194c8 | ||
|
|
8bdd8258be | ||
|
|
aa0135515c | ||
|
|
9a0fe44acc | ||
|
|
b74b382e30 | ||
|
|
180c42b9d5 | ||
|
|
ec3dcaa287 | ||
|
|
ac6260bf0d | ||
|
|
1f54d5de0e | ||
|
|
2c335e37b0 | ||
|
|
4afed0067e | ||
|
|
49719a2e8c | ||
|
|
197bdf8228 | ||
|
|
9890fbd57a | ||
|
|
72ae296db0 | ||
|
|
51ad4b2b06 | ||
|
|
80bc3e3455 | ||
|
|
0fe9de4f09 | ||
|
|
958d17831c | ||
|
|
6b6991bf6a | ||
|
|
bc9b36165c | ||
|
|
5fdf39edb3 | ||
|
|
00c6a8905d | ||
|
|
6ad037e469 | ||
|
|
aaa56f7c02 | ||
|
|
f6c0d93c47 | ||
|
|
cd3b5b7cea | ||
|
|
2bdb0575ad | ||
|
|
e095b245e2 | ||
|
|
b7f2f315e2 | ||
|
|
0bd543b57b | ||
|
|
7c4b1daed6 | ||
|
|
66203b0685 | ||
|
|
a5f23035ae | ||
|
|
0ff64751e8 | ||
|
|
670ebee06d | ||
|
|
53aadde343 | ||
|
|
699550c879 | ||
|
|
58111b3ba1 | ||
|
|
44d837c1eb | ||
|
|
689dd72363 | ||
|
|
0f34966f43 | ||
|
|
50baf5fd50 | ||
|
|
48fb8f00ca | ||
|
|
a30e91052e | ||
|
|
abd86c676b | ||
|
|
df5f6c692f | ||
|
|
3f410ea688 | ||
|
|
c29b5f2fef | ||
|
|
471f6cb5e5 | ||
|
|
1758e18bd2 | ||
|
|
40def352d9 | ||
|
|
0e965f73b7 | ||
|
|
ecaab49c08 | ||
|
|
f671b89da5 | ||
|
|
e4b2988864 | ||
|
|
8ea3963f62 | ||
|
|
99b192c4bc | ||
|
|
94c838dfde | ||
|
|
a9034de9cd | ||
|
|
69833f3d72 | ||
|
|
6671414da5 | ||
|
|
a4a075655d | ||
|
|
9aad67ae04 | ||
|
|
63f813d8ad | ||
|
|
e35c4b1461 | ||
|
|
9ec781fb41 | ||
|
|
064a554985 | ||
|
|
8aef955c77 | ||
|
|
492f4b6480 | ||
|
|
69cf9b34b1 | ||
|
|
d2b11a9ba4 | ||
|
|
66bbfbbb3c | ||
|
|
9295e2436d | ||
|
|
615383e665 | ||
|
|
d1977f148e | ||
|
|
9d70c6ad9c | ||
|
|
c8101d481e | ||
|
|
3ac6b3c1fb | ||
|
|
d0db80335b | ||
|
|
f0defa1799 | ||
|
|
f73c569f9a | ||
|
|
6819743850 | ||
|
|
f28f2c6e8c | ||
|
|
10b34965bd | ||
|
|
9e7fd7f74f | ||
|
|
b0d5ca2830 | ||
|
|
6273929184 | ||
|
|
9e9266712a | ||
|
|
6acb074993 | ||
|
|
986a8815ff | ||
|
|
add96e9c04 | ||
|
|
289d0cac63 | ||
|
|
90389996d1 | ||
|
|
d28bfee704 | ||
|
|
cc32844a9c | ||
|
|
6f3a0bdc55 | ||
|
|
06601ba5df | ||
|
|
928be8d8e7 | ||
|
|
7fabb182f1 | ||
|
|
815e12be66 | ||
|
|
7c2e6875c6 | ||
|
|
8de321c780 | ||
|
|
99f6492f29 | ||
|
|
bb135f041a | ||
|
|
a45869be49 | ||
|
|
26b7d5fa8b | ||
|
|
9ef4a92613 | ||
|
|
86cc38cd69 | ||
|
|
19a4140f7d | ||
|
|
62284c9218 | ||
|
|
6291804775 | ||
|
|
0b05b4b7d8 | ||
|
|
490ad97f7b | ||
|
|
03ec852804 | ||
|
|
1ef0e1c078 | ||
|
|
b371a73644 | ||
|
|
e859e9efc0 | ||
|
|
3b82ef5fde | ||
|
|
17bb6aac05 | ||
|
|
44e4af0f02 | ||
|
|
9d34f3d4e6 | ||
|
|
e05e8788d6 | ||
|
|
e926aad568 | ||
|
|
0559bac7a9 | ||
|
|
c2ed5b68a1 | ||
|
|
03f1cf8ec4 | ||
|
|
cc1a3ee93f | ||
|
|
869db920a9 | ||
|
|
6d27e5d0f8 | ||
|
|
32372c68cd | ||
|
|
fb3c43ef6a | ||
|
|
0af841cfd4 | ||
|
|
4a24923edb | ||
|
|
33cd18e109 | ||
|
|
84f6564cd2 | ||
|
|
f61a82d0eb | ||
|
|
88f3186839 | ||
|
|
541b73e322 | ||
|
|
89476fb54e | ||
|
|
1a56d10bef | ||
|
|
b3c71fef9e | ||
|
|
6696eca847 | ||
|
|
d942ed415b | ||
|
|
fb7535286c | ||
|
|
2c51252c09 | ||
|
|
6a5bf822ab | ||
|
|
c6529f6bf7 | ||
|
|
481cedb871 | ||
|
|
78b84be3fd | ||
|
|
3235cfd288 | ||
|
|
899db8fe0b | ||
|
|
08ba49ed46 | ||
|
|
0a8b08ebec | ||
|
|
78503a9380 | ||
|
|
67658876d5 | ||
|
|
d361cffc75 | ||
|
|
b9cd78fde9 | ||
|
|
42451ece28 | ||
|
|
f5963ecc30 | ||
|
|
74e3bfe6ce | ||
|
|
2b455ecfc3 | ||
|
|
a1802ff043 | ||
|
|
5b7d6e2e1f | ||
|
|
ac8ecdb7f3 | ||
|
|
0af5bb05fc | ||
|
|
35fc44e183 | ||
|
|
aabe06eb3f | ||
|
|
ef7000a29d | ||
|
|
bec47ec814 | ||
|
|
b29dc6052e | ||
|
|
3afd7a9a69 | ||
|
|
3305385311 | ||
|
|
ce5cfca43d | ||
|
|
08a3b64483 | ||
|
|
9fa56531c6 | ||
|
|
459316f102 | ||
|
|
554aa77707 | ||
|
|
4eb1490d80 | ||
|
|
670efb196e | ||
|
|
8b68729041 | ||
|
|
3b299aa5b4 | ||
|
|
14f267da47 | ||
|
|
059456571d | ||
|
|
f7571f83c8 | ||
|
|
bd42a03cf0 | ||
|
|
66c7997ed0 | ||
|
|
9cbefdda28 | ||
|
|
389a44dfc1 | ||
|
|
bc30541b9c | ||
|
|
8fa5217318 | ||
|
|
7ad1c68249 | ||
|
|
ef0baea3ad | ||
|
|
69b1685280 | ||
|
|
508e8b04a1 | ||
|
|
365a5f182c | ||
|
|
bbd632fa34 | ||
|
|
488078ac04 | ||
|
|
a9b57d4187 | ||
|
|
2d887d0a7e | ||
|
|
cd9a3a68ec | ||
|
|
d73450d8fa | ||
|
|
5eb7be054e | ||
|
|
70e1fe5a4b | ||
|
|
75015ce466 | ||
|
|
c2b9ebd4b9 | ||
|
|
7c117f22a7 | ||
|
|
f278de3a8c | ||
|
|
b584f8bc46 | ||
|
|
b08e98d0ab | ||
|
|
de5d83aedd | ||
|
|
0b48863a51 | ||
|
|
5f66874d3e | ||
|
|
79ba2af699 |
@@ -0,0 +1,3 @@
|
||||
.DS_Store
|
||||
Frameworks
|
||||
Build
|
||||
@@ -0,0 +1,12 @@
|
||||
[submodule "External/narwhal"]
|
||||
path = External/narwhal
|
||||
url = git://github.com/tlrobinson/narwhal.git
|
||||
[submodule "External/jack"]
|
||||
path = External/jack
|
||||
url = git://github.com/tlrobinson/jack.git
|
||||
[submodule "External/browserjs"]
|
||||
path = External/browserjs
|
||||
url = git://github.com/tlrobinson/browserjs.git
|
||||
[submodule "External/ojunit"]
|
||||
path = External/ojunit
|
||||
url = git://github.com/280north/ojunit.git
|
||||
@@ -24,7 +24,12 @@
|
||||
@import "CPAlert.j"
|
||||
@import "CPAnimation.j"
|
||||
@import "CPApplication.j"
|
||||
@import "CPBezierPath.j"
|
||||
@import "CPButton.j"
|
||||
@import "CPButtonBar.j"
|
||||
@import "CPCheckBox.j"
|
||||
@import "CPCib.j"
|
||||
@import "CPCibLoading.j"
|
||||
@import "CPClipView.j"
|
||||
@import "CPCollectionView.j"
|
||||
@import "CPColor.j"
|
||||
@@ -49,6 +54,7 @@
|
||||
@import "CPPasteboard.j"
|
||||
@import "CPPopUpButton.j"
|
||||
@import "CPProgressIndicator.j"
|
||||
@import "CPRadio.j"
|
||||
@import "CPResponder.j"
|
||||
@import "CPScrollView.j"
|
||||
@import "CPScroller.j"
|
||||
@@ -58,6 +64,8 @@
|
||||
@import "CPSlider.j"
|
||||
@import "CPSplitView.j"
|
||||
@import "CPTabView.j"
|
||||
@import "CPTableColumn.j"
|
||||
@import "CPTableView.j"
|
||||
@import "CPTextField.j"
|
||||
@import "CPToolbar.j"
|
||||
@import "CPToolbarItem.j"
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>AppKit</string>
|
||||
<key>Targets</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>Name</key>
|
||||
<string>AppKit</string>
|
||||
<key>Excluded</key>
|
||||
<array>
|
||||
<string>CPOutlineView.j</string>
|
||||
<string>CPTableColumn.j</string>
|
||||
<string>CPTableView.j</string>
|
||||
<!-- These get compiled into CGContext -->
|
||||
<string>CoreGraphics/CGContextCanvas.j</string>
|
||||
<string>CoreGraphics/CGContextVML.j</string>
|
||||
</array>
|
||||
<key>Flags</key>
|
||||
<string>-DPLATFORM_DOM</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Name</key>
|
||||
<string>AppKit-Rhino</string>
|
||||
<key>Excluded</key>
|
||||
<array>
|
||||
<string>CPOutlineView.j</string>
|
||||
<string>CPTableColumn.j</string>
|
||||
<string>CPTableView.j</string>
|
||||
<!-- These get compiled into CGContext -->
|
||||
<string>CoreGraphics/CGContextCanvas.j</string>
|
||||
<string>CoreGraphics/CGContextVML.j</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>Configurations</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>Name</key>
|
||||
<string>Debug</string>
|
||||
<key>Flags</key>
|
||||
<string>-DDEBUG -g</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Name</key>
|
||||
<string>Release</string>
|
||||
<key>Flags</key>
|
||||
<string>-O</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -56,7 +56,9 @@ var CPAlertWarningImage,
|
||||
CPAlertInformationImage,
|
||||
CPAlertErrorImage;
|
||||
|
||||
/*
|
||||
/*!
|
||||
@ingroup appkit
|
||||
|
||||
CPAlert is an alert panel that can be displayed modally to present the
|
||||
user with a message and one or more options.
|
||||
|
||||
@@ -84,7 +86,10 @@ var CPAlertWarningImage,
|
||||
CPImageView _alertImageView;
|
||||
|
||||
CPAlertStyle _alertStyle;
|
||||
CPString _windowTitle;
|
||||
int _windowStyle;
|
||||
int _buttonCount;
|
||||
CPArray _buttons;
|
||||
|
||||
id _delegate;
|
||||
}
|
||||
@@ -97,13 +102,13 @@ var CPAlertWarningImage,
|
||||
var bundle = [CPBundle bundleForClass:[self class]];
|
||||
|
||||
CPAlertWarningImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-warning.png"]
|
||||
size:CGSizeMake(32,32)];
|
||||
size:CGSizeMake(32.0, 32.0)];
|
||||
|
||||
CPAlertInformationImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-information.png"]
|
||||
size:CGSizeMake(32,32)];
|
||||
size:CGSizeMake(32.0, 32.0)];
|
||||
|
||||
CPAlertErrorImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-error.png"]
|
||||
size:CGSizeMake(32,32)];
|
||||
size:CGSizeMake(32.0, 32.0)];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -116,27 +121,76 @@ var CPAlertWarningImage,
|
||||
if (self)
|
||||
{
|
||||
_buttonCount = 0;
|
||||
_buttons = [CPArray array];
|
||||
_alertStyle = CPWarningAlertStyle;
|
||||
|
||||
_alertPanel = [[CPPanel alloc] initWithContentRect:CGRectMake(0, 0, 300, 150) styleMask:CPHUDBackgroundWindowMask|CPTitledWindowMask];
|
||||
[_alertPanel setFloatingPanel:YES];
|
||||
[_alertPanel center];
|
||||
|
||||
_messageLabel = [[CPTextField alloc] initWithFrame: CGRectMake(70,10, 200, 100)];
|
||||
[_messageLabel setFont: [CPFont fontWithName: "Helvetica Neue" size: 12.0]];
|
||||
[_messageLabel setTextColor: [CPColor whiteColor]];
|
||||
_messageLabel = [[CPTextField alloc] initWithFrame:CGRectMake(57.0, 10.0, 220.0, 80.0)];
|
||||
[_messageLabel setFont:[CPFont systemFontOfSize:12.0]];
|
||||
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
|
||||
|
||||
[[_alertPanel contentView] addSubview: _messageLabel];
|
||||
|
||||
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMake(25,12,32,32)];
|
||||
[_messageLabel setAlignment:CPJustifiedTextAlignment];
|
||||
|
||||
[[_alertPanel contentView] addSubview: _alertImageView];
|
||||
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMake(15.0, 12.0, 32.0, 32.0)];
|
||||
|
||||
[self setWindowStyle:nil];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the window appearance.
|
||||
@param styleMask - Either CPHUDBackgroundWindowMask or nil for standard.
|
||||
*/
|
||||
- (void)setWindowStyle:(int)styleMask
|
||||
{
|
||||
_windowStyle = styleMask;
|
||||
|
||||
_alertPanel = [[CPPanel alloc] initWithContentRect:CGRectMake(0.0, 0.0, 300.0, 130.0) styleMask:styleMask ? styleMask | CPTitledWindowMask : CPTitledWindowMask];
|
||||
[_alertPanel setFloatingPanel:YES];
|
||||
[_alertPanel center];
|
||||
|
||||
[_messageLabel setTextColor:(styleMask == CPHUDBackgroundWindowMask) ? [CPColor whiteColor] : [CPColor blackColor]];
|
||||
|
||||
var count = [_buttons count];
|
||||
for(var i=0; i < count; i++)
|
||||
{
|
||||
var button = _buttons[i];
|
||||
|
||||
[button setFrameSize:CGSizeMake([button frame].size.width, (styleMask == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)];
|
||||
[button setBezelStyle:(styleMask == CPHUDBackgroundWindowMask) ? CPHUDBezelStyle : CPRoundedBezelStyle];
|
||||
|
||||
[[_alertPanel contentView] addSubview:button];
|
||||
}
|
||||
|
||||
[[_alertPanel contentView] addSubview:_messageLabel];
|
||||
[[_alertPanel contentView] addSubview:_alertImageView];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the window's title. If this is not defined, a default title based on your warning level will be used.
|
||||
@param aTitle the title to use in place of the default. Set to nil to use default.
|
||||
*/
|
||||
- (void)setTitle:(CPString)aTitle
|
||||
{
|
||||
_windowTitle = aTitle;
|
||||
}
|
||||
|
||||
/*!
|
||||
Gets the window's title.
|
||||
*/
|
||||
- (CPString)title
|
||||
{
|
||||
return _windowTitle;
|
||||
}
|
||||
|
||||
/*!
|
||||
Gets the window's style.
|
||||
*/
|
||||
- (int)windowStyle
|
||||
{
|
||||
return _windowStyle;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the receiver’s delegate.
|
||||
@param delegate - Delegate for the alert. nil removes the delegate.
|
||||
@@ -197,17 +251,21 @@ var CPAlertWarningImage,
|
||||
*/
|
||||
- (void)addButtonWithTitle:(CPString)title
|
||||
{
|
||||
var button = [[CPButton alloc] initWithFrame:CGRectMake(190 - (_buttonCount * 90),80,80,18)];
|
||||
var button = [[CPButton alloc] initWithFrame:CGRectMake(200.0 - (_buttonCount * 90.0), 98.0, 80.0, (_windowStyle == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)];
|
||||
|
||||
[button setTitle:title];
|
||||
[button setTarget:self];
|
||||
[button setTag:_buttonCount];
|
||||
[button setBezelStyle:CPHUDBezelStyle];
|
||||
[button setAction:@selector(_notifyDelegate:)];
|
||||
|
||||
[button setBezelStyle:(_windowStyle == CPHUDBackgroundWindowMask) ? CPHUDBezelStyle : CPRoundRectBezelStyle];
|
||||
[[_alertPanel contentView] addSubview:button];
|
||||
|
||||
if (_buttonCount == 0)
|
||||
[_alertPanel setDefaultButton:button];
|
||||
|
||||
_buttonCount++;
|
||||
[_buttons addObject:button];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -217,16 +275,23 @@ var CPAlertWarningImage,
|
||||
*/
|
||||
- (void)runModal
|
||||
{
|
||||
var theTitle;
|
||||
|
||||
switch (_alertStyle)
|
||||
{
|
||||
case CPWarningAlertStyle: [_alertImageView setImage:CPAlertWarningImage];
|
||||
break;
|
||||
case CPInformationalAlertStyle: [_alertImageView setImage:CPAlertInformationImage];
|
||||
break;
|
||||
case CPCriticalAlertStyle: [_alertImageView setImage:CPAlertErrorImage];
|
||||
break;
|
||||
case CPWarningAlertStyle: [_alertImageView setImage:CPAlertWarningImage];
|
||||
theTitle = @"Warning";
|
||||
break;
|
||||
case CPInformationalAlertStyle: [_alertImageView setImage:CPAlertInformationImage];
|
||||
theTitle = @"Information";
|
||||
break;
|
||||
case CPCriticalAlertStyle: [_alertImageView setImage:CPAlertErrorImage];
|
||||
theTitle = @"Error";
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
[_alertPanel setTitle:_windowTitle ? _windowTitle : theTitle];
|
||||
|
||||
[CPApp runModalForWindow:_alertPanel];
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,10 @@ CPAnimationLinear = 3;
|
||||
|
||||
ACTUAL_FRAME_RATE = 0;
|
||||
|
||||
/*! @class CPAnimation
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPAnimation
|
||||
|
||||
Manages an animation. Contains timing and progress information.
|
||||
|
||||
@par Delegate Methods
|
||||
@@ -76,7 +79,7 @@ ACTUAL_FRAME_RATE = 0;
|
||||
*/
|
||||
@implementation CPAnimation : CPObject
|
||||
{
|
||||
CPTimeInterval _startTime;
|
||||
CPTimeInterval _lastTime;
|
||||
CPTimeInterval _duration;
|
||||
|
||||
CPAnimationCurve _animationCurve;
|
||||
@@ -101,6 +104,7 @@ ACTUAL_FRAME_RATE = 0;
|
||||
|
||||
if (self)
|
||||
{
|
||||
_progress = 0.0;
|
||||
_duration = MAX(0.0, aDuration);
|
||||
_animationCurve = anAnimationCurve;
|
||||
_frameRate = 60.0;
|
||||
@@ -116,10 +120,6 @@ ACTUAL_FRAME_RATE = 0;
|
||||
*/
|
||||
- (void)setAnimationCurve:(CPAnimationCurve)anAnimationCurve
|
||||
{
|
||||
_animationCurve = anAnimationCurve;
|
||||
|
||||
var timingFunctionName = kCAMediaTimingFunctionLinear;
|
||||
|
||||
switch (_animationCurve)
|
||||
{
|
||||
case CPAnimationEaseInOut: timingFunctionName = kCAMediaTimingFunctionEaseInEaseOut;
|
||||
@@ -130,12 +130,16 @@ ACTUAL_FRAME_RATE = 0;
|
||||
|
||||
case CPAnimationEaseOut: timingFunctionName = kCAMediaTimingFunctionEaseOut;
|
||||
break;
|
||||
|
||||
case CPAnimationLinear: timingFunctionName = kCAMediaTimingFunctionLinear;
|
||||
break;
|
||||
|
||||
default: [CPException raise:CPInvalidArgumentException
|
||||
reason:"Invalid value provided for animation curve"];
|
||||
break;
|
||||
}
|
||||
|
||||
_animationCurve = anAnimationCurve;
|
||||
_timingFunction = [CAMediaTimingFunction functionWithName:timingFunctionName];
|
||||
}
|
||||
|
||||
@@ -217,9 +221,11 @@ ACTUAL_FRAME_RATE = 0;
|
||||
if (_timer || _delegate && [_delegate respondsToSelector:@selector(animationShouldStart)] && ![_delegate animationShouldStart:self])
|
||||
return;
|
||||
|
||||
_progress = 0.0;
|
||||
if (_progress === 1.0)
|
||||
_progress = 0.0;
|
||||
|
||||
ACTUAL_FRAME_RATE = 0;
|
||||
_startTime = new Date();
|
||||
_lastTime = new Date();
|
||||
|
||||
_timer = [CPTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(animationTimerDidFire:) userInfo:nil repeats:YES];
|
||||
}
|
||||
@@ -229,8 +235,10 @@ ACTUAL_FRAME_RATE = 0;
|
||||
*/
|
||||
- (void)animationTimerDidFire:(CPTimer)aTimer
|
||||
{
|
||||
var elapsed = new Date() - _startTime,
|
||||
progress = MIN(1.0, 1.0 - (_duration - elapsed / 1000.0) / _duration);
|
||||
var currentTime = new Date(),
|
||||
progress = MIN(1.0, [self currentProgress] + (currentTime - _lastTime) / (_duration * 1000.0));
|
||||
|
||||
_lastTime = currentTime;
|
||||
|
||||
++ACTUAL_FRAME_RATE;
|
||||
|
||||
@@ -244,7 +252,6 @@ ACTUAL_FRAME_RATE = 0;
|
||||
if ([_delegate respondsToSelector:@selector(animationDidEnd:)])
|
||||
[_delegate animationDidEnd:self];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
@@ -27,7 +27,10 @@
|
||||
@import "CPMenu.j"
|
||||
@import "CPResponder.j"
|
||||
@import "CPDocumentController.j"
|
||||
@import "CPThemeBlend.j"
|
||||
|
||||
var CPMainCibFile = @"CPMainCibFile",
|
||||
CPMainCibFileHumanFriendly = @"Main cib file base name";
|
||||
|
||||
CPApp = nil;
|
||||
|
||||
@@ -38,7 +41,9 @@ CPRunStoppedResponse = -1000;
|
||||
CPRunAbortedResponse = -1001;
|
||||
CPRunContinuesResponse = -1002;
|
||||
|
||||
/*! @class CPApplication
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPApplication
|
||||
|
||||
CPApplication is THE way to start up the Cappucino framework for your application to use.
|
||||
Every GUI application has exactly one instance of CPApplication (or of a custom subclass of
|
||||
@@ -81,6 +86,7 @@ CPRunContinuesResponse = -1002;
|
||||
|
||||
CPDictionary _namedArgs;
|
||||
CPArray _args;
|
||||
CPString _fullArgsString;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -135,19 +141,19 @@ CPRunContinuesResponse = -1002;
|
||||
[_mainMenu addItem:openMenuItem];
|
||||
|
||||
var saveMenu = [[CPMenu alloc] initWithTitle:@"Save"],
|
||||
saveMenuItem = [[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:@""];
|
||||
saveMenuItem = [[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:nil];
|
||||
|
||||
[saveMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Save.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||
[saveMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/SaveHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||
|
||||
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:@"S"]];
|
||||
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save As" action:@selector(saveDocumentAs:) keyEquivalent:@""]];
|
||||
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save As" action:@selector(saveDocumentAs:) keyEquivalent:nil]];
|
||||
|
||||
[saveMenuItem setSubmenu:saveMenu];
|
||||
|
||||
[_mainMenu addItem:saveMenuItem];
|
||||
|
||||
var editMenuItem = [[CPMenuItem alloc] initWithTitle:@"Edit" action:nil keyEquivalent:@""],
|
||||
var editMenuItem = [[CPMenuItem alloc] initWithTitle:@"Edit" action:nil keyEquivalent:nil],
|
||||
editMenu = [[CPMenu alloc] initWithTitle:@"Edit"],
|
||||
|
||||
undoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Undo" action:@selector(undo:) keyEquivalent:CPUndoKeyEquivalent],
|
||||
@@ -305,7 +311,7 @@ CPRunContinuesResponse = -1002;
|
||||
_currentSession._state = aCode;
|
||||
_currentSession = _currentSession._previous;
|
||||
|
||||
if (aCode == CPRunAbortedResponse)
|
||||
// if (aCode == CPRunAbortedResponse)
|
||||
[self _removeRunModalLoop];
|
||||
}
|
||||
|
||||
@@ -315,7 +321,7 @@ CPRunContinuesResponse = -1002;
|
||||
var count = _eventListeners.length;
|
||||
|
||||
while (count--)
|
||||
if (_eventListeners[count]._callback == _CPRunModalLoop)
|
||||
if (_eventListeners[count]._callback === _CPRunModalLoop)
|
||||
{
|
||||
_eventListeners.splice(count, 1);
|
||||
|
||||
@@ -470,6 +476,16 @@ CPRunContinuesResponse = -1002;
|
||||
_mainMenu = aMenu;
|
||||
}
|
||||
|
||||
- (void)orderFrontStandardAboutPanel:(id)aSender
|
||||
{
|
||||
[self orderFrontStandardAboutPanelWithOptions:nil];
|
||||
}
|
||||
|
||||
- (void)orderFrontStandardAboutPanelWithOptions:(CPDictionary)aDictionary
|
||||
{
|
||||
// FIXME: Implement.
|
||||
}
|
||||
|
||||
// Posting Actions
|
||||
/*!
|
||||
Tries to perform the action with an argument. Performs
|
||||
@@ -485,12 +501,12 @@ CPRunContinuesResponse = -1002;
|
||||
if (!anAction)
|
||||
return NO;
|
||||
|
||||
if ([self tryToPerform:anAction with:anObject])
|
||||
if ([super tryToPerform:anAction with:anObject])
|
||||
return YES;
|
||||
|
||||
if([_delegate respondsToSelector:aSelector])
|
||||
if([_delegate respondsToSelector:anAction])
|
||||
{
|
||||
[_delegate performSelector:aSelector withObject:anObject];
|
||||
[_delegate performSelector:anAction withObject:anObject];
|
||||
|
||||
return YES;
|
||||
}
|
||||
@@ -663,9 +679,47 @@ CPRunContinuesResponse = -1002;
|
||||
|
||||
- (CPArray)arguments
|
||||
{
|
||||
if(_fullArgsString != window.location.hash)
|
||||
[self _reloadArguments];
|
||||
|
||||
return _args;
|
||||
}
|
||||
|
||||
- (void)setArguments:(CPArray)args
|
||||
{
|
||||
if(!args || args.length == 0)
|
||||
{
|
||||
_args = [];
|
||||
window.location.hash = @"#";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if([args class] != CPArray)
|
||||
args = [CPArray arrayWithObject:args];
|
||||
|
||||
_args = args;
|
||||
|
||||
var toEncode = [_args copy];
|
||||
for(var i=0, count = toEncode.length; i<count; i++)
|
||||
toEncode[i] = encodeURIComponent(toEncode[i]);
|
||||
|
||||
var hash = [toEncode componentsJoinedByString:@"/"];
|
||||
|
||||
window.location.hash = @"#" + hash;
|
||||
}
|
||||
|
||||
- (void)_reloadArguments
|
||||
{
|
||||
_fullArgsString = window.location.hash;
|
||||
var args = _fullArgsString.replace("#", "").split("/").slice(0);
|
||||
|
||||
for(var i=0, count = args.length; i<count; i++)
|
||||
args[i] = decodeURIComponent(args[i]);
|
||||
|
||||
_args = args;
|
||||
}
|
||||
|
||||
- (CPDictionary)namedArguments
|
||||
{
|
||||
return _namedArgs;
|
||||
@@ -686,18 +740,12 @@ var _CPEventListenerMake = function(anEventMask, aCallback)
|
||||
var _CPRunModalLoop = function(anEvent)
|
||||
{
|
||||
[CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO];
|
||||
|
||||
// FIXME: abortModal from event loop?
|
||||
|
||||
var theWindow = [anEvent window],
|
||||
modalSession = CPApp._currentSession;
|
||||
|
||||
if (theWindow == modalSession._window || [theWindow worksWhenModal])
|
||||
[theWindow sendEvent:anEvent];
|
||||
/*else
|
||||
[[session modalWindow] makeKeyAndOrderFront:]*/
|
||||
|
||||
if (modalSession._state != CPRunContinuesResponse)
|
||||
[CPApp _removeRunModalLoop];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -706,31 +754,27 @@ var _CPRunModalLoop = function(anEvent)
|
||||
@class CPApplication
|
||||
@return void
|
||||
*/
|
||||
|
||||
function CPApplicationMain(args, namedArgs)
|
||||
{
|
||||
var mainBundle = [CPBundle mainBundle],
|
||||
principalClass = [mainBundle principalClass];
|
||||
|
||||
|
||||
if (!principalClass)
|
||||
principalClass = [CPApplication class];
|
||||
|
||||
[principalClass sharedApplication];
|
||||
|
||||
//[NSBundle loadNibNamed:@"myMain" owner:NSApp];
|
||||
|
||||
|
||||
//FIXME?
|
||||
if (!args && !namedArgs)
|
||||
{
|
||||
var args = window.location.hash.replace("#", "").split("/").slice(0),
|
||||
var args = [CPApp arguments],
|
||||
searchParams = window.location.search.substring(1).split("&");
|
||||
namedArgs = [CPDictionary dictionary];
|
||||
|
||||
for(var i=0, count = args.length; i<count; i++)
|
||||
args[i] = decodeURIComponent(args[i]);
|
||||
|
||||
|
||||
if([args containsObject:"debug"])
|
||||
CPLogRegister(CPLogPopup);
|
||||
|
||||
|
||||
for(var i=0; i<searchParams.length; i++)
|
||||
{
|
||||
var index = searchParams[i].indexOf('=');
|
||||
@@ -740,9 +784,76 @@ function CPApplicationMain(args, namedArgs)
|
||||
[namedArgs setObject: searchParams[i].substring(index+1) forKey: searchParams[i].substring(0, index)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CPApp._args = args;
|
||||
CPApp._namedArgs = namedArgs;
|
||||
|
||||
|
||||
[_CPAppBootstrapper performActions];
|
||||
}
|
||||
|
||||
var _CPAppBootstrapperActions = nil;
|
||||
|
||||
@implementation _CPAppBootstrapper : CPObject
|
||||
{
|
||||
}
|
||||
|
||||
+ (void)actions
|
||||
{
|
||||
return [@selector(loadDefaultTheme), @selector(loadMainCibFile)];
|
||||
}
|
||||
|
||||
+ (void)performActions
|
||||
{
|
||||
if (!_CPAppBootstrapperActions)
|
||||
_CPAppBootstrapperActions = [self actions];
|
||||
|
||||
while (_CPAppBootstrapperActions.length)
|
||||
{
|
||||
var action = _CPAppBootstrapperActions.shift();
|
||||
|
||||
if (objj_msgSend(self, action))
|
||||
return;
|
||||
}
|
||||
|
||||
[CPApp run];
|
||||
}
|
||||
|
||||
+ (BOOL)loadDefaultTheme
|
||||
{
|
||||
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:[[CPBundle bundleForClass:[CPApplication class]] pathForResource:@"Aristo.blend"]];
|
||||
|
||||
[blend loadWithDelegate:self];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (void)blendDidFinishLoading:(CPBundle)aBundle
|
||||
{
|
||||
[CPTheme setDefaultTheme:[CPTheme themeNamed:@"Aristo"]];
|
||||
|
||||
[self performActions];
|
||||
}
|
||||
|
||||
+ (BOOL)loadMainCibFile
|
||||
{
|
||||
var mainBundle = [CPBundle mainBundle],
|
||||
mainCibFile = [mainBundle objectForInfoDictionaryKey:CPMainCibFile] || [mainBundle objectForInfoDictionaryKey:CPMainCibFileHumanFriendly];
|
||||
|
||||
if (mainCibFile)
|
||||
{
|
||||
[CPBundle loadCibFile:[mainBundle pathForResource:mainCibFile]
|
||||
externalNameTable:[CPDictionary dictionaryWithObject:CPApp forKey:CPCibOwner]
|
||||
loadDelegate:self];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (void)cibDidFinishLoading:(CPCib)aCib
|
||||
{
|
||||
[self performActions];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* CPBezierPath.j
|
||||
*
|
||||
* Created by Ross Boucher.
|
||||
* Copyright 2009, 280 North, Inc.
|
||||
*
|
||||
* Adapted from Kevin Wojniak, portions Copyright 2009 Kevin Wojniak.
|
||||
*
|
||||
* 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
|
||||
* Copyright 2009 280 North, Inc.
|
||||
|
||||
*/
|
||||
|
||||
@import <AppKit/CPGraphicsContext.j>
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
|
||||
// Class defaults
|
||||
|
||||
var DefaultLineWidth = 1.0;
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPBezierPath
|
||||
|
||||
A CPBezierPath allows you to create paths for drawing to the screen using a simpler API than CoreGraphics.
|
||||
Paths can form any shape, including regular polgyons like squares and triangles; circles, arcs; or complex
|
||||
line segments.
|
||||
|
||||
A path can be stroked and filled using the relevant method. The currently active fill and stroke color will
|
||||
be used, which can be set by calling setFill: and setStroke: on any CPColor object (or set: for both).
|
||||
*/
|
||||
|
||||
@implementation CPBezierPath : CPObject
|
||||
{
|
||||
CGPath _path;
|
||||
float _lineWidth;
|
||||
}
|
||||
|
||||
+ (CPBezierPath)bezierPath
|
||||
{
|
||||
return [[[self class] alloc] init];
|
||||
}
|
||||
|
||||
+ (CPBezierPath)bezierPathWithOvalInRect:(CGRect)rect
|
||||
{
|
||||
var path = [[self class] bezierPath];
|
||||
|
||||
[path appendBezierPathWithOvalInRect:rect];
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
+ (CPBezierPath)bezierPathWithRect:(CGRect)rect
|
||||
{
|
||||
var path = [[self class] bezierPath];
|
||||
|
||||
[path appendBezierPathWithRect:rect];
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
+ (float)defaultLineWidth
|
||||
{
|
||||
return DefaultLineWidth;
|
||||
}
|
||||
|
||||
+ (void)setDefaultLineWidth:(float)width
|
||||
{
|
||||
DefaultLineWidth = width;
|
||||
}
|
||||
|
||||
+ (void)fillRect:(CGRect)rect
|
||||
{
|
||||
[[[self class] bezierPathWithRect:rect] fill];
|
||||
}
|
||||
|
||||
+ (void)strokeRect:(CGRect)rect
|
||||
{
|
||||
[[[self class] bezierPathWithRect:rect] stroke];
|
||||
}
|
||||
|
||||
+ (void)strokeLineFromPoint:(CGPoint)point1 toPoint:(CGPoint)point2
|
||||
{
|
||||
var path = [[self class] bezierPath];
|
||||
|
||||
[path moveToPoint:point1];
|
||||
[path lineToPoint:point2];
|
||||
|
||||
[path stroke];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_path = CGPathCreateMutable();
|
||||
_lineWidth = [[self class] defaultLineWidth];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)moveToPoint:(CGPoint)point
|
||||
{
|
||||
CGPathMoveToPoint(_path, nil, point.x, point.y);
|
||||
}
|
||||
|
||||
- (void)lineToPoint:(CGPoint)point
|
||||
{
|
||||
CGPathAddLineToPoint(_path, nil, point.x, point.y);
|
||||
}
|
||||
|
||||
- (void)curveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2
|
||||
{
|
||||
CGPathAddCurveToPoint(_path, nil, controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, endPoint.x, endPoint.y);
|
||||
}
|
||||
|
||||
- (void)closePath
|
||||
{
|
||||
CGPathCloseSubpath(_path);
|
||||
}
|
||||
|
||||
- (void)stroke
|
||||
{
|
||||
var ctx = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
CGContextBeginPath(ctx);
|
||||
CGContextAddPath(ctx, _path);
|
||||
CGContextSetLineWidth(ctx, [self lineWidth]);
|
||||
CGContextClosePath(ctx);
|
||||
CGContextStrokePath(ctx);
|
||||
}
|
||||
|
||||
- (void)fill
|
||||
{
|
||||
var ctx = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
CGContextBeginPath(ctx);
|
||||
CGContextAddPath(ctx, _path);
|
||||
CGContextSetLineWidth(ctx, [self lineWidth]);
|
||||
CGContextClosePath(ctx);
|
||||
CGContextFillPath(ctx);
|
||||
}
|
||||
|
||||
- (float)lineWidth
|
||||
{
|
||||
return _lineWidth;
|
||||
}
|
||||
|
||||
- (void)setLineWidth:(float)lineWidth
|
||||
{
|
||||
_lineWidth = lineWidth;
|
||||
}
|
||||
|
||||
- (unsigned)elementCount
|
||||
{
|
||||
return _path.count;
|
||||
}
|
||||
|
||||
- (BOOL)isEmpty
|
||||
{
|
||||
return CGPathIsEmpty(_path);
|
||||
}
|
||||
|
||||
- (CGPoint)currentPoint
|
||||
{
|
||||
return CGPathGetCurrentPoint(_path);
|
||||
}
|
||||
|
||||
- (void)appendBezierPathWithPoints:(CPArray)points count:(unsigned)count
|
||||
{
|
||||
CGPathAddLines(_path, nil, points, count);
|
||||
}
|
||||
|
||||
- (void)appendBezierPathWithRect:(CGRect)rect
|
||||
{
|
||||
CGPathAddRect(_path, nil, rect);
|
||||
}
|
||||
|
||||
- (void)appendBezierPathWithOvalInRect:(CGRect)rect
|
||||
{
|
||||
CGPathAddPath(_path, nil, CGPathWithEllipseInRect(rect));
|
||||
}
|
||||
|
||||
- (void)appendBezierPathWithRoundedRect:(CGRect)rect xRadius:(float)xRadius yRadius:(float)yRadius
|
||||
{
|
||||
CGPathAddPath(_path, nil, CGPathWithRoundedRectangleInRect(rect, xRadius, yRadius, YES, YES, YES, YES));
|
||||
}
|
||||
|
||||
- (void)appendBezierPath:(NSBezierPath *)other
|
||||
{
|
||||
CGPathAddPath(_path, nil, other._path);
|
||||
}
|
||||
|
||||
- (void)removeAllPoints
|
||||
{
|
||||
_path = CGPathCreateMutable();
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
@import <AppKit/CPView.j>
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
@implementation CPButtonBar : CPControl
|
||||
{
|
||||
}
|
||||
|
||||
+ (CPString)themeClass
|
||||
{
|
||||
return @"button-bar";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[nil]
|
||||
forKeys:[@"bezel-color"]];
|
||||
}
|
||||
|
||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
if (aName === "bezel-view")
|
||||
return [self bounds];
|
||||
|
||||
return [super rectForEphemeralSubviewNamed:aName];
|
||||
}
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
if (aName === "bezel-view")
|
||||
{
|
||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
return [super createEphemeralSubviewNamed:aName];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:@""];
|
||||
|
||||
if (bezelView)
|
||||
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
|
||||
}
|
||||
|
||||
- (void)addSubview:(CPView)aSubview
|
||||
{
|
||||
[super addSubview:aSubview];
|
||||
|
||||
[aSubview setAutoresizingMask:CPViewMinXMargin];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* CPCheckBox.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 "CPButton.j"
|
||||
|
||||
|
||||
@implementation CPCheckBox : CPButton
|
||||
{
|
||||
}
|
||||
|
||||
+ (id)checkBoxWithTitle:(CPString)aTitle theme:(CPTheme)aTheme
|
||||
{
|
||||
return [self buttonWithTitle:aTitle theme:aTheme];
|
||||
}
|
||||
|
||||
+ (id)checkBoxWithTitle:(CPString)aTitle
|
||||
{
|
||||
return [self buttonWithTitle:aTitle];
|
||||
}
|
||||
|
||||
+ (CPString)themeClass
|
||||
{
|
||||
return @"check-box";
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self setHighlightsBy:CPContentsCellMask];
|
||||
[self setShowsStateBy:CPContentsCellMask];
|
||||
|
||||
// Defaults?
|
||||
[self setImagePosition:CPImageLeft];
|
||||
[self setAlignment:CPLeftTextAlignment];
|
||||
|
||||
[self setBordered:YES];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -25,7 +25,9 @@
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
/*! @class CPClipView
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPClipView
|
||||
|
||||
CPClipView allows you to define a clip rect and display only that portion of its containing view.
|
||||
It is used to hold the document view in a CPScrollView.
|
||||
@@ -65,9 +67,6 @@
|
||||
|
||||
if (_documentView)
|
||||
{
|
||||
// FIXME: remove when bounds.
|
||||
[_documentView setFrameOrigin:CGPointMake(0.0, 0.0)];
|
||||
|
||||
[self addSubview:_documentView];
|
||||
|
||||
[_documentView setPostsFrameChangedNotifications:YES];
|
||||
@@ -103,6 +102,9 @@
|
||||
*/
|
||||
- (CGPoint)constrainScrollPoint:(CGPoint)aPoint
|
||||
{
|
||||
if (!_documentView)
|
||||
return _CGPointMakeZero();
|
||||
|
||||
var documentFrame = [_documentView frame];
|
||||
|
||||
aPoint.x = MAX(0.0, MIN(aPoint.x, MAX(_CGRectGetWidth(documentFrame) - _CGRectGetWidth(_bounds), 0.0)));
|
||||
@@ -139,7 +141,7 @@
|
||||
*/
|
||||
- (void)viewBoundsChanged:(CPNotification)aNotification
|
||||
{
|
||||
[self viewFrameChanged:aNotification];
|
||||
[self _constrainScrollPoint];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -147,6 +149,17 @@
|
||||
@param aNotification the notification event
|
||||
*/
|
||||
- (void)viewFrameChanged:(CPNotification)aNotification
|
||||
{
|
||||
[self _constrainScrollPoint];
|
||||
}
|
||||
|
||||
- (void)resizeSubviewsWithOldSize:(CGSize)aSize
|
||||
{
|
||||
[super resizeSubviewsWithOldSize:aSize];
|
||||
[self _constrainScrollPoint];
|
||||
}
|
||||
|
||||
- (void)_constrainScrollPoint
|
||||
{
|
||||
var oldScrollPoint = [self bounds].origin;
|
||||
|
||||
@@ -166,4 +179,42 @@
|
||||
[superview reflectScrolledClipView:self];
|
||||
}
|
||||
|
||||
- (BOOL)autoscroll:(CPEvent)anEvent
|
||||
{
|
||||
var bounds = [self bounds],
|
||||
eventLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
|
||||
if (CPRectContainsPoint(bounds, eventLocation))
|
||||
return NO;
|
||||
|
||||
var newRect = CGRectMakeZero();
|
||||
|
||||
newRect.origin = eventLocation;
|
||||
newRect.size = CPSizeMake(10, 10);
|
||||
|
||||
return [_documentView scrollRectToVisible:newRect];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPClipViewDocumentViewKey = @"CPScrollViewDocumentView";
|
||||
|
||||
@implementation CPClipView (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
[self setDocumentView:[aCoder decodeObjectForKey:CPClipViewDocumentViewKey]];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeObject:_documentView forKey:CPClipViewDocumentViewKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -29,7 +29,9 @@
|
||||
@import <AppKit/CPView.j>
|
||||
|
||||
|
||||
/*! @class CPCollectionView
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPCollectionView
|
||||
|
||||
This class displays an array as a grid of objects, where each object is represented by a view.
|
||||
The view is controlled by creating a CPCollectionViewItem and specifying its view, then
|
||||
@@ -79,6 +81,7 @@
|
||||
|
||||
BOOL _isSelectable;
|
||||
BOOL _allowsMultipleSelection;
|
||||
BOOL _allowsEmptySelection;
|
||||
CPIndexSet _selectionIndexes;
|
||||
|
||||
CGSize _itemSize;
|
||||
@@ -111,6 +114,8 @@
|
||||
_tileWidth = -1.0;
|
||||
|
||||
_selectionIndexes = [CPIndexSet indexSet];
|
||||
_allowsEmptySelection = YES;
|
||||
_isSelectable = YES;
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -124,6 +129,7 @@
|
||||
{
|
||||
_itemData = [CPKeyedArchiver archivedDataWithRootObject:anItem];
|
||||
_itemForDragging = anItem//[CPKeyedUnarchiver unarchiveObjectWithData:_itemData];
|
||||
_itemPrototype = anItem;
|
||||
|
||||
[self reloadContent];
|
||||
}
|
||||
@@ -235,6 +241,23 @@
|
||||
return _isSelected;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets whether the user may have no items selected. If YES, mouse clicks not on any item will empty the current selection. The first item will also start off as selected.
|
||||
@param shouldAllowMultipleSelection <code>YES</code> allows the user to select multiple items
|
||||
*/
|
||||
- (void)setAllowsEmptySelection:(BOOL)shouldAllowEmptySelection
|
||||
{
|
||||
_allowsEmptySelection = shouldAllowEmptySelection;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns <code>YES</code> if the user can select no items, <code>NO</code> otherwise.
|
||||
*/
|
||||
- (BOOL)allowsEmptySelection
|
||||
{
|
||||
return _allowsEmptySelection;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets whether the user can select multiple items.
|
||||
@param shouldAllowMultipleSelection <code>YES</code> allows the user to select multiple items
|
||||
@@ -258,21 +281,21 @@
|
||||
*/
|
||||
- (void)setSelectionIndexes:(CPIndexSet)anIndexSet
|
||||
{
|
||||
if (_selectionIndexes == anIndexSet)
|
||||
if (_selectionIndexes == anIndexSet || !_isSelectable)
|
||||
return;
|
||||
|
||||
var index = CPNotFound;
|
||||
|
||||
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
|
||||
[_items[index] setSelected:NO];
|
||||
|
||||
|
||||
_selectionIndexes = anIndexSet;
|
||||
|
||||
|
||||
var index = CPNotFound;
|
||||
|
||||
|
||||
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
|
||||
[_items[index] setSelected:YES];
|
||||
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)])
|
||||
[_delegate collectionViewDidChangeSelection:self]
|
||||
}
|
||||
@@ -328,7 +351,7 @@
|
||||
// either proportioned out to the views (if their minSize != maxSize) or used as
|
||||
// margin
|
||||
var itemSize = CGSizeMakeCopy(_minItemSize);
|
||||
|
||||
|
||||
_numberOfColumns = MAX(1.0, FLOOR(width / itemSize.width));
|
||||
|
||||
if (_maxNumberOfColumns > 0)
|
||||
@@ -340,6 +363,10 @@
|
||||
if (remaining > 0 && itemSize.width < _maxItemSize.width)
|
||||
itemSize.width = MIN(_maxItemSize.width, itemSize.width + FLOOR(remaining / _numberOfColumns));
|
||||
|
||||
// When we ONE column and a non-integral width, the FLOORing above can cause the item width to be smaller than the total width.
|
||||
if (_maxNumberOfColumns == 1 && itemSize.width < _maxItemSize.width && itemSize.width < width)
|
||||
itemSize.width = MIN(_maxItemSize.width, width);
|
||||
|
||||
if (!CGSizeEqualToSize(_itemSize, itemSize))
|
||||
{
|
||||
_itemSize = itemSize;
|
||||
@@ -432,6 +459,23 @@
|
||||
return _maxNumberOfColumns;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the current number of rows
|
||||
*/
|
||||
- (unsigned)numberOfRows
|
||||
{
|
||||
return _numberOfRows;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the current number of columns
|
||||
*/
|
||||
|
||||
- (unsigned)numberOfColumns
|
||||
{
|
||||
return _numberOfColumns;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the minimum size for an item
|
||||
@param aSize the new minimum item size
|
||||
@@ -491,6 +535,8 @@
|
||||
|
||||
if (index >= 0 && index < _items.length)
|
||||
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
||||
else if (_allowsEmptySelection)
|
||||
[self setSelectionIndexes:[CPIndexSet indexSet]];
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(CPEvent)anEvent
|
||||
@@ -515,6 +561,7 @@
|
||||
frame = [view frame];
|
||||
|
||||
[view setFrameSize:_itemSize];
|
||||
[view setAlphaValue:0.7];
|
||||
|
||||
[self dragView:view
|
||||
at:[[_items[[_selectionIndexes firstIndex]] view] frame].origin
|
||||
@@ -537,6 +584,11 @@
|
||||
|
||||
// Cappuccino Additions
|
||||
|
||||
/*!
|
||||
Sets the collection view's vertical spacing between elements.
|
||||
@param aVerticalMargin the number of pixels to place between elements
|
||||
*/
|
||||
|
||||
- (void)setVerticalMargin:(float)aVerticalMargin
|
||||
{
|
||||
if (_verticalMargin == aVerticalMargin)
|
||||
@@ -547,6 +599,15 @@
|
||||
[self tile];
|
||||
}
|
||||
|
||||
/*!
|
||||
Gets the collection view's current vertical spacing between elements.
|
||||
*/
|
||||
|
||||
- (float)verticalMargin
|
||||
{
|
||||
return _verticalMargin;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the collection view's delegate
|
||||
@param aDelegate the new delegate
|
||||
@@ -655,6 +716,49 @@
|
||||
|
||||
@end
|
||||
|
||||
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
||||
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
|
||||
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey";
|
||||
|
||||
|
||||
@implementation CPCollectionView (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_items = [];
|
||||
_content = [];
|
||||
|
||||
_cachedItems = [];
|
||||
|
||||
_itemSize = CGSizeMakeZero();
|
||||
_minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey];
|
||||
_maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey];
|
||||
|
||||
_verticalMargin = [aCoder decodeSizeForKey:CPCollectionViewVerticalMarginKey];
|
||||
_tileWidth = -1.0;
|
||||
|
||||
_selectionIndexes = [CPIndexSet indexSet];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeSize:_minItemSize forKey:CPCollectionViewMinItemSizeKey];
|
||||
[aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey];
|
||||
|
||||
[aCoder encodeSize:_verticalMargin forKey:CPCollectionViewVerticalMarginKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPCollectionViewItemViewKey = @"CPCollectionViewItemViewKey";
|
||||
|
||||
@implementation CPCollectionViewItem (CPCoding)
|
||||
|
||||
@@ -37,7 +37,21 @@ var _hueComponent = 0,
|
||||
_saturationComponent = 1,
|
||||
_brightnessComponent = 2;
|
||||
|
||||
/*! @code CPColor
|
||||
var cachedBlackColor,
|
||||
cachedRedColor,
|
||||
cachedGreenColor,
|
||||
cachedBlueColor,
|
||||
cachedYellowColor,
|
||||
cachedGrayColor,
|
||||
cachedLightGrayColor,
|
||||
cachedDarkGrayColor,
|
||||
cachedWhiteColor,
|
||||
cachedShadowColor,
|
||||
cachedClearColor;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@code CPColor
|
||||
|
||||
<code>CPColor</code> can be used to represent color
|
||||
in an RGB or HSB model with an optional transparency value.</p>
|
||||
@@ -71,11 +85,32 @@ var _hueComponent = 0,
|
||||
|
||||
@return a color initialized to the values specified
|
||||
*/
|
||||
+ (CPColor)colorWithCalibratedRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha
|
||||
+ (CPColor)colorWithRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha
|
||||
{
|
||||
return [[CPColor alloc] _initWithRGBA:[red, green, blue, alpha]];
|
||||
}
|
||||
|
||||
/*!
|
||||
@deprecated in favor of colorWithRed:green:blue:alpha:
|
||||
|
||||
Creates a color in the RGB color space, with an alpha value.
|
||||
Each component should be between the range of 0.0 to 1.0. For
|
||||
the alpha component, a value of 1.0 is opaque, and 0.0 means
|
||||
completely transparent.
|
||||
|
||||
@param red the red component of the color
|
||||
@param green the green component of the color
|
||||
@param blue the blue component of the color
|
||||
@param alpha the alpha component
|
||||
|
||||
@return a color initialized to the values specified
|
||||
*/
|
||||
+ (CPColor)colorWithCalibratedRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha
|
||||
{
|
||||
return [self colorWithRed:red green:green blue:blue alpha:alpha];
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Creates a new color object with <code>white</code> for the RGB components.
|
||||
For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent.
|
||||
@@ -85,11 +120,27 @@ var _hueComponent = 0,
|
||||
|
||||
@return a color initialized to the values specified
|
||||
*/
|
||||
+ (CPColor)colorWithCalibratedWhite:(float)white alpha:(float)alpha
|
||||
+ (CPColor)colorWithWhite:(float)white alpha:(float)alpha
|
||||
{
|
||||
return [[CPColor alloc] _initWithRGBA:[white, white, white, alpha]];
|
||||
}
|
||||
|
||||
/*!
|
||||
@deprecated in favor of colorWithWhite:apha:
|
||||
|
||||
Creates a new color object with <code>white</code> for the RGB components.
|
||||
For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent.
|
||||
|
||||
@param white a float between 0.0 and 1.0
|
||||
@param alpha the alpha component between 0.0 and 1.0
|
||||
|
||||
@return a color initialized to the values specified
|
||||
*/
|
||||
+ (CPColor)colorWithCalibratedWhite:(float)white alpha:(float)alpha
|
||||
{
|
||||
return [self colorWithWhite:white alpha:alpha];
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a new color in HSB space.
|
||||
|
||||
@@ -101,8 +152,13 @@ var _hueComponent = 0,
|
||||
*/
|
||||
+ (CPColor)colorWithHue:(float)hue saturation:(float)saturation brightness:(float)brightness
|
||||
{
|
||||
if(saturation == 0.0)
|
||||
return [CPColor colorWithCalibratedWhite: brightness/100.0 alpha: 1.0];
|
||||
return [self colorWithHue:hue saturation:saturation brightness:brightness alpha:1.0];
|
||||
}
|
||||
|
||||
+ (CPColor)colorWithHue:(float)hue saturation:(float)saturation brightness:(float)brightness alpha:(float)alpha
|
||||
{
|
||||
if(saturation === 0.0)
|
||||
return [CPColor colorWithCalibratedWhite:brightness / 100.0 alpha:alpha];
|
||||
|
||||
var f = hue % 60,
|
||||
p = (brightness * (100 - saturation)) / 10000,
|
||||
@@ -112,12 +168,12 @@ var _hueComponent = 0,
|
||||
|
||||
switch(FLOOR(hue / 60))
|
||||
{
|
||||
case 0: return [CPColor colorWithCalibratedRed: b green: t blue: p alpha: 1.0];
|
||||
case 1: return [CPColor colorWithCalibratedRed: q green: b blue: p alpha: 1.0];
|
||||
case 2: return [CPColor colorWithCalibratedRed: p green: b blue: t alpha: 1.0];
|
||||
case 3: return [CPColor colorWithCalibratedRed: p green: q blue: b alpha: 1.0];
|
||||
case 4: return [CPColor colorWithCalibratedRed: t green: p blue: b alpha: 1.0];
|
||||
case 5: return [CPColor colorWithCalibratedRed: b green: p blue: q alpha: 1.0];
|
||||
case 0: return [CPColor colorWithCalibratedRed: b green: t blue: p alpha: alpha];
|
||||
case 1: return [CPColor colorWithCalibratedRed: q green: b blue: p alpha: alpha];
|
||||
case 2: return [CPColor colorWithCalibratedRed: p green: b blue: t alpha: alpha];
|
||||
case 3: return [CPColor colorWithCalibratedRed: p green: q blue: b alpha: alpha];
|
||||
case 4: return [CPColor colorWithCalibratedRed: t green: p blue: b alpha: alpha];
|
||||
case 5: return [CPColor colorWithCalibratedRed: b green: p blue: q alpha: alpha];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +197,10 @@ var _hueComponent = 0,
|
||||
*/
|
||||
+ (CPColor)blackColor
|
||||
{
|
||||
return [[CPColor alloc] _initWithRGBA:[0.0, 0.0, 0.0, 1.0]];
|
||||
if (!cachedBlackColor)
|
||||
cachedBlackColor = [[CPColor alloc] _initWithRGBA:[0.0, 0.0, 0.0, 1.0]];
|
||||
|
||||
return cachedBlackColor;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -149,7 +208,10 @@ var _hueComponent = 0,
|
||||
*/
|
||||
+ (CPColor)blueColor
|
||||
{
|
||||
return [[CPColor alloc] _initWithRGBA:[0.0, 0.0, 1.0, 1.0]];
|
||||
if (!cachedBlueColor)
|
||||
cachedBlueColor = [[CPColor alloc] _initWithRGBA:[0.0, 0.0, 1.0, 1.0]];
|
||||
|
||||
return cachedBlueColor;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -157,7 +219,10 @@ var _hueComponent = 0,
|
||||
*/
|
||||
+ (CPColor)darkGrayColor
|
||||
{
|
||||
return [CPColor colorWithCalibratedWhite:1.0 / 3.0 alpha:1.0];
|
||||
if (!cachedDarkGrayColor)
|
||||
cachedDarkGrayColor = [CPColor colorWithCalibratedWhite:1.0 / 3.0 alpha:1.0];
|
||||
|
||||
return cachedDarkGrayColor;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -165,7 +230,10 @@ var _hueComponent = 0,
|
||||
*/
|
||||
+ (CPColor)grayColor
|
||||
{
|
||||
return [CPColor colorWithCalibratedWhite:0.5 alpha: 1.0];
|
||||
if (!cachedGrayColor)
|
||||
cachedGrayColor = [CPColor colorWithCalibratedWhite:0.5 alpha: 1.0];
|
||||
|
||||
return cachedGrayColor;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -173,7 +241,10 @@ var _hueComponent = 0,
|
||||
*/
|
||||
+ (CPColor)greenColor
|
||||
{
|
||||
return [[CPColor alloc] _initWithRGBA:[0.0, 1.0, 0.0, 1.0]];
|
||||
if (!cachedGreenColor)
|
||||
cachedGreenColor = [[CPColor alloc] _initWithRGBA:[0.0, 1.0, 0.0, 1.0]];
|
||||
|
||||
return cachedGreenColor;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -181,7 +252,10 @@ var _hueComponent = 0,
|
||||
*/
|
||||
+ (CPColor)lightGrayColor
|
||||
{
|
||||
return [CPColor colorWithCalibratedWhite:2.0 / 3.0 alpha:1.0];
|
||||
if (!cachedLightGrayColor)
|
||||
cachedLightGrayColor = [CPColor colorWithCalibratedWhite:2.0 / 3.0 alpha:1.0];
|
||||
|
||||
return cachedLightGrayColor;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -189,7 +263,10 @@ var _hueComponent = 0,
|
||||
*/
|
||||
+ (CPColor)redColor
|
||||
{
|
||||
return [[CPColor alloc] _initWithRGBA:[1.0, 0.0, 0.0, 1.0]];
|
||||
if (!cachedRedColor)
|
||||
cachedRedColor = [[CPColor alloc] _initWithRGBA:[1.0, 0.0, 0.0, 1.0]];
|
||||
|
||||
return cachedRedColor;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -197,7 +274,10 @@ var _hueComponent = 0,
|
||||
*/
|
||||
+ (CPColor)whiteColor
|
||||
{
|
||||
return [[CPColor alloc] _initWithRGBA:[1.0, 1.0, 1.0, 1.0]];
|
||||
if (!cachedWhiteColor)
|
||||
cachedWhiteColor = [[CPColor alloc] _initWithRGBA:[1.0, 1.0, 1.0, 1.0]];
|
||||
|
||||
return cachedWhiteColor;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -205,15 +285,34 @@ var _hueComponent = 0,
|
||||
*/
|
||||
+ (CPColor)yellowColor
|
||||
{
|
||||
return [[CPColor alloc] _initWithRGBA:[1.0, 1.0, 0.0, 1.0]];
|
||||
if (!cachedYellowColor)
|
||||
cachedYellowColor = [[CPColor alloc] _initWithRGBA:[1.0, 1.0, 0.0, 1.0]];
|
||||
|
||||
return cachedYellowColor;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a shadow looking color (RGBA=[0.0, 0.0, 0.0, 0.33])
|
||||
*/
|
||||
|
||||
+ (CPColor)shadowColor
|
||||
{
|
||||
return [[CPColor alloc] _initWithRGBA:[0.0, 0.0, 0.0, 1.0 / 3.0]];
|
||||
if (!cachedShadowColor)
|
||||
cachedShadowColor = [[CPColor alloc] _initWithRGBA:[0.0, 0.0, 0.0, 1.0 / 3.0]];
|
||||
|
||||
return cachedShadowColor;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a clear color (RGBA=[0.0, 0.0, 0.0, 0.0])
|
||||
*/
|
||||
|
||||
+ (CPColor)clearColor
|
||||
{
|
||||
if (!cachedClearColor)
|
||||
cachedClearColor = [self colorWithCalibratedWhite:0.0 alpha:0.0];
|
||||
|
||||
return cachedClearColor;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -324,7 +423,7 @@ var _hueComponent = 0,
|
||||
if (self)
|
||||
{
|
||||
_patternImage = anImage;
|
||||
_cssString = "url(\"" + _patternImage._filename + "\")";
|
||||
_cssString = "url(\"" + [_patternImage filename] + "\")";
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -475,6 +574,53 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
|
||||
return rgbToHex([self redComponent], [self greenComponent], [self blueComponent])
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(CPColor)aColor
|
||||
{
|
||||
if (!aColor)
|
||||
return NO;
|
||||
|
||||
if (aColor === self)
|
||||
return YES;
|
||||
|
||||
return [aColor isKindOfClass:CPColor] && [aColor cssString] === [self cssString];
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
return [super description]+" "+[self cssString];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPColor (CoreGraphicsExtensions)
|
||||
|
||||
/*!
|
||||
Set's the receiver to be the fill and stroke color in the current graphics context
|
||||
*/
|
||||
- (void)set
|
||||
{
|
||||
[self setFill];
|
||||
[self setStroke];
|
||||
}
|
||||
|
||||
/*!
|
||||
Set's the receiver to be the fill color in the current graphics context
|
||||
*/
|
||||
- (void)setFill
|
||||
{
|
||||
var ctx = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
CGContextSetFillColor(ctx, self);
|
||||
}
|
||||
|
||||
/*!
|
||||
Set's the receiver to be the stroke color in the current graphics context
|
||||
*/
|
||||
- (void)setStroke
|
||||
{
|
||||
var ctx = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
CGContextSetStrokeColor(ctx, self);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPColorComponentsKey = @"CPColorComponentsKey",
|
||||
@@ -518,6 +664,8 @@ var hexCharacters = "0123456789ABCDEF";
|
||||
*/
|
||||
function hexToRGB(hex)
|
||||
{
|
||||
if ( hex.length == 3 )
|
||||
hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2);
|
||||
if(hex.length != 6)
|
||||
return null;
|
||||
|
||||
|
||||
@@ -52,7 +52,9 @@ CPSliderColorPickerMode = 2;
|
||||
CPColorPickerViewWidth = 265,
|
||||
CPColorPickerViewHeight = 370;
|
||||
|
||||
/*! @class CPColorPanel
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPColorPanel
|
||||
|
||||
CPColorPanel provides a reusable panel that can be used
|
||||
displayed on screen to prompt the user for a color selection. To
|
||||
@@ -63,19 +65,19 @@ CPColorPickerViewHeight = 370;
|
||||
_CPColorPanelToolbar _toolbar;
|
||||
_CPColorPanelSwatches _swatchView;
|
||||
_CPColorPanelPreview _previewView;
|
||||
|
||||
CPTextField _previewLabel;
|
||||
CPTextField _swatchLabel;
|
||||
|
||||
|
||||
CPSlider _opacitySlider;
|
||||
|
||||
CPArray _colorPickers;
|
||||
CPView _currentView;
|
||||
|
||||
CPView _currentView;
|
||||
id _activePicker;
|
||||
|
||||
CPColor _color;
|
||||
|
||||
|
||||
id _target;
|
||||
SEL _action;
|
||||
|
||||
int _mode;
|
||||
SEL _action;
|
||||
|
||||
int _mode;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -114,19 +116,21 @@ CPColorPickerViewHeight = 370;
|
||||
*/
|
||||
- (id)init
|
||||
{
|
||||
self = [super initWithContentRect:CGRectMake(500.0, 50.0, 218.0, 360.0)
|
||||
styleMask:(CPHUDBackgroundWindowMask | CPTitledWindowMask | CPClosableWindowMask | CPResizableWindowMask)];
|
||||
|
||||
self = [super initWithContentRect:CGRectMake(500.0, 50.0, 219.0, 370.0)
|
||||
styleMask:(CPTitledWindowMask | CPClosableWindowMask | CPResizableWindowMask)];
|
||||
|
||||
if (self)
|
||||
{
|
||||
[[self contentView] setBackgroundColor:[CPColor colorWithWhite:0.95 alpha:1.0]];
|
||||
|
||||
[self setTitle:@"Color Panel"];
|
||||
[self setLevel:CPFloatingWindowLevel];
|
||||
|
||||
[self setFloatingPanel:YES];
|
||||
[self setBecomesKeyOnlyIfNeeded:YES];
|
||||
|
||||
[self setMinSize:CGSizeMake(218.0, 360.0)];
|
||||
[self setMaxSize:CGSizeMake(327.0, 540.0)];
|
||||
[self setMinSize:CGSizeMake(219.0, 342.0)];
|
||||
[self setMaxSize:CGSizeMake(323.0, 537.0)];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -136,7 +140,7 @@ CPColorPickerViewHeight = 370;
|
||||
Sets the color of the panel, and updates the picker. Also posts a <code>CPColorPanelDidChangeNotification</code>.
|
||||
*/
|
||||
- (void)setColor:(CPColor)aColor
|
||||
{
|
||||
{
|
||||
_color = aColor;
|
||||
[_previewView setBackgroundColor: _color];
|
||||
|
||||
@@ -148,6 +152,9 @@ CPColorPickerViewHeight = 370;
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPColorPanelColorDidChangeNotification
|
||||
object:self];
|
||||
|
||||
[_activePicker setColor:_color];
|
||||
[_opacitySlider setFloatValue:[_color alphaComponent]];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -171,6 +178,11 @@ CPColorPickerViewHeight = 370;
|
||||
return _color;
|
||||
}
|
||||
|
||||
- (float)opacity
|
||||
{
|
||||
return [_opacitySlider floatValue];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the target for the color panel. Messages are sent
|
||||
to the target when colors are selected in the panel.
|
||||
@@ -231,7 +243,7 @@ CPColorPickerViewHeight = 370;
|
||||
[view setFrame:[_currentView frame]];
|
||||
else
|
||||
{
|
||||
var height = (TOOLBAR_HEIGHT+10+PREVIEW_HEIGHT+5+SWATCH_HEIGHT+10),
|
||||
var height = (TOOLBAR_HEIGHT+10+PREVIEW_HEIGHT+5+SWATCH_HEIGHT+32),
|
||||
bounds = [[self contentView] bounds];
|
||||
|
||||
[view setFrameSize: CPSizeMake(bounds.size.width - 10, bounds.size.height - height)];
|
||||
@@ -266,28 +278,31 @@ CPColorPickerViewHeight = 370;
|
||||
{
|
||||
if (_toolbar)
|
||||
return;
|
||||
|
||||
|
||||
if (!_color)
|
||||
_color = [CPColor whiteColor];
|
||||
|
||||
_colorPickers = [];
|
||||
|
||||
|
||||
var count = [ColorPickerClasses count];
|
||||
for (var i=0; i<count; i++)
|
||||
{
|
||||
var currentPickerClass = ColorPickerClasses[i],
|
||||
currentPicker = [[currentPickerClass alloc] initWithPickerMask:0 colorPanel:self];
|
||||
|
||||
|
||||
_colorPickers.push(currentPicker);
|
||||
}
|
||||
|
||||
var contentView = [self contentView],
|
||||
bounds = [contentView bounds];
|
||||
|
||||
_toolbar = [[CPView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(bounds), TOOLBAR_HEIGHT)];
|
||||
|
||||
_toolbar = [[CPView alloc] initWithFrame:CGRectMake(0, 6, CGRectGetWidth(bounds), TOOLBAR_HEIGHT)];
|
||||
[_toolbar setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
var totalToolbarWidth = count * ICON_WIDTH + (count - 1) * ICON_PADDING,
|
||||
leftOffset = (CGRectGetWidth(bounds) - totalToolbarWidth) / 2.0,
|
||||
buttonForLater = nil;
|
||||
|
||||
|
||||
for (var i=0; i<count; i++)
|
||||
{
|
||||
var image = [_colorPickers[i] provideNewButtonImage],
|
||||
@@ -311,57 +326,80 @@ CPColorPickerViewHeight = 370;
|
||||
|
||||
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
||||
var previewBox = [[CPView alloc] initWithFrame:CGRectMake(76, TOOLBAR_HEIGHT + 10, CGRectGetWidth(bounds) - 86, PREVIEW_HEIGHT)];
|
||||
|
||||
|
||||
_previewView = [[_CPColorPanelPreview alloc] initWithFrame:CGRectInset([previewBox bounds], 2.0, 2.0)];
|
||||
|
||||
|
||||
[_previewView setColorPanel:self];
|
||||
[_previewView setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
[previewBox setBackgroundColor:[CPColor grayColor]];
|
||||
|
||||
[previewBox setBackgroundColor:[CPColor colorWithWhite:0.8 alpha:1.0]];
|
||||
[previewBox setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
|
||||
[previewBox addSubview:_previewView];
|
||||
|
||||
_previewLabel = [[CPTextField alloc] initWithFrame: CPRectMake(10, TOOLBAR_HEIGHT + 14, 60, 15)];
|
||||
|
||||
var _previewLabel = [[CPTextField alloc] initWithFrame: CPRectMake(10, TOOLBAR_HEIGHT + 10, 60, 15)];
|
||||
[_previewLabel setStringValue: "Preview:"];
|
||||
[_previewLabel setTextColor:[CPColor whiteColor]];
|
||||
[_previewLabel setTextColor:[CPColor blackColor]];
|
||||
[_previewLabel setAlignment:CPRightTextAlignment];
|
||||
|
||||
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
||||
var swatchBox = [[CPView alloc] initWithFrame:CGRectMake(76, TOOLBAR_HEIGHT + 10 + PREVIEW_HEIGHT + 5, CGRectGetWidth(bounds) - 86, SWATCH_HEIGHT + 2.0)];
|
||||
|
||||
[swatchBox setBackgroundColor:[CPColor grayColor]];
|
||||
[swatchBox setBackgroundColor:[CPColor colorWithWhite:0.8 alpha:1.0]];
|
||||
[swatchBox setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
|
||||
_swatchView = [[_CPColorPanelSwatches alloc] initWithFrame:CGRectInset([swatchBox bounds], 1.0, 1.0)];
|
||||
|
||||
|
||||
[_swatchView setColorPanel: self];
|
||||
[_swatchView setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
[swatchBox addSubview:_swatchView];
|
||||
|
||||
_swatchLabel = [[CPTextField alloc] initWithFrame: CPRectMake(10, TOOLBAR_HEIGHT + 8 + PREVIEW_HEIGHT + 5, 60, 15)];
|
||||
var _swatchLabel = [[CPTextField alloc] initWithFrame: CPRectMake(10, TOOLBAR_HEIGHT + 8 + PREVIEW_HEIGHT + 6, 60, 15)];
|
||||
[_swatchLabel setStringValue: "Swatches:"];
|
||||
[_swatchLabel setTextColor:[CPColor whiteColor]];
|
||||
[_swatchLabel setTextColor:[CPColor blackColor]];
|
||||
[_swatchLabel setAlignment:CPRightTextAlignment];
|
||||
|
||||
|
||||
[contentView addSubview: _toolbar];
|
||||
[contentView addSubview: previewBox];
|
||||
[contentView addSubview: _previewLabel];
|
||||
[contentView addSubview: swatchBox];
|
||||
[contentView addSubview: _swatchLabel];
|
||||
var opacityLabel = [[CPTextField alloc] initWithFrame: CPRectMake(10, TOOLBAR_HEIGHT + PREVIEW_HEIGHT + 35, 60, 20)];
|
||||
[opacityLabel setStringValue: "Opacity:"];
|
||||
[opacityLabel setTextColor:[CPColor blackColor]];
|
||||
[opacityLabel setAlignment:CPRightTextAlignment];
|
||||
|
||||
_opacitySlider = [[CPSlider alloc] initWithFrame:CGRectMake(76, TOOLBAR_HEIGHT + PREVIEW_HEIGHT + 34, CGRectGetWidth(bounds) - 86, 20.0)];
|
||||
|
||||
[_opacitySlider setMinValue:0.0];
|
||||
[_opacitySlider setMaxValue:1.0];
|
||||
|
||||
[_opacitySlider setTarget:self];
|
||||
[_opacitySlider setAction:@selector(setOpacity:)];
|
||||
|
||||
[contentView addSubview:_toolbar];
|
||||
[contentView addSubview:previewBox];
|
||||
[contentView addSubview:_previewLabel];
|
||||
[contentView addSubview:swatchBox];
|
||||
[contentView addSubview:_swatchLabel];
|
||||
[contentView addSubview:opacityLabel];
|
||||
[contentView addSubview:_opacitySlider];
|
||||
|
||||
_target = nil;
|
||||
_action = nil;
|
||||
_activePicker = nil;
|
||||
|
||||
[self setColor:[CPColor whiteColor]];
|
||||
|
||||
|
||||
[_previewView setBackgroundColor: _color];
|
||||
|
||||
if (buttonForLater)
|
||||
[self _setPicker:buttonForLater];
|
||||
}
|
||||
|
||||
- (void)setOpacity:(id)sender
|
||||
{
|
||||
var components = [[self color] components],
|
||||
alpha = [sender floatValue];
|
||||
|
||||
[self setColor:[_color colorWithAlphaComponent:alpha] updatePicker:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@
|
||||
@import <Foundation/CPObject.j>
|
||||
@import "CPColorPanel.j"
|
||||
|
||||
/*! @class CPColorPicker
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPColorPicker
|
||||
|
||||
CPColorPicker is an abstract superclass for all color picker subclasses. If you want a particular color picker, use CPColorPanel's <code>setPickerMode:</code> method. The simplest way to implement your own color picker is to create a subclass of CPColorPicker.
|
||||
*/
|
||||
@@ -41,10 +43,10 @@
|
||||
- (id)initWithPickerMask:(int)aMask colorPanel:(CPColorPanel)aPanel
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
_panel = aPanel;
|
||||
_mask = aMask;
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -92,54 +94,44 @@
|
||||
*/
|
||||
@implementation CPColorWheelColorPicker : CPColorPicker
|
||||
{
|
||||
CPView _pickerView;
|
||||
CPView _pickerView;
|
||||
CPView _brightnessSlider;
|
||||
DOMElement _brightnessBarImage;
|
||||
__CPColorWheel _hueSaturationView;
|
||||
|
||||
CPColor _cachedColor;
|
||||
}
|
||||
|
||||
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
|
||||
{
|
||||
return [super initWithPickerMask:mask colorPanel: owningColorPanel];
|
||||
}
|
||||
|
||||
|
||||
-(id)initView
|
||||
{
|
||||
aFrame = CPRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
|
||||
|
||||
|
||||
_pickerView = [[CPView alloc] initWithFrame:aFrame];
|
||||
[_pickerView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||
|
||||
var path = [[CPBundle bundleForClass: CPColorPicker] pathForResource:@"brightness_bar.png"];
|
||||
|
||||
_brightnessBarImage = new Image();
|
||||
_brightnessBarImage.src = path;
|
||||
_brightnessBarImage.style.width = "100%";
|
||||
_brightnessBarImage.style.height = "100%";
|
||||
_brightnessBarImage.style.position = "absolute";
|
||||
_brightnessBarImage.style.top = "0px";
|
||||
_brightnessBarImage.style.left = "0px";
|
||||
|
||||
var brightnessBarView = [[CPView alloc] initWithFrame: CPRectMake(0, (aFrame.size.height - 34), aFrame.size.width, 15)];
|
||||
[brightnessBarView setAutoresizingMask: (CPViewWidthSizable | CPViewMinYMargin)];
|
||||
brightnessBarView._DOMElement.appendChild(_brightnessBarImage);
|
||||
|
||||
_brightnessSlider = [[CPSlider alloc] initWithFrame: CPRectMake(0, aFrame.size.height - 22, aFrame.size.width, 12)];
|
||||
[_brightnessSlider setMaxValue: 100.0];
|
||||
[_brightnessSlider setMinValue: 0.0];
|
||||
_brightnessSlider = [[CPSlider alloc] initWithFrame:CGRectMake(0, (aFrame.size.height - 34), aFrame.size.width, 15)];
|
||||
|
||||
[_brightnessSlider setValue:15.0 forThemeAttribute:@"track-width"];
|
||||
[_brightnessSlider setValue:[CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPColorPicker class]] pathForResource:@"brightness_bar.png"]]] forThemeAttribute:@"track-color"];
|
||||
|
||||
[_brightnessSlider setMinValue:0.0];
|
||||
[_brightnessSlider setMaxValue:100.0];
|
||||
[_brightnessSlider setFloatValue:100.0];
|
||||
|
||||
[_brightnessSlider setTarget: self];
|
||||
[_brightnessSlider setAction: @selector(brightnessSliderDidChange:)];
|
||||
[_brightnessSlider setAutoresizingMask: (CPViewWidthSizable | CPViewMinYMargin)];
|
||||
[_brightnessSlider setTarget:self];
|
||||
[_brightnessSlider setAction:@selector(brightnessSliderDidChange:)];
|
||||
[_brightnessSlider setAutoresizingMask:CPViewWidthSizable | CPViewMinYMargin];
|
||||
|
||||
_hueSaturationView = [[__CPColorWheel alloc] initWithFrame: CPRectMake(0, 0, aFrame.size.width, aFrame.size.height - 38)];
|
||||
[_hueSaturationView setDelegate: self];
|
||||
[_hueSaturationView setAutoresizingMask: (CPViewWidthSizable | CPViewHeightSizable)];
|
||||
|
||||
[_pickerView addSubview: brightnessBarView];
|
||||
[_pickerView addSubview: _hueSaturationView];
|
||||
[_pickerView addSubview: _brightnessSlider];
|
||||
[_pickerView addSubview:_hueSaturationView];
|
||||
[_pickerView addSubview:_brightnessSlider];
|
||||
}
|
||||
|
||||
-(void)brightnessSliderDidChange:(id)sender
|
||||
@@ -158,39 +150,47 @@
|
||||
saturation = [_hueSaturationView distance],
|
||||
brightness = [_brightnessSlider floatValue];
|
||||
|
||||
[_hueSaturationView setWheelBrightness: brightness / 100.0];
|
||||
_brightnessBarImage.style.backgroundColor = "#"+[[CPColor colorWithHue: hue saturation: saturation brightness: 100] hexString];
|
||||
[_hueSaturationView setWheelBrightness:brightness / 100.0];
|
||||
[_brightnessSlider setBackgroundColor:[CPColor colorWithHue:hue saturation:saturation brightness:100]];
|
||||
|
||||
[[self colorPanel] setColor:[CPColor colorWithHue: hue saturation: saturation brightness: brightness]];
|
||||
var colorPanel = [self colorPanel],
|
||||
opacity = [colorPanel opacity];
|
||||
|
||||
_cachedColor = [CPColor colorWithHue:hue saturation:saturation brightness:brightness alpha:opacity];
|
||||
|
||||
[[self colorPanel] setColor:_cachedColor];
|
||||
}
|
||||
|
||||
- (BOOL)supportsMode:(int)mode
|
||||
|
||||
- (BOOL)supportsMode:(int)mode
|
||||
{
|
||||
return (mode == CPWheelColorPickerMode) ? YES : NO;
|
||||
}
|
||||
|
||||
- (int)currentMode
|
||||
|
||||
- (int)currentMode
|
||||
{
|
||||
return CPWheelColorPickerMode;
|
||||
}
|
||||
|
||||
- (CPView)provideNewView:(BOOL)initialRequest
|
||||
|
||||
- (CPView)provideNewView:(BOOL)initialRequest
|
||||
{
|
||||
if (initialRequest)
|
||||
if (initialRequest)
|
||||
[self initView];
|
||||
|
||||
|
||||
return _pickerView;
|
||||
}
|
||||
|
||||
- (void)setColor:(CPColor)newColor
|
||||
|
||||
- (void)setColor:(CPColor)newColor
|
||||
{
|
||||
if ([newColor isEqual:_cachedColor])
|
||||
return;
|
||||
|
||||
var hsb = [newColor hsbComponents];
|
||||
|
||||
|
||||
[_hueSaturationView setPositionToColor:newColor];
|
||||
[_brightnessSlider setFloatValue:hsb[2]];
|
||||
[_hueSaturationView setWheelBrightness:hsb[2] / 100.0];
|
||||
|
||||
_brightnessBarImage.style.backgroundColor = "#"+[[CPColor colorWithHue:hsb[0] saturation:hsb[1] brightness:100] hexString];
|
||||
[_brightnessSlider setBackgroundColor:[CPColor colorWithHue:hsb[0] saturation:hsb[1] brightness:100]];
|
||||
}
|
||||
|
||||
- (CPImage)provideNewButtonImage
|
||||
@@ -210,28 +210,28 @@
|
||||
{
|
||||
DOMElement _wheelImage;
|
||||
DOMElement _blackWheelImage;
|
||||
|
||||
|
||||
CPView _crosshair;
|
||||
|
||||
|
||||
id _delegate;
|
||||
|
||||
|
||||
float _angle;
|
||||
float _distance;
|
||||
|
||||
|
||||
float _radius;
|
||||
}
|
||||
|
||||
-(id)initWithFrame:(CPRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame: aFrame];
|
||||
|
||||
var path = [[CPBundle bundleForClass: CPColorPicker] pathForResource:@"wheel.png"];
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
var path = [[CPBundle bundleForClass:CPColorPicker] pathForResource:@"wheel.png"];
|
||||
|
||||
_wheelImage = new Image();
|
||||
_wheelImage.src = path;
|
||||
_wheelImage.style.position = "absolute";
|
||||
|
||||
path = [[CPBundle bundleForClass: CPColorPicker] pathForResource:@"wheel_black.png"];
|
||||
|
||||
path = [[CPBundle bundleForClass:CPColorPicker] pathForResource:@"wheel_black.png"];
|
||||
|
||||
_blackWheelImage = new Image();
|
||||
_blackWheelImage.src = path;
|
||||
@@ -241,19 +241,19 @@
|
||||
|
||||
_DOMElement.appendChild(_wheelImage);
|
||||
_DOMElement.appendChild(_blackWheelImage);
|
||||
|
||||
[self setWheelSize: aFrame.size];
|
||||
|
||||
[self setWheelSize:aFrame.size];
|
||||
|
||||
_crosshair = [[CPView alloc] initWithFrame:CPRectMake(_radius - 2, _radius - 2, 4, 4)];
|
||||
[_crosshair setBackgroundColor:[CPColor blackColor]];
|
||||
|
||||
|
||||
var view = [[CPView alloc] initWithFrame:CGRectInset([_crosshair bounds], 1.0, 1.0)];
|
||||
[view setBackgroundColor:[CPColor whiteColor]];
|
||||
|
||||
|
||||
[_crosshair addSubview:view];
|
||||
|
||||
[self addSubview: _crosshair];
|
||||
|
||||
|
||||
[self addSubview:_crosshair];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -265,8 +265,8 @@
|
||||
|
||||
-(void)setFrameSize:(CPSize)aSize
|
||||
{
|
||||
[super setFrameSize: aSize];
|
||||
[self setWheelSize: aSize];
|
||||
[super setFrameSize:aSize];
|
||||
[self setWheelSize:aSize];
|
||||
}
|
||||
|
||||
-(void)setWheelSize:(CPSize)aSize
|
||||
@@ -288,8 +288,8 @@
|
||||
_wheelImage.style.left = (aSize.width - min) / 2.0 + "px";
|
||||
|
||||
_radius = min / 2.0;
|
||||
|
||||
[self setAngle: [self degreesToRadians: _angle] distance: (_distance / 100.0) * _radius];
|
||||
|
||||
[self setAngle:[self degreesToRadians:_angle] distance:(_distance / 100.0) * _radius];
|
||||
}
|
||||
|
||||
-(void)setDelegate:(id)aDelegate
|
||||
@@ -314,29 +314,28 @@
|
||||
|
||||
-(void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
[self reposition: anEvent];
|
||||
[self reposition:anEvent];
|
||||
}
|
||||
|
||||
-(void)mouseDragged:(CPEvent)anEvent
|
||||
{
|
||||
[self reposition: anEvent];
|
||||
[self reposition:anEvent];
|
||||
}
|
||||
|
||||
-(void)reposition:(CPEvent)anEvent
|
||||
{
|
||||
var bounds = [self bounds],
|
||||
location = [self convertPoint: [anEvent locationInWindow] fromView: nil];
|
||||
location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
|
||||
var midX = CGRectGetMidX(bounds);
|
||||
var midY = CGRectGetMidY(bounds);
|
||||
|
||||
|
||||
var distance = MIN(SQRT((location.x - midX)*(location.x - midX) + (location.y - midY)*(location.y - midY)), _radius);
|
||||
var angle = ATAN2(location.y - midY, location.x - midX);
|
||||
|
||||
[self setAngle: angle distance: distance];
|
||||
|
||||
if(_delegate)
|
||||
[_delegate colorWheelDidChange: self];
|
||||
[self setAngle:angle distance:distance];
|
||||
|
||||
[_delegate colorWheelDidChange:self];
|
||||
}
|
||||
|
||||
-(void)setAngle:(int)angle distance:(float)distance
|
||||
@@ -344,10 +343,10 @@
|
||||
var bounds = [self bounds];
|
||||
var midX = CGRectGetMidX(bounds);
|
||||
var midY = CGRectGetMidY(bounds);
|
||||
|
||||
_angle = [self radiansToDegrees: angle];
|
||||
_distance = (distance / _radius) * 100.0;
|
||||
|
||||
|
||||
_angle = [self radiansToDegrees:angle];
|
||||
_distance = (distance / _radius) * 100.0;
|
||||
|
||||
[_crosshair setFrameOrigin:CPPointMake(COS(angle) * distance + midX - 2.0, SIN(angle) * distance + midY - 2.0)];
|
||||
}
|
||||
|
||||
@@ -355,11 +354,11 @@
|
||||
{
|
||||
var hsb = [aColor hsbComponents],
|
||||
bounds = [self bounds];
|
||||
|
||||
var angle = [self degreesToRadians: hsb[0]],
|
||||
|
||||
var angle = [self degreesToRadians:hsb[0]],
|
||||
distance = (hsb[1] / 100.0) * _radius;
|
||||
|
||||
[self setAngle: angle distance: distance];
|
||||
|
||||
[self setAngle:angle distance:distance];
|
||||
}
|
||||
|
||||
-(int)radiansToDegrees:(float)radians
|
||||
@@ -371,6 +370,6 @@
|
||||
{
|
||||
return -(((degrees - 360) / 180) * PI);
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -29,7 +29,9 @@
|
||||
|
||||
var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiveNotification";
|
||||
|
||||
/*! @class CPColorWell
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPColorWell
|
||||
|
||||
CPColorWell is a CPControl for selecting and displaying a single color value. An example of a CPColorWell object (or simply color well) is found in CPColorPanel, which uses a color well to display the current color selection.</p>
|
||||
|
||||
@@ -249,7 +251,6 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
var colorPanel = [CPColorPanel sharedColorPanel];
|
||||
|
||||
[colorPanel setColor:_color];
|
||||
|
||||
[colorPanel orderFront:self];
|
||||
}
|
||||
|
||||
|
||||
@@ -49,14 +49,23 @@ CPJavascriptRemedialKeySupport = 1 << 15;
|
||||
CPJavaScriptShadowFeature = 1 << 20;
|
||||
|
||||
CPJavaScriptNegativeMouseWheelValues = 1 << 22;
|
||||
CPJavaScriptMouseWheelValues_8_15 = 1 << 23
|
||||
|
||||
CPOpacityRequiresFilterFeature = 1 << 23;
|
||||
CPOpacityRequiresFilterFeature = 1 << 24;
|
||||
|
||||
var USER_AGENT = "";
|
||||
|
||||
//Internet explorer does not allow dynamically changing the type of an input element
|
||||
CPInputTypeCanBeChangedFeature = 1 << 25;
|
||||
|
||||
|
||||
|
||||
var USER_AGENT = "",
|
||||
PLATFORM_ENGINE = CPUnknownBrowserEngine,
|
||||
PLATFORM_FEATURES = 0;
|
||||
|
||||
// default these features to true
|
||||
|
||||
PLATFORM_FEATURES |= CPInputTypeCanBeChangedFeature;
|
||||
|
||||
if (typeof window != "undfined" && typeof window.navigator != "undefined")
|
||||
USER_AGENT = window.navigator.userAgent;
|
||||
|
||||
@@ -79,6 +88,8 @@ else if (window.attachEvent) // Must follow Opera check.
|
||||
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
|
||||
|
||||
PLATFORM_FEATURES |= CPOpacityRequiresFilterFeature;
|
||||
|
||||
PLATFORM_FEATURES &= ~CPInputTypeCanBeChangedFeature;
|
||||
}
|
||||
|
||||
// WebKit
|
||||
@@ -115,10 +126,16 @@ else if (USER_AGENT.indexOf("Gecko") != -1) // Must follow KHTML check.
|
||||
PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature;
|
||||
|
||||
var index = USER_AGENT.indexOf("Firefox"),
|
||||
version = (index == -1) ? 2.0 : parseFloat(USER_AGENT.substring(index+"Firefox".length+1));
|
||||
version = (index == -1) ? 2.0 : parseFloat(USER_AGENT.substring(index + "Firefox".length + 1));
|
||||
|
||||
if (version >= 3.0)
|
||||
PLATFORM_FEATURES |= CPCSSRGBAFeature;
|
||||
|
||||
var geckoIndex = USER_AGENT.indexOf("Gecko"),
|
||||
geckoVersion = (geckoIndex === -1) ? 0.0 : parseFloat(USER_AGENT.substring(geckoIndex + "Gecko".length + 1, USER_AGENT.indexOf(' ', geckoIndex)));
|
||||
|
||||
if (version < 20061028)
|
||||
PLATFORM_FEATURES |= CPJavaScriptMouseWheelValues_8_15;
|
||||
}
|
||||
|
||||
// Feature Specific Checks
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
@import "CPShadow.j"
|
||||
@import "CPView.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
|
||||
/*
|
||||
@global
|
||||
@group CPTextAlignment
|
||||
@@ -80,27 +80,57 @@ CPControlTextDidEndEditingNotification = "CPControlTextDidEndEditingNotific
|
||||
|
||||
var CPControlBlackColor = [CPColor blackColor];
|
||||
|
||||
/*! @class CPControl
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPControl
|
||||
|
||||
CPControl is an abstract superclass used to implement user interface elements. As a subclass of CPView and CPResponder it has the ability to handle screen drawing and handling user input.
|
||||
*/
|
||||
@implementation CPControl : CPView
|
||||
{
|
||||
id _value;
|
||||
id _value;
|
||||
|
||||
// Target-Action Support
|
||||
id _target;
|
||||
SEL _action;
|
||||
int _sendActionOn;
|
||||
|
||||
// Mouse Tracking Support
|
||||
BOOL _continuousTracking;
|
||||
BOOL _trackingWasWithinFrame;
|
||||
unsigned _trackingMouseDownFlags;
|
||||
CGPoint _previousTrackingLocation;
|
||||
|
||||
JSObject _ephemeralSubviewsForNames;
|
||||
CPSet _ephereralSubviews;
|
||||
|
||||
BOOL _isEnabled;
|
||||
|
||||
int _alignment;
|
||||
CPFont _font;
|
||||
CPColor _textColor;
|
||||
CPShadow _textShadow;
|
||||
|
||||
id _target;
|
||||
SEL _action;
|
||||
int _sendActionOn;
|
||||
|
||||
CPDictionary _backgroundColors;
|
||||
CPString _currentBackgroundColorName;
|
||||
CPString _toolTip;
|
||||
}
|
||||
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[CPLeftTextAlignment,
|
||||
CPTopVerticalTextAlignment,
|
||||
CPLineBreakByClipping,
|
||||
[CPColor blackColor],
|
||||
[CPFont systemFontOfSize:12.0],
|
||||
nil,
|
||||
_CGSizeMakeZero(),
|
||||
CPImageLeft,
|
||||
CPScaleToFit,
|
||||
_CGSizeMakeZero(),
|
||||
_CGSizeMake(-1.0, -1.0)]
|
||||
forKeys:[@"alignment",
|
||||
@"vertical-alignment",
|
||||
@"line-break-mode",
|
||||
@"text-color",
|
||||
@"font",
|
||||
@"text-shadow-color",
|
||||
@"text-shadow-offset",
|
||||
@"image-position",
|
||||
@"image-scaling",
|
||||
@"min-size",
|
||||
@"max-size"]];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -110,124 +140,12 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
if (self)
|
||||
{
|
||||
_sendActionOn = CPLeftMouseUpMask;
|
||||
_isEnabled = YES;
|
||||
|
||||
[self setFont:[CPFont systemFontOfSize:12.0]];
|
||||
[self setTextColor:CPControlBlackColor];
|
||||
|
||||
_backgroundColors = [CPDictionary dictionary];
|
||||
_trackingMouseDownFlags = 0;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets whether the receiver responds to mouse events.
|
||||
@param isEnabled whether the receiver will respond to mouse events
|
||||
*/
|
||||
- (void)setEnabled:(BOOL)isEnabled
|
||||
{
|
||||
[self setAlphaValue:(_isEnabled = isEnabled) ? 1.0 : 0.3];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns <code>YES</code> if the receiver responds to mouse events.
|
||||
*/
|
||||
- (BOOL)isEnabled
|
||||
{
|
||||
return _isEnabled;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Sets the color of the receiver's text.
|
||||
*/
|
||||
- (void)setTextColor:(CPColor)aColor
|
||||
{
|
||||
if (_textColor == aColor)
|
||||
return;
|
||||
|
||||
_textColor = aColor;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
_DOMElement.style.color = [aColor cssString];
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the color of the receiver's text
|
||||
*/
|
||||
- (CPColor)textColor
|
||||
{
|
||||
return _textColor;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the receiver's alignment
|
||||
*/
|
||||
- (CPTextAlignment)alignment
|
||||
{
|
||||
return _alignment;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the receiver's alignment
|
||||
@param anAlignment the receiver's alignment
|
||||
*/
|
||||
- (void)setAlignment:(CPTextAlignment)anAlignment
|
||||
{
|
||||
_alignment = anAlignment;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the receiver's font
|
||||
@param aFont the font for the receiver
|
||||
*/
|
||||
- (void)setFont:(CPFont)aFont
|
||||
{
|
||||
if (_font == aFont)
|
||||
return;
|
||||
|
||||
_font = aFont;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
_DOMElement.style.font = [_font ? _font : [CPFont systemFontOfSize:12.0] cssString];
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the receiver's font
|
||||
*/
|
||||
- (CPFont)font
|
||||
{
|
||||
return _font;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the shadow for the receiver's text.
|
||||
@param aTextShadow the text shadow
|
||||
*/
|
||||
- (void)setTextShadow:(CPShadow)aTextShadow
|
||||
{
|
||||
_DOMElement.style.textShadow = [_textShadow = aTextShadow cssString];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the receiver's text shadow
|
||||
*/
|
||||
- (CPShadow)textShadow
|
||||
{
|
||||
return _textShadow;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the receiver's target action
|
||||
*/
|
||||
- (SEL)action
|
||||
{
|
||||
return _action;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the receiver's target action
|
||||
@param anAction Sets the action message that gets sent to the target.
|
||||
@@ -238,11 +156,11 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the receiver's target. The target receives action messages from the receiver.
|
||||
Returns the receiver's target action
|
||||
*/
|
||||
- (id)target
|
||||
- (SEL)action
|
||||
{
|
||||
return _target;
|
||||
return _action;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -254,12 +172,12 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
_target = aTarget;
|
||||
}
|
||||
|
||||
- (void)mouseUp:(CPEvent)anEvent
|
||||
/*!
|
||||
Returns the receiver's target. The target receives action messages from the receiver.
|
||||
*/
|
||||
- (id)target
|
||||
{
|
||||
if (_sendActionOn & CPLeftMouseUpMask && CPRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil]))
|
||||
[self sendAction:_action to:_target];
|
||||
|
||||
[super mouseUp:anEvent];
|
||||
return _target;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -281,13 +199,40 @@ 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.
|
||||
*/
|
||||
- (BOOL)isContinuous
|
||||
{
|
||||
// Some subclasses should redefine this with CPLeftMouseDraggedMask
|
||||
return (_sendActionOn & CPPeriodicMask) != 0;
|
||||
return (_sendActionOn & CPPeriodicMask) !== 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -302,6 +247,93 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
_sendActionOn &= ~CPPeriodicMask;
|
||||
}
|
||||
|
||||
- (BOOL)tracksMouseOutsideOfFrame
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)trackMouse:(CPEvent)anEvent
|
||||
{
|
||||
var type = [anEvent type],
|
||||
currentLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
isWithinFrame = [self tracksMouseOutsideOfFrame] || CGRectContainsPoint([self bounds], currentLocation);
|
||||
|
||||
if (type === CPLeftMouseUp)
|
||||
{
|
||||
[self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:YES];
|
||||
|
||||
_trackingMouseDownFlags = 0;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (type === CPLeftMouseDown)
|
||||
{
|
||||
_trackingMouseDownFlags = [anEvent modifierFlags];
|
||||
_continuousTracking = [self startTrackingAt:currentLocation];
|
||||
}
|
||||
else if (type === CPLeftMouseDragged)
|
||||
{
|
||||
if (isWithinFrame)
|
||||
{
|
||||
if (!_trackingWasWithinFrame)
|
||||
_continuousTracking = [self startTrackingAt:currentLocation];
|
||||
|
||||
else if (_continuousTracking)
|
||||
_continuousTracking = [self continueTracking:_previousTrackingLocation at:currentLocation];
|
||||
}
|
||||
else
|
||||
[self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:NO];
|
||||
}
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
}
|
||||
|
||||
if ((_sendActionOn & (1 << type)) && isWithinFrame)
|
||||
[self sendAction:_action to:_target];
|
||||
|
||||
_trackingWasWithinFrame = isWithinFrame;
|
||||
_previousTrackingLocation = currentLocation;
|
||||
}
|
||||
|
||||
- (void)performClick:(id)sender
|
||||
{
|
||||
[self highlight:YES];
|
||||
[self setState:[self nextState]];
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
[self highlight:NO];
|
||||
}
|
||||
|
||||
- (unsigned)mouseDownFlags
|
||||
{
|
||||
return _trackingMouseDownFlags;
|
||||
}
|
||||
|
||||
- (BOOL)startTrackingAt:(CGPoint)aPoint
|
||||
{
|
||||
[self highlight:YES];
|
||||
|
||||
return (_sendActionOn & CPPeriodicMask) || (_sendActionOn & CPLeftMouseDraggedMask);
|
||||
}
|
||||
|
||||
- (BOOL)continueTracking:(CGPoint)lastPoint at:(CGPoint)aPoint
|
||||
{
|
||||
return (_sendActionOn & CPPeriodicMask) || (_sendActionOn & CPLeftMouseDraggedMask);
|
||||
}
|
||||
|
||||
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
|
||||
{
|
||||
[self highlight:NO];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
if (![self isEnabled])
|
||||
return;
|
||||
|
||||
[self trackMouse:anEvent];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the receiver's object value
|
||||
*/
|
||||
@@ -316,6 +348,9 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
- (void)setObjectValue:(id)anObject
|
||||
{
|
||||
_value = anObject;
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -369,7 +404,6 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
[self setObjectValue:anObject];
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Returns the receiver's int value
|
||||
*/
|
||||
@@ -392,7 +426,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
*/
|
||||
- (CPString)stringValue
|
||||
{
|
||||
return _value ? String(_value) : "";
|
||||
return (_value === undefined || _value === nil) ? "" : String(_value);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -403,7 +437,6 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
[self setObjectValue:anObject];
|
||||
}
|
||||
|
||||
|
||||
- (void)takeDoubleValueFrom:(id)sender
|
||||
{
|
||||
if ([sender respondsToSelector:@selector(doubleValue)])
|
||||
@@ -444,44 +477,6 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
[self setStringValue:[sender stringValue]];
|
||||
}
|
||||
|
||||
|
||||
- (void)setBackgroundColor:(CPColor)aColor
|
||||
{
|
||||
_backgroundColors = [CPDictionary dictionary];
|
||||
|
||||
[self setBackgroundColor:aColor forName:CPControlNormalBackgroundColor];
|
||||
|
||||
[super setBackgroundColor:aColor];
|
||||
}
|
||||
|
||||
- (void)setBackgroundColor:(CPColor)aColor forName:(CPString)aName
|
||||
{
|
||||
if (!aColor)
|
||||
[_backgroundColors removeObjectForKey:aName];
|
||||
else
|
||||
[_backgroundColors setObject:aColor forKey:aName];
|
||||
|
||||
if (_currentBackgroundColorName == aName)
|
||||
[self setBackgroundColorWithName:_currentBackgroundColorName];
|
||||
}
|
||||
|
||||
- (CPColor)backgroundColorForName:(CPString)aName
|
||||
{
|
||||
var backgroundColor = [_backgroundColors objectForKey:aName];
|
||||
|
||||
if (!backgroundColor && aName != CPControlNormalBackgroundColor)
|
||||
return [_backgroundColors objectForKey:CPControlNormalBackgroundColor];
|
||||
|
||||
return backgroundColor;
|
||||
}
|
||||
|
||||
- (void)setBackgroundColorWithName:(CPString)aName
|
||||
{
|
||||
_currentBackgroundColorName = aName;
|
||||
|
||||
[super setBackgroundColor:[self backgroundColorForName:aName]];
|
||||
}
|
||||
|
||||
- (void)textDidBeginEditing:(CPNotification)note
|
||||
{
|
||||
//this looks to prevent false propagation of notifications for other objects
|
||||
@@ -509,31 +504,117 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidEndEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
|
||||
}
|
||||
|
||||
/*
|
||||
Ð doubleValue
|
||||
Ð setDoubleValue:
|
||||
Ð intValue
|
||||
Ð setIntValue:
|
||||
Ð objectValue
|
||||
Ð setObjectValue:
|
||||
Ð stringValue
|
||||
Ð setStringValue:
|
||||
Ð setNeedsDisplay
|
||||
Ð attributedStringValue
|
||||
Ð setAttributedStringValue:
|
||||
*/
|
||||
#define BRIDGE(UPPERCASE, LOWERCASE, ATTRIBUTENAME) \
|
||||
- (void)set##UPPERCASE:(id)aValue\
|
||||
{\
|
||||
[self setValue:aValue forThemeAttribute:ATTRIBUTENAME];\
|
||||
}\
|
||||
- (id)LOWERCASE\
|
||||
{\
|
||||
return [self valueForThemeAttribute:ATTRIBUTENAME];\
|
||||
}
|
||||
|
||||
BRIDGE(Alignment, alignment, "alignment")
|
||||
BRIDGE(VerticalAlignment, verticalAlignment, "vertical-alignment")
|
||||
BRIDGE(LineBreakMode, lineBreakMode, "line-break-mode")
|
||||
BRIDGE(TextColor, textColor, "text-color")
|
||||
BRIDGE(Font, font, "font")
|
||||
BRIDGE(TextShadowColor, textShadowColor, "text-shadow-color")
|
||||
BRIDGE(TextShadowOffset, textShadowOffset, "text-shadow-offset")
|
||||
BRIDGE(ImagePosition, imagePosition, "image-position")
|
||||
BRIDGE(ImageScaling, imageScaling, "image-scaling")
|
||||
|
||||
- (void)setEnabled:(BOOL)isEnabled
|
||||
{
|
||||
if (isEnabled)
|
||||
[self unsetThemeState:CPThemeStateDisabled];
|
||||
else
|
||||
[self setThemeState:CPThemeStateDisabled];
|
||||
}
|
||||
|
||||
- (BOOL)isEnabled
|
||||
{
|
||||
return ![self hasThemeState:CPThemeStateDisabled];
|
||||
}
|
||||
|
||||
- (void)highlight:(BOOL)shouldHighlight
|
||||
{
|
||||
[self setHighlighted:shouldHighlight];
|
||||
}
|
||||
|
||||
- (void)setHighlighted:(BOOL)isHighlighted
|
||||
{
|
||||
if (isHighlighted)
|
||||
[self setThemeState:CPThemeStateHighlighted];
|
||||
else
|
||||
[self unsetThemeState:CPThemeStateHighlighted];
|
||||
}
|
||||
|
||||
- (BOOL)isHighlighted
|
||||
{
|
||||
return [self hasThemeState:CPThemeStateHighlighted];
|
||||
}
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aViewName
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
|
||||
{
|
||||
return _CGRectMakeZero();
|
||||
}
|
||||
|
||||
- (CPView)layoutEphemeralSubviewNamed:(CPString)aViewName
|
||||
positioned:(CPWindowOrderingMode)anOrderingMode
|
||||
relativeToEphemeralSubviewNamed:(CPString)relativeToViewName
|
||||
{
|
||||
if (!_ephemeralSubviewsForNames)
|
||||
{
|
||||
_ephemeralSubviewsForNames = {};
|
||||
_ephemeralSubviews = [CPSet set];
|
||||
}
|
||||
|
||||
var frame = [self rectForEphemeralSubviewNamed:aViewName];
|
||||
|
||||
if (frame && !_CGRectIsEmpty(frame))
|
||||
{
|
||||
if (!_ephemeralSubviewsForNames[aViewName])
|
||||
{
|
||||
_ephemeralSubviewsForNames[aViewName] = [self createEphemeralSubviewNamed:aViewName];
|
||||
|
||||
[_ephemeralSubviews addObject:_ephemeralSubviewsForNames[aViewName]];
|
||||
|
||||
if (_ephemeralSubviewsForNames[aViewName])
|
||||
[self addSubview:_ephemeralSubviewsForNames[aViewName] positioned:anOrderingMode relativeTo:_ephemeralSubviewsForNames[relativeToViewName]];
|
||||
}
|
||||
|
||||
if (_ephemeralSubviewsForNames[aViewName])
|
||||
[_ephemeralSubviewsForNames[aViewName] setFrame:frame];
|
||||
}
|
||||
else if (_ephemeralSubviewsForNames[aViewName])
|
||||
{
|
||||
[_ephemeralSubviewsForNames[aViewName] removeFromSuperview];
|
||||
|
||||
[_ephemeralSubviews removeObject:_ephemeralSubviewsForNames[aViewName]];
|
||||
delete _ephemeralSubviewsForNames[aViewName];
|
||||
}
|
||||
|
||||
return _ephemeralSubviewsForNames[aViewName];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPControlValueKey = "CPControlValueKey",
|
||||
CPControlControlStateKey = @"CPControlControlStateKey",
|
||||
CPControlIsEnabledKey = "CPControlIsEnabledKey",
|
||||
CPControlAlignmentKey = "CPControlAlignmentKey",
|
||||
CPControlFontKey = "CPControlFontKey",
|
||||
CPControlTextColorKey = "CPControlTextColorKey",
|
||||
|
||||
CPControlTargetKey = "CPControlTargetKey",
|
||||
CPControlActionKey = "CPControlActionKey",
|
||||
CPControlSendActionOnKey = "CPControlSendActionOnKey";
|
||||
|
||||
var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
|
||||
|
||||
@implementation CPControl (CPCoding)
|
||||
|
||||
/*
|
||||
@@ -544,19 +625,14 @@ var CPControlValueKey = "CPControlValueKey",
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self setObjectValue:[aCoder decodeObjectForKey:CPControlValueKey]];
|
||||
|
||||
[self setEnabled:[aCoder decodeBoolForKey:CPControlIsEnabledKey]];
|
||||
|
||||
[self setAlignment:[aCoder decodeIntForKey:CPControlAlignmentKey]];
|
||||
[self setFont:[aCoder decodeObjectForKey:CPControlFontKey]];
|
||||
[self setTextColor:[aCoder decodeObjectForKey:CPControlTextColorKey]];
|
||||
|
||||
|
||||
[self setTarget:[aCoder decodeObjectForKey:CPControlTargetKey]];
|
||||
[self setAction:[aCoder decodeObjectForKey:CPControlActionKey]];
|
||||
|
||||
[self sendActionOn:[aCoder decodeIntForKey:CPControlSendActionOnKey]];
|
||||
}
|
||||
|
||||
@@ -569,26 +645,39 @@ var CPControlValueKey = "CPControlValueKey",
|
||||
*/
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
var count = [_subviews count],
|
||||
ephemeral
|
||||
subviews = nil;
|
||||
|
||||
if (count > 0 && [_ephemeralSubviews count] > 0)
|
||||
{
|
||||
subviews = [_subviews.slice(0) copy];
|
||||
|
||||
while (count--)
|
||||
if ([_ephemeralSubviews containsObject:_subviews[count]])
|
||||
_subviews.splice(count, 1);
|
||||
}
|
||||
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeObject:_value forKey:CPControlValueKey];
|
||||
|
||||
[aCoder encodeBool:_isEnabled forKey:CPControlIsEnabledKey];
|
||||
|
||||
[aCoder encodeInt:_alignment forKey:CPControlAlignmentKey];
|
||||
[aCoder encodeObject:_font forKey:CPControlFontKey];
|
||||
[aCoder encodeObject:_textColor forKey:CPControlTextColorKey];
|
||||
|
||||
[aCoder encodeConditionalObject:_target forKey:CPControlTargetKey];
|
||||
[aCoder encodeObject:_action forKey:CPControlActionKey];
|
||||
|
||||
|
||||
if (subviews)
|
||||
_subviews = subviews;
|
||||
|
||||
if (_value !== nil)
|
||||
[aCoder encodeObject:_value forKey:CPControlValueKey];
|
||||
|
||||
if (_target !== nil)
|
||||
[aCoder encodeConditionalObject:_target forKey:CPControlTargetKey];
|
||||
|
||||
if (_action !== NULL)
|
||||
[aCoder encodeObject:_action forKey:CPControlActionKey];
|
||||
|
||||
[aCoder encodeInt:_sendActionOn forKey:CPControlSendActionOnKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var _CPControlSizeIdentifiers = [],
|
||||
_CPControlCachedThreePartImages = {},
|
||||
_CPControlCachedColorWithPatternImages = {},
|
||||
_CPControlCachedThreePartImagePattern = {};
|
||||
|
||||
@@ -624,36 +713,6 @@ function _CPControlColorWithPatternImage(sizes, aClassName)
|
||||
return color;
|
||||
}
|
||||
|
||||
function _CPControlThreePartImages(sizes, aClassName)
|
||||
{
|
||||
var index = 1,
|
||||
count = arguments.length,
|
||||
identifier = "";
|
||||
|
||||
for (; index < count; ++index)
|
||||
identifier += arguments[index];
|
||||
|
||||
var images = _CPControlCachedThreePartImages[identifier];
|
||||
|
||||
if (!images)
|
||||
{
|
||||
var bundle = [CPBundle bundleForClass:[CPControl class]],
|
||||
path = aClassName + "/" + identifier;
|
||||
|
||||
sizes = sizes[identifier];
|
||||
|
||||
images = [
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "0.png"] size:sizes[0]],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "1.png"] size:sizes[1]],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "2.png"] size:sizes[2]]
|
||||
];
|
||||
|
||||
_CPControlCachedThreePartImages[identifier] = images;
|
||||
}
|
||||
|
||||
return images;
|
||||
}
|
||||
|
||||
function _CPControlThreePartImagePattern(isVertical, sizes, aClassName)
|
||||
{
|
||||
var index = 2,
|
||||
@@ -683,4 +742,3 @@ function _CPControlThreePartImagePattern(isVertical, sizes, aClassName)
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
|
||||
/*! @class CPCookie
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPCookie
|
||||
CPCookie is the Cappuccino interface to a web browser cookie. You can set the name
|
||||
*/
|
||||
@implementation CPCookie : CPObject
|
||||
|
||||
@@ -80,7 +80,9 @@ CPDocumentDidFailToSaveNotification = @"CPDocumentDidFailToSaveNotification";
|
||||
|
||||
var CPDocumentUntitledCount = 0;
|
||||
|
||||
/*! @class CPDocument
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPDocument
|
||||
|
||||
CPDocument is used to represent a document/file in a Cappuccino application.
|
||||
In a document-based application, generally multiple documents are open simutaneously
|
||||
@@ -386,10 +388,14 @@ var CPDocumentUntitledCount = 0;
|
||||
*/
|
||||
- (void)connection:(CPURLConnection)aConnection didReceiveResponse:(CPURLResponse)aResponse
|
||||
{
|
||||
// If we got this far and it wasn't an HTTP request, then everything is fine.
|
||||
if (![aResponse isKindOfClass:[CPHTTPURLResponse class]])
|
||||
return;
|
||||
|
||||
var statusCode = [aResponse statusCode];
|
||||
|
||||
// Nothing to do if everything is hunky dory.
|
||||
if (statusCode == 200)
|
||||
if (statusCode === 200)
|
||||
return;
|
||||
|
||||
var session = aConnection.session;
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
|
||||
var CPSharedDocumentController = nil;
|
||||
|
||||
/*! @class CPDocumentController
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPDocumentController
|
||||
This class is responsible for managing an application's open documents.
|
||||
*/
|
||||
@implementation CPDocumentController : CPObject
|
||||
|
||||
@@ -25,17 +25,23 @@
|
||||
@import <AppKit/CPPasteboard.j>
|
||||
@import <AppKit/CPImageView.j>
|
||||
|
||||
#import "CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
#define DRAGGING_WINDOW(anObject) ([anObject isKindOfClass:[CPWindow class]] ? anObject : [anObject window])
|
||||
|
||||
var CPSharedDragServer = nil;
|
||||
|
||||
var CPDragServerView = nil,
|
||||
CPDragServerSource = nil,
|
||||
CPDragServerWindow = nil,
|
||||
CPDragServerOffset = nil,
|
||||
CPDragServerLocation = nil,
|
||||
CPDragServerPasteboard = nil,
|
||||
CPDragServerDestination = nil,
|
||||
CPDragServerDraggingInfo = nil;
|
||||
var CPDragServerView = nil,
|
||||
CPDragServerSource = nil,
|
||||
CPDragServerWindow = nil,
|
||||
CPDragServerOffset = nil,
|
||||
CPDragServerLocation = nil,
|
||||
CPDragServerPasteboard = nil,
|
||||
CPDragServerDestination = nil,
|
||||
CPDragServerDraggingInfo = nil,
|
||||
CPDragServerPreviousEvent = nil,
|
||||
CPDragServerAutoscrollInterval = nil;
|
||||
|
||||
var CPDragServerIsDraggingImage = NO,
|
||||
|
||||
@@ -45,6 +51,11 @@ var CPDragServerIsDraggingImage = NO,
|
||||
CPDragServerShouldSendDraggedViewEndedAtOperation = NO,
|
||||
CPDragServerShouldSendDraggedImageEndedAtOperation = NO;
|
||||
|
||||
var CPDragServerAutoscroll = function()
|
||||
{
|
||||
[CPDragServerSource autoscroll:CPDragServerPreviousEvent];
|
||||
}
|
||||
|
||||
var CPDragServerStartDragging = function(anEvent)
|
||||
{
|
||||
CPDragServerUpdateDragging(anEvent);
|
||||
@@ -55,7 +66,12 @@ var CPDragServerUpdateDragging = function(anEvent)
|
||||
// If this is a mouse up, then complete the drag.
|
||||
if([anEvent type] == CPLeftMouseUp)
|
||||
{
|
||||
CPDragServerLocation = [[CPDragServerDestination window] convertBridgeToBase:[[anEvent window] convertBaseToBridge:[anEvent locationInWindow]]];
|
||||
if (CPDragServerAutoscrollInterval !== nil)
|
||||
clearInterval(CPDragServerAutoscrollInterval);
|
||||
|
||||
CPDragServerAutoscrollInterval = nil;
|
||||
|
||||
CPDragServerLocation = [DRAGGING_WINDOW(CPDragServerDestination) convertBridgeToBase:[[anEvent window] convertBaseToBridge:[anEvent locationInWindow]]];
|
||||
|
||||
[CPDragServerView removeFromSuperview];
|
||||
[CPSharedDragServer._dragWindow orderOut:nil];
|
||||
@@ -73,10 +89,18 @@ var CPDragServerUpdateDragging = function(anEvent)
|
||||
|
||||
CPDragServerIsDraggingImage = NO;
|
||||
CPDragServerDestination = nil;
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (CPDragServerAutoscrollInterval === nil)
|
||||
{
|
||||
if ([CPDragServerSource respondsToSelector:@selector(autoscroll:)])
|
||||
CPDragServerAutoscrollInterval = setInterval(CPDragServerAutoscroll, 100);
|
||||
}
|
||||
|
||||
CPDragServerPreviousEvent = anEvent;
|
||||
|
||||
// If we're not a mouse up, then we're going to want to grab the next event.
|
||||
[CPApp setCallback:CPDragServerUpdateDragging
|
||||
forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask
|
||||
@@ -89,7 +113,7 @@ var CPDragServerUpdateDragging = function(anEvent)
|
||||
// We have to convert base to bridge since the drag event comes from the source window, not the drag window.
|
||||
var draggingDestination = [[CPDOMWindowBridge sharedDOMWindowBridge] _dragHitTest:bridgeLocation pasteboard:CPDragServerPasteboard];
|
||||
|
||||
CPDragServerLocation = [[CPDragServerDestination window] convertBridgeToBase:bridgeLocation];
|
||||
CPDragServerLocation = [DRAGGING_WINDOW(draggingDestination) convertBridgeToBase:bridgeLocation];
|
||||
|
||||
if(draggingDestination != CPDragServerDestination)
|
||||
{
|
||||
@@ -121,20 +145,6 @@ var CPDragServerUpdateDragging = function(anEvent)
|
||||
*/
|
||||
@implementation CPDraggingInfo : CPObject
|
||||
{
|
||||
CPWindow _window;
|
||||
}
|
||||
|
||||
/*
|
||||
Initializes the receiver with the window
|
||||
*/
|
||||
- (id)initWithWindow:(CPWindow)aWindow
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
_window = aWindow;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
- (id)draggingSource
|
||||
@@ -152,6 +162,26 @@ var CPDragServerUpdateDragging = function(anEvent)
|
||||
return CPDragServerPasteboard;
|
||||
}
|
||||
|
||||
- (CPImage)draggedImage
|
||||
{
|
||||
return [CPDragServerView image];
|
||||
}
|
||||
|
||||
- (CGPoint)draggedImageLocation
|
||||
{
|
||||
return [self draggedViewLocation];
|
||||
}
|
||||
|
||||
- (CGPoint)draggedViewLocation
|
||||
{
|
||||
return [DRAGGING_WINDOW(CPDragServerDestination) convertBridgeToBase:[CPDragServerView frame].origin];
|
||||
}
|
||||
|
||||
- (CPView)draggedView
|
||||
{
|
||||
return CPDragServerView;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPDragServer : CPObject
|
||||
@@ -278,23 +308,31 @@ var CPDragServerUpdateDragging = function(anEvent)
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPView (CPDraggingAdditions)
|
||||
@implementation CPWindow (CPDraggingAdditions)
|
||||
|
||||
/* @ignore */
|
||||
- (CPView)_dragHitTest:(CPPoint)aPoint pasteboard:(CPPasteboard)aPasteboard
|
||||
- (id)_dragHitTest:(CGPoint)aPoint pasteboard:(CPPasteboard)aPasteboard
|
||||
{
|
||||
if(!CPRectContainsPoint(_frame, aPoint) || self == CPDragServerView)
|
||||
// If none of our views or ourselves has registered for drag events...
|
||||
if (!_inclusiveRegisteredDraggedTypes)
|
||||
return nil;
|
||||
|
||||
// We don't need to do this because the only place this gets called
|
||||
// -_dragHitTest: in CPDOMWindowBridge does this already. Perhaps to
|
||||
// be safe?
|
||||
// if (![self containsPoint:aPoint])
|
||||
// return nil;
|
||||
|
||||
var adjustedPoint = _CGPointMake(aPoint.x - _CGRectGetMinX(_frame), aPoint.y - _CGRectGetMinY(_frame)),
|
||||
hitView = [_windowView hitTest:adjustedPoint];
|
||||
|
||||
while (hitView && ![aPasteboard availableTypeFromArray:[hitView registeredDraggedTypes]])
|
||||
hitView = [hitView superview];
|
||||
|
||||
var view = nil,
|
||||
i = [_subviews count],
|
||||
adjustedPoint = CPPointMake(aPoint.x - CPRectGetMinX(_frame), aPoint.y - CPRectGetMinY(_frame));
|
||||
|
||||
while (i--)
|
||||
if (view = [_subviews[i] _dragHitTest:adjustedPoint pasteboard:aPasteboard])
|
||||
return view;
|
||||
|
||||
if ([aPasteboard availableTypeFromArray:_registeredDraggedTypes])
|
||||
if (hitView)
|
||||
return hitView;
|
||||
|
||||
if ([aPasteboard availableTypeFromArray:[self registeredDraggedTypes]])
|
||||
return self;
|
||||
|
||||
return nil;
|
||||
|
||||
@@ -130,6 +130,13 @@ CPOtherMouseUp = 26;
|
||||
@group CPEventType
|
||||
*/
|
||||
CPOtherMouseDragged = 27;
|
||||
|
||||
// iPhone Event Types
|
||||
CPTouchStart = 28;
|
||||
CPTouchMove = 29;
|
||||
CPTouchEnd = 30;
|
||||
CPTouchCancel = 31;
|
||||
|
||||
|
||||
CPAlphaShiftKeyMask = 1 << 16;
|
||||
CPShiftKeyMask = 1 << 17;
|
||||
@@ -175,11 +182,17 @@ CPDOMEventKeyPress = "keypress";
|
||||
CPDOMEventCopy = "copy";
|
||||
CPDOMEventPaste = "paste";
|
||||
CPDOMEventScrollWheel = "mousewheel";
|
||||
CPDOMEventTouchStart = "touchstart";
|
||||
CPDOMEventTouchMove = "touchmove";
|
||||
CPDOMEventTouchEnd = "touchend";
|
||||
CPDOMEventTouchCancel = "touchcancel";
|
||||
|
||||
var _CPEventPeriodicEventPeriod = 0,
|
||||
_CPEventPeriodicEventTimer = nil;
|
||||
|
||||
/*! @class CPEvent
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPEvent
|
||||
CPEvent encapsulates the details of a Cappuccino keyboard or mouse event.
|
||||
*/
|
||||
@implementation CPEvent : CPObject
|
||||
|
||||
@@ -22,17 +22,32 @@
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPFlashMovie
|
||||
|
||||
CPFlashMovie is used to represent a Flash movie in the Cappuccino framework.
|
||||
*/
|
||||
@implementation CPFlashMovie : CPObject
|
||||
{
|
||||
CPString _fileName;
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a new Flash movie with the swf at <code>aFileName</code>.
|
||||
@param aFilename the swf to load
|
||||
@return the initialized CPFlashMovie
|
||||
*/
|
||||
+ (id)flashMovieWithFile:(CPString)aFileName
|
||||
{
|
||||
return [[self alloc] initWithFile:aFileName];
|
||||
}
|
||||
|
||||
/*!
|
||||
Initializes the Flash movie.
|
||||
@param aFilename the swf to load
|
||||
@return the initialized CPFlashMovie
|
||||
*/
|
||||
- (id)initWithFile:(CPString)aFileName
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
@import "CPFlashMovie.j"
|
||||
@import "CPView.j"
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
*/
|
||||
@implementation CPFlashView : CPView
|
||||
{
|
||||
CPFlashMovie _flashMovie;
|
||||
@@ -61,7 +63,7 @@
|
||||
_DOMEmbedElement = document.createElement("embed");
|
||||
|
||||
_DOMEmbedElement.type = "application/x-shockwave-flash";
|
||||
_DOMEmbedElement.wmode = "transparent";
|
||||
_DOMEmbedElement.setAttribute("wmode", "transparent");
|
||||
_DOMEmbedElement.width = "100%";
|
||||
_DOMEmbedElement.height = "100%";
|
||||
|
||||
|
||||
@@ -25,7 +25,9 @@ var _CPFonts = {};
|
||||
|
||||
#define _CPCachedFont(aName, aSize, isBold) _CPFonts[(isBold ? @"bold " : @"") + ROUND(aSize) + @"px '" + aName + @"'"]
|
||||
|
||||
/*! @class CPFont
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPFont
|
||||
|
||||
The CPFont class allows control of the fonts used for displaying text anywhere on the screen. The primary method for getting a particular font is through one of the class methods that take a name and/or size as arguments, and return the appropriate CPFont.
|
||||
*/
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
var CPSharedFontManager = nil,
|
||||
CPFontManagerFactory = Nil;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
*/
|
||||
@implementation CPFontManager : CPObject
|
||||
{
|
||||
CPArray _availableFonts;
|
||||
|
||||
@@ -33,6 +33,11 @@ CPMakePoint = CGPointMake;
|
||||
CPMakeSize = CGSizeMake;
|
||||
CPMakeRect = CGRectMake;
|
||||
|
||||
/*!
|
||||
@addtogroup appkit
|
||||
@{
|
||||
*/
|
||||
|
||||
/*!
|
||||
Creates a copy of a specified point and returns the copy
|
||||
@group CGPoint
|
||||
@@ -498,3 +503,7 @@ function CPPointMakeZero()
|
||||
{
|
||||
return CPPointMake(0, 0, 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
@}
|
||||
*/
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
var CPGraphicsContextCurrent = nil;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
Provides an interface for drawing to the screen.
|
||||
*/
|
||||
@implementation CPGraphicsContext : CPObject
|
||||
|
||||
@@ -38,6 +38,17 @@ CPImageLoadStatusReadError = 6;
|
||||
|
||||
CPImageDidLoadNotification = @"CPImageDidLoadNotification";
|
||||
|
||||
function CPImageInBundle(aFilename, aSize, aBundle)
|
||||
{
|
||||
if (!aBundle)
|
||||
aBundle = [CPBundle mainBundle];
|
||||
|
||||
if (aSize)
|
||||
return [[CPImage alloc] initWithContentsOfFile:[aBundle pathForResource:aFilename] size:aSize];
|
||||
|
||||
return [[CPImage alloc] initWithContentsOfFile:[aBundle pathForResource:aFilename]];
|
||||
}
|
||||
|
||||
@implementation CPBundle (CPImageAdditions)
|
||||
|
||||
- (CPString)pathForResource:(CPString)aFilename
|
||||
@@ -47,7 +58,9 @@ CPImageDidLoadNotification = @"CPImageDidLoadNotification";
|
||||
|
||||
@end
|
||||
|
||||
/*! @class CPImage
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPImage
|
||||
|
||||
CPImage is used to represent images in the Cappuccino framework. It supports loading
|
||||
all image types supported by the browser.
|
||||
@@ -208,6 +221,7 @@ CPImageDidLoadNotification = @"CPImageDidLoadNotification";
|
||||
[self _imageDidLoad];
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
[self _derefFromImage];
|
||||
}
|
||||
|
||||
_image.onerror = function ()
|
||||
@@ -219,6 +233,7 @@ CPImageDidLoadNotification = @"CPImageDidLoadNotification";
|
||||
[self _imageDidError];
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
[self _derefFromImage];
|
||||
}
|
||||
|
||||
_image.onabort = function ()
|
||||
@@ -230,6 +245,7 @@ CPImageDidLoadNotification = @"CPImageDidLoadNotification";
|
||||
[self _imageDidAbort];
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
[self _derefFromImage];
|
||||
}
|
||||
|
||||
_image.src = _filename;
|
||||
@@ -247,6 +263,14 @@ CPImageDidLoadNotification = @"CPImageDidLoadNotification";
|
||||
return NO;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)_derefFromImage
|
||||
{
|
||||
_image.onload = null;
|
||||
_image.onerror = null;
|
||||
_image.onabort = null;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)_imageDidLoad
|
||||
{
|
||||
@@ -327,6 +351,11 @@ CPImageDidLoadNotification = @"CPImageDidLoadNotification";
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPString)filename
|
||||
{
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (CPArray)imageSlices
|
||||
{
|
||||
return _imageSlices;
|
||||
@@ -391,6 +420,11 @@ var CPThreePartImageImageSlicesKey = @"CPThreePartImageImageSlicesKey",
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPString)filename
|
||||
{
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (CPArray)imageSlices
|
||||
{
|
||||
return _imageSlices;
|
||||
|
||||
@@ -58,17 +58,16 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
VERTICAL_SHADOW_INSET = TOP_SHADOW_INSET + BOTTOM_SHADOW_INSET,
|
||||
HORIZONTAL_SHADOW_INSET = LEFT_SHADOW_INSET + RIGHT_SHADOW_INSET;
|
||||
|
||||
/*! @class CPImageView
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPImageView
|
||||
|
||||
This class is a control that displays an image.
|
||||
*/
|
||||
@implementation CPImageView : CPControl
|
||||
{
|
||||
CPImage _image;
|
||||
DOMElement _DOMImageElement;
|
||||
|
||||
CPImageScaling _imageScaling;
|
||||
|
||||
BOOL _hasShadow;
|
||||
CPView _shadowView;
|
||||
|
||||
@@ -101,48 +100,62 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
*/
|
||||
- (CPImage)image
|
||||
{
|
||||
return _image;
|
||||
return [self objectValue];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the image for the view.
|
||||
@param anImage the view's image
|
||||
*/
|
||||
- (void)setImage:(CPImage)anImage
|
||||
{
|
||||
if (_image == anImage)
|
||||
[self setObjectValue:anImage];
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (void)setObjectValue:(CPImage)anImage
|
||||
{
|
||||
var oldImage = [self objectValue];
|
||||
|
||||
if (oldImage === anImage)
|
||||
return;
|
||||
|
||||
[super setObjectValue:anImage];
|
||||
|
||||
var center = [CPNotificationCenter defaultCenter];
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
if (_image)
|
||||
[center removeObserver:self name:CPImageDidLoadNotification object:_image];
|
||||
if (oldImage)
|
||||
[defaultCenter removeObserver:self name:CPImageDidLoadNotification object:oldImage];
|
||||
|
||||
_image = anImage;
|
||||
_DOMImageElement.src = [anImage filename];
|
||||
|
||||
var size = [_image size];
|
||||
var newImage = [self objectValue];
|
||||
|
||||
if (size && size.width == -1 && size.height == -1)
|
||||
#if PLATFORM(DOM)
|
||||
_DOMImageElement.src = newImage ? [newImage filename] : "";
|
||||
#endif
|
||||
|
||||
var size = [newImage size];
|
||||
|
||||
if (size && size.width === -1 && size.height === -1)
|
||||
{
|
||||
[center addObserver:self selector:@selector(imageDidLoad:) name:CPImageDidLoadNotification object:_image];
|
||||
|
||||
[defaultCenter addObserver:self selector:@selector(imageDidLoad:) name:CPImageDidLoadNotification object:newImage];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
_DOMImageElement.width = 0;
|
||||
_DOMImageElement.height = 0;
|
||||
|
||||
#endif
|
||||
|
||||
[_shadowView setHidden:YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self hideOrDisplayContents];
|
||||
[self tile];
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)imageDidLoad:(CPNotification)aNotification
|
||||
{
|
||||
[self hideOrDisplayContents];
|
||||
[self tile];
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -171,7 +184,8 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
|
||||
[self addSubview:_shadowView];
|
||||
|
||||
[self tile];
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -190,33 +204,17 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
*/
|
||||
- (void)setImageScaling:(CPImageScaling)anImageScaling
|
||||
{
|
||||
if (_imageScaling == anImageScaling)
|
||||
return;
|
||||
[super setImageScaling:anImageScaling];
|
||||
|
||||
_imageScaling = anImageScaling;
|
||||
|
||||
if (_imageScaling == CPScaleToFit)
|
||||
#if PLATFORM(DOM)
|
||||
if ([self currentValueForThemeAttribute:@"image-scaling"] === CPScaleToFit)
|
||||
{
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, 0.0, 0.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the image scaling method used to
|
||||
render this image.
|
||||
*/
|
||||
- (CPImageScaling)imageScaling
|
||||
{
|
||||
return _imageScaling;
|
||||
}
|
||||
|
||||
- (void)setFrameSize:(CGSize)aSize
|
||||
{
|
||||
[super setFrameSize:aSize];
|
||||
|
||||
[self tile];
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -224,14 +222,18 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
*/
|
||||
- (void)hideOrDisplayContents
|
||||
{
|
||||
if (!_image)
|
||||
if (![self image])
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
_DOMImageElement.style.visibility = "hidden";
|
||||
#endif
|
||||
[_shadowView setHidden:YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
_DOMImageElement.style.visibility = "visible";
|
||||
#endif
|
||||
[_shadowView setHidden:NO];
|
||||
}
|
||||
}
|
||||
@@ -247,12 +249,14 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
/*!
|
||||
Add a description
|
||||
*/
|
||||
- (void)tile
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
if (!_image)
|
||||
if (![self image])
|
||||
return;
|
||||
|
||||
var bounds = [self bounds],
|
||||
image = [self image],
|
||||
imageScaling = [self currentValueForThemeAttribute:@"image-scaling"],
|
||||
x = 0.0,
|
||||
y = 0.0,
|
||||
insetWidth = (_hasShadow ? HORIZONTAL_SHADOW_INSET : 0.0),
|
||||
@@ -261,20 +265,22 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
boundsHeight = _CGRectGetHeight(bounds),
|
||||
width = boundsWidth - insetWidth,
|
||||
height = boundsHeight - insetHeight;
|
||||
|
||||
if (_imageScaling == CPScaleToFit)
|
||||
|
||||
if (imageScaling === CPScaleToFit)
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
_DOMImageElement.width = ROUND(width);
|
||||
_DOMImageElement.height = ROUND(height);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
var size = [_image size];
|
||||
var size = [image size];
|
||||
|
||||
if (size.width == -1 && size.height == -1)
|
||||
return;
|
||||
|
||||
if (_imageScaling == CPScaleProportionally)
|
||||
if (imageScaling === CPScaleProportionally)
|
||||
{
|
||||
// The max size it can be is size.width x size.height, so only
|
||||
// only proportion otherwise.
|
||||
@@ -293,9 +299,11 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
else
|
||||
height = width / imageRatio;
|
||||
}
|
||||
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
_DOMImageElement.width = ROUND(width);
|
||||
_DOMImageElement.height = ROUND(height);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -303,16 +311,20 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
height = size.height;
|
||||
}
|
||||
|
||||
if (_imageScaling == CPScaleNone)
|
||||
if (imageScaling == CPScaleNone)
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
_DOMImageElement.width = ROUND(size.width);
|
||||
_DOMImageElement.height = ROUND(size.height);
|
||||
#endif
|
||||
}
|
||||
|
||||
var x = (boundsWidth - width) / 2.0,
|
||||
y = (boundsHeight - height) / 2.0;
|
||||
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, x, y);
|
||||
#endif
|
||||
}
|
||||
|
||||
_imageRect = _CGRectMake(x, y, width, height);
|
||||
@@ -321,6 +333,12 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
[_shadowView setFrame:_CGRectMake(x - LEFT_SHADOW_INSET, y - TOP_SHADOW_INSET, width + insetWidth, height + insetHeight)];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
// Should we do something with this event?
|
||||
[[self nextResponder] mouseDown:anEvent];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPImageViewImageKey = @"CPImageViewImageKey",
|
||||
@@ -336,24 +354,26 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
|
||||
*/
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
_DOMImageElement = document.createElement("img");
|
||||
_DOMImageElement.style.position = "absolute";
|
||||
_DOMImageElement.style.left = "0px";
|
||||
_DOMImageElement.style.top = "0px";
|
||||
_DOMImageElement.style.visibility = "hidden";
|
||||
#endif
|
||||
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_DOMImageElement = document.createElement("img");
|
||||
_DOMImageElement.style.position = "absolute";
|
||||
_DOMImageElement.style.left = "0px";
|
||||
_DOMImageElement.style.top = "0px";
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
_DOMElement.appendChild(_DOMImageElement);
|
||||
_DOMImageElement.style.visibility = "hidden";
|
||||
|
||||
[self setImage:[aCoder decodeObjectForKey:CPImageViewImageKey]];
|
||||
|
||||
[self setImageScaling:[aCoder decodeIntForKey:CPImageViewImageScalingKey]];
|
||||
#endif
|
||||
|
||||
[self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]];
|
||||
|
||||
[self tile];
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -381,9 +401,6 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
|
||||
if (_shadowView)
|
||||
_subviews = actualSubviews;
|
||||
|
||||
[aCoder encodeObject:_image forKey:CPImageViewImageKey];
|
||||
|
||||
[aCoder encodeInt:_imageScaling forKey:CPImageViewImageScalingKey];
|
||||
[aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey];
|
||||
}
|
||||
|
||||
|
||||
@@ -48,12 +48,17 @@ var _CPMenuBarVisible = NO,
|
||||
_CPMenuBarAttributes = nil,
|
||||
_CPMenuBarSharedWindow = nil;
|
||||
|
||||
/*! @class CPMenu
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPMenu
|
||||
|
||||
Menus provide the user with a list of actions and/or submenus. Submenus themselves are full fledged menus and so a heirarchical structure appears.
|
||||
Menus provide the user with a list of actions and/or submenus. Submenus themselves are full fledged menus
|
||||
and so a heirarchical structure appears.
|
||||
*/
|
||||
@implementation CPMenu : CPObject
|
||||
{
|
||||
CPMenu _supermenu;
|
||||
|
||||
CPString _title;
|
||||
|
||||
CPMutableArray _items;
|
||||
@@ -61,7 +66,7 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
BOOL _autoenablesItems;
|
||||
BOOL _showsStateColumn;
|
||||
|
||||
|
||||
id _delegate;
|
||||
|
||||
CPMenuItem _highlightedIndex;
|
||||
@@ -70,6 +75,11 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
// Managing the Menu Bar
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
[[self class] setMenuBarAttributes:[CPDictionary dictionary]];
|
||||
}
|
||||
|
||||
+ (BOOL)menuBarVisible
|
||||
{
|
||||
return _CPMenuBarVisible;
|
||||
@@ -96,11 +106,16 @@ var _CPMenuBarVisible = NO,
|
||||
[_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]];
|
||||
[_CPMenuBarSharedWindow setTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextColor"]];
|
||||
[_CPMenuBarSharedWindow setTitleColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTitleColor"]];
|
||||
[_CPMenuBarSharedWindow setTextShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextShadowColor"]];
|
||||
[_CPMenuBarSharedWindow setTitleShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTitleShadowColor"]];
|
||||
[_CPMenuBarSharedWindow setHighlightColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightColor"]];
|
||||
[_CPMenuBarSharedWindow setHighlightTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextColor"]];
|
||||
[_CPMenuBarSharedWindow setHighlightTextShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextShadowColor"]];
|
||||
|
||||
[_CPMenuBarSharedWindow orderFront:self];
|
||||
}
|
||||
else
|
||||
[_CPMenuBarWindow orderOut:self];
|
||||
[_CPMenuBarSharedWindow orderOut:self];
|
||||
|
||||
// FIXME: There must be a better way to do this.
|
||||
#if PLATFORM(DOM)
|
||||
@@ -130,6 +145,7 @@ var _CPMenuBarVisible = NO,
|
||||
return _CPMenuBarImage;
|
||||
}
|
||||
|
||||
|
||||
+ (void)setMenuBarAttributes:(CPDictionary)attributes
|
||||
{
|
||||
if (_CPMenuBarAttributes == attributes)
|
||||
@@ -138,7 +154,12 @@ var _CPMenuBarVisible = NO,
|
||||
_CPMenuBarAttributes = [attributes copy];
|
||||
|
||||
var textColor = [attributes objectForKey:@"CPMenuBarTextColor"],
|
||||
titleColor = [attributes objectForKey:@"CPMenuBarTitleColor"];
|
||||
titleColor = [attributes objectForKey:@"CPMenuBarTitleColor"],
|
||||
textShadowColor = [attributes objectForKey:@"CPMenuBarTextShadowColor"],
|
||||
titleShadowColor = [attributes objectForKey:@"CPMenuBarTitleShadowColor"],
|
||||
highlightColor = [attributes objectForKey:@"CPMenuBarHighlightColor"],
|
||||
highlightTextColor = [attributes objectForKey:@"CPMenuBarHighlightTextColor"],
|
||||
highlightTextShadowColor = [attributes objectForKey:@"CPMenuBarHighlightTextShadowColor"];
|
||||
|
||||
if (!textColor && titleColor)
|
||||
[_CPMenuBarAttributes setObject:titleColor forKey:@"CPMenuBarTextColor"];
|
||||
@@ -148,15 +169,41 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
else if (!textColor && !titleColor)
|
||||
{
|
||||
[_CPMenuBarAttributes setObject:[CPColor blackColor] forKey:@"CPMenuBarTextColor"];
|
||||
[_CPMenuBarAttributes setObject:[CPColor blackColor] forKey:@"CPMenuBarTitleColor"];
|
||||
[_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTextColor"];
|
||||
[_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTitleColor"];
|
||||
}
|
||||
|
||||
if (!textShadowColor && titleShadowColor)
|
||||
[_CPMenuBarAttributes setObject:titleShadowColor forKey:@"CPMenuBarTextShadowColor"];
|
||||
|
||||
else if (textShadowColor && !titleShadowColor)
|
||||
[_CPMenuBarAttributes setObject:textShadowColor forKey:@"CPMenuBarTitleShadowColor"];
|
||||
|
||||
else if (!textShadowColor && !titleShadowColor)
|
||||
{
|
||||
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTextShadowColor"];
|
||||
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTitleShadowColor"];
|
||||
}
|
||||
|
||||
if (!highlightColor)
|
||||
[_CPMenuBarAttributes setObject:[CPColor colorWithCalibratedRed:94.0/255.0 green:130.0/255.0 blue:186.0/255.0 alpha:1.0] forKey:@"CPMenuBarHighlightColor"];
|
||||
|
||||
if (!highlightTextColor)
|
||||
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarHighlightTextColor"];
|
||||
|
||||
if (!highlightTextShadowColor)
|
||||
[_CPMenuBarAttributes setObject:[CPColor blackColor] forKey:@"CPMenuBarHighlightTextShadowColor"];
|
||||
|
||||
if (_CPMenuBarSharedWindow)
|
||||
{
|
||||
[_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]];
|
||||
[_CPMenuBarSharedWindow setTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextColor"]];
|
||||
[_CPMenuBarSharedWindow setTitleColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTitleColor"]];
|
||||
[_CPMenuBarSharedWindow setTextShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextShadowColor"]];
|
||||
[_CPMenuBarSharedWindow setTitleShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTitleShadowColor"]];
|
||||
[_CPMenuBarSharedWindow setHighlightColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightColor"]];
|
||||
[_CPMenuBarSharedWindow setHighlightTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextColor"]];
|
||||
[_CPMenuBarSharedWindow setHighlightTextShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextShadowColor"]];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,6 +226,11 @@ var _CPMenuBarVisible = NO,
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
+ (float)menuBarHeight
|
||||
{
|
||||
return MENUBAR_HEIGHT;
|
||||
}
|
||||
|
||||
// Creating a CPMenu Object
|
||||
/*!
|
||||
Initializes the menu with a specified title.
|
||||
@@ -201,6 +253,11 @@ var _CPMenuBarVisible = NO,
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
return [self initWithTitle:@""];
|
||||
}
|
||||
|
||||
// Setting Up Menu Commands
|
||||
/*!
|
||||
Inserts a menu item at the specified index.
|
||||
@@ -608,10 +665,10 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
if (!aFont)
|
||||
aFont = [CPFont systemFontOfSize:12.0];
|
||||
|
||||
|
||||
var theWindow = [aView window],
|
||||
menuWindow = [_CPMenuWindow menuWindowWithMenu:aMenu font:aFont];
|
||||
|
||||
|
||||
[menuWindow setDelegate:self];
|
||||
[menuWindow setBackgroundStyle:isForMenuBar ? _CPMenuWindowMenuBarBackgroundStyle : _CPMenuWindowPopUpBackgroundStyle];
|
||||
|
||||
@@ -623,27 +680,17 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
+ (void)_menuWindowDidFinishTracking:(_CPMenuWindow)aMenuWindow highlightedItem:(CPMenuItem)aMenuItem
|
||||
{
|
||||
[_CPMenuWindow poolMenuWindow:aMenuWindow];
|
||||
|
||||
// var index = [self indexOfItem:aMenuItem];
|
||||
|
||||
// if (index == CPNotFound)
|
||||
// return;
|
||||
|
||||
var target = nil,
|
||||
action = [aMenuItem action];
|
||||
|
||||
if (!action)
|
||||
{
|
||||
// target = [self target];
|
||||
// action = [self action];
|
||||
}
|
||||
|
||||
// FIXME: If [selectedItem target] == nil do we use our own target?
|
||||
else
|
||||
target = [aMenuItem target];
|
||||
var menu = [aMenuWindow menu];
|
||||
|
||||
[CPApp sendAction:action to:target from:nil];
|
||||
[_CPMenuWindow poolMenuWindow:aMenuWindow];
|
||||
|
||||
if([aMenuItem isEnabled])
|
||||
[CPApp sendAction:[aMenuItem action] to:[aMenuItem target] from:aMenuItem];
|
||||
|
||||
var delegate = [menu delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuDidClose:)])
|
||||
[delegate menuDidClose:menu];
|
||||
}
|
||||
|
||||
// Managing Display of State Column
|
||||
@@ -782,8 +829,9 @@ var _CPMenuBarVisible = NO,
|
||||
@end
|
||||
|
||||
|
||||
var CPMenuTitleKey = @"CPMenuTitleKey",
|
||||
CPMenuItemsKey = @"CPMenuItemsKey";
|
||||
var CPMenuTitleKey = @"CPMenuTitleKey",
|
||||
CPMenuItemsKey = @"CPMenuItemsKey",
|
||||
CPMenuShowsStateColumnKey = @"CPMenuShowsStateColumnKey";
|
||||
|
||||
@implementation CPMenu (CPCoding)
|
||||
|
||||
@@ -800,6 +848,8 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
|
||||
{
|
||||
_title = [aCoder decodeObjectForKey:CPMenuTitleKey];
|
||||
_items = [aCoder decodeObjectForKey:CPMenuItemsKey];
|
||||
|
||||
_showsStateColumn = ![aCoder containsValueForKey:CPMenuShowsStateColumnKey] || [aCoder decodeBoolForKey:CPMenuShowsStateColumnKey];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -813,6 +863,9 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
|
||||
{
|
||||
[aCoder encodeObject:_title forKey:CPMenuTitleKey];
|
||||
[aCoder encodeObject:_items forKey:CPMenuItemsKey];
|
||||
|
||||
if (!_showsStateColumn)
|
||||
[aCoder encodeBool:_showsStateColumn forKey:CPMenuShowsStateColumnKey];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -905,7 +958,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self setLevel:CPTornOffMenuWindowLevel];
|
||||
[self setLevel:CPPopUpMenuWindowLevel];
|
||||
[self setHasShadow:YES];
|
||||
[self setAcceptsMouseMovedEvents:YES];
|
||||
|
||||
@@ -938,6 +991,11 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CGFloat)overlapOffsetWidth
|
||||
{
|
||||
return LEFT_MARGIN;
|
||||
}
|
||||
|
||||
- (void)setFont:(CPFont)aFont
|
||||
{
|
||||
[_menuView setFont:aFont];
|
||||
@@ -1232,6 +1290,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
@implementation _CPMenuView : CPView
|
||||
{
|
||||
CPArray _menuItemViews;
|
||||
CPArray _visibleMenuItemInfos;
|
||||
|
||||
CPFont _font;
|
||||
}
|
||||
@@ -1258,21 +1317,33 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
|
||||
- (int)itemIndexAtPoint:(CGPoint)aPoint
|
||||
{
|
||||
var index = 0,
|
||||
count = _menuItemViews.length;
|
||||
var x = aPoint.x,
|
||||
bounds = [self bounds];
|
||||
|
||||
for (; index < count; ++index)
|
||||
if (x < CGRectGetMinX(bounds) || x > CGRectGetMaxX(bounds))
|
||||
return CPNotFound;
|
||||
|
||||
var y = aPoint.y,
|
||||
low = 0,
|
||||
high = _visibleMenuItemInfos.length - 1;
|
||||
|
||||
while (low <= high)
|
||||
{
|
||||
var view = _menuItemViews[index];
|
||||
var middle = FLOOR(low + (high - low) / 2),
|
||||
info = _visibleMenuItemInfos[middle]
|
||||
frame = [info.view frame];
|
||||
|
||||
if ([view isHidden])
|
||||
continue;
|
||||
if (y < CGRectGetMinY(frame))
|
||||
high = middle - 1;
|
||||
|
||||
if (CGRectContainsPoint([view frame], aPoint))
|
||||
return index;
|
||||
}
|
||||
|
||||
return CPNotFound;
|
||||
else if (y > CGRectGetMaxY(frame))
|
||||
low = middle + 1;
|
||||
|
||||
else
|
||||
return info.index;
|
||||
}
|
||||
|
||||
return CPNotFound;
|
||||
}
|
||||
|
||||
- (void)setMenu:(CPMenu)aMenu
|
||||
@@ -1282,6 +1353,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||
|
||||
_menuItemViews = [];
|
||||
_visibleMenuItemInfos = [];
|
||||
|
||||
var menu = [self menu];
|
||||
|
||||
@@ -1305,6 +1377,8 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
if ([item isHidden])
|
||||
continue;
|
||||
|
||||
_visibleMenuItemInfos.push({ view:view, index:index });
|
||||
|
||||
[view setFont:_font];
|
||||
[view setShowsStateColumn:showsStateColumn];
|
||||
[view synchronizeWithMenuItem];
|
||||
@@ -1357,6 +1431,13 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
|
||||
CPColor _textColor;
|
||||
CPColor _titleColor;
|
||||
|
||||
CPColor _textShadowColor;
|
||||
CPColor _titleShadowColor;
|
||||
|
||||
CPColor _highlightColor;
|
||||
CPColor _highlightTextColor;
|
||||
CPColor _highlightTextShadowColor;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
@@ -1396,6 +1477,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
|
||||
[_titleField setFont:[CPFont boldSystemFontOfSize:12.0]];
|
||||
[_titleField setAlignment:CPCenterTextAlignment];
|
||||
[_titleField setTextShadowOffset:CGSizeMake(0, 1)];
|
||||
|
||||
[contentView addSubview:_titleField];
|
||||
}
|
||||
@@ -1468,6 +1550,54 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
[_titleField setTextColor:aColor ? aColor : [CPColor blackColor]];
|
||||
}
|
||||
|
||||
- (void)setTextShadowColor:(CPColor)aColor
|
||||
{
|
||||
if (_textShadowColor == aColor)
|
||||
return;
|
||||
|
||||
_textShadowColor = aColor;
|
||||
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setTextShadowColor:) withObject:_textShadowColor];
|
||||
}
|
||||
|
||||
- (void)setTitleShadowColor:(CPColor)aColor
|
||||
{
|
||||
if (_titleShadowColor == aColor)
|
||||
return;
|
||||
|
||||
_titleShadowColor = aColor;
|
||||
|
||||
[_titleField setTextShadowColor:aColor ? aColor : [CPColor whiteColor]];
|
||||
}
|
||||
|
||||
- (void)setHighlightColor:(CPColor)aColor
|
||||
{
|
||||
if (_highlightColor == aColor)
|
||||
return;
|
||||
|
||||
_highlightColor = aColor;
|
||||
}
|
||||
|
||||
- (void)setHighlightTextColor:(CPColor)aColor
|
||||
{
|
||||
if (_highlightTextColor == aColor)
|
||||
return;
|
||||
|
||||
_highlightTextColor = aColor;
|
||||
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setActivateColor:) withObject:_highlightTextColor];
|
||||
}
|
||||
|
||||
- (void)setHighlightTextShadowColor:(CPColor)aColor
|
||||
{
|
||||
if (_highlightTextShadowColor == aColor)
|
||||
return;
|
||||
|
||||
_highlightTextShadowColor = aColor;
|
||||
|
||||
[_menuItemViews makeObjectsPerformSelector:@selector(setActivateShadowColor:) withObject:_highlightTextShadowColor];
|
||||
}
|
||||
|
||||
- (void)setMenu:(CPMenu)aMenu
|
||||
{
|
||||
if (_menu == aMenu)
|
||||
@@ -1653,8 +1783,11 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
{
|
||||
if ([_trackingMenuItem submenu] != nil)
|
||||
{
|
||||
var action = [_trackingMenuItem action];
|
||||
|
||||
// If the item has a submenu, but not direct action, a.k.a. a "pure" menu, simply show the menu.
|
||||
if (![_trackingMenuItem action])
|
||||
// FIXME: (?) should we use submenuAction: or not?
|
||||
if (!action || action === @selector(submenuAction:))
|
||||
return [self showMenu:anEvent];
|
||||
|
||||
// If this is a hybrid button/menu, show it in a bit...
|
||||
@@ -1679,7 +1812,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
[menuItemView highlight:NO];
|
||||
|
||||
if (onMenuItemView)
|
||||
[CPApp sendAction:[_trackingMenuItem action] to:[_trackingMenuItem target] from:nil];
|
||||
[CPApp sendAction:[_trackingMenuItem action] to:[_trackingMenuItem target] from:_trackingMenuItem];
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1698,7 +1831,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
{
|
||||
_highlightView = [[CPView alloc] initWithFrame:frame];
|
||||
|
||||
[_highlightView setBackgroundColor:[CPColor colorWithCalibratedRed:81.0 / 255.0 green:83.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]];
|
||||
[_highlightView setBackgroundColor:_highlightColor ? _highlightColor : [CPColor colorWithRed:95.0/255.0 green:131.0/255.0 blue:185.0/255.0 alpha:1.0]];
|
||||
}
|
||||
else
|
||||
[_highlightView setFrame:frame];
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
@import <AppKit/CPMenu.j>
|
||||
@import <AppKit/CPView.j>
|
||||
|
||||
/*! @class CPMenuItem
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPMenuItem
|
||||
|
||||
A CPMenuItem is added to a CPMenu.
|
||||
It has an action and a target for that action to be sent to
|
||||
@@ -92,6 +94,7 @@
|
||||
|
||||
_isEnabled = YES;
|
||||
|
||||
_tag = 0;
|
||||
_state = CPOffState;
|
||||
|
||||
_keyEquivalent = aKeyEquivalent || @"";
|
||||
@@ -112,11 +115,11 @@
|
||||
{
|
||||
if ([_menu autoenablesItems])
|
||||
return;
|
||||
|
||||
|
||||
_isEnabled = isEnabled;
|
||||
|
||||
|
||||
[_menuItemView setDirty];
|
||||
|
||||
|
||||
[_menu itemChanged:self];
|
||||
}
|
||||
|
||||
@@ -229,6 +232,14 @@
|
||||
return _title;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set's the item's text color
|
||||
*/
|
||||
- (void)setTextColor:(CPString)aColor
|
||||
{
|
||||
//FIXME IMPLEMENT
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the font for the text of this menu item
|
||||
@param aFont the font for the menu item
|
||||
@@ -677,7 +688,7 @@ CPControlKeyMask
|
||||
*/
|
||||
- (void)setView:(CPView)aView
|
||||
{
|
||||
if (_view == aView)
|
||||
if (_view === aView)
|
||||
return;
|
||||
|
||||
_view = aView;
|
||||
@@ -727,7 +738,12 @@ CPControlKeyMask
|
||||
|
||||
- (id)init
|
||||
{
|
||||
return [super initWithTitle:@"" action:nil keyEquivalent:@""];
|
||||
self = [super initWithTitle:@"" action:nil keyEquivalent:nil];
|
||||
|
||||
if (self)
|
||||
[self setEnabled:NO];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isSeparatorItem
|
||||
@@ -740,17 +756,24 @@ CPControlKeyMask
|
||||
var CPMenuItemTitleKey = @"CPMenuItemTitleKey",
|
||||
CPMenuItemTargetKey = @"CPMenuItemTargetKey",
|
||||
CPMenuItemActionKey = @"CPMenuItemActionKey",
|
||||
|
||||
|
||||
CPMenuItemIsEnabledKey = @"CPMenuItemIsEnabledKey",
|
||||
CPMenuItemIsHiddenKey = @"CPMenuItemIsHiddenKey",
|
||||
|
||||
|
||||
CPMenuItemTagKey = @"CPMenuItemTagKey",
|
||||
CPMenuItemStateKey = @"CPMenuItemStateKey",
|
||||
|
||||
CPMenuItemImageKey = @"CPMenuItemImageKey",
|
||||
CPMenuItemAlternateImageKey = @"CPMenuItemAlternateImageKey",
|
||||
|
||||
|
||||
CPMenuItemSubmenuKey = @"CPMenuItemSubmenuKey",
|
||||
CPMenuItemMenuKey = @"CPMenuItemMenuKey",
|
||||
|
||||
CPMenuItemRepresentedObjectKey = @"CPMenuItemRepresentedObjectKey";
|
||||
|
||||
CPMenuItemRepresentedObjectKey = @"CPMenuItemRepresentedObjectKey",
|
||||
CPMenuItemViewKey = @"CPMenuItemViewKey";
|
||||
|
||||
#define DEFAULT_VALUE(aKey, aDefaultValue) [aCoder containsValueForKey:(aKey)] ? [aCoder decodeObjectForKey:(aKey)] : (aDefaultValue)
|
||||
#define ENCODE_IFNOT(aKey, aValue, aDefaultValue) if ((aValue) !== (aDefaultValue)) [aCoder encodeObject:(aValue) forKey:(aKey)];
|
||||
|
||||
@implementation CPMenuItem (CPCoding)
|
||||
/*!
|
||||
@@ -771,21 +794,21 @@ var CPMenuItemTitleKey = @"CPMenuItemTitleKey",
|
||||
_target = [aCoder decodeObjectForKey:CPMenuItemTargetKey];
|
||||
_action = [aCoder decodeObjectForKey:CPMenuItemActionKey];
|
||||
|
||||
_isEnabled = [aCoder decodeObjectForKey:CPMenuItemIsEnabledKey];
|
||||
_isHidden = [aCoder decodeObjectForKey:CPMenuItemIsHiddenKey];
|
||||
|
||||
// int _tag;
|
||||
_isEnabled = DEFAULT_VALUE(CPMenuItemIsEnabledKey, YES);
|
||||
_isHidden = DEFAULT_VALUE(CPMenuItemIsHiddenKey, NO);
|
||||
_tag = DEFAULT_VALUE(CPMenuItemTagKey, 0);
|
||||
_state = DEFAULT_VALUE(CPMenuItemStateKey, CPOffState);
|
||||
// int _state;
|
||||
|
||||
_image = [aCoder decodeObjectForKey:CPMenuItemImageKey];
|
||||
_alternateImage = [aCoder decodeObjectForKey:CPMenuItemAlternateImageKey];
|
||||
|
||||
_image = DEFAULT_VALUE(CPMenuItemImageKey, nil);
|
||||
_alternateImage = DEFAULT_VALUE(CPMenuItemAlternateImageKey, nil);
|
||||
// CPImage _onStateImage;
|
||||
// CPImage _offStateImage;
|
||||
// CPImage _mixedStateImage;
|
||||
|
||||
_submenu = [aCoder decodeObjectForKey:CPMenuItemSubmenuKey];
|
||||
_menu = [aCoder decodeObjectForKey:CPMenuItemMenuKey];
|
||||
|
||||
_submenu = DEFAULT_VALUE(CPMenuItemSubmenuKey, nil);
|
||||
_menu = DEFAULT_VALUE(CPMenuItemMenuKey, nil);
|
||||
|
||||
// CPString _keyEquivalent;
|
||||
// unsigned _keyEquivalentModifierMask;
|
||||
|
||||
@@ -793,12 +816,11 @@ var CPMenuItemTitleKey = @"CPMenuItemTitleKey",
|
||||
|
||||
// BOOL _isAlternate;
|
||||
// int _indentationLevel;
|
||||
|
||||
|
||||
// CPString _toolTip;
|
||||
|
||||
_representedObject = [aCoder decodeObjectForKey:CPMenuItemRepresentedObjectKey];
|
||||
// id _representedObject;
|
||||
// CPView _view;
|
||||
_representedObject = DEFAULT_VALUE(CPMenuItemRepresentedObjectKey, nil);
|
||||
_view = DEFAULT_VALUE(CPMenuItemViewKey, nil);
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -815,16 +837,20 @@ var CPMenuItemTitleKey = @"CPMenuItemTitleKey",
|
||||
[aCoder encodeObject:_target forKey:CPMenuItemTargetKey];
|
||||
[aCoder encodeObject:_action forKey:CPMenuItemActionKey];
|
||||
|
||||
[aCoder encodeObject:_isEnabled forKey:CPMenuItemIsEnabledKey];
|
||||
[aCoder encodeObject:_isHidden forKey:CPMenuItemIsHiddenKey];
|
||||
ENCODE_IFNOT(CPMenuItemIsEnabledKey, _isEnabled, YES);
|
||||
ENCODE_IFNOT(CPMenuItemIsHiddenKey, _isHidden, NO);
|
||||
|
||||
[aCoder encodeObject:_image forKey:CPMenuItemImageKey];
|
||||
[aCoder encodeObject:_alternateImage forKey:CPMenuItemAlternateImageKey];
|
||||
ENCODE_IFNOT(CPMenuItemTagKey, _tag, 0);
|
||||
ENCODE_IFNOT(CPMenuItemStateKey, _state, CPOffState);
|
||||
|
||||
ENCODE_IFNOT(CPMenuItemImageKey, _image, nil);
|
||||
ENCODE_IFNOT(CPMenuItemAlternateImageKey, _alternateImage, nil);
|
||||
|
||||
[aCoder encodeObject:_submenu forKey:CPMenuItemSubmenuKey];
|
||||
[aCoder encodeObject:_menu forKey:CPMenuItemMenuKey];
|
||||
|
||||
[aCoder encodeObject:_representedObject forKey:CPMenuItemRepresentedObjectKey];
|
||||
ENCODE_IFNOT(CPMenuItemSubmenuKey, _submenu, nil);
|
||||
ENCODE_IFNOT(CPMenuItemMenuKey, _menu, nil);
|
||||
|
||||
ENCODE_IFNOT(CPMenuItemRepresentedObjectKey, _representedObject, nil);
|
||||
ENCODE_IFNOT(CPMenuItemViewKey, _view, nil);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -832,9 +858,11 @@ var CPMenuItemTitleKey = @"CPMenuItemTitleKey",
|
||||
var LEFT_MARGIN = 3.0,
|
||||
RIGHT_MARGIN = 16.0,
|
||||
STATE_COLUMN_WIDTH = 14.0,
|
||||
INDENTATION_WIDTH = 17.0;
|
||||
INDENTATION_WIDTH = 17.0,
|
||||
VERTICAL_MARGIN = 4.0;
|
||||
|
||||
var _CPMenuItemSelectionColor = nil,
|
||||
_CPMenuItemTextShadowColor = nil,
|
||||
|
||||
_CPMenuItemDefaultStateImages = [],
|
||||
_CPMenuItemDefaultStateHighlightedImages = [];
|
||||
@@ -848,6 +876,9 @@ var _CPMenuItemSelectionColor = nil,
|
||||
|
||||
CPFont _font;
|
||||
CPColor _textColor;
|
||||
CPColor _textShadowColor;
|
||||
CPColor _activateColor;
|
||||
CPColor _activateShadowColor;
|
||||
|
||||
CGSize _minSize;
|
||||
BOOL _isDirty;
|
||||
@@ -855,7 +886,7 @@ var _CPMenuItemSelectionColor = nil,
|
||||
BOOL _belongsToMenuBar;
|
||||
|
||||
CPImageView _stateView;
|
||||
_CPImageAndTitleView _imageAndTitleView;
|
||||
_CPImageAndTextView _imageAndTextView;
|
||||
CPView _submenuView;
|
||||
}
|
||||
|
||||
@@ -864,7 +895,8 @@ var _CPMenuItemSelectionColor = nil,
|
||||
if (self != [_CPMenuItemView class])
|
||||
return;
|
||||
|
||||
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:81.0 / 255.0 green:83.0 / 255.0 blue:109.0 / 255.0 alpha:1.0];
|
||||
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
|
||||
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
@@ -920,10 +952,24 @@ var _CPMenuItemSelectionColor = nil,
|
||||
|
||||
var view = [_menuItem view];
|
||||
|
||||
if ([_menuItem isSeparatorItem])
|
||||
{
|
||||
var line = [[CPView alloc] initWithFrame:CGRectMake(0.0, 5.0, 10.0, 1.0)];
|
||||
|
||||
view = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 10.0)];
|
||||
|
||||
[view setAutoresizingMask:CPViewWidthSizable];
|
||||
[line setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
[line setBackgroundColor:[CPColor lightGrayColor]];
|
||||
|
||||
[view addSubview:line];
|
||||
}
|
||||
|
||||
if (view)
|
||||
{
|
||||
[_imageAndTitleView removeFromSuperview];
|
||||
_imageAndTitleView = nil;
|
||||
[_imageAndTextView removeFromSuperview];
|
||||
_imageAndTextView = nil;
|
||||
|
||||
[_stateView removeFromSuperview];
|
||||
_stateView = nil;
|
||||
@@ -977,13 +1023,14 @@ var _CPMenuItemSelectionColor = nil,
|
||||
|
||||
// Image and Title
|
||||
|
||||
if (!_imageAndTitleView)
|
||||
if (!_imageAndTextView)
|
||||
{
|
||||
_imageAndTitleView = [[_CPImageAndTitleView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
|
||||
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
|
||||
|
||||
[_imageAndTitleView setImagePosition:CPImageLeft];
|
||||
[_imageAndTextView setImagePosition:CPImageLeft];
|
||||
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||
|
||||
[self addSubview:_imageAndTitleView];
|
||||
[self addSubview:_imageAndTextView];
|
||||
}
|
||||
|
||||
var font = [_menuItem font];
|
||||
@@ -991,21 +1038,30 @@ var _CPMenuItemSelectionColor = nil,
|
||||
if (!font)
|
||||
font = _font;
|
||||
|
||||
[_imageAndTitleView setFont:font];
|
||||
[_imageAndTitleView setImage:[_menuItem image]];
|
||||
[_imageAndTitleView setTitle:[_menuItem title]];
|
||||
[_imageAndTitleView setTextColor:[self textColor]];
|
||||
[_imageAndTitleView setFrameOrigin:CGPointMake(x, 0.0)];
|
||||
[_imageAndTextView setFont:font];
|
||||
[_imageAndTextView setVerticalAlignment:CPCenterVerticalTextAlignment];
|
||||
[_imageAndTextView setImage:[_menuItem image]];
|
||||
[_imageAndTextView setText:[_menuItem title]];
|
||||
[_imageAndTextView setTextColor:[self textColor]];
|
||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||
[_imageAndTextView setTextShadowOffset:CGSizeMake(0, 1)];
|
||||
[_imageAndTextView setFrameOrigin:CGPointMake(x, VERTICAL_MARGIN)];
|
||||
[_imageAndTextView sizeToFit];
|
||||
|
||||
[_imageAndTitleView sizeToFit];
|
||||
var frame = [_imageAndTextView frame];
|
||||
|
||||
var frame = [_imageAndTitleView frame];
|
||||
// frame.size.height += 1.0;
|
||||
// [_imageAndTextView setFrame:frame];
|
||||
|
||||
frame.size.height += 2 * VERTICAL_MARGIN;
|
||||
|
||||
x += CGRectGetWidth(frame);
|
||||
|
||||
// Submenu Arrow
|
||||
if ([_menuItem hasSubmenu])
|
||||
{
|
||||
x += 3.0;
|
||||
|
||||
if (!_submenuView)
|
||||
{
|
||||
_submenuView = [[_CPMenuItemArrowView alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 10.0)];
|
||||
@@ -1022,17 +1078,14 @@ var _CPMenuItemSelectionColor = nil,
|
||||
else
|
||||
[_submenuView setHidden:YES];
|
||||
|
||||
_minSize = CGSizeMake(x + (_belongsToMenuBar ? 0.0 : RIGHT_MARGIN), CGRectGetHeight(frame));
|
||||
_minSize = CGSizeMake(x + (_belongsToMenuBar ? 0.0 : RIGHT_MARGIN) + 3.0, CGRectGetHeight(frame));
|
||||
|
||||
[self setFrameSize:_minSize];
|
||||
}
|
||||
|
||||
- (float)calculatedLeftMargin
|
||||
- (CGFloat)overlapOffsetWidth
|
||||
{
|
||||
if (_belongsToMenuBar)
|
||||
return 0.0;
|
||||
|
||||
return LEFT_MARGIN + ([[_menuItem menu] showsStateColumn] ? STATE_COLUMN_WIDTH : 0.0) + [_menuItem indentationLevel] * INDENTATION_WIDTH;
|
||||
return LEFT_MARGIN + ([[_menuItem menu] showsStateColumn] ? STATE_COLUMN_WIDTH : 0.0);
|
||||
}
|
||||
|
||||
- (void)setShowsStateColumn:(BOOL)shouldShowStateColumn
|
||||
@@ -1050,26 +1103,34 @@ var _CPMenuItemSelectionColor = nil,
|
||||
// ASSERT(![_menuItem view]);
|
||||
|
||||
if (_belongsToMenuBar)
|
||||
[_imageAndTitleView setImage:shouldHighlight ? [_menuItem alternateImage] : [_menuItem image]];
|
||||
[_imageAndTextView setImage:shouldHighlight ? [_menuItem alternateImage] : [_menuItem image]];
|
||||
|
||||
else
|
||||
else if ([_menuItem isEnabled])
|
||||
{
|
||||
[_imageAndTitleView setTextColor:shouldHighlight ? [CPColor whiteColor] : [self textColor]];
|
||||
|
||||
if (shouldHighlight)
|
||||
{
|
||||
[self setBackgroundColor:_CPMenuItemSelectionColor];
|
||||
|
||||
[_imageAndTextView setTextColor:[CPColor whiteColor]];
|
||||
[_imageAndTextView setTextShadowColor:_CPMenuItemTextShadowColor];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self setBackgroundColor:nil];
|
||||
|
||||
[_imageAndTextView setTextColor:[self textColor]];
|
||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||
}
|
||||
|
||||
var state = [_menuItem state];
|
||||
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case CPOffState:
|
||||
case CPOnState:
|
||||
case CPMixedState: [_stateView setImage:shouldHighlight ? _CPMenuItemDefaultStateHighlightedImages[state] : _CPMenuItemDefaultStateImages[state]];
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
default: [_stateView setImage:nil];
|
||||
}
|
||||
}
|
||||
@@ -1077,16 +1138,18 @@ var _CPMenuItemSelectionColor = nil,
|
||||
|
||||
- (void)activate:(BOOL)shouldActivate
|
||||
{
|
||||
[_imageAndTitleView setImage:[_menuItem image]];
|
||||
[_imageAndTextView setImage:[_menuItem image]];
|
||||
|
||||
if (shouldActivate)
|
||||
{
|
||||
[_imageAndTitleView setTextColor:[CPColor whiteColor]];
|
||||
[_submenuView setColor:[CPColor whiteColor]];
|
||||
[_imageAndTextView setTextColor:[self activateColor] || [CPColor whiteColor]];
|
||||
[_imageAndTextView setTextShadowColor:[self activateShadowColor] || [CPColor blackColor]];
|
||||
[_submenuView setColor:[self activateColor] || [CPColor whiteColor]];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_imageAndTitleView setTextColor:[self textColor]];
|
||||
[_imageAndTextView setTextColor:[self textColor]];
|
||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||
[_submenuView setColor:[self textColor]];
|
||||
}
|
||||
}
|
||||
@@ -1126,13 +1189,49 @@ var _CPMenuItemSelectionColor = nil,
|
||||
|
||||
_textColor = aColor;
|
||||
|
||||
[_imageAndTitleView setTextColor:[self textColor]];
|
||||
[_imageAndTextView setTextColor:[self textColor]];
|
||||
[_submenuView setColor:[self textColor]];
|
||||
}
|
||||
|
||||
- (CPColor)textColor
|
||||
{
|
||||
return [_menuItem isEnabled] ? (_textColor ? _textColor : [CPColor blackColor]) : [CPColor darkGrayColor];
|
||||
return [_menuItem isEnabled] ? (_textColor ? _textColor : [CPColor colorWithCalibratedRed:70.0 / 255.0 green:69.0 / 255.0 blue:69.0 / 255.0 alpha:1.0]) : [CPColor darkGrayColor];
|
||||
}
|
||||
|
||||
- (void)setTextShadowColor:(CPColor)aColor
|
||||
{
|
||||
if (_textShadowColor == aColor)
|
||||
return;
|
||||
|
||||
_textShadowColor = aColor;
|
||||
|
||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||
//[_submenuView setColor:[self textColor]];
|
||||
}
|
||||
|
||||
- (CPColor)textShadowColor
|
||||
{
|
||||
return [_menuItem isEnabled] ? (_textShadowColor ? _textShadowColor : [CPColor colorWithWhite:1.0 alpha:0.8]) : [CPColor colorWithWhite:0.8 alpha:0.8];
|
||||
}
|
||||
|
||||
- (void)setActivateColor:(CPColor)aColor
|
||||
{
|
||||
_activateColor = aColor;
|
||||
}
|
||||
|
||||
- (CPColor)activateColor
|
||||
{
|
||||
return _activateColor;
|
||||
}
|
||||
|
||||
- (void)setActivateShadowColor:(CPColor)aColor
|
||||
{
|
||||
_activateShadowColor = aColor;
|
||||
}
|
||||
|
||||
- (CPColor)activateShadowColor
|
||||
{
|
||||
return _activateShadowColor;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -26,7 +26,9 @@
|
||||
CPOKButton = 1;
|
||||
CPCancelButton = 0;
|
||||
|
||||
/*! @class CPPanel
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPPanel
|
||||
|
||||
The CPPanel class defines objects that manage the panels of the Cappuccino user interface. A panel is a window that serves an auxiliary function within an application. It generally displays controls that the user can act on to give instructions to the application or to modify the contents of a standard window.</p>
|
||||
|
||||
|
||||
@@ -42,7 +42,9 @@ CPImagePboardType = @"CPImagePboardType";
|
||||
|
||||
var CPPasteboards = nil;
|
||||
|
||||
/*! @class CPPasteboard
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPPasteboard
|
||||
|
||||
CPPasteBoard is the object responsible for cut/copy/paste and drag&drop operations.
|
||||
*/
|
||||
|
||||
@@ -25,26 +25,32 @@
|
||||
@import "CPMenu.j"
|
||||
@import "CPMenuItem.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
var VISIBLE_MARGIN = 7.0;
|
||||
|
||||
var CPPopUpButtonArrowsImage = nil;
|
||||
CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
|
||||
/*! @class CPPopUpButton
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPPopUpButton
|
||||
|
||||
A CPPopUpButton contains a pop-up menu of items that a user can select from.
|
||||
*/
|
||||
@implementation CPPopUpButton : CPButton
|
||||
{
|
||||
BOOL _pullsDown;
|
||||
int _selectedIndex;
|
||||
CPRectEdge _preferredEdge;
|
||||
|
||||
CPImageView _arrowsView;
|
||||
|
||||
CPMenu _menu;
|
||||
}
|
||||
|
||||
+ (CPString)themeClass
|
||||
{
|
||||
return "popup-button";
|
||||
}
|
||||
|
||||
/*!
|
||||
Initializes the pop-up button to the specified size.
|
||||
@param aFrame the size for the button
|
||||
@@ -57,16 +63,16 @@ var CPPopUpButtonArrowsImage = nil;
|
||||
|
||||
if (self)
|
||||
{
|
||||
_pullsDown = shouldPullDown;
|
||||
_selectedIndex = CPNotFound;
|
||||
_preferredEdge = CPMaxYEdge;
|
||||
|
||||
[self setBezelStyle:CPTexturedRoundedBezelStyle];
|
||||
|
||||
[self setImagePosition:CPImageLeft];
|
||||
[self setAlignment:CPLeftTextAlignment];
|
||||
[self setValue:CPImageLeft forThemeAttribute:@"image-position"];
|
||||
[self setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"];
|
||||
[self setValue:CPLineBreakByTruncatingTail forThemeAttribute:@"line-break-mode"];
|
||||
|
||||
[self setMenu:[[CPMenu alloc] initWithTitle:@""]];
|
||||
|
||||
[self setPullsDown:shouldPullDown];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -77,33 +83,6 @@ var CPPopUpButtonArrowsImage = nil;
|
||||
return [self initWithFrame:aFrame pullsDown:NO];
|
||||
}
|
||||
|
||||
- (void)setBordered:(BOOL)shouldBeBordered
|
||||
{
|
||||
if (shouldBeBordered)
|
||||
{
|
||||
var bounds = [self bounds];
|
||||
|
||||
_arrowsView = [[CPImageView alloc] initWithFrame:CGRectMake(CGRectGetWidth(bounds) - 10.0, (CGRectGetHeight(bounds) - 8.0) / 2.0, 5.0, 8.0)];
|
||||
|
||||
if (!CPPopUpButtonArrowsImage)
|
||||
CPPopUpButtonArrowsImage = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPPopUpButton class]] pathForResource:@"CPPopUpButton/CPPopUpButtonArrows.png"] size:CGSizeMake(5.0, 8.0)];
|
||||
|
||||
[_arrowsView setImage:CPPopUpButtonArrowsImage];
|
||||
[_arrowsView setAutoresizingMask:CPViewMaxXMargin | CPViewMinYMargin | CPViewMaxYMargin];
|
||||
|
||||
|
||||
[self addSubview:_arrowsView];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_arrowsView removeFromSuperview];
|
||||
|
||||
_arrowsView = nil;
|
||||
}
|
||||
|
||||
[super setBordered:shouldBeBordered];
|
||||
}
|
||||
|
||||
// Setting the Type of Menu
|
||||
|
||||
/*!
|
||||
@@ -113,18 +92,21 @@ var CPPopUpButtonArrowsImage = nil;
|
||||
*/
|
||||
- (void)setPullsDown:(BOOL)shouldPullDown
|
||||
{
|
||||
if (_pullsDown == shouldPullDown)
|
||||
if (shouldPullDown)
|
||||
var changed = [self setThemeState:CPPopUpButtonStatePullsDown];
|
||||
else
|
||||
var changed = [self unsetThemeState:CPPopUpButtonStatePullsDown];
|
||||
|
||||
if (!changed)
|
||||
return;
|
||||
|
||||
_pullsDown = shouldPullDown;
|
||||
|
||||
var items = [_menu itemArray];
|
||||
|
||||
if (items.length <= 0)
|
||||
|
||||
if ([items count] <= 0)
|
||||
return;
|
||||
|
||||
[items[0] setHidden:_pullsDown];
|
||||
|
||||
|
||||
[items[0] setHidden:[self pullsDown]];
|
||||
|
||||
[self synchronizeTitleAndSelectedItem];
|
||||
}
|
||||
|
||||
@@ -133,17 +115,26 @@ var CPPopUpButtonArrowsImage = nil;
|
||||
*/
|
||||
- (BOOL)pullsDown
|
||||
{
|
||||
return _pullsDown;
|
||||
return [self hasThemeState:CPPopUpButtonStatePullsDown];
|
||||
}
|
||||
|
||||
// Inserting and Deleting Items
|
||||
|
||||
/*!
|
||||
Adds a new menu item using a CPMenuItem object.
|
||||
*/
|
||||
- (void)addItem:(CPMenuItem)anItem
|
||||
{
|
||||
[_menu addItem:anItem];
|
||||
}
|
||||
|
||||
/*!
|
||||
Adds a new menu item with the specified title.
|
||||
@param the new menu item's tite
|
||||
*/
|
||||
- (void)addItemWithTitle:(CPString)aTitle
|
||||
{
|
||||
[_menu addItemWithTitle:aTitle action:NULL keyEquivalent:NULL];
|
||||
[_menu addItemWithTitle:aTitle action:NULL keyEquivalent:nil];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -173,7 +164,7 @@ var CPPopUpButtonArrowsImage = nil;
|
||||
if ([items[count] title] == aTitle)
|
||||
[self removeItemAtIndex:count];
|
||||
|
||||
[_menu insertItemWithTitle:aTitle action:NULL keyEquivalent:NULL atIndex:anIndex];
|
||||
[_menu insertItemWithTitle:aTitle action:NULL keyEquivalent:nil atIndex:anIndex];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -263,12 +254,12 @@ var CPPopUpButtonArrowsImage = nil;
|
||||
if (_selectedIndex == anIndex)
|
||||
return;
|
||||
|
||||
if (_selectedIndex >= 0 && !_pullsDown)
|
||||
if (_selectedIndex >= 0 && ![self pullsDown])
|
||||
[[self selectedItem] setState:CPOffState];
|
||||
|
||||
_selectedIndex = anIndex;
|
||||
|
||||
if (_selectedIndex >= 0 && !_pullsDown)
|
||||
if (_selectedIndex >= 0 && ![self pullsDown])
|
||||
[[self selectedItem] setState:CPOnState];
|
||||
|
||||
[self synchronizeTitleAndSelectedItem];
|
||||
@@ -315,7 +306,7 @@ var CPPopUpButtonArrowsImage = nil;
|
||||
*/
|
||||
- (void)setMenu:(CPMenu)aMenu
|
||||
{
|
||||
if (_menu == aMenu)
|
||||
if (_menu === aMenu)
|
||||
return;
|
||||
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
@@ -446,7 +437,7 @@ var CPPopUpButtonArrowsImage = nil;
|
||||
*/
|
||||
- (int)indexOfItemWithTag:(int)aTag
|
||||
{
|
||||
return [_menu indexOfItemWithTag:aMenuItem];
|
||||
return [_menu indexOfItemWithTag:aTag];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -466,7 +457,7 @@ var CPPopUpButtonArrowsImage = nil;
|
||||
*/
|
||||
- (int)indexOfItemWithRepresentedObject:(id)anObject
|
||||
{
|
||||
return [_menu indexOfItemWithRepresentedObejct:anObject];
|
||||
return [_menu indexOfItemWithRepresentedObject:anObject];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -509,13 +500,21 @@ var CPPopUpButtonArrowsImage = nil;
|
||||
*/
|
||||
- (void)setTitle:(CPString)aTitle
|
||||
{
|
||||
if ([self title] == aTitle)
|
||||
if ([self title] === aTitle)
|
||||
return;
|
||||
|
||||
if (_pullsDown)
|
||||
if ([self pullsDown])
|
||||
{
|
||||
[_items[0] setTitle:aTitle];
|
||||
[self synchronizeTitleAndSelectedItem];
|
||||
var items = [_menu itemArray];
|
||||
|
||||
if ([items count] <= 0)
|
||||
[self addItemWithTitle:aTitle];
|
||||
|
||||
else
|
||||
{
|
||||
[items[0] setTitle:aTitle];
|
||||
[self synchronizeTitleAndSelectedItem];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -552,11 +551,11 @@ var CPPopUpButtonArrowsImage = nil;
|
||||
{
|
||||
var item = nil;
|
||||
|
||||
if (_pullsDown)
|
||||
if ([self pullsDown])
|
||||
{
|
||||
var items = [_menu itemArray];
|
||||
|
||||
if (items.length > 0)
|
||||
if ([items count] > 0)
|
||||
item = items[0];
|
||||
}
|
||||
else
|
||||
@@ -584,7 +583,7 @@ var CPPopUpButtonArrowsImage = nil;
|
||||
else if (index < _selectedIndex)
|
||||
++_selectedIndex;
|
||||
|
||||
if (index == 0 && _pullsDown)
|
||||
if (index == 0 && [self pullsDown])
|
||||
{
|
||||
var items = [_menu itemArray];
|
||||
|
||||
@@ -593,6 +592,15 @@ var CPPopUpButtonArrowsImage = nil;
|
||||
if (items.length > 0)
|
||||
[items[1] setHidden:NO];
|
||||
}
|
||||
|
||||
var item = [_menu itemArray][index],
|
||||
action = [item action];
|
||||
|
||||
if (!action || (action === @selector(_popUpItemAction:)))
|
||||
{
|
||||
[item setTarget:self];
|
||||
[item setAction:@selector(_popUpItemAction:)];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -603,10 +611,10 @@ var CPPopUpButtonArrowsImage = nil;
|
||||
{
|
||||
var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"];
|
||||
|
||||
if (_pullsDown && index != 0)
|
||||
if ([self pullsDown] && index != 0)
|
||||
return;
|
||||
|
||||
if (!_pullsDown && index != _selectedIndex)
|
||||
if (![self pullsDown] && index != _selectedIndex)
|
||||
return;
|
||||
|
||||
[self synchronizeTitleAndSelectedItem];
|
||||
@@ -631,34 +639,40 @@ var CPPopUpButtonArrowsImage = nil;
|
||||
|
||||
[self highlight:YES];
|
||||
|
||||
var theWindow = [self window],
|
||||
menuWindow = [_CPMenuWindow menuWindowWithMenu:[self menu] font:[self font]];
|
||||
var menu = [self menu],
|
||||
theWindow = [self window],
|
||||
menuWindow = [_CPMenuWindow menuWindowWithMenu:menu font:[self font]];
|
||||
|
||||
[menuWindow setDelegate:self];
|
||||
[menuWindow setBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle];
|
||||
|
||||
var menuOrigin = [theWindow convertBaseToBridge:[self convertPoint:CGPointMakeZero() toView:nil]];
|
||||
|
||||
// Pull Down Menus show up directly below their buttons.
|
||||
if (_pullsDown)
|
||||
menuOrigin.y += CGRectGetHeight([self frame]);
|
||||
if ([self pullsDown])
|
||||
var menuOrigin = [theWindow convertBaseToBridge:[self convertPoint:CGPointMake(0.0, CGRectGetMaxY([self bounds])) toView:nil]];
|
||||
|
||||
// Pop Up Menus attempt to show up "on top" of the selected item.
|
||||
else
|
||||
{
|
||||
var contentRect = [menuWindow rectForItemAtIndex:_selectedIndex];
|
||||
// This is confusing, I KNOW, so let me explain it to you.
|
||||
// We want the *content* of the selected menu item to overlap the *content* of our pop up.
|
||||
// 1. So calculate where our content is, then calculate where the menu item is.
|
||||
// 2. Move LEFT by whatever indentation we have (offsetWidths, aka, window margin, item margin, etc).
|
||||
// 3. MOVE UP by the difference in sizes of the content and menu item, this will only work if the content is vertically centered.
|
||||
var contentRect = [self convertRect:[self contentRectForBounds:[self bounds]] toView:nil],
|
||||
menuOrigin = [theWindow convertBaseToBridge:contentRect.origin],
|
||||
menuItemRect = [menuWindow rectForItemAtIndex:_selectedIndex];
|
||||
|
||||
menuOrigin.x -= CGRectGetMinX(contentRect) + [_CPMenuItemView leftMargin];
|
||||
menuOrigin.y -= CGRectGetMinY(contentRect);
|
||||
menuOrigin.x -= CGRectGetMinX(menuItemRect) + [menuWindow overlapOffsetWidth] + [[[menu itemAtIndex:_selectedIndex] _menuItemView] overlapOffsetWidth];
|
||||
menuOrigin.y -= CGRectGetMinY(menuItemRect) + (CGRectGetHeight(menuItemRect) - CGRectGetHeight(contentRect)) / 2.0;
|
||||
}
|
||||
|
||||
[menuWindow setFrameOrigin:menuOrigin];
|
||||
|
||||
var menuMaxX = CGRectGetMaxX([menuWindow frame]),
|
||||
buttonMaxX = CGRectGetMaxX([self convertRect:[self bounds] toView:nil]);
|
||||
buttonMaxX = [theWindow convertBaseToBridge:CGPointMake(CGRectGetMaxX([self convertRect:[self bounds] toView:nil]), 0.0)].x;
|
||||
|
||||
if (menuMaxX < buttonMaxX)
|
||||
[menuWindow setMinWidth:CGRectGetWidth([menuWindow frame]) + buttonMaxX - menuMaxX - VISIBLE_MARGIN];
|
||||
[menuWindow setMinWidth:CGRectGetWidth([menuWindow frame]) + buttonMaxX - menuMaxX - ([self pullsDown] ? 0.0 : VISIBLE_MARGIN)];
|
||||
|
||||
[menuWindow orderFront:self];
|
||||
[menuWindow beginTrackingWithEvent:anEvent sessionDelegate:self didEndSelector:@selector(menuWindowDidFinishTracking:highlightedItem:)];
|
||||
@@ -680,21 +694,12 @@ var CPPopUpButtonArrowsImage = nil;
|
||||
|
||||
[self selectItemAtIndex:index];
|
||||
|
||||
var selectedItem = [self selectedItem],
|
||||
target = nil,
|
||||
action = [selectedItem action];
|
||||
|
||||
if (!action)
|
||||
{
|
||||
target = [self target];
|
||||
action = [self action];
|
||||
}
|
||||
|
||||
// FIXME: If [selectedItem target] == nil do we use our own target?
|
||||
else
|
||||
target = [selectedItem target];
|
||||
[CPApp sendAction:[aMenuItem action] to:[aMenuItem target] from:aMenuItem];
|
||||
}
|
||||
|
||||
[self sendAction:action to:target];
|
||||
- (void)_popUpItemAction:(id)aSender
|
||||
{
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -717,9 +722,11 @@ var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
|
||||
|
||||
if (self)
|
||||
{
|
||||
// Nothing is currently selected
|
||||
_selectedIndex = -1;
|
||||
|
||||
[self setMenu:[aCoder decodeObjectForKey:CPPopUpButtonMenuKey]];
|
||||
[self selectItemAtIndex:[aCoder decodeObjectForKey:CPPopUpButtonSelectedIndexKey]];
|
||||
[self setPullsDown:[aCoder decodeBoolForKey:CPPopUpButtonPullsDownKey]];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -736,7 +743,6 @@ var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
|
||||
|
||||
[aCoder encodeObject:_menu forKey:CPPopUpButtonMenuKey];
|
||||
[aCoder encodeInt:_selectedIndex forKey:CPPopUpButtonSelectedIndexKey];
|
||||
[aCoder encodeBool:_pullsDown forKey:CPPopUpButtonPullsDownKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -49,7 +49,9 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
||||
CPProgressIndicatorStyleIdentifiers = nil,
|
||||
CPProgressIndicatorStyleSizes = nil;
|
||||
|
||||
/*! @class CPProgressIndicator
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPProgressIndicator
|
||||
|
||||
This class is used in a Cappuccino GUI to display the progress of a
|
||||
function or task. If the duration of the task is unknown, there is
|
||||
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* CPRadio.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2009, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPSet.j>
|
||||
|
||||
@import "CPButton.j"
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
|
||||
from this mailing list thread:
|
||||
http://groups.google.com/group/objectivej/browse_thread/thread/7c41cbd9cbee9ea3
|
||||
|
||||
-----------------------------------
|
||||
|
||||
Creating a checkbox is easy enough:
|
||||
|
||||
checkbox = [[CPCheckBox alloc] initWithFrame:aFrame];
|
||||
|
||||
That's basically all there is to it. Radio buttons are very similar,
|
||||
the key difference is the introduction of a new class CPRadioGroup,
|
||||
which defines which radio buttons are part of the same group:
|
||||
|
||||
[myRadioButton setRadioGroup:aRadioGroup];
|
||||
|
||||
Every radio button receives a unique radio group by default (so if you
|
||||
do nothing further, they will all behave independently), but you can
|
||||
use an existing radio button's group with other buttons as so:
|
||||
|
||||
button1 = [[CPRadio alloc] initWithFrame:aFrame];
|
||||
...
|
||||
button2 = [[CPRadio alloc] initWithFrame:aFrame radioGroup:[button1
|
||||
radioGroup]];
|
||||
...
|
||||
button3 = [[CPRadio alloc] initWithFrame:aFrame radioGroup:[button1
|
||||
radioGroup]];
|
||||
...etc...
|
||||
|
||||
Here, all the radio buttons will act "together". [[button1 radioGroup]
|
||||
allRadios] returns every button that's part of this group, and
|
||||
[[button1 radioGroup] selectedRadio] returns the currently selected
|
||||
option.
|
||||
|
||||
*/
|
||||
@implementation CPRadio : CPButton
|
||||
{
|
||||
CPRadioGroup _radioGroup;
|
||||
}
|
||||
|
||||
+ (id)radioWithTitle:(CPString)aTitle theme:(CPTheme)aTheme
|
||||
{
|
||||
return [self buttonWithTitle:aTitle theme:aTheme];
|
||||
}
|
||||
|
||||
+ (id)radioWithTitle:(CPString)aTitle
|
||||
{
|
||||
return [self buttonWithTitle:aTitle];
|
||||
}
|
||||
|
||||
+ (CPButton)standardButtonWithTitle:(CPString)aTitle
|
||||
{
|
||||
var button = [[CPRadio alloc] init];
|
||||
|
||||
[button setTitle:aTitle];
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
+ (CPString)themeClass
|
||||
{
|
||||
return @"radio";
|
||||
}
|
||||
|
||||
// Designated Initializer
|
||||
- (id)initWithFrame:(CGRect)aFrame radioGroup:(CPRadioGroup)aRadioGroup
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self setRadioGroup:aRadioGroup || [CPRadioGroup new]];
|
||||
|
||||
[self setHighlightsBy:CPContentsCellMask];
|
||||
[self setShowsStateBy:CPContentsCellMask];
|
||||
|
||||
// Defaults?
|
||||
[self setImagePosition:CPImageLeft];
|
||||
[self setAlignment:CPLeftTextAlignment];
|
||||
|
||||
[self setBordered:YES];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
return [self initWithFrame:aFrame radioGroup:nil];
|
||||
}
|
||||
|
||||
- (CPInteger)nextState
|
||||
{
|
||||
return CPOnState;
|
||||
}
|
||||
|
||||
- (void)setRadioGroup:(CPRadioGroup)aRadioGroup
|
||||
{
|
||||
if (_radioGroup === aRadioGroup)
|
||||
return;
|
||||
|
||||
[_radioGroup _removeRadio:self];
|
||||
_radioGroup = aRadioGroup;
|
||||
[_radioGroup _addRadio:self];
|
||||
}
|
||||
|
||||
- (CPRadioGroup)radioGroup
|
||||
{
|
||||
return _radioGroup;
|
||||
}
|
||||
|
||||
- (void)setObjectValue:(id)aValue
|
||||
{
|
||||
[super setObjectValue:aValue];
|
||||
|
||||
if ([self state] === CPOnState)
|
||||
[_radioGroup _setSelectedRadio:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
|
||||
|
||||
@implementation CPRadio (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self)
|
||||
_radioGroup = [aCoder decodeObjectForKey:CPRadioRadioGroupKey];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeObject:_radioGroup forKey:CPRadioRadioGroupKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPRadioGroup : CPObject
|
||||
{
|
||||
CPSet _radios;
|
||||
CPRadio _selectedRadio;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_radios = [CPSet set];
|
||||
_selectedRadio = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_addRadio:(CPRadio)aRadio
|
||||
{
|
||||
[_radios addObject:aRadio];
|
||||
|
||||
if ([aRadio state] === CPOnState)
|
||||
[self _setSelectedRadio:aRadio];
|
||||
}
|
||||
|
||||
- (void)_removeRadio:(CPRadio)aRadio
|
||||
{
|
||||
if (_selectedRadio === aRadio)
|
||||
_selectedRadio = nil;
|
||||
|
||||
[_radios removeObject:aRadio];
|
||||
}
|
||||
|
||||
- (void)_setSelectedRadio:(CPRadio)aRadio
|
||||
{
|
||||
if (_selectedRadio === aRadio)
|
||||
return;
|
||||
|
||||
[_selectedRadio setState:CPOffState];
|
||||
_selectedRadio = aRadio;
|
||||
}
|
||||
|
||||
- (CPRadio)selectedRadio
|
||||
{
|
||||
return _selectedRadio;
|
||||
}
|
||||
|
||||
- (CPArray)radios
|
||||
{
|
||||
return [_radios allObjects];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPRadioGroupRadiosKey = @"CPRadioGroupRadiosKey",
|
||||
CPRadioGroupSelectedRadioKey = @"CPRadioGroupSelectedRadioKey";
|
||||
|
||||
@implementation CPRadioGroup (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_radios = [aCoder decodeObjectForKey:CPRadioGroupRadiosKey];
|
||||
_selectedRadio = [aCoder decodeObjectForKey:CPRadioGroupSelectedRadioKey];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeObject:_radios forKey:CPRadioGroupRadiosKey];
|
||||
[aCoder encodeObject:_selectedRadio forKey:CPRadioGroupSelectedRadioKey];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -24,12 +24,16 @@
|
||||
|
||||
|
||||
CPDeleteKeyCode = 8;
|
||||
CPUpArrowKeyCode = 63232;
|
||||
CPDownArrowKeyCode = 63233;
|
||||
CPLeftArrowKeyCode = 63234;
|
||||
CPRightArrowKeyCode = 63235;
|
||||
CPTabKeyCode = 9;
|
||||
CPReturnKeyCode = 13;
|
||||
CPEscapeKeyCode = 27;
|
||||
CPLeftArrowKeyCode = 37;
|
||||
CPUpArrowKeyCode = 38;
|
||||
CPRightArrowKeyCode = 39;
|
||||
CPDownArrowKeyCode = 40;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPResponder
|
||||
|
||||
Subclasses of CPResonder can be part of the responder chain.
|
||||
@@ -109,9 +113,22 @@ CPRightArrowKeyCode = 63235;
|
||||
break;
|
||||
case CPDeleteKeyCode: [self deleteBackward:self];
|
||||
break;
|
||||
case 3:
|
||||
case 13: [self insertLineBreak:self];
|
||||
case CPReturnKeyCode:
|
||||
case 3: [self insertLineBreak:self];
|
||||
break;
|
||||
|
||||
case CPEscapeKeyCode: [self cancel:self];
|
||||
break;
|
||||
|
||||
case CPTabKeyCode: var shift = [event modifierFlags] & CPShiftKeyMask;
|
||||
|
||||
if (!shift)
|
||||
[self insertTab:self];
|
||||
else
|
||||
[self insertBackTab:self];
|
||||
|
||||
break;
|
||||
|
||||
default: [self insertText:[event characters]];
|
||||
}
|
||||
}
|
||||
@@ -220,6 +237,28 @@ CPRightArrowKeyCode = 63235;
|
||||
@param aSender the object requesting this
|
||||
*/
|
||||
- (void)insertLineBreak:(id)aSender
|
||||
{
|
||||
[self insertNewline:aSender];
|
||||
}
|
||||
|
||||
/*!
|
||||
Insert a line break at the caret position or selection.
|
||||
@param aSender the object requesting this
|
||||
*/
|
||||
- (void)insertNewline:(id)aSender
|
||||
{
|
||||
[self insertNewline:aSender];
|
||||
}
|
||||
|
||||
- (void)cancel:(id)sender
|
||||
{
|
||||
}
|
||||
|
||||
- (void)insertTab:(id)sender
|
||||
{
|
||||
}
|
||||
|
||||
- (void)insertBackTab:(id)sender
|
||||
{
|
||||
}
|
||||
|
||||
@@ -321,7 +360,9 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey";
|
||||
*/
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeConditionalObject:_nextResponder forKey:CPResponderNextResponderKey];
|
||||
// This will come out nil on the other side with decodeObjectForKey:
|
||||
if (_nextResponder !== nil)
|
||||
[aCoder encodeConditionalObject:_nextResponder forKey:CPResponderNextResponderKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
/*! @class CPScrollView
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPScrollView
|
||||
|
||||
Used to display views that are too large for the viewing area. the CPScrollView
|
||||
places scroll bars on the side of the view to allow the user to scroll and see the entire
|
||||
@@ -142,7 +144,7 @@
|
||||
*/
|
||||
- (void)reflectScrolledClipView:(CPClipView)aClipView
|
||||
{
|
||||
if(_contentView != aClipView)
|
||||
if(_contentView !== aClipView)
|
||||
return;
|
||||
|
||||
if (_recursionCount > 5)
|
||||
@@ -161,8 +163,8 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
[_verticalScroller setEnabled:NO];
|
||||
[_horizontalScroller setEnabled:NO];
|
||||
// [_verticalScroller setEnabled:NO];
|
||||
// [_horizontalScroller setEnabled:NO];
|
||||
}
|
||||
|
||||
[_contentView setFrame:[self bounds]];
|
||||
@@ -180,22 +182,24 @@
|
||||
shouldShowHorizontalScroller = (!_autohidesScrollers || difference.width > 0.0) && _hasHorizontalScroller,
|
||||
wasShowingVerticalScroller = ![_verticalScroller isHidden],
|
||||
wasShowingHorizontalScroller = ![_horizontalScroller isHidden],
|
||||
verticalScrollerWidth = [CPScroller scrollerWidthForControlSize:[_verticalScroller controlSize]],
|
||||
horizontalScrollerHeight = [CPScroller scrollerWidthForControlSize:[_horizontalScroller controlSize]];
|
||||
verticalScrollerWidth = _CGRectGetWidth([_verticalScroller frame]);
|
||||
horizontalScrollerHeight = _CGRectGetHeight([_horizontalScroller frame]);
|
||||
|
||||
if (_autohidesScrollers)
|
||||
{
|
||||
// Check to see if either affected the other!
|
||||
if (shouldShowVerticalScroller)
|
||||
shouldShowHorizontalScroller = (!_autohidesScrollers || difference.width > -verticalScrollerWidth) && _hasHorizontalScroller;
|
||||
|
||||
if (shouldShowHorizontalScroller)
|
||||
shouldShowVerticalScroller = (!_autohidesScrollers || difference.height > -horizontalScrollerHeight) && _hasVerticalScroller;
|
||||
}
|
||||
|
||||
|
||||
[_verticalScroller setHidden:!shouldShowVerticalScroller];
|
||||
[_verticalScroller setEnabled:!_autohidesScrollers && difference.height < 0];
|
||||
[_verticalScroller setEnabled:difference.height > 0.0];
|
||||
|
||||
[_horizontalScroller setHidden:!shouldShowHorizontalScroller];
|
||||
[_horizontalScroller setEnabled:!_autohidesScrollers && difference.width < 0];
|
||||
[_horizontalScroller setEnabled:difference.width > 0.0];
|
||||
|
||||
if (shouldShowVerticalScroller)
|
||||
{
|
||||
@@ -238,7 +242,7 @@
|
||||
*/
|
||||
- (void)setHorizontalScroller:(CPScroller)aScroller
|
||||
{
|
||||
if (_horizontalScroller == aScroller)
|
||||
if (_horizontalScroller === aScroller)
|
||||
return;
|
||||
|
||||
[_horizontalScroller removeFromSuperview];
|
||||
@@ -270,13 +274,13 @@
|
||||
*/
|
||||
- (void)setHasHorizontalScroller:(BOOL)shouldHaveHorizontalScroller
|
||||
{
|
||||
if (_hasHorizontalScroller == shouldHaveHorizontalScroller)
|
||||
if (_hasHorizontalScroller === shouldHaveHorizontalScroller)
|
||||
return;
|
||||
|
||||
_hasHorizontalScroller = shouldHaveHorizontalScroller;
|
||||
|
||||
if (_hasHorizontalScroller && !_horizontalScroller)
|
||||
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CPRectMake(0.0, 0.0, CPRectGetWidth([self bounds]), [CPScroller scrollerWidth])]];
|
||||
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, CPRectGetWidth([self bounds]), [CPScroller scrollerWidth])]];
|
||||
|
||||
else if (!_hasHorizontalScroller && _horizontalScroller)
|
||||
{
|
||||
@@ -300,7 +304,7 @@
|
||||
*/
|
||||
- (void)setVerticalScroller:(CPScroller)aScroller
|
||||
{
|
||||
if (_verticalScroller == aScroller)
|
||||
if (_verticalScroller === aScroller)
|
||||
return;
|
||||
|
||||
[_verticalScroller removeFromSuperview];
|
||||
@@ -333,7 +337,7 @@
|
||||
*/
|
||||
- (void)setHasVerticalScroller:(BOOL)shouldHaveVerticalScroller
|
||||
{
|
||||
if (_hasVerticalScroller == shouldHaveVerticalScroller)
|
||||
if (_hasVerticalScroller === shouldHaveVerticalScroller)
|
||||
return;
|
||||
|
||||
_hasVerticalScroller = shouldHaveVerticalScroller;
|
||||
@@ -352,9 +356,9 @@
|
||||
/*!
|
||||
Returns <code>YES</code> if the scroll view can have a vertical scroller.
|
||||
*/
|
||||
- (BOOL)hasHorizontalScroller
|
||||
- (BOOL)hasVerticalScroller
|
||||
{
|
||||
return _hasHorizontalScroller;
|
||||
return _hasVerticalScroller;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -626,3 +630,63 @@
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
||||
CPScrollViewVLineScrollKey = "CPScrollViewVLineScroll",
|
||||
CPScrollViewHLineScrollKey = "CPScrollViewHLineScroll",
|
||||
CPScrollViewVPageScrollKey = "CPScrollViewVPageScroll",
|
||||
CPScrollViewHPageScrollKey = "CPScrollViewHPageScroll",
|
||||
CPScrollViewHasVScrollerKey = "CPScrollViewHasVScroller",
|
||||
CPScrollViewHasHScrollerKey = "CPScrollViewHasHScroller",
|
||||
CPScrollViewVScrollerKey = "CPScrollViewVScroller",
|
||||
CPScrollViewHScrollerKey = "CPScrollViewHScroller",
|
||||
CPScrollViewAutohidesScrollerKey = "CPScrollViewAutohidesScroller";
|
||||
|
||||
@implementation CPScrollView (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
{
|
||||
_verticalLineScroll = [aCoder decodeFloatForKey:CPScrollViewVLineScrollKey];
|
||||
_verticalPageScroll = [aCoder decodeFloatForKey:CPScrollViewVPageScrollKey];
|
||||
|
||||
_horizontalLineScroll = [aCoder decodeFloatForKey:CPScrollViewHLineScrollKey];
|
||||
_horizontalPageScroll = [aCoder decodeFloatForKey:CPScrollViewHPageScrollKey];
|
||||
|
||||
_contentView = [aCoder decodeObjectForKey:CPScrollViewContentViewKey];
|
||||
|
||||
_verticalScroller = [aCoder decodeObjectForKey:CPScrollViewVScrollerKey];
|
||||
_horizontalScroller = [aCoder decodeObjectForKey:CPScrollViewHScrollerKey];
|
||||
|
||||
_hasVerticalScroller = [aCoder decodeBoolForKey:CPScrollViewHasVScrollerKey];
|
||||
_hasHorizontalScroller = [aCoder decodeBoolForKey:CPScrollViewHasHScrollerKey];
|
||||
_autohidesScrollers = [aCoder decodeBoolForKey:CPScrollViewAutohidesScrollerKey];
|
||||
|
||||
// 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]];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeObject:_contentView forKey:CPScrollViewContentViewKey];
|
||||
|
||||
[aCoder encodeObject:_verticalScroller forKey:CPScrollViewVScrollerKey];
|
||||
[aCoder encodeObject:_horizontalScroller forKey:CPScrollViewHScrollerKey];
|
||||
|
||||
[aCoder encodeFloat:_verticalLineScroll forKey:CPScrollViewVLineScrollKey];
|
||||
[aCoder encodeFloat:_verticalPageScroll forKey:CPScrollViewVPageScrollKey];
|
||||
[aCoder encodeFloat:_horizontalLineScroll forKey:CPScrollViewHLineScrollKey];
|
||||
[aCoder encodeFloat:_horizontalPageScroll forKey:CPScrollViewHPageScrollKey];
|
||||
|
||||
[aCoder encodeBool:_hasVerticalScroller forKey:CPScrollViewHasVScrollerKey];
|
||||
[aCoder encodeBool:_hasHorizontalScroller forKey:CPScrollViewHasHScrollerKey];
|
||||
[aCoder encodeBool:_autohidesScrollers forKey:CPScrollViewAutohidesScrollerKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -41,50 +41,28 @@ CPNoScrollerParts = 0;
|
||||
CPOnlyScrollerArrows = 1;
|
||||
CPAllScrollerParts = 2;
|
||||
|
||||
var _CPScrollerWidths = [],
|
||||
_CPScrollerKnobMinimumHeights = [],
|
||||
_CPScrollerArrowHeights = [],
|
||||
_CPScrollerArrowUsableHeights = [];
|
||||
|
||||
_CPScrollerWidths[CPRegularControlSize] = 14.0;
|
||||
_CPScrollerWidths[CPSmallControlSize] = 11.0;
|
||||
_CPScrollerWidths[CPMiniControlSize] = 11.0; // FIXME
|
||||
|
||||
_CPScrollerKnobMinimumHeights[CPRegularControlSize] = 18.0;
|
||||
_CPScrollerKnobMinimumHeights[CPSmallControlSize] = 12.0;
|
||||
_CPScrollerKnobMinimumHeights[CPMiniControlSize] = 12.0; // FIXME
|
||||
|
||||
_CPScrollerArrowHeights[CPRegularControlSize] = 21.0;
|
||||
_CPScrollerArrowHeights[CPSmallControlSize] = 16.0;
|
||||
_CPScrollerArrowHeights[CPMiniControlSize] = 16.0; // FIXME
|
||||
|
||||
_CPScrollerArrowUsableHeights[CPRegularControlSize] = 16.0
|
||||
_CPScrollerArrowUsableHeights[CPSmallControlSize] = 10.0;
|
||||
_CPScrollerArrowUsableHeights[CPMiniControlSize] = 10.0; // FIXME
|
||||
|
||||
var _CPScrollerKnobIdentifier = @"Knob",
|
||||
_CPScrollerKnobSlotIdentifier = @"KnobSlot",
|
||||
_CPScrollerDecrementArrowIdentifier = @"DecrementArrow",
|
||||
_CPScrollerIncrementArrowIdentifier = @"IncrementArrow",
|
||||
_CPScrollerHorizontalIdentifier = @"Horizontal",
|
||||
_CPScrollerVerticalIdentifier = @"Vertical",
|
||||
_CPScrollerHighlightedIdentifier = @"Highlighted",
|
||||
_CPScrollerDisabledIdentifier = @"Disabled";
|
||||
|
||||
var _CPScrollerClassName = nil,
|
||||
_CPScrollerPartSizes = {};
|
||||
|
||||
/*! @class CPScroller
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPScroller
|
||||
*/
|
||||
|
||||
var PARTS_ARRANGEMENT = [CPScrollerKnobSlot, CPScrollerDecrementLine, CPScrollerIncrementLine, CPScrollerKnob],
|
||||
NAMES_FOR_PARTS = {},
|
||||
PARTS_FOR_NAMES = {};
|
||||
|
||||
NAMES_FOR_PARTS[CPScrollerDecrementLine] = @"decrement-line";
|
||||
NAMES_FOR_PARTS[CPScrollerIncrementLine] = @"increment-line";
|
||||
NAMES_FOR_PARTS[CPScrollerKnobSlot] = @"knob-slot";
|
||||
NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
|
||||
|
||||
@implementation CPScroller : CPControl
|
||||
{
|
||||
CPControlSize _controlSize;
|
||||
CPUsableScrollerParts _usableParts;
|
||||
CPArray _partRects;
|
||||
|
||||
BOOL _isHorizontal;
|
||||
BOOL _isVertical @accessors(readonly, getter=isVertical);
|
||||
float _knobProportion;
|
||||
|
||||
CPScrollerPart _hitPart;
|
||||
@@ -92,97 +70,29 @@ var _CPScrollerClassName = nil,
|
||||
CPScrollerPart _trackingPart;
|
||||
float _trackingFloatValue;
|
||||
CGPoint _trackingStartPoint;
|
||||
|
||||
CPView _knobView;
|
||||
CPView _knobSlotView;
|
||||
|
||||
CPView _decrementArrowView;
|
||||
CPView _incrementArrowView;
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
+ (void)initialize
|
||||
+ (CPString)themeClass
|
||||
{
|
||||
if (self != [CPScroller class])
|
||||
return;
|
||||
|
||||
_CPScrollerClassName = [self className];
|
||||
|
||||
var regularIdentifier = _CPControlIdentifierForControlSize(CPRegularControlSize),
|
||||
smallIdentifier = _CPControlIdentifierForControlSize(CPSmallControlSize),
|
||||
miniIdentifier = _CPControlIdentifierForControlSize(CPMiniControlSize);
|
||||
|
||||
// Horizontal Knob Sizes
|
||||
var prefix = _CPScrollerClassName + _CPScrollerKnobIdentifier + _CPScrollerHorizontalIdentifier;
|
||||
|
||||
_CPScrollerPartSizes[prefix + regularIdentifier] = [_CGSizeMake(9.0, _CPScrollerWidths[CPRegularControlSize]), _CGSizeMake(1.0, _CPScrollerWidths[CPRegularControlSize]), _CGSizeMake(9.0, _CPScrollerWidths[CPRegularControlSize])];
|
||||
_CPScrollerPartSizes[prefix + smallIdentifier] = [_CGSizeMake(6.0, _CPScrollerWidths[CPSmallControlSize]), _CGSizeMake(1.0, _CPScrollerWidths[CPSmallControlSize]), _CGSizeMake(6.0, _CPScrollerWidths[CPSmallControlSize])];
|
||||
_CPScrollerPartSizes[prefix + miniIdentifier] = [_CGSizeMake(6.0, _CPScrollerWidths[CPMiniControlSize]), _CGSizeMake(1.0, _CPScrollerWidths[CPMiniControlSize]), _CGSizeMake(6.0, _CPScrollerWidths[CPMiniControlSize])];
|
||||
|
||||
// Vertical Knob Sizes
|
||||
var prefix = _CPScrollerClassName + _CPScrollerKnobIdentifier + _CPScrollerVerticalIdentifier;
|
||||
|
||||
_CPScrollerPartSizes[prefix + regularIdentifier] = [_CGSizeMake(_CPScrollerWidths[CPRegularControlSize], 9.0), _CGSizeMake(_CPScrollerWidths[CPRegularControlSize], 1.0), _CGSizeMake(_CPScrollerWidths[CPRegularControlSize], 9.0)];
|
||||
_CPScrollerPartSizes[prefix + smallIdentifier] = [_CGSizeMake(_CPScrollerWidths[CPSmallControlSize], 6.0), _CGSizeMake(_CPScrollerWidths[CPSmallControlSize], 1.0), _CGSizeMake(_CPScrollerWidths[CPSmallControlSize], 6.0)];
|
||||
_CPScrollerPartSizes[prefix + miniIdentifier] = [_CGSizeMake(_CPScrollerWidths[CPMiniControlSize], 6.0), _CGSizeMake(_CPScrollerWidths[CPMiniControlSize], 1.0), _CGSizeMake(_CPScrollerWidths[CPMiniControlSize], 6.0)];
|
||||
|
||||
// Horizontal Knob Slot Sizes
|
||||
var prefix = _CPScrollerClassName + _CPScrollerKnobSlotIdentifier + _CPScrollerHorizontalIdentifier;
|
||||
|
||||
_CPScrollerPartSizes[prefix + regularIdentifier] = _CGSizeMake(1.0, _CPScrollerWidths[CPRegularControlSize]);
|
||||
_CPScrollerPartSizes[prefix + smallIdentifier] = _CGSizeMake(1.0, _CPScrollerWidths[CPSmallControlSize]);
|
||||
_CPScrollerPartSizes[prefix + miniIdentifier] = _CGSizeMake(1.0, _CPScrollerWidths[CPMiniControlSize]);
|
||||
|
||||
// Vertical Knob Slot Sizes
|
||||
var prefix = _CPScrollerClassName + _CPScrollerKnobSlotIdentifier + _CPScrollerVerticalIdentifier;
|
||||
|
||||
_CPScrollerPartSizes[prefix + regularIdentifier] = _CGSizeMake(_CPScrollerWidths[CPRegularControlSize], 1.0);
|
||||
_CPScrollerPartSizes[prefix + smallIdentifier] = _CGSizeMake(_CPScrollerWidths[CPSmallControlSize], 1.0);
|
||||
_CPScrollerPartSizes[prefix + miniIdentifier] = _CGSizeMake(_CPScrollerWidths[CPMiniControlSize], 1.0);
|
||||
|
||||
// Horizontal Decrement Arrows Sizes
|
||||
var prefix = _CPScrollerClassName + _CPScrollerDecrementArrowIdentifier + _CPScrollerHorizontalIdentifier;
|
||||
|
||||
_CPScrollerPartSizes[prefix + regularIdentifier] = _CGSizeMake(_CPScrollerArrowHeights[CPRegularControlSize], _CPScrollerWidths[CPRegularControlSize]);
|
||||
_CPScrollerPartSizes[prefix + regularIdentifier + _CPScrollerHighlightedIdentifier] = _CGSizeMake(_CPScrollerArrowHeights[CPRegularControlSize], _CPScrollerWidths[CPRegularControlSize]);
|
||||
_CPScrollerPartSizes[prefix + smallIdentifier] = _CGSizeMake(_CPScrollerArrowHeights[CPSmallControlSize] , _CPScrollerWidths[CPSmallControlSize]);
|
||||
_CPScrollerPartSizes[prefix + smallIdentifier + _CPScrollerHighlightedIdentifier] = _CGSizeMake(_CPScrollerArrowHeights[CPSmallControlSize] , _CPScrollerWidths[CPSmallControlSize]);
|
||||
_CPScrollerPartSizes[prefix + miniIdentifier] = _CGSizeMake(_CPScrollerArrowHeights[CPMiniControlSize], _CPScrollerWidths[CPMiniControlSize]);
|
||||
_CPScrollerPartSizes[prefix + miniIdentifier + _CPScrollerHighlightedIdentifier] = _CGSizeMake(_CPScrollerArrowHeights[CPMiniControlSize], _CPScrollerWidths[CPMiniControlSize]);
|
||||
|
||||
// Vertical Decrement Arrows Sizes
|
||||
var prefix = _CPScrollerClassName + _CPScrollerDecrementArrowIdentifier + _CPScrollerVerticalIdentifier;
|
||||
|
||||
_CPScrollerPartSizes[prefix + regularIdentifier] = _CGSizeMake(_CPScrollerWidths[CPRegularControlSize], _CPScrollerArrowHeights[CPRegularControlSize]);
|
||||
_CPScrollerPartSizes[prefix + regularIdentifier + _CPScrollerHighlightedIdentifier] = _CGSizeMake(_CPScrollerWidths[CPRegularControlSize], _CPScrollerArrowHeights[CPRegularControlSize]);
|
||||
_CPScrollerPartSizes[prefix + smallIdentifier] = _CGSizeMake(_CPScrollerWidths[CPSmallControlSize], _CPScrollerArrowHeights[CPSmallControlSize]);
|
||||
_CPScrollerPartSizes[prefix + smallIdentifier + _CPScrollerHighlightedIdentifier] = _CGSizeMake(_CPScrollerWidths[CPSmallControlSize], _CPScrollerArrowHeights[CPSmallControlSize]);
|
||||
_CPScrollerPartSizes[prefix + miniIdentifier] = _CGSizeMake(_CPScrollerWidths[CPMiniControlSize], _CPScrollerArrowHeights[CPMiniControlSize]);
|
||||
_CPScrollerPartSizes[prefix + miniIdentifier + _CPScrollerHighlightedIdentifier] = _CGSizeMake(_CPScrollerWidths[CPMiniControlSize], _CPScrollerArrowHeights[CPMiniControlSize]);
|
||||
|
||||
// Horizontal Increment Arrows Sizes
|
||||
var prefix = _CPScrollerClassName + _CPScrollerIncrementArrowIdentifier + _CPScrollerHorizontalIdentifier;
|
||||
|
||||
_CPScrollerPartSizes[prefix + regularIdentifier] = _CGSizeMake(_CPScrollerArrowHeights[CPRegularControlSize], _CPScrollerWidths[CPRegularControlSize]);
|
||||
_CPScrollerPartSizes[prefix + regularIdentifier + _CPScrollerHighlightedIdentifier] = _CGSizeMake(_CPScrollerArrowHeights[CPRegularControlSize], _CPScrollerWidths[CPRegularControlSize]);
|
||||
_CPScrollerPartSizes[prefix + smallIdentifier] = _CGSizeMake(_CPScrollerArrowHeights[CPSmallControlSize], _CPScrollerWidths[CPSmallControlSize]);
|
||||
_CPScrollerPartSizes[prefix + smallIdentifier + _CPScrollerHighlightedIdentifier] = _CGSizeMake(_CPScrollerArrowHeights[CPSmallControlSize], _CPScrollerWidths[CPSmallControlSize]);
|
||||
_CPScrollerPartSizes[prefix + miniIdentifier] = _CGSizeMake(_CPScrollerArrowHeights[CPMiniControlSize], _CPScrollerWidths[CPMiniControlSize]);
|
||||
_CPScrollerPartSizes[prefix + miniIdentifier + _CPScrollerHighlightedIdentifier] = _CGSizeMake(_CPScrollerArrowHeights[CPMiniControlSize], _CPScrollerWidths[CPMiniControlSize]);
|
||||
|
||||
// Vertical Increment Arrows Sizes
|
||||
var prefix = _CPScrollerClassName + _CPScrollerIncrementArrowIdentifier + _CPScrollerVerticalIdentifier;
|
||||
|
||||
_CPScrollerPartSizes[prefix + regularIdentifier] = _CGSizeMake(_CPScrollerWidths[CPRegularControlSize], _CPScrollerArrowHeights[CPRegularControlSize]);
|
||||
_CPScrollerPartSizes[prefix + regularIdentifier + _CPScrollerHighlightedIdentifier] = _CGSizeMake(_CPScrollerWidths[CPRegularControlSize], _CPScrollerArrowHeights[CPRegularControlSize]);
|
||||
_CPScrollerPartSizes[prefix + smallIdentifier] = _CGSizeMake(_CPScrollerWidths[CPSmallControlSize], _CPScrollerArrowHeights[CPSmallControlSize]);
|
||||
_CPScrollerPartSizes[prefix + smallIdentifier + _CPScrollerHighlightedIdentifier] = _CGSizeMake(_CPScrollerWidths[CPSmallControlSize], _CPScrollerArrowHeights[CPSmallControlSize]);
|
||||
_CPScrollerPartSizes[prefix + miniIdentifier] = _CGSizeMake(_CPScrollerWidths[CPMiniControlSize], _CPScrollerArrowHeights[CPMiniControlSize]);
|
||||
_CPScrollerPartSizes[prefix + miniIdentifier + _CPScrollerHighlightedIdentifier] = _CGSizeMake(_CPScrollerWidths[CPMiniControlSize], _CPScrollerArrowHeights[CPMiniControlSize]);
|
||||
return "scroller";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[ nil, nil, nil, nil,
|
||||
_CGSizeMakeZero(), _CGSizeMakeZero(), _CGInsetMakeZero(), _CGInsetMakeZero(), _CGSizeMakeZero()]
|
||||
forKeys:[ @"knob-slot-color",
|
||||
@"decrement-line-color",
|
||||
@"increment-line-color",
|
||||
@"knob-color",
|
||||
@"decrement-line-size",
|
||||
@"increment-line-size",
|
||||
@"track-inset",
|
||||
@"knob-inset",
|
||||
@"minimum-knob-length"]];
|
||||
}
|
||||
|
||||
|
||||
// Calculating Layout
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -196,14 +106,9 @@ var _CPScrollerClassName = nil,
|
||||
|
||||
[self setFloatValue:0.0 knobProportion:1.0];
|
||||
|
||||
_isHorizontal = CPRectGetWidth(aFrame) > CPRectGetHeight(aFrame);
|
||||
|
||||
_hitPart = CPScrollerNoPart;
|
||||
|
||||
[self checkSpaceForParts];
|
||||
[self drawParts];
|
||||
|
||||
[self layoutSubviews];
|
||||
|
||||
[self _recalculateIsVertical];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -215,7 +120,7 @@ var _CPScrollerClassName = nil,
|
||||
*/
|
||||
+ (float)scrollerWidth
|
||||
{
|
||||
return [self scrollerWidthForControlSize:CPRegularControlSize];
|
||||
return 17.0;//[self scrollerWidthForControlSize:CPRegularControlSize];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -224,7 +129,7 @@ var _CPScrollerClassName = nil,
|
||||
*/
|
||||
+ (float)scrollerWidthForControlSize:(CPControlSize)aControlSize
|
||||
{
|
||||
return _CPScrollerWidths[aControlSize];
|
||||
return 17.0;//_CPScrollerWidths[aControlSize];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -238,12 +143,8 @@ var _CPScrollerClassName = nil,
|
||||
|
||||
_controlSize = aControlSize;
|
||||
|
||||
[self drawKnobSlot];
|
||||
[self drawKnob];
|
||||
[self drawArrow:CPScrollerDecrementArrow highlight:NO];
|
||||
[self drawArrow:CPScrollerIncrementArrow highlight:NO];
|
||||
|
||||
[self layoutSubviews];
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -263,8 +164,7 @@ var _CPScrollerClassName = nil,
|
||||
{
|
||||
[super setFloatValue:MIN(1.0, MAX(0.0, aValue))];
|
||||
|
||||
[self checkSpaceForParts];
|
||||
[self layoutSubviews];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -287,6 +187,16 @@ var _CPScrollerClassName = nil,
|
||||
return _knobProportion;
|
||||
}
|
||||
|
||||
- (id)currentValueForThemeAttribute:(CPString)anAttributeName
|
||||
{
|
||||
var themeState = _themeState;
|
||||
|
||||
if (NAMES_FOR_PARTS[_hitPart] + "-color" !== anAttributeName)
|
||||
themeState &= ~CPThemeStateHighlighted;
|
||||
|
||||
return [self valueForThemeAttribute:anAttributeName inState:themeState];
|
||||
}
|
||||
|
||||
// Calculating Layout
|
||||
|
||||
- (CGRect)rectForPart:(CPScrollerPart)aPart
|
||||
@@ -338,7 +248,7 @@ var _CPScrollerClassName = nil,
|
||||
var bounds = [self bounds];
|
||||
|
||||
// Assume we won't be needing the arrows.
|
||||
if (_knobProportion == 1.0)
|
||||
if (_knobProportion === 1.0)
|
||||
{
|
||||
_usableParts = CPNoScrollerParts;
|
||||
|
||||
@@ -354,39 +264,52 @@ var _CPScrollerClassName = nil,
|
||||
return;
|
||||
}
|
||||
|
||||
var width = _CGRectGetWidth(bounds),
|
||||
height = _CGRectGetHeight(bounds),
|
||||
usableArrowHeight = _CPScrollerArrowUsableHeights[_controlSize],
|
||||
slotWidth = (_isHorizontal ? width : height) - 2.0 * usableArrowHeight,
|
||||
knobWidth = MAX(_CPScrollerKnobMinimumHeights[_controlSize], (slotWidth * _knobProportion));
|
||||
|
||||
_usableParts = CPAllScrollerParts;
|
||||
|
||||
var arrowHeight = _CPScrollerArrowHeights[_controlSize],
|
||||
knobLocation = usableArrowHeight + (slotWidth - knobWidth) * [self floatValue];
|
||||
|
||||
// At this point we know we're going to need arrows.
|
||||
if (_isHorizontal)
|
||||
_usableParts = CPAllScrollerParts;
|
||||
|
||||
var knobInset = [self currentValueForThemeAttribute:@"knob-inset"],
|
||||
trackInset = [self currentValueForThemeAttribute:@"track-inset"],
|
||||
width = _CGRectGetWidth(bounds),
|
||||
height = _CGRectGetHeight(bounds);
|
||||
|
||||
if ([self isVertical])
|
||||
{
|
||||
// ASSERT(_CPScrollerWidths[_controlSize] == height)
|
||||
|
||||
_partRects[CPScrollerDecrementPage] = _CGRectMake(usableArrowHeight, 0.0, knobLocation - usableArrowHeight, height);
|
||||
_partRects[CPScrollerKnob] = _CGRectMake(knobLocation, 0.0, knobWidth, _CPScrollerWidths[_controlSize]);
|
||||
_partRects[CPScrollerIncrementPage] = _CGRectMake(knobLocation + knobWidth, 0.0, width - (knobLocation + knobWidth) - usableArrowHeight, height);
|
||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(usableArrowHeight, 0.0, slotWidth, height);
|
||||
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, arrowHeight, height);
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMake(width - _CPScrollerArrowHeights[_controlSize], 0.0, arrowHeight, height);
|
||||
var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"],
|
||||
incrementLineSize = [self currentValueForThemeAttribute:"increment-line-size"],
|
||||
effectiveDecrementLineHeight = decrementLineSize.height + trackInset.top,
|
||||
effectiveIncrementLineHeight = incrementLineSize.height + trackInset.bottom,
|
||||
slotHeight = 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];
|
||||
|
||||
_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[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// ASSERT(_CPScrollerWidths[_controlSize] == width)
|
||||
|
||||
_partRects[CPScrollerDecrementPage] = _CGRectMake(0.0, usableArrowHeight, width, knobLocation - usableArrowHeight);
|
||||
_partRects[CPScrollerKnob] = _CGRectMake(0.0, knobLocation, _CPScrollerWidths[_controlSize], knobWidth);
|
||||
_partRects[CPScrollerIncrementPage] = _CGRectMake(0.0, knobLocation + knobWidth, width, height - (knobLocation + knobWidth) - usableArrowHeight);
|
||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(0.0, usableArrowHeight, width, slotWidth);
|
||||
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, width, arrowHeight);
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMake(0.0, height - _CPScrollerArrowHeights[_controlSize], width, arrowHeight);
|
||||
var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"],
|
||||
incrementLineSize = [self currentValueForThemeAttribute:"increment-line-size"],
|
||||
effectiveDecrementLineWidth = decrementLineSize.width + trackInset.left,
|
||||
effectiveIncrementLineWidth = incrementLineSize.width + trackInset.right;
|
||||
slotWidth = width - effectiveDecrementLineWidth - effectiveIncrementLineWidth,
|
||||
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
|
||||
knobWidth = MAX(minimumKnobLength, (slotWidth * _knobProportion)),
|
||||
knobHeight = height - knobInset.top - knobInset.bottom,
|
||||
knobLocation = effectiveDecrementLineWidth + (slotWidth - 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[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMake(width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.height);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,16 +330,6 @@ var _CPScrollerClassName = nil,
|
||||
*/
|
||||
- (void)drawArrow:(CPScrollerArrow)anArrow highlight:(BOOL)shouldHighlight
|
||||
{
|
||||
var identifier = (anArrow == CPScrollerDecrementArrow ? _CPScrollerDecrementArrowIdentifier : _CPScrollerIncrementArrowIdentifier),
|
||||
arrowView = (anArrow == CPScrollerDecrementArrow ? _decrementArrowView : _incrementArrowView);
|
||||
|
||||
[arrowView setBackgroundColor:_CPControlColorWithPatternImage(
|
||||
_CPScrollerPartSizes,
|
||||
_CPScrollerClassName,
|
||||
identifier,
|
||||
_isHorizontal ? _CPScrollerHorizontalIdentifier : _CPScrollerVerticalIdentifier,
|
||||
_CPControlIdentifierForControlSize(_controlSize),
|
||||
shouldHighlight ? _CPScrollerHighlightedIdentifier : @"")];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -424,13 +337,6 @@ var _CPScrollerClassName = nil,
|
||||
*/
|
||||
- (void)drawKnob
|
||||
{
|
||||
[_knobView setBackgroundColor:_CPControlThreePartImagePattern(
|
||||
!_isHorizontal,
|
||||
_CPScrollerPartSizes,
|
||||
_CPScrollerClassName,
|
||||
_CPScrollerKnobIdentifier,
|
||||
_isHorizontal ? _CPScrollerHorizontalIdentifier : _CPScrollerVerticalIdentifier,
|
||||
_CPControlIdentifierForControlSize(_controlSize))];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -438,67 +344,63 @@ var _CPScrollerClassName = nil,
|
||||
*/
|
||||
- (void)drawKnobSlot
|
||||
{
|
||||
[_knobSlotView setBackgroundColor:_CPControlColorWithPatternImage(
|
||||
_CPScrollerPartSizes,
|
||||
_CPScrollerClassName,
|
||||
_CPScrollerKnobSlotIdentifier,
|
||||
_isHorizontal ? _CPScrollerHorizontalIdentifier : _CPScrollerVerticalIdentifier,
|
||||
_CPControlIdentifierForControlSize(_controlSize))];
|
||||
}
|
||||
|
||||
- (CPView)createViewForPart:(CPScrollerPart)aPart
|
||||
{
|
||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
return _partRects[aName];
|
||||
}
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[self checkSpaceForParts];
|
||||
|
||||
var index = 0,
|
||||
count = PARTS_ARRANGEMENT.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var part = PARTS_ARRANGEMENT[index];
|
||||
|
||||
if (index === 0)
|
||||
view = [self layoutEphemeralSubviewNamed:part positioned:CPWindowBelow relativeToEphemeralSubviewNamed:PARTS_ARRANGEMENT[index + 1]];
|
||||
else
|
||||
view = [self layoutEphemeralSubviewNamed:part positioned:CPWindowAbove relativeToEphemeralSubviewNamed:PARTS_ARRANGEMENT[index - 1]];
|
||||
|
||||
if (view)
|
||||
[view setBackgroundColor:[self currentValueForThemeAttribute:NAMES_FOR_PARTS[part] + "-color"]];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Caches images for the scroll arrow and knob.
|
||||
*/
|
||||
- (void)drawParts
|
||||
{
|
||||
_knobSlotView = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
[_knobSlotView setHitTests:NO];
|
||||
|
||||
[self addSubview:_knobSlotView];
|
||||
|
||||
{
|
||||
[self drawKnobSlot];
|
||||
|
||||
_knobView = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
[_knobView setHitTests:NO];
|
||||
|
||||
[self addSubview:_knobView];
|
||||
|
||||
[self drawKnob];
|
||||
|
||||
_decrementArrowView = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
[_decrementArrowView setHitTests:NO];
|
||||
|
||||
[self addSubview:_decrementArrowView];
|
||||
|
||||
[self drawArrow:CPScrollerDecrementArrow highlight:NO];
|
||||
|
||||
_incrementArrowView = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
[_incrementArrowView setHitTests:NO];
|
||||
|
||||
[self addSubview:_incrementArrowView];
|
||||
|
||||
[self drawArrow:CPScrollerIncrementArrow highlight:NO];
|
||||
}
|
||||
|
||||
/*!
|
||||
Draws the scroller's arrow with a possible highlight,
|
||||
if the user's mouse is over it.
|
||||
@param shouldHighlight <code>YES</code> will draw the
|
||||
arrow highlighted if the mouse is hovering over it.
|
||||
*/
|
||||
- (void)highlight:(BOOL)shouldHighlight
|
||||
{
|
||||
if (_trackingPart == CPScrollerDecrementLine)
|
||||
[self drawArrow:CPScrollerDecrementArrow highlight:shouldHighlight];
|
||||
|
||||
else if (_trackingPart == CPScrollerIncrementLine)
|
||||
[self drawArrow:CPScrollerIncrementArrow highlight:shouldHighlight];
|
||||
}
|
||||
|
||||
// Event Handling
|
||||
/*!
|
||||
Returns the part of the scroller that was hit.
|
||||
@@ -516,31 +418,31 @@ var _CPScrollerClassName = nil,
|
||||
{
|
||||
var type = [anEvent type];
|
||||
|
||||
if (type == CPLeftMouseUp)
|
||||
if (type === CPLeftMouseUp)
|
||||
{
|
||||
_hitPart = CPScrollerNoPart;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == CPLeftMouseDown)
|
||||
if (type === CPLeftMouseDown)
|
||||
{
|
||||
_trackingFloatValue = [self floatValue];
|
||||
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
}
|
||||
|
||||
else if (type == CPLeftMouseDragged)
|
||||
else if (type === CPLeftMouseDragged)
|
||||
{
|
||||
var knobRect = [self rectForPart:CPScrollerKnob],
|
||||
knobSlotRect = [self rectForPart:CPScrollerKnobSlot],
|
||||
remainder = _isHorizontal ? (_CGRectGetWidth(knobSlotRect) - _CGRectGetWidth(knobRect)) : (_CGRectGetHeight(knobSlotRect) - _CGRectGetHeight(knobRect));
|
||||
remainder = ![self isVertical] ? (_CGRectGetWidth(knobSlotRect) - _CGRectGetWidth(knobRect)) : (_CGRectGetHeight(knobSlotRect) - _CGRectGetHeight(knobRect));
|
||||
|
||||
if (remainder <= 0)
|
||||
[self setFloatValue:0.0];
|
||||
else
|
||||
{
|
||||
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
delta = _isHorizontal ? location.x - _trackingStartPoint.x : location.y - _trackingStartPoint.y;
|
||||
delta = ![self isVertical] ? location.x - _trackingStartPoint.x : location.y - _trackingStartPoint.y;
|
||||
|
||||
[self setFloatValue:_trackingFloatValue + delta / remainder];
|
||||
}
|
||||
@@ -559,7 +461,7 @@ var _CPScrollerClassName = nil,
|
||||
{
|
||||
var type = [anEvent type];
|
||||
|
||||
if (type == CPLeftMouseUp)
|
||||
if (type === CPLeftMouseUp)
|
||||
{
|
||||
[self highlight:NO];
|
||||
[CPEvent stopPeriodicEvents];
|
||||
@@ -569,7 +471,7 @@ var _CPScrollerClassName = nil,
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == CPLeftMouseDown)
|
||||
if (type === CPLeftMouseDown)
|
||||
{
|
||||
_trackingPart = [self hitPart];
|
||||
|
||||
@@ -579,16 +481,18 @@ var _CPScrollerClassName = nil,
|
||||
{
|
||||
if (_trackingPart == CPScrollerDecrementLine)
|
||||
_hitPart = CPScrollerDecrementPage;
|
||||
|
||||
else if (_trackingPart == CPScrollerIncrementLine)
|
||||
_hitPart = CPScrollerIncrementPage;
|
||||
|
||||
else if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage)
|
||||
{
|
||||
var knobRect = [self rectForPart:CPScrollerKnob],
|
||||
knobWidth = _isHorizontal ? _CGRectGetWidth(knobRect) : _CGRectGetHeight(knobRect),
|
||||
knobWidth = ![self isVertical] ? _CGRectGetWidth(knobRect) : _CGRectGetHeight(knobRect),
|
||||
knobSlotRect = [self rectForPart:CPScrollerKnobSlot],
|
||||
remainder = (_isHorizontal ? _CGRectGetWidth(knobSlotRect) : _CGRectGetHeight(knobSlotRect)) - knobWidth;
|
||||
remainder = (![self isVertical] ? _CGRectGetWidth(knobSlotRect) : _CGRectGetHeight(knobSlotRect)) - knobWidth;
|
||||
|
||||
[self setFloatValue:((_isHorizontal ? _trackingStartPoint.x - _CGRectGetMinX(knobSlotRect) : _trackingStartPoint.y - _CGRectGetMinY(knobSlotRect)) - knobWidth / 2.0) / remainder];
|
||||
[self setFloatValue:((![self isVertical] ? _trackingStartPoint.x - _CGRectGetMinX(knobSlotRect) : _trackingStartPoint.y - _CGRectGetMinY(knobSlotRect)) - knobWidth / 2.0) / remainder];
|
||||
|
||||
_hitPart = CPScrollerKnob;
|
||||
|
||||
@@ -605,7 +509,7 @@ var _CPScrollerClassName = nil,
|
||||
[CPEvent startPeriodicEventsAfterDelay:0.5 withPeriod:0.04];
|
||||
}
|
||||
|
||||
else if (type == CPLeftMouseDragged)
|
||||
else if (type === CPLeftMouseDragged)
|
||||
{
|
||||
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
|
||||
@@ -629,52 +533,36 @@ var _CPScrollerClassName = nil,
|
||||
|
||||
}
|
||||
|
||||
- (void)_recalculateIsVertical
|
||||
{
|
||||
// Recalculate isVertical.
|
||||
var bounds = [self bounds],
|
||||
width = _CGRectGetWidth(bounds),
|
||||
height = _CGRectGetHeight(bounds);
|
||||
|
||||
_isVertical = width < height ? 1 : (width > height ? 0 : -1);
|
||||
|
||||
if (_isVertical === 1)
|
||||
[self setThemeState:CPThemeStateVertical];
|
||||
else if (_isVertical === 0)
|
||||
[self unsetThemeState:CPThemeStateVertical];
|
||||
}
|
||||
|
||||
- (void)setFrameSize:(CGSize)aSize
|
||||
{
|
||||
[super setFrameSize:aSize];
|
||||
|
||||
|
||||
[self _recalculateIsVertical];
|
||||
|
||||
[self checkSpaceForParts];
|
||||
|
||||
var frame = [self frame],
|
||||
isHorizontal = CPRectGetWidth(frame) > CPRectGetHeight(frame);
|
||||
|
||||
if (_isHorizontal != isHorizontal)
|
||||
{
|
||||
_isHorizontal = isHorizontal;
|
||||
|
||||
[self drawParts];
|
||||
}
|
||||
|
||||
[self layoutSubviews];
|
||||
}
|
||||
|
||||
/*!
|
||||
Lays out the scrollers subviews
|
||||
*/
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[_knobSlotView setFrame:[self rectForPart:CPScrollerKnobSlot]];
|
||||
|
||||
var usableParts = [self usableParts],
|
||||
hidden = !(usableParts == CPAllScrollerParts);
|
||||
|
||||
if (hidden != [_knobView isHidden])
|
||||
{
|
||||
[_knobView setHidden:hidden];
|
||||
[_decrementArrowView setHidden:hidden];
|
||||
[_incrementArrowView setHidden:hidden];
|
||||
}
|
||||
|
||||
if (!hidden)
|
||||
{
|
||||
[_knobView setFrame:[self rectForPart:CPScrollerKnob]];
|
||||
[_decrementArrowView setFrame:[self rectForPart:CPScrollerDecrementLine]];
|
||||
[_incrementArrowView setFrame:[self rectForPart:CPScrollerIncrementLine]];
|
||||
}
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
if (![self isEnabled])
|
||||
return;
|
||||
|
||||
_hitPart = [self testPart:[anEvent locationInWindow]];
|
||||
|
||||
switch (_hitPart)
|
||||
@@ -688,9 +576,43 @@ var _CPScrollerClassName = nil,
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: This is a result of the "dumb" code that just makes things transparent when disabled.
|
||||
- (void)setEnabled:(BOOL)shouldBeEnabled
|
||||
@end
|
||||
|
||||
var CPScrollerControlSizeKey = "CPScrollerControlSize",
|
||||
CPScrollerKnobProportionKey = "CPScrollerKnobProportion";
|
||||
|
||||
@implementation CPScroller (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
{
|
||||
_controlSize = CPRegularControlSize;
|
||||
if ([aCoder containsValueForKey:CPScrollerControlSizeKey])
|
||||
_controlSize = [aCoder decodeIntForKey:CPScrollerControlSizeKey];
|
||||
|
||||
_knobProportion = 1.0;
|
||||
if ([aCoder containsValueForKey:CPScrollerKnobProportionKey])
|
||||
_knobProportion = [aCoder decodeFloatForKey:CPScrollerKnobProportionKey];
|
||||
|
||||
_partRects = [];
|
||||
|
||||
_hitPart = CPScrollerNoPart;
|
||||
|
||||
[self _recalculateIsVertical];
|
||||
// [self checkSpaceForParts];
|
||||
// [self setNeedsLayout];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeInt:_controlSize forKey:CPScrollerControlSizeKey];
|
||||
[aCoder encodeFloat:_knobProportion forKey:CPScrollerKnobProportionKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,103 +1,16 @@
|
||||
|
||||
@import "CPTextField.j"
|
||||
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
|
||||
var TOP_PADDING = 4.0,
|
||||
BOTTOM_PADDING = 3.0;
|
||||
HORIZONTAL_PADDING = 3.0;
|
||||
|
||||
var CPSecureTextFieldDOMInputElement = nil;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
*/
|
||||
@implementation CPSecureTextField : CPTextField
|
||||
{
|
||||
}
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
+ (DOMElement)_inputElement
|
||||
- (BOOL)isSecure
|
||||
{
|
||||
if (!CPSecureTextFieldDOMInputElement)
|
||||
{
|
||||
CPSecureTextFieldDOMInputElement = document.createElement("input");
|
||||
CPSecureTextFieldDOMInputElement.type = "password";
|
||||
CPSecureTextFieldDOMInputElement.style.position = "absolute";
|
||||
CPSecureTextFieldDOMInputElement.style.top = "0px";
|
||||
CPSecureTextFieldDOMInputElement.style.left = "0px";
|
||||
CPSecureTextFieldDOMInputElement.style.width = "100%"
|
||||
CPSecureTextFieldDOMInputElement.style.height = "100%";
|
||||
CPSecureTextFieldDOMInputElement.style.border = "0px";
|
||||
CPSecureTextFieldDOMInputElement.style.padding = "0px";
|
||||
CPSecureTextFieldDOMInputElement.style.whiteSpace = "pre";
|
||||
CPSecureTextFieldDOMInputElement.style.background = "transparent";
|
||||
CPSecureTextFieldDOMInputElement.style.outline = "none";
|
||||
CPSecureTextFieldDOMInputElement.style.paddingLeft = HORIZONTAL_PADDING + "px";
|
||||
CPSecureTextFieldDOMInputElement.style.paddingTop = TOP_PADDING - 2.0 + "px";
|
||||
CPSecureTextFieldDOMInputElement.style.margin = "0px";
|
||||
}
|
||||
|
||||
return CPSecureTextFieldDOMInputElement;
|
||||
}
|
||||
#endif
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
if (self)
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
_DOMElement.removeChild(_DOMTextElement);
|
||||
|
||||
_DOMTextElement = document.createElement("input");
|
||||
_DOMTextElement.type = "password";
|
||||
_DOMTextElement.style.position = "absolute";
|
||||
_DOMTextElement.style.top = TOP_PADDING + "px";
|
||||
_DOMTextElement.style.left = HORIZONTAL_PADDING + "px";
|
||||
_DOMTextElement.style.width = MAX(0.0, CGRectGetWidth(aFrame) - 2.0 * HORIZONTAL_PADDING) + "px";
|
||||
_DOMTextElement.style.height = MAX(0.0, CGRectGetHeight(aFrame) - TOP_PADDING - BOTTOM_PADDING) + "px";
|
||||
_DOMTextElement.style.whiteSpace = "pre";
|
||||
_DOMTextElement.style.cursor = "default";
|
||||
_DOMTextElement.style.zIndex = 100;
|
||||
_DOMTextElement.style.border = "0";
|
||||
_DOMTextElement.style.font = _DOMElement.style.font;
|
||||
_DOMTextElement.style.padding = "0px";
|
||||
_DOMTextElement.style.margin = "0px";
|
||||
|
||||
_DOMElement.appendChild(_DOMTextElement);
|
||||
#endif
|
||||
}
|
||||
|
||||
return self;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)setFont:(CPFont)aFont
|
||||
{
|
||||
[super setFont:aFont];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
if (_DOMTextElement)
|
||||
_DOMTextElement.style.font = _DOMElement.style.font;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (CPString)stringValue
|
||||
{
|
||||
// All of this needs to be better.
|
||||
#if PLATFORM(DOM)
|
||||
if ([[self window] firstResponder] == self)
|
||||
return [[self class] _inputElement].value;
|
||||
#endif
|
||||
|
||||
return _DOMTextElement.value;
|
||||
}
|
||||
|
||||
- (void)setStringValue:(CPString)aStringValue
|
||||
{
|
||||
_value = aStringValue;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
_DOMTextElement.value = _value;
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
@import "CPControl.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
/*
|
||||
@global
|
||||
@group CPSegmentSwitchTracking
|
||||
@@ -40,33 +42,47 @@ CPSegmentSwitchTrackingSelectAny = 1;
|
||||
*/
|
||||
CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
/*! @class CPSegmentedControl
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPSegmentedControl
|
||||
|
||||
This class is a horizontal button with multiple segments.
|
||||
*/
|
||||
@implementation CPSegmentedControl : CPControl
|
||||
{
|
||||
unsigned _segmentCount;
|
||||
|
||||
CPArray _segments;
|
||||
CPArray _selectedSegment;
|
||||
|
||||
CPArray _themeStates;
|
||||
|
||||
int _selectedSegment;
|
||||
int _segmentStyle;
|
||||
CPSegmentSwitchTracking _trackingMode;
|
||||
|
||||
unsigned _trackingSegment;
|
||||
BOOL _trackingHighlighted;
|
||||
}
|
||||
|
||||
+ (CPString)themeClass
|
||||
{
|
||||
return "segmented-control";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[CPCenterTextAlignment, CPCenterVerticalTextAlignment, CPImageLeft, CPScaleNone, _CGInsetMakeZero(), _CGInsetMakeZero(), nil, nil, nil, nil, 1.0, 24.0]
|
||||
forKeys:[@"alignment", @"vertical-alignment", @"image-position", @"image-scaling", @"bezel-inset", @"content-inset", @"left-segment-bezel-color", @"right-segment-bezel-color", @"center-segment-bezel-color", @"divider-bezel-color", @"divider-thickness", @"default-height"]];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aRect
|
||||
{
|
||||
_segments = [];
|
||||
_themeStates = [];
|
||||
|
||||
self = [super initWithFrame:aRect];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_segments = [];
|
||||
_selectedSegment = -1;
|
||||
|
||||
_segmentCount = 0;
|
||||
|
||||
_trackingMode = CPSegmentSwitchTrackingSelectOne;
|
||||
}
|
||||
|
||||
@@ -88,37 +104,26 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setSegmentCount:(unsigned)aCount
|
||||
{
|
||||
if (_segmentCount == aCount)
|
||||
if (_segments.length == aCount)
|
||||
return;
|
||||
|
||||
var height = CGRectGetHeight([self bounds]);
|
||||
|
||||
if (_segmentCount < aCount)
|
||||
{
|
||||
var index = _segmentCount;
|
||||
|
||||
for (; index < aCount; ++index)
|
||||
if (_segments.length < aCount)
|
||||
{
|
||||
for (var index = _segments.length; index < aCount; ++index)
|
||||
{
|
||||
_segments[index] = _CPSegmentMake();
|
||||
_segments[index].frame.size.height = height;
|
||||
_segments[index] = [[_CPSegmentItem alloc] init];
|
||||
_themeStates[index] = CPThemeStateNormal;
|
||||
}
|
||||
}
|
||||
else if (aCount < _segmentCount)
|
||||
else if (aCount < _segments.length)
|
||||
{
|
||||
var index = aCount;
|
||||
|
||||
for (; index < _segmentCount; ++index)
|
||||
{
|
||||
[_segments[index].imageView removeFromSuperview];
|
||||
[_segments[index].labelView removeFromSuperview];
|
||||
|
||||
for (var index = aCount; index < _segments.length; ++index)
|
||||
_segments[index] = nil;
|
||||
}
|
||||
}
|
||||
|
||||
_segmentCount = aCount;
|
||||
|
||||
if (_selectedSegment < _segmentCount)
|
||||
if (_selectedSegment < _segments.length)
|
||||
_selectedSegment = -1;
|
||||
|
||||
[self tileWithChangedSegment:0];
|
||||
@@ -129,7 +134,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (unsigned)segmentCount
|
||||
{
|
||||
return _segmentCount;
|
||||
return _segments.length;
|
||||
}
|
||||
|
||||
// Specifying Selected Segment
|
||||
@@ -159,7 +164,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
{
|
||||
var index = 0;
|
||||
|
||||
for (; index < _segmentCount; ++index)
|
||||
for (; index < _segments.length; ++index)
|
||||
if (_segments[index].tag == aTag)
|
||||
{
|
||||
[self setSelectedSegment:index];
|
||||
@@ -189,7 +194,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
var index = 0,
|
||||
selected = NO;
|
||||
|
||||
for (; index < _segmentCount; ++index)
|
||||
for (; index < _segments.length; ++index)
|
||||
if (_segments[index].selected)
|
||||
if (selected)
|
||||
[self setSelected:NO forSegment:index];
|
||||
@@ -201,7 +206,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
{
|
||||
var index = 0;
|
||||
|
||||
for (; index < _segmentCount; ++index)
|
||||
for (; index < _segments.length; ++index)
|
||||
if (_segments[index].selected)
|
||||
[self setSelected:NO forSegment:index];
|
||||
}
|
||||
@@ -249,32 +254,9 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
{
|
||||
var segment = _segments[aSegment];
|
||||
|
||||
if (!anImage)
|
||||
{
|
||||
[segment.imageView removeFromSuperview];
|
||||
|
||||
segment.imageView = nil;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (!segment.imageView)
|
||||
{
|
||||
segment.imageView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[self addSubview:segment.imageView];
|
||||
}
|
||||
|
||||
[segment.imageView setImage:anImage];
|
||||
[segment.imageView setFrameSize:CGSizeMakeCopy([anImage size])];
|
||||
}
|
||||
|
||||
segment.image = anImage;
|
||||
|
||||
if (segment.width)
|
||||
[self drawSegment:aSegment highlight:NO];
|
||||
else
|
||||
[self tileWithChangedSegment:aSegment];
|
||||
[self tileWithChangedSegment:aSegment];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -296,35 +278,10 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
- (void)setLabel:(CPString)aLabel forSegment:(unsigned)aSegment
|
||||
{
|
||||
var segment = _segments[aSegment];
|
||||
|
||||
if (!aLabel || !aLabel.length)
|
||||
{
|
||||
[segment.labelView removeFromSuperview];
|
||||
|
||||
segment.labelView = nil;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (!segment.labelView)
|
||||
{
|
||||
segment.labelView = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[segment.labelView setFont:[self font]];
|
||||
|
||||
[self addSubview:segment.labelView];
|
||||
}
|
||||
|
||||
[segment.labelView setStringValue:aLabel];
|
||||
[segment.labelView sizeToFit];
|
||||
}
|
||||
|
||||
_segments[aSegment].label = aLabel;
|
||||
|
||||
if (segment.width)
|
||||
[self drawSegment:aSegment highlight:NO];
|
||||
else
|
||||
[self tileWithChangedSegment:aSegment];
|
||||
[self tileWithChangedSegment:aSegment];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -375,6 +332,8 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
segment.selected = isSelected;
|
||||
|
||||
_themeStates[aSegment] = isSelected ? CPThemeStateSelected : CPThemeStateNormal;
|
||||
|
||||
// We need to do some cleanup if we only allow one selection.
|
||||
if (isSelected)
|
||||
{
|
||||
@@ -385,6 +344,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
if (_trackingMode == CPSegmentSwitchTrackingSelectOne && oldSelectedSegment != aSegment && oldSelectedSegment != -1)
|
||||
{
|
||||
_segments[oldSelectedSegment].selected = NO;
|
||||
_themeStates[oldSelectedSegment] = CPThemeStateNormal;
|
||||
|
||||
[self drawSegmentBezel:oldSelectedSegment highlight:NO];
|
||||
}
|
||||
@@ -392,6 +352,9 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
if (_trackingMode != CPSegmentSwitchTrackingMomentary)
|
||||
[self drawSegmentBezel:aSegment highlight:NO];
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -413,6 +376,9 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
- (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
|
||||
{
|
||||
_segments[aSegment].enabled = isEnabled;
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -452,8 +418,167 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)drawSegmentBezel:(int)aSegment highlight:(BOOL)shouldHighlight
|
||||
{
|
||||
if (shouldHighlight)
|
||||
_themeStates[aSegment] |= CPThemeStateHighlighted;
|
||||
else
|
||||
_themeStates[aSegment] &= ~CPThemeStateHighlighted;
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (float)_leftOffsetForSegment:(unsigned)segment
|
||||
{
|
||||
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
|
||||
|
||||
if (segment == 0)
|
||||
return bezelInset.left;
|
||||
|
||||
var thickness = [self currentValueForThemeAttribute:@"divider-thickness"];
|
||||
|
||||
return [self _leftOffsetForSegment:segment - 1] + [self widthForSegment:segment - 1] + thickness;
|
||||
}
|
||||
|
||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
var height = [self currentValueForThemeAttribute:@"default-height"],
|
||||
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||
bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"],
|
||||
bounds = [self bounds];
|
||||
|
||||
if (aName === "left-segment-bezel")
|
||||
{
|
||||
return CGRectMake(bezelInset.left, bezelInset.top, contentInset.left, height);
|
||||
}
|
||||
else if (aName === "right-segment-bezel")
|
||||
{
|
||||
return CGRectMake(CGRectGetMaxX(bounds) - contentInset.right - bezelInset.right, bezelInset.top, contentInset.right, height);
|
||||
}
|
||||
else if (aName.substring(0, "segment-bezel".length) == "segment-bezel")
|
||||
{
|
||||
var segment = parseInt(aName.substring("segment-bezel-".length), 10),
|
||||
frame = CGRectCreateCopy(_segments[segment].frame);
|
||||
|
||||
if (segment == 0)
|
||||
{
|
||||
frame.origin.x += contentInset.left;
|
||||
frame.size.width -= contentInset.left;
|
||||
}
|
||||
|
||||
if (segment == _segments.length - 1)
|
||||
frame.size.width -= contentInset.right;
|
||||
|
||||
return frame;
|
||||
}
|
||||
else if (aName.substring(0, "divider-bezel".length) == "divider-bezel")
|
||||
{
|
||||
var segment = parseInt(aName.substring("divider-bezel-".length), 10),
|
||||
width = [self widthForSegment:segment],
|
||||
left = [self _leftOffsetForSegment:segment],
|
||||
thickness = [self currentValueForThemeAttribute:@"divider-thickness"];
|
||||
|
||||
return CGRectMake(left + width, bezelInset.top, thickness, height);
|
||||
}
|
||||
else if (aName.substring(0, "segment-content".length) == "segment-content")
|
||||
{
|
||||
var segment = parseInt(aName.substring("segment-content-".length), 10);
|
||||
|
||||
return [self contentFrameForSegment:segment];
|
||||
}
|
||||
|
||||
return [super rectForEphemeralSubviewNamed:aName];
|
||||
}
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
if (aName.substring(0, "segment-content".length) == "segment-content")
|
||||
return [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
return [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
|
||||
inState:_themeStates[0]];
|
||||
|
||||
var leftBezelView = [self layoutEphemeralSubviewNamed:@"left-segment-bezel"
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:nil];
|
||||
|
||||
[leftBezelView setBackgroundColor:leftCapColor];
|
||||
|
||||
var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color"
|
||||
inState:_themeStates[_themeStates.length - 1]];
|
||||
|
||||
var rightBezelView = [self layoutEphemeralSubviewNamed:@"right-segment-bezel"
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:nil];
|
||||
|
||||
[rightBezelView setBackgroundColor:rightCapColor];
|
||||
|
||||
for (var i=0, count = _themeStates.length; i<count; i++)
|
||||
{
|
||||
var themeState = _themeStates[i];
|
||||
|
||||
themeState |= _themeState & CPThemeStateDisabled;
|
||||
|
||||
var bezelColor = [self valueForThemeAttribute:@"center-segment-bezel-color"
|
||||
inState:themeState];
|
||||
|
||||
var bezelView = [self layoutEphemeralSubviewNamed:"segment-bezel-"+i
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:nil];
|
||||
|
||||
[bezelView setBackgroundColor:bezelColor];
|
||||
|
||||
|
||||
//layout image/title views
|
||||
var segment = _segments[i];
|
||||
|
||||
|
||||
var contentView = [self layoutEphemeralSubviewNamed:@"segment-content-"+i
|
||||
positioned:CPWindowAbove
|
||||
relativeToEphemeralSubviewNamed:@"segment-bezel-"+i];
|
||||
|
||||
[contentView setText:segment.label];
|
||||
[contentView setImage:segment.image];
|
||||
|
||||
[contentView setFont:[self valueForThemeAttribute:@"font" inState:themeState]];
|
||||
[contentView setTextColor:[self valueForThemeAttribute:@"text-color" inState:themeState]];
|
||||
[contentView setAlignment:[self valueForThemeAttribute:@"alignment" inState:themeState]];
|
||||
[contentView setVerticalAlignment:[self valueForThemeAttribute:@"vertical-alignment" inState:themeState]];
|
||||
[contentView setLineBreakMode:[self valueForThemeAttribute:@"line-break-mode" inState:themeState]];
|
||||
[contentView setTextShadowColor:[self valueForThemeAttribute:@"text-shadow-color" inState:themeState]];
|
||||
[contentView setTextShadowOffset:[self valueForThemeAttribute:@"text-shadow-offset" inState:themeState]];
|
||||
[contentView setImageScaling:[self valueForThemeAttribute:@"image-scaling" inState:themeState]];
|
||||
|
||||
if (segment.image && segment.label)
|
||||
[contentView setImagePosition:[self valueForThemeAttribute:@"image-position" inState:themeState]];
|
||||
else if (segment.image)
|
||||
[contentView setImagePosition:CPImageOnly];
|
||||
|
||||
if (i == count - 1)
|
||||
continue;
|
||||
|
||||
var borderState = _themeStates[i] | _themeStates[i+1];
|
||||
|
||||
borderState = (borderState & CPThemeStateSelected & ~CPThemeStateHighlighted) ? CPThemeStateSelected : CPThemeStateNormal;
|
||||
|
||||
borderState |= _themeState & CPThemeStateDisabled;
|
||||
|
||||
var borderColor = [self valueForThemeAttribute:@"divider-bezel-color"
|
||||
inState:borderState];
|
||||
|
||||
var borderView = [self layoutEphemeralSubviewNamed:"divider-bezel-"+i
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:nil];
|
||||
|
||||
[borderView setBackgroundColor:borderColor];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Draws the specified segment
|
||||
@param aSegment the segment to draw
|
||||
@@ -461,67 +586,33 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)drawSegment:(int)aSegment highlight:(BOOL)shouldHighlight
|
||||
{
|
||||
var segment = _segments[aSegment],
|
||||
|
||||
imageView = segment.imageView,
|
||||
labelView = segment.labelView,
|
||||
|
||||
frame = segment.frame,
|
||||
|
||||
segmentX = CGRectGetMinX(frame),
|
||||
segmentWidth = CGRectGetWidth(frame),
|
||||
segmentHeight = CGRectGetHeight(frame) - 1.0;
|
||||
|
||||
if (imageView && labelView)
|
||||
{
|
||||
var imageViewSize = [imageView frame].size,
|
||||
labelViewSize = [labelView frame].size,
|
||||
totalHeight = imageViewSize.height + labelViewSize.height,
|
||||
labelWidth = MIN(labelViewSize.width, width),
|
||||
y = (segmentHeight - totalHeight) / 2.0;
|
||||
|
||||
[imageView setFrameOrigin:CGPointMake(segmentX + (segmentWidth - imageViewSize.width) / 2.0, y)];
|
||||
|
||||
if (labelWidth < labelViewSize.width)
|
||||
[labelView setFrameSize:CGSizeMake(labelWidth, labelViewSize.height)];
|
||||
|
||||
[labelView setFrameOrigin:CGPointMake(segmentX + (segmentWidth - labelWidth) / 2.0, y + imageViewSize.height)];
|
||||
}
|
||||
else if (imageView)
|
||||
{
|
||||
var imageViewSize = [imageView frame].size;
|
||||
|
||||
[imageView setFrameOrigin:CGPointMake(segmentX + (segmentWidth - imageViewSize.width) / 2.0, (segmentHeight - imageViewSize.height) / 2.0)];
|
||||
}
|
||||
else if (labelView)
|
||||
{
|
||||
var labelViewSize = [labelView frame].size,
|
||||
labelWidth = MIN(labelViewSize.width, segmentWidth);
|
||||
|
||||
if (labelWidth < labelViewSize.width)
|
||||
[labelView setFrameSize:CGSizeMake(labelWidth, labelViewSize.height)];
|
||||
|
||||
[labelView setFrameOrigin:CGPointMake(segmentX + (segmentWidth - labelWidth) / 2.0, (segmentHeight - labelViewSize.height) / 2.0)];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)tileWithChangedSegment:(unsigned)aSegment
|
||||
{
|
||||
if (aSegment >= _segments.length)
|
||||
return;
|
||||
|
||||
var segment = _segments[aSegment],
|
||||
segmentWidth = segment.width;
|
||||
|
||||
segmentWidth = segment.width,
|
||||
themeState = _themeStates[aSegment] | (_themeState & CPThemeStateDisabled),
|
||||
contentInset = [self valueForThemeAttribute:@"content-inset" inState:themeState],
|
||||
font = [self valueForThemeAttribute:@"font" inState:themeState];
|
||||
|
||||
if (!segmentWidth)
|
||||
{
|
||||
if (segment.labelView && segment.imageView)
|
||||
segmentWidth = MAX(CGRectGetWidth([segment.labelView frame]) , CGRectGetWidth([segment.imageView frame]));
|
||||
else if (segment.labelView)
|
||||
segmentWidth = CGRectGetWidth([segment.labelView frame]);
|
||||
else if (segment.imageView)
|
||||
segmentWidth = CGRectGetWidth([segment.imageView frame]);
|
||||
if (segment.image && segment.label)
|
||||
segmentWidth = [segment.label sizeWithFont:font].width + [segment.image size].width + contentInset.left + contentInset.right;
|
||||
else if (segment.image)
|
||||
segmentWidth = [segment.image size].width + contentInset.left + contentInset.right;
|
||||
else if (segment.label)
|
||||
segmentWidth = [segment.label sizeWithFont:font].width + contentInset.left + contentInset.right;
|
||||
else
|
||||
segmentWidth = 0.0;
|
||||
}
|
||||
|
||||
|
||||
var delta = segmentWidth - CGRectGetWidth(segment.frame);
|
||||
|
||||
|
||||
if (!delta)
|
||||
return;
|
||||
|
||||
@@ -531,12 +622,13 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
[self setFrameSize:CGSizeMake(CGRectGetWidth(frame) + delta, CGRectGetHeight(frame))];
|
||||
|
||||
// Update Segment Width
|
||||
segment.frame.size.width = segmentWidth;
|
||||
segment.width = segmentWidth;
|
||||
segment.frame = [self frameForSegment:aSegment];;
|
||||
|
||||
// Update Following Segments Widths
|
||||
var index = aSegment + 1;
|
||||
|
||||
for (; index < _segmentCount; ++index)
|
||||
for (; index < _segments.length; ++index)
|
||||
{
|
||||
_segments[index].frame.origin.x += delta;
|
||||
|
||||
@@ -546,6 +638,9 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
[self drawSegmentBezel:aSegment highlight:NO];
|
||||
[self drawSegment:aSegment highlight:NO];
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -554,7 +649,27 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (CGRect)frameForSegment:(unsigned)aSegment
|
||||
{
|
||||
return _segments[aSegment].frame;
|
||||
return [self bezelFrameForSegment:aSegment];
|
||||
}
|
||||
|
||||
- (CGRect)bezelFrameForSegment:(unsigned)aSegment
|
||||
{
|
||||
var height = [self currentValueForThemeAttribute:@"default-height"],
|
||||
bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"],
|
||||
width = [self widthForSegment:aSegment],
|
||||
left = [self _leftOffsetForSegment:aSegment];
|
||||
|
||||
return CGRectMake(left, bezelInset.top, width, height);
|
||||
}
|
||||
|
||||
- (CGRect)contentFrameForSegment:(unsigned)aSegment
|
||||
{
|
||||
var height = [self currentValueForThemeAttribute:@"default-height"],
|
||||
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||
width = [self widthForSegment:aSegment],
|
||||
left = [self _leftOffsetForSegment:aSegment];
|
||||
|
||||
return CGRectMake(left + contentInset.left, contentInset.top, width - contentInset.left - contentInset.right, height - contentInset.top - contentInset.bottom);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -598,6 +713,9 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
if (type == CPLeftMouseUp)
|
||||
{
|
||||
if (_trackingSegment == -1)
|
||||
return;
|
||||
|
||||
if (CGRectContainsPoint(_segments[_trackingSegment].frame, location))
|
||||
{
|
||||
if (_trackingMode == CPSegmentSwitchTrackingSelectAny)
|
||||
@@ -631,12 +749,15 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
{
|
||||
_trackingHighlighted = YES;
|
||||
_trackingSegment = [self testSegment:location];
|
||||
|
||||
|
||||
[self drawSegmentBezel:_trackingSegment highlight:YES];
|
||||
}
|
||||
|
||||
else if (type == CPLeftMouseDragged)
|
||||
{
|
||||
if (_trackingSegment == -1)
|
||||
return;
|
||||
|
||||
var highlighted = CGRectContainsPoint(_segments[_trackingSegment].frame, location);
|
||||
|
||||
if (highlighted != _trackingHighlighted)
|
||||
@@ -654,20 +775,150 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
{
|
||||
[super setFont:aFont];
|
||||
|
||||
var count = _segmentCount;
|
||||
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
while (count--)
|
||||
[_segments[count].labelView setFont:aFont];
|
||||
|
||||
[self tileWithChangedSegment:0];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var _CPSegmentMake = function()
|
||||
var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
|
||||
CPSegmentedControlSelectedKey = "CPSegmentedControlSelectedKey",
|
||||
CPSegmentedControlSegmentStyleKey = "CPSegmentedControlSegmentStyleKey",
|
||||
CPSegmentedControlTrackingModeKey = "CPSegmentedControlTrackingModeKey";
|
||||
|
||||
@implementation CPSegmentedControl (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
return { width:0, image:nil, label:@"", menu:nil, selected:NO, enabled:NO, tag:0, labelView:nil, imageView:nil, frame:CGRectMakeZero() }
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
var frame = [self frame],
|
||||
originalWidth = frame.size.width;
|
||||
|
||||
frame.size.width = 0;
|
||||
|
||||
[self setFrame:frame];
|
||||
|
||||
_segments = [aCoder decodeObjectForKey:CPSegmentedControlSegmentsKey];
|
||||
_segmentStyle = [aCoder decodeIntForKey:CPSegmentedControlSegmentStyleKey];
|
||||
_themeStates = [];
|
||||
|
||||
if ([aCoder containsValueForKey:CPSegmentedControlSelectedKey])
|
||||
_selectedSegment = [aCoder decodeIntForKey:CPSegmentedControlSelectedKey];
|
||||
else
|
||||
_selectedSegment = -1;
|
||||
|
||||
if ([aCoder containsValueForKey:CPSegmentedControlTrackingModeKey])
|
||||
_trackingMode = [aCoder decodeIntForKey:CPSegmentedControlTrackingModeKey];
|
||||
else
|
||||
_trackingMode = CPSegmentSwitchTrackingSelectOne;
|
||||
|
||||
// HACK
|
||||
|
||||
for (var i = 0; i < _segments.length; i++)
|
||||
{
|
||||
_themeStates[i] = _segments[i].selected ? CPThemeStateSelected : CPThemeStateNormal;
|
||||
[self tileWithChangedSegment:i];
|
||||
}
|
||||
|
||||
var difference = MAX(originalWidth - [self frame].size.width, 0.0),
|
||||
remainingWidth = FLOOR(difference / _segments.length);
|
||||
|
||||
for (var i=0; i < _segments.length; i++)
|
||||
[self setWidth:_segments[i].width + remainingWidth forSegment:i];
|
||||
|
||||
[self tileWithChangedSegment:0];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeObject:_segments forKey:CPSegmentedControlSegmentsKey];
|
||||
[aCoder encodeInt:_selectedSegment forKey:CPSegmentedControlSelectedKey];
|
||||
[aCoder encodeInt:_segmentStyle forKey:CPSegmentedControlSegmentStyleKey];
|
||||
[aCoder encodeInt:_trackingMode forKey:CPSegmentedControlTrackingModeKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation _CPSegmentItem : CPObject
|
||||
{
|
||||
CPImage image;
|
||||
CPString label;
|
||||
CPMenu menu;
|
||||
BOOL selected;
|
||||
BOOL enabled;
|
||||
int tag;
|
||||
int width;
|
||||
|
||||
CGRect frame;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
image = nil;
|
||||
label = @"";
|
||||
menu = nil;
|
||||
selected = NO;
|
||||
enabled = NO;
|
||||
tag = 0;
|
||||
width = 0;
|
||||
|
||||
frame = CGRectMakeZero();
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPSegmentItemImageKey = "CPSegmentItemImageKey",
|
||||
CPSegmentItemLabelKey = "CPSegmentItemLabelKey",
|
||||
CPSegmentItemMenuKey = "CPSegmentItemMenuKey",
|
||||
CPSegmentItemSelectedKey = "CPSegmentItemSelectedKey",
|
||||
CPSegmentItemEnabledKey = "CPSegmentItemEnabledKey",
|
||||
CPSegmentItemTagKey = "CPSegmentItemTagKey",
|
||||
CPSegmentItemWidthKey = "CPSegmentItemWidthKey";
|
||||
|
||||
@implementation _CPSegmentItem (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
image = [aCoder decodeObjectForKey:CPSegmentItemImageKey];
|
||||
label = [aCoder decodeObjectForKey:CPSegmentItemLabelKey];
|
||||
menu = [aCoder decodeObjectForKey:CPSegmentItemMenuKey];
|
||||
selected = [aCoder decodeBoolForKey:CPSegmentItemSelectedKey];
|
||||
enabled = [aCoder decodeBoolForKey:CPSegmentItemEnabledKey];
|
||||
tag = [aCoder decodeIntForKey:CPSegmentItemTagKey];
|
||||
width = [aCoder decodeFloatForKey:CPSegmentItemWidthKey];
|
||||
|
||||
frame = CGRectMakeZero();
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeObject:image forKey:CPSegmentItemImageKey];
|
||||
[aCoder encodeObject:label forKey:CPSegmentItemLabelKey];
|
||||
[aCoder encodeObject:menu forKey:CPSegmentItemMenuKey];
|
||||
[aCoder encodeBool:selected forKey:CPSegmentItemSelectedKey];
|
||||
[aCoder encodeBool:enabled forKey:CPSegmentItemEnabledKey];
|
||||
[aCoder encodeInt:tag forKey:CPSegmentItemTagKey];
|
||||
[aCoder encodeFloat:width forKey:CPSegmentItemWidthKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
|
||||
/*! @class CPShadow
|
||||
/*!
|
||||
@deprecated
|
||||
@class CPShadow
|
||||
|
||||
Instances of this class contain the attributes of a drop shadow used in Cappuccino.
|
||||
*/
|
||||
|
||||
@@ -46,6 +46,10 @@ var LIGHT_LEFT_INSET = 3.0,
|
||||
HEAVY_TOP_INSET = 5.0,
|
||||
HEAVY_BOTTOM_INSET = 5.0;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
*/
|
||||
|
||||
@implementation CPShadowView : CPView
|
||||
{
|
||||
CPShadowWeight _weight;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2008, 280 North, Inc.
|
||||
* 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
|
||||
@@ -22,131 +22,364 @@
|
||||
|
||||
@import "CPControl.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
var CPSliderHorizontalKnobImage = nil,
|
||||
CPSliderHorizontalBarLeftImage = nil,
|
||||
CPSliderHorizontalBarRightImage = nil,
|
||||
CPSliderHorizontalBarCenterImage = nil;
|
||||
/*! SLIDER STATES */
|
||||
|
||||
/*! @class CPSlider
|
||||
CPLinearSlider = 0;
|
||||
CPCircularSlider = 1;
|
||||
|
||||
An CPSlider displays, and allows control of, some value in the application. It represents a continuous stream of values of type <code>float</code>, which can be retrieved by the method <code>floatValue</code> and set by the method <code>setFloatValue:</code>.
|
||||
/*!
|
||||
@ingroup appkit
|
||||
*/
|
||||
|
||||
@implementation CPSlider : CPControl
|
||||
{
|
||||
double _minValue;
|
||||
double _maxValue;
|
||||
double _altIncrementValue;
|
||||
BOOL _isVertical;
|
||||
|
||||
CPView _bar;
|
||||
CPView _knob;
|
||||
double _minValue;
|
||||
double _maxValue;
|
||||
double _altIncrementValue;
|
||||
|
||||
CPImageView _standardKnob;
|
||||
CPView _standardVerticalBar;
|
||||
CPView _standardHorizontalBar;
|
||||
BOOL _isVertical;
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
+ (void)initialize
|
||||
+ (CPString)themeClass
|
||||
{
|
||||
if (self != [CPSlider class])
|
||||
return;
|
||||
return "slider";
|
||||
}
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
CPSliderKnobImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:"CPSlider/CPSliderKnobRegular.png"] size:CPSizeMake(11.0, 11.0)],
|
||||
CPSliderKnobPushedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:"CPSlider/CPSliderKnobRegularPushed.png"] size:CPSizeMake(11.0, 11.0)],
|
||||
CPSliderHorizontalBarLeftImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:"CPSlider/CPSliderTrackHorizontalLeft.png"] size:CPSizeMake(2.0, 4.0)],
|
||||
CPSliderHorizontalBarRightImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:"CPSlider/CPSliderTrackHorizontalRight.png"] size:CPSizeMake(2.0, 4.0)],
|
||||
CPSliderHorizontalBarCenterImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:"CPSlider/CPSliderTrackHorizontalCenter.png"] size:CPSizeMake(1.0, 4.0)];
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[nil, _CGSizeMakeZero(), 0.0, nil]
|
||||
forKeys:[@"knob-color", @"knob-size", @"track-width", @"track-color"]];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_value = 50.0;
|
||||
_minValue = 0.0;
|
||||
_maxValue = 100.0;
|
||||
|
||||
_bar = [self bar];
|
||||
_knob = [self knob];
|
||||
_knobSize = [[self knobImage] size];
|
||||
_isVertical = [self isVertical];
|
||||
|
||||
[self setObjectValue:50.0];
|
||||
|
||||
[self setContinuous:YES];
|
||||
|
||||
[_knob setFrameOrigin:[self knobPosition]];
|
||||
|
||||
[self addSubview:_bar];
|
||||
[self addSubview:_knob];
|
||||
|
||||
[self _recalculateIsVertical];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setFrameSize:(CGSize)aSize
|
||||
|
||||
- (void)setMinValue:(float)aMinimumValue
|
||||
{
|
||||
if (aSize.height > 21.0)
|
||||
aSize.height = 21.0;
|
||||
if (_minValue === aMinimumValue)
|
||||
return;
|
||||
|
||||
if (_isVertical != [self isVertical])
|
||||
_minValue = aMinimumValue;
|
||||
|
||||
var doubleValue = [self doubleValue];
|
||||
|
||||
if (doubleValue < _minValue)
|
||||
[self setDoubleValue:_minValue];
|
||||
}
|
||||
|
||||
- (float)minValue
|
||||
{
|
||||
return _minValue;
|
||||
}
|
||||
|
||||
- (void)setMaxValue:(float)aMaximumValue
|
||||
{
|
||||
if (_maxValue === aMaximumValue)
|
||||
return;
|
||||
|
||||
_maxValue = aMaximumValue;
|
||||
|
||||
var doubleValue = [self doubleValue];
|
||||
|
||||
if (doubleValue > _maxValue)
|
||||
[self setDoubleValue:_maxValue];
|
||||
}
|
||||
|
||||
- (float)maxValue
|
||||
{
|
||||
return _maxValue;
|
||||
}
|
||||
|
||||
- (void)setObjectValue:(id)aValue
|
||||
{
|
||||
[super setObjectValue:MIN(MAX(aValue, _minValue), _maxValue)];
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)setSliderType:(CPSliderType)aSliderType
|
||||
{
|
||||
if (aSliderType === CPCircularSlider)
|
||||
[self setThemeState:CPThemeStateCircular];
|
||||
else
|
||||
[self unsetThemeState:CPThemeStateCircular];
|
||||
}
|
||||
|
||||
- (CPSliderType)sliderType
|
||||
{
|
||||
return [self hasThemeState:CPThemeStateCircular] ? CPCircularSlider : CPLinearSlider;
|
||||
}
|
||||
|
||||
- (CGRect)trackRectForBounds:(CGRect)bounds
|
||||
{
|
||||
if ([self hasThemeState:CPThemeStateCircular])
|
||||
{
|
||||
_isVertical = [self isVertical];
|
||||
|
||||
var bar = [self bar],
|
||||
knob = [self knob];
|
||||
|
||||
if (_bar != bar)
|
||||
[self replaceSubview:_bar = bar withView:_bar];
|
||||
|
||||
if (_knob != knob)
|
||||
var originalBounds = CGRectCreateCopy(bounds);
|
||||
|
||||
bounds.size.width = MIN(bounds.size.width, bounds.size.height);
|
||||
bounds.size.height = bounds.size.width;
|
||||
|
||||
if (bounds.size.width < originalBounds.size.width)
|
||||
bounds.origin.x += (originalBounds.size.width - bounds.size.width) / 2.0;
|
||||
else
|
||||
bounds.origin.y += (originalBounds.size.height - bounds.size.height) / 2.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
var trackWidth = [self currentValueForThemeAttribute:@"track-width"];
|
||||
|
||||
if (trackWidth <= 0)
|
||||
return _CGRectMakeZero();
|
||||
|
||||
if ([self isVertical])
|
||||
{
|
||||
[self replaceSubview:knob withView:_knob];
|
||||
|
||||
_knob = knob;
|
||||
[_knob setFrameOrigin:[self knobPosition]];
|
||||
bounds.origin.x = (_CGRectGetWidth(bounds) - trackWidth) / 2.0;
|
||||
bounds.size.width = trackWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
bounds.origin.y = (_CGRectGetHeight(bounds) - trackWidth) / 2.0;
|
||||
bounds.size.height = trackWidth;
|
||||
}
|
||||
}
|
||||
|
||||
[super setFrameSize:aSize];
|
||||
|
||||
[_knob setFrameOrigin:[self knobPosition]];
|
||||
return bounds;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the value by which the slider will be
|
||||
incremented if the user holds down the <code>ALT</code>s key.
|
||||
*/
|
||||
- (double)altIncrementValue
|
||||
- (CGRect)knobRectForBounds:(CGRect)bounds
|
||||
{
|
||||
var knobSize = [self currentValueForThemeAttribute:@"knob-size"];
|
||||
|
||||
if (knobSize.width <= 0 || knobSize.height <= 0)
|
||||
return _CGRectMakeZero();
|
||||
|
||||
var knobRect = _CGRectMake(0.0, 0.0, knobSize.width, knobSize.height),
|
||||
trackRect = [self trackRectForBounds:bounds];
|
||||
|
||||
// No track, do our best to approximate a place for this thing.
|
||||
if (!trackRect || _CGRectIsEmpty(trackRect))
|
||||
trackRect = bounds;
|
||||
|
||||
if ([self hasThemeState:CPThemeStateCircular])
|
||||
{
|
||||
var angle = 3*PI_2 - (1.0 - [self doubleValue] - _minValue) / (_maxValue - _minValue) * PI2,
|
||||
radius = CGRectGetWidth(trackRect) / 2.0 - 8.0;
|
||||
|
||||
knobRect.origin.x = radius * COS(angle) + CGRectGetMidX(trackRect) - 3.0;
|
||||
knobRect.origin.y = radius * SIN(angle) + CGRectGetMidY(trackRect) - 2.0;
|
||||
}
|
||||
else if ([self isVertical])
|
||||
{
|
||||
knobRect.origin.x = _CGRectGetMidX(trackRect) - knobSize.width / 2.0;
|
||||
knobRect.origin.y = (([self doubleValue] - _minValue) / (_maxValue - _minValue)) * (_CGRectGetHeight(trackRect) - knobSize.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
knobRect.origin.x = (([self doubleValue] - _minValue) / (_maxValue - _minValue)) * (_CGRectGetWidth(trackRect) - knobSize.width);
|
||||
knobRect.origin.y = _CGRectGetMidY(trackRect) - knobSize.height / 2.0;
|
||||
}
|
||||
|
||||
return knobRect;
|
||||
}
|
||||
|
||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
if (aName === "track-view")
|
||||
return [self trackRectForBounds:[self bounds]];
|
||||
|
||||
else if (aName === "knob-view")
|
||||
return [self knobRectForBounds:[self bounds]];
|
||||
|
||||
return [super rectForEphemeralSubviewNamed:aName];
|
||||
}
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
if (aName === "track-view" || aName === "knob-view")
|
||||
{
|
||||
var view = [[CPView alloc] init];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
return [super createEphemeralSubviewNamed:aName];
|
||||
}
|
||||
|
||||
- (void)setAltIncrementValue:(float)anAltIncrementValue
|
||||
{
|
||||
_altIncrementValue = anAltIncrementValue;
|
||||
}
|
||||
|
||||
- (float)altIncrementValue
|
||||
{
|
||||
return _altIncrementValue;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the value the slider will be incremented if the user holds the <code>ALT</code> key.
|
||||
*/
|
||||
- (void)setAltIncrementValue:(double)anIncrementValue
|
||||
- (void)setFrameSize:(CGSize)aSize
|
||||
{
|
||||
_altIncrementValue = anIncrementValue;
|
||||
[super setFrameSize:aSize];
|
||||
[self _recalculateIsVertical];
|
||||
}
|
||||
|
||||
- (void)_recalculateIsVertical
|
||||
{
|
||||
// Recalculate isVertical.
|
||||
var bounds = [self bounds],
|
||||
width = _CGRectGetWidth(bounds),
|
||||
height = _CGRectGetHeight(bounds);
|
||||
|
||||
_isVertical = width < height ? 1 : (width > height ? 0 : -1);
|
||||
|
||||
if (_isVertical === 1)
|
||||
[self setThemeState:CPThemeStateVertical];
|
||||
else if (_isVertical === 0)
|
||||
[self unsetThemeState:CPThemeStateVertical];
|
||||
}
|
||||
|
||||
- (int)isVertical
|
||||
{
|
||||
return _isVertical;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
var trackView = [self layoutEphemeralSubviewNamed:@"track-view"
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:@"knob-view"];
|
||||
|
||||
if (trackView)
|
||||
[trackView setBackgroundColor:[self currentValueForThemeAttribute:@"track-color"]];
|
||||
|
||||
var knobView = [self layoutEphemeralSubviewNamed:@"knob-view"
|
||||
positioned:CPWindowAbove
|
||||
relativeToEphemeralSubviewNamed:@"track-view"];
|
||||
|
||||
if (knobView)
|
||||
[knobView setBackgroundColor:[self currentValueForThemeAttribute:"knob-color"]];
|
||||
}
|
||||
|
||||
- (BOOL)tracksMouseOutsideOfFrame
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (float)_valueAtPoint:(CGPoint)aPoint
|
||||
{
|
||||
var bounds = [self bounds],
|
||||
knobRect = [self knobRectForBounds:bounds],
|
||||
trackRect = [self trackRectForBounds:bounds];
|
||||
|
||||
if ([self hasThemeState:CPThemeStateCircular])
|
||||
{
|
||||
var knobWidth = _CGRectGetWidth(knobRect);
|
||||
|
||||
trackRect.origin.x += knobWidth / 2;
|
||||
trackRect.size.width -= knobWidth;
|
||||
|
||||
var minValue = [self minValue],
|
||||
dx = aPoint.x - _CGRectGetMidX(trackRect),
|
||||
dy = aPoint.y - _CGRectGetMidY(trackRect);
|
||||
|
||||
return MAX(0.0, MIN(1.0, 1.0 - (3 * PI_2 - ATAN2(dy, dx)) % PI2 / PI2)) * ([self maxValue] - minValue) + minValue;
|
||||
}
|
||||
else if ([self isVertical])
|
||||
{
|
||||
var knobHeight = _CGRectGetHeight(knobRect);
|
||||
|
||||
trackRect.origin.y += knobHeight / 2;
|
||||
trackRect.size.height -= knobHeight;
|
||||
|
||||
var minValue = [self minValue];
|
||||
|
||||
return MAX(0.0, MIN(1.0, (aPoint.y - _CGRectGetMinY(trackRect)) / _CGRectGetHeight(trackRect))) * ([self maxValue] - minValue) + minValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
var knobWidth = _CGRectGetWidth(knobRect);
|
||||
|
||||
trackRect.origin.x += knobWidth / 2;
|
||||
trackRect.size.width -= knobWidth;
|
||||
|
||||
var minValue = [self minValue];
|
||||
|
||||
return MAX(0.0, MIN(1.0, (aPoint.x - _CGRectGetMinX(trackRect)) / _CGRectGetWidth(trackRect))) * ([self maxValue] - minValue) + minValue;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)startTrackingAt:(CGPoint)aPoint
|
||||
{
|
||||
var bounds = [self bounds],
|
||||
knobRect = [self knobRectForBounds:_CGRectMakeCopy(bounds)];
|
||||
|
||||
if (_CGRectContainsPoint(knobRect, aPoint))
|
||||
_dragOffset = _CGSizeMake(_CGRectGetMidX(knobRect) - aPoint.x, _CGRectGetMidY(knobRect) - aPoint.y);
|
||||
|
||||
else
|
||||
{
|
||||
var trackRect = [self trackRectForBounds:bounds];
|
||||
|
||||
if (trackRect && _CGRectContainsPoint(trackRect, aPoint))
|
||||
{
|
||||
_dragOffset = _CGSizeMakeZero();
|
||||
|
||||
[self setObjectValue:[self _valueAtPoint:aPoint]];
|
||||
}
|
||||
|
||||
else
|
||||
return NO;
|
||||
}
|
||||
|
||||
[self setHighlighted:YES];
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)continueTracking:(CGPoint)lastPoint at:(CGPoint)aPoint
|
||||
{
|
||||
[self setObjectValue:[self _valueAtPoint:_CGPointMake(aPoint.x + _dragOffset.width, aPoint.y + _dragOffset.height)]];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
|
||||
{
|
||||
[self setHighlighted:NO];
|
||||
|
||||
if ([_target respondsToSelector:@selector(sliderDidFinish:)])
|
||||
[_target sliderDidFinish:self];
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns whether the control can continuously send its action messages.
|
||||
@ignore
|
||||
shoudl we have _continuous?
|
||||
*/
|
||||
- (BOOL)isContinuous
|
||||
{
|
||||
return (_sendActionOn & CPLeftMouseDraggedMask) != 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets whether the cell can continuously send its action messages.
|
||||
*/
|
||||
- (void)setContinuous:(BOOL)flag
|
||||
{
|
||||
if (flag)
|
||||
@@ -155,300 +388,61 @@ var CPSliderHorizontalKnobImage = nil,
|
||||
_sendActionOn &= ~CPLeftMouseDraggedMask;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the thickness of the slider's knob. This value is in pixels,
|
||||
and is the size of the knob along the slider's track.
|
||||
*/
|
||||
- (float)knobThickness
|
||||
{
|
||||
return CPRectGetWidth([_knob frame]);
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
- (CPImage)leftTrackImage
|
||||
{
|
||||
return CPSliderHorizontalBarLeftImage;
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
- (CPImage)rightTrackImage
|
||||
{
|
||||
return CPSliderHorizontalBarRightImage;
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
- (CPImage)centerTrackImage
|
||||
{
|
||||
return CPSliderHorizontalBarCenterImage
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
- (CPImage)knobImage
|
||||
{
|
||||
return CPSliderKnobImage;
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
- (CPImage)pushedKnobImage
|
||||
{
|
||||
return CPSliderKnobPushedImage;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the slider's knob.
|
||||
*/
|
||||
- (CPView)knob
|
||||
{
|
||||
if (!_standardKnob)
|
||||
{
|
||||
var knobImage = [self knobImage],
|
||||
knobSize = [knobImage size];
|
||||
|
||||
_standardKnob = [[CPImageView alloc] initWithFrame:CPRectMake(0.0, 0.0, knobSize.width, knobSize.height)];
|
||||
|
||||
[_standardKnob setImage:knobImage];
|
||||
}
|
||||
|
||||
return _standardKnob;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the slider's bar.
|
||||
*/
|
||||
- (CPView)bar
|
||||
{
|
||||
// FIXME: veritcal.
|
||||
if ([self isVertical])
|
||||
return nil;
|
||||
else
|
||||
{
|
||||
if (!_standardHorizontalBar)
|
||||
{
|
||||
var frame = [self frame],
|
||||
barFrame = CPRectMake(0.0, 0.0, CPRectGetWidth(frame), 4.0);
|
||||
|
||||
_standardHorizontalBar = [[CPView alloc] initWithFrame:barFrame];
|
||||
|
||||
[_standardHorizontalBar setBackgroundColor:[CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
||||
[[self leftTrackImage], [self centerTrackImage], [self rightTrackImage]] isVertical:NO]]];
|
||||
|
||||
[_standardHorizontalBar setFrame:CPRectMake(0.0, (CPRectGetHeight(frame) - CPRectGetHeight(barFrame)) / 2.0, CPRectGetWidth(_isVertical ? barFrame : frame), CPRectGetHeight(_isVertical ? frame : barFrame))];
|
||||
[_standardHorizontalBar setAutoresizingMask:_isVertical ? CPViewHeightSizable : CPViewWidthSizable];
|
||||
}
|
||||
|
||||
return _standardHorizontalBar;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns <code>YES</code> if the slider is vertical.
|
||||
*/
|
||||
- (BOOL)isVertical
|
||||
{
|
||||
var frame = [self frame];
|
||||
|
||||
if (CPRectGetWidth(frame) == CPRectGetHeight(frame))
|
||||
return -1;
|
||||
|
||||
return CPRectGetWidth(frame) < CPRectGetHeight(frame);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the slider's maximum value
|
||||
*/
|
||||
- (double)maxValue
|
||||
{
|
||||
return _maxValue;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the slider's minimum value
|
||||
*/
|
||||
- (double)minValue
|
||||
{
|
||||
return _minValue;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the slider's maximum value
|
||||
@param aMaxValue the new maximum value
|
||||
*/
|
||||
- (void)setMaxValue:(double)aMaxValue
|
||||
{
|
||||
_maxValue = aMaxValue;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the slider's minimum value
|
||||
@param aMinValue the new minimum value
|
||||
*/
|
||||
- (void)setMinValue:(double)aMinValue
|
||||
{
|
||||
_minValue = aMinValue;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the slider's value
|
||||
@param aValue the new slider value
|
||||
@deprecated Use setFloatValue, setObjectValue, etc
|
||||
*/
|
||||
- (void)setValue:(double)aValue
|
||||
{
|
||||
[self setObjectValue:aValue];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the slider's value
|
||||
@deprecated Use floatValue, objectValue, etc
|
||||
*/
|
||||
- (double)value
|
||||
{
|
||||
return [self floatValue];
|
||||
}
|
||||
|
||||
- (void)setObjectValue:(id)anObject
|
||||
{
|
||||
[super setObjectValue:anObject];
|
||||
|
||||
if (_knob)
|
||||
[_knob setFrameOrigin:[self knobPosition]];
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the knob's position
|
||||
@ignore
|
||||
*/
|
||||
- (CGPoint)knobPosition
|
||||
{
|
||||
if ([self isVertical])
|
||||
return CPPointMake(0.0, 0.0);
|
||||
else
|
||||
return CPPointMake(
|
||||
(([self floatValue] - _minValue) / (_maxValue - _minValue)) * (CPRectGetWidth([self frame]) - CPRectGetWidth([_knob frame])),
|
||||
(CPRectGetHeight([self frame]) - CPRectGetHeight([_knob frame])) / 2.0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
- (float)valueForKnobPosition:(CGPoint)aPoint
|
||||
{
|
||||
if ([self isVertical])
|
||||
return 0.0;
|
||||
else
|
||||
return MAX(MIN((aPoint.x) * (_maxValue - _minValue) / ( CPRectGetWidth([self frame]) - CPRectGetWidth([_knob frame]) ) + _minValue, _maxValue), _minValue);
|
||||
}
|
||||
|
||||
- (CGPoint)constrainKnobPosition:(CGPoint)aPoint
|
||||
{
|
||||
//FIXME
|
||||
aPoint.x -= _knobSize.width / 2.0;
|
||||
return CPPointMake(MAX(MIN(CPRectGetWidth([self bounds]) - _knobSize.width, aPoint.x), 0.0), (CPRectGetHeight([self bounds]) - CPRectGetHeight([_knob frame])) / 2.0);
|
||||
}
|
||||
|
||||
- (void)mouseUp:(CPEvent)anEvent
|
||||
{
|
||||
[[self knob] setImage:[self knobImage]];
|
||||
|
||||
if ([_target respondsToSelector:@selector(sliderDidFinish:)])
|
||||
[_target sliderDidFinish:self];
|
||||
|
||||
if (_sendActionOn & CPLeftMouseUpMask)
|
||||
[self sendAction:_action to:_target];
|
||||
//[super mouseUp:anEvent];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
[_knob setFrameOrigin:[self constrainKnobPosition:[self convertPoint:[anEvent locationInWindow] fromView:nil]]];
|
||||
|
||||
[super setObjectValue:[self valueForKnobPosition:[_knob frame].origin]];
|
||||
|
||||
[[self knob] setImage:[self pushedKnobImage]];
|
||||
|
||||
if (_sendActionOn & CPLeftMouseDraggedMask)
|
||||
[self sendAction:_action to:_target];
|
||||
//[super mouseDown:anEvent];
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(CPEvent)anEvent
|
||||
{
|
||||
[_knob setFrameOrigin:[self constrainKnobPosition:[self convertPoint:[anEvent locationInWindow] fromView:nil]]];
|
||||
|
||||
[super setObjectValue:[self valueForKnobPosition:[_knob frame].origin]];
|
||||
|
||||
if (_sendActionOn & CPLeftMouseDraggedMask)
|
||||
[self sendAction:_action to:_target];
|
||||
//[super mouseDown:anEvent];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPSliderMinValueKey = "CPSliderMinValueKey",
|
||||
CPSliderMaxValueKey = "CPSliderMaxValueKey",
|
||||
CPSliderAltIncrValueKey = "CPSliderAltIncrValueKey",
|
||||
CPSliderIsVerticalKey = "CPSliderIsVerticalKey";
|
||||
var CPSliderMinValueKey = "CPSliderMinValueKey",
|
||||
CPSliderMaxValueKey = "CPSliderMaxValueKey",
|
||||
CPSliderAltIncrValueKey = "CPSliderAltIncrValueKey";
|
||||
|
||||
@implementation CPSlider (CPCoding)
|
||||
|
||||
/*!
|
||||
Initializes the slider from the data in a coder.
|
||||
@param aCoder the coder from which to read the data
|
||||
@return the initialized slider
|
||||
*/
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
_minValue = [aCoder decodeDoubleForKey:CPSliderMinValueKey];
|
||||
_maxValue = [aCoder decodeDoubleForKey:CPSliderMaxValueKey];
|
||||
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_minValue = [aCoder decodeDoubleForKey:CPSliderMinValueKey];
|
||||
_maxValue = [aCoder decodeDoubleForKey:CPSliderMaxValueKey];
|
||||
_altIncrementValue = [aCoder decodeDoubleForKey:CPSliderAltIncrValueKey];
|
||||
_isVertical = [aCoder decodeDoubleForKey:CPSliderIsVerticalKey];
|
||||
|
||||
_bar = [self bar];
|
||||
_knob = [self knob];
|
||||
_knobSize = [[self knobImage] size];
|
||||
_isVertical = [self isVertical];
|
||||
|
||||
[_knob setFrameOrigin:[self knobPosition]];
|
||||
|
||||
[self addSubview:_bar];
|
||||
[self addSubview:_knob];
|
||||
|
||||
[self setContinuous:YES];
|
||||
|
||||
[self _recalculateIsVertical];
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Writes out the slider's instance information to a coder.
|
||||
@param aCoder the coder to which to write the data
|
||||
*/
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
var subviews = _subviews;
|
||||
|
||||
_subviews = [];
|
||||
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
_subviews = subviews;
|
||||
|
||||
|
||||
[aCoder encodeDouble:_minValue forKey:CPSliderMinValueKey];
|
||||
[aCoder encodeDouble:_maxValue forKey:CPSliderMaxValueKey];
|
||||
[aCoder encodeDouble:_altIncrementValue forKey:CPSliderAltIncrValueKey];
|
||||
[aCoder encodeBool:_isVertical forKey:CPSliderIsVerticalKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPSlider (Deprecated)
|
||||
|
||||
- (id)value
|
||||
{
|
||||
CPLog.warn("[CPSlider value] is deprecated, use doubleValue or objectValue instead.");
|
||||
|
||||
return [self doubleValue];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue
|
||||
{
|
||||
CPLog.warn("[CPSlider setValue:] is deprecated, use setDoubleValue: or setObjectValue: instead.");
|
||||
|
||||
[self setObjectValue:aValue];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -68,12 +68,12 @@
|
||||
[_contentView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||
|
||||
_rgbLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 10, 100, 20)];
|
||||
[_rgbLabel setStringValue: "RGB"];
|
||||
[_rgbLabel setTextColor:[CPColor whiteColor]];
|
||||
[_rgbLabel setStringValue: "Red, Green, Blue"];
|
||||
[_rgbLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_redLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 35, 15, 20)];
|
||||
[_redLabel setStringValue: "R"];
|
||||
[_redLabel setTextColor:[CPColor whiteColor]];
|
||||
[_redLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_redSlider = [[CPSlider alloc] initWithFrame: CPRectMake(15, 35, aFrame.size.width - 70, 20)];
|
||||
[_redSlider setMaxValue: 1.0];
|
||||
@@ -138,8 +138,8 @@
|
||||
_redValue = document.createElement("input");
|
||||
_redValue.style.width = "40px";
|
||||
_redValue.style.backgroundColor = "transparent";
|
||||
_redValue.style.border = "1px solid white";
|
||||
_redValue.style.color = "white";
|
||||
_redValue.style.border = "1px solid black";
|
||||
_redValue.style.color = "black";
|
||||
_redValue.style.position = "absolute";
|
||||
_redValue.style.top = "0px";
|
||||
_redValue.style.left = "0px";
|
||||
@@ -150,7 +150,7 @@
|
||||
|
||||
_greenLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 58, 15, 20)];
|
||||
[_greenLabel setStringValue: "G"];
|
||||
[_greenLabel setTextColor:[CPColor whiteColor]];
|
||||
[_greenLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_greenSlider = [[CPSlider alloc] initWithFrame: CPRectMake(15, 58, aFrame.size.width - 70, 20)];
|
||||
[_greenSlider setMaxValue: 1.0];
|
||||
@@ -171,7 +171,7 @@
|
||||
|
||||
_blueLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 81, 15, 20)];
|
||||
[_blueLabel setStringValue: "B"];
|
||||
[_blueLabel setTextColor:[CPColor whiteColor]];
|
||||
[_blueLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_blueSlider = [[CPSlider alloc] initWithFrame: CPRectMake(15, 81, aFrame.size.width - 70, 20)];
|
||||
[_blueSlider setMaxValue: 1.0];
|
||||
@@ -190,13 +190,13 @@
|
||||
blueValue._DOMElement.appendChild(_blueValue);
|
||||
[_contentView addSubview: blueValue];
|
||||
|
||||
_hsbLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 120, 100, 20)];
|
||||
[_hsbLabel setStringValue: "HSB"];
|
||||
[_hsbLabel setTextColor:[CPColor whiteColor]];
|
||||
_hsbLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 120, 190, 20)];
|
||||
[_hsbLabel setStringValue: "Hue, Saturation, Brightness"];
|
||||
[_hsbLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_hueLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 145, 15, 20)];
|
||||
[_hueLabel setStringValue: "H"];
|
||||
[_hueLabel setTextColor:[CPColor whiteColor]];
|
||||
[_hueLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_hueSlider = [[CPSlider alloc] initWithFrame: CPRectMake(15, 145, aFrame.size.width - 70, 20)];
|
||||
[_hueSlider setMaxValue: 359.0];
|
||||
@@ -217,7 +217,7 @@
|
||||
|
||||
_saturationLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 168, 15, 20)];
|
||||
[_saturationLabel setStringValue: "S"];
|
||||
[_saturationLabel setTextColor:[CPColor whiteColor]];
|
||||
[_saturationLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_saturationSlider = [[CPSlider alloc] initWithFrame: CPRectMake(15, 168, aFrame.size.width - 70, 20)];
|
||||
[_saturationSlider setMaxValue: 100.0];
|
||||
@@ -238,7 +238,7 @@
|
||||
|
||||
_brightnessLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 191, 15, 20)];
|
||||
[_brightnessLabel setStringValue: "B"];
|
||||
[_brightnessLabel setTextColor:[CPColor whiteColor]];
|
||||
[_brightnessLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
_brightnessSlider = [[CPSlider alloc] initWithFrame: CPRectMake(15, 191, aFrame.size.width - 70, 20)];
|
||||
[_brightnessSlider setMaxValue: 100.0];
|
||||
@@ -257,15 +257,15 @@
|
||||
brightnessValue._DOMElement.appendChild(_brightnessValue);
|
||||
[_contentView addSubview: brightnessValue];
|
||||
|
||||
_hexLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 230, 100, 20)];
|
||||
_hexLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 230, 30, 20)];
|
||||
[_hexLabel setStringValue: "Hex"];
|
||||
[_hexLabel setTextColor:[CPColor whiteColor]];
|
||||
[_hexLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
//hex input box
|
||||
_hexValue = _redValue.cloneNode(false);
|
||||
_hexValue.style.top = "255px";
|
||||
_hexValue.style.top = "228px";
|
||||
_hexValue.style.width = "80px";
|
||||
_hexValue.style.left = "0px";
|
||||
_hexValue.style.left = "35px";
|
||||
_hexValue.onkeypress = function(aDOMEvent)
|
||||
{
|
||||
aDOMEvent = aDOMEvent || window.event;
|
||||
@@ -329,7 +329,9 @@
|
||||
|
||||
-(void)sliderChanged:(id)sender
|
||||
{
|
||||
var newColor;
|
||||
var newColor,
|
||||
colorPanel = [self colorPanel],
|
||||
alpha = [colorPanel opacity];
|
||||
|
||||
switch(sender)
|
||||
{
|
||||
@@ -337,7 +339,8 @@
|
||||
case _saturationSlider:
|
||||
case _brightnessSlider: newColor = [CPColor colorWithHue: [_hueSlider floatValue]
|
||||
saturation: [_saturationSlider floatValue]
|
||||
brightness: [_brightnessSlider floatValue]];
|
||||
brightness: [_brightnessSlider floatValue]
|
||||
alpha: alpha];
|
||||
|
||||
[self updateRGBSliders: newColor];
|
||||
break;
|
||||
@@ -347,7 +350,7 @@
|
||||
case _blueSlider: newColor = [CPColor colorWithCalibratedRed: [_redSlider floatValue]
|
||||
green: [_greenSlider floatValue]
|
||||
blue: [_blueSlider floatValue]
|
||||
alpha: 1.0];
|
||||
alpha: alpha];
|
||||
|
||||
[self updateHSBSliders: newColor];
|
||||
break;
|
||||
@@ -355,7 +358,7 @@
|
||||
|
||||
[self updateLabels];
|
||||
[self updateHex: newColor];
|
||||
[[self colorPanel] setColor: newColor];
|
||||
[colorPanel setColor: newColor];
|
||||
}
|
||||
|
||||
-(void)setColor:(CPColor)aColor
|
||||
|
||||
@@ -34,6 +34,10 @@ CPSplitViewWillResizeSubviewsNotification = @"CPSplitViewWillResizeSubviewsNotif
|
||||
var CPSplitViewHorizontalImage = nil,
|
||||
CPSplitViewVerticalImage = nil;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
*/
|
||||
|
||||
@implementation CPSplitView : CPView
|
||||
{
|
||||
id _delegate;
|
||||
@@ -190,9 +194,11 @@ var CPSplitViewHorizontalImage = nil,
|
||||
{
|
||||
var count = [_subviews count] - 1;
|
||||
|
||||
if (count > 0)
|
||||
while (count--)
|
||||
[self drawDividerInRect:[self rectOfDividerAtIndex:count]];
|
||||
while ((count--) > 0)
|
||||
{
|
||||
_drawingDivider = count;
|
||||
[self drawDividerInRect:[self rectOfDividerAtIndex:count]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)drawDividerInRect:(CGRect)aRect
|
||||
@@ -367,6 +373,7 @@ var CPSplitViewHorizontalImage = nil,
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
// FIXME: This should not trap events if not on a divider!
|
||||
[self trackDivider:anEvent];
|
||||
}
|
||||
|
||||
@@ -382,10 +389,12 @@ var CPSplitViewHorizontalImage = nil,
|
||||
|
||||
- (float)minPossiblePositionOfDividerAtIndex:(int)dividerIndex
|
||||
{
|
||||
var frame = [_subviews[dividerIndex - 1] frame];
|
||||
|
||||
if (dividerIndex > 0)
|
||||
{
|
||||
var frame = [_subviews[dividerIndex - 1] frame];
|
||||
|
||||
return frame.origin[_originComponent] + frame.size[_sizeComponent] + [self dividerThickness];
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
@@ -412,7 +421,7 @@ var CPSplitViewHorizontalImage = nil,
|
||||
var frame = [self frame],
|
||||
viewA = _subviews[dividerIndex],
|
||||
frameA = [viewA frame],
|
||||
viewB = _subviews[dividerIndex+1],
|
||||
viewB = _subviews[dividerIndex + 1],
|
||||
frameB = [viewB frame];
|
||||
|
||||
var realPosition = MAX(MIN(position, actualMax), actualMin);
|
||||
@@ -454,20 +463,56 @@ var CPSplitViewHorizontalImage = nil,
|
||||
var index = 0,
|
||||
count = [_subviews count],
|
||||
bounds = [self bounds],
|
||||
dividerThickness = [self dividerThickness];
|
||||
|
||||
for (; index < count; ++index)
|
||||
dividerThickness = [self dividerThickness],
|
||||
totalDividers = count - 1,
|
||||
totalSizableSpace = 0,
|
||||
nonSizableSpace = 0,
|
||||
lastSizableIndex = -1,
|
||||
totalSizablePanes = 0,
|
||||
isVertical = [self isVertical];
|
||||
|
||||
for (index = 0; index < count; ++index)
|
||||
{
|
||||
var view = _subviews[index],
|
||||
viewFrame = CGRectMakeCopy(bounds);
|
||||
|
||||
if (index + 1 == count)
|
||||
viewFrame.size[_sizeComponent] = bounds.size[_sizeComponent] - viewFrame.origin[_originComponent];
|
||||
else
|
||||
viewFrame.size[_sizeComponent] = bounds.size[_sizeComponent] * ([view frame].size[_sizeComponent] / oldSize[_sizeComponent]);
|
||||
|
||||
bounds.origin[_originComponent] += viewFrame.size[_sizeComponent] + dividerThickness;
|
||||
|
||||
isSizable = isVertical ? [view autoresizingMask] & CPViewWidthSizable : [view autoresizingMask] & CPViewHeightSizable;
|
||||
|
||||
if (isSizable)
|
||||
{
|
||||
totalSizableSpace += [view frame].size[_sizeComponent];
|
||||
lastSizableIndex = index;
|
||||
totalSizablePanes++;
|
||||
}
|
||||
}
|
||||
|
||||
if (totalSizablePanes === count)
|
||||
totalSizableSpace = 0;
|
||||
|
||||
var nonSizableSpace = totalSizableSpace ? bounds.size[_sizeComponent] - totalSizableSpace : 0,
|
||||
ratio = (bounds.size[_sizeComponent] - totalDividers*dividerThickness - nonSizableSpace) / (oldSize[_sizeComponent]- totalDividers*dividerThickness - nonSizableSpace),
|
||||
remainingFlexibleSpace = bounds.size[_sizeComponent] - oldSize[_sizeComponent];
|
||||
|
||||
for (index = 0; index < count; ++index)
|
||||
{
|
||||
var view = _subviews[index],
|
||||
viewFrame = CGRectMakeCopy(bounds),
|
||||
isSizable = isVertical ? [view autoresizingMask] & CPViewWidthSizable : [view autoresizingMask] & CPViewHeightSizable;
|
||||
|
||||
if (index + 1 == count)
|
||||
viewFrame.size[_sizeComponent] = bounds.size[_sizeComponent] - viewFrame.origin[_originComponent];
|
||||
else if (totalSizableSpace && isSizable && lastSizableIndex === index)
|
||||
viewFrame.size[_sizeComponent] = MAX(0, ROUND([view frame].size[_sizeComponent] + remainingFlexibleSpace))
|
||||
else if (isSizable || !totalSizableSpace)
|
||||
{
|
||||
viewFrame.size[_sizeComponent] = MAX(0, ROUND(ratio * [view frame].size[_sizeComponent]));
|
||||
remainingFlexibleSpace -= (viewFrame.size[_sizeComponent] - [view frame].size[_sizeComponent]);
|
||||
}
|
||||
else if (totalSizableSpace && !isSizable)
|
||||
viewFrame.size[_sizeComponent] = [view frame].size[_sizeComponent];
|
||||
else
|
||||
alert("SHOULD NEVER GET HERE");
|
||||
|
||||
bounds.origin[_originComponent] += viewFrame.size[_sizeComponent] + dividerThickness;
|
||||
|
||||
[view setFrame:viewFrame];
|
||||
}
|
||||
|
||||
|
||||
@@ -22,8 +22,12 @@
|
||||
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
var CPStringReferenceElement = nil;
|
||||
|
||||
var CPStringReferenceElement = nil,
|
||||
CPStringDefaultFont = nil;
|
||||
|
||||
@implementation CPString (CPStringDrawing)
|
||||
|
||||
@@ -37,6 +41,12 @@ var CPStringReferenceElement = nil;
|
||||
|
||||
- (CGSize)sizeWithFont:(CPFont)aFont
|
||||
{
|
||||
return [self sizeWithFont:aFont inWidth:NULL];
|
||||
}
|
||||
|
||||
- (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
if (!CPStringReferenceElement)
|
||||
{
|
||||
CPStringReferenceElement = document.createElement("span");
|
||||
@@ -56,15 +66,55 @@ var CPStringReferenceElement = nil;
|
||||
|
||||
document.getElementsByTagName("body")[0].appendChild(CPStringReferenceElement);
|
||||
}
|
||||
|
||||
if (!aFont)
|
||||
{
|
||||
if (!CPStringDefaultFont)
|
||||
CPStringDefaultFont = [CPFont systemFontOfSize:12.0];
|
||||
|
||||
aFont = CPStringDefaultFont;
|
||||
}
|
||||
|
||||
var style = CPStringReferenceElement.style;
|
||||
|
||||
CPStringReferenceElement.style.font = [aFont ? aFont : [CPFont systemFontOfSize:12.0] cssString];
|
||||
if (aWidth === NULL)
|
||||
{
|
||||
style.width = "";
|
||||
style.whiteSpace = "pre";
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
style.width = ROUND(aWidth) + "px";
|
||||
|
||||
if (document.attachEvent)
|
||||
style.wordWrap = "break-word";
|
||||
|
||||
else
|
||||
{
|
||||
style.whiteSpace = "-o-pre-wrap";
|
||||
style.whiteSpace = "-pre-wrap";
|
||||
style.whiteSpace = "-moz-pre-wrap";
|
||||
style.whiteSpace = "pre-wrap";
|
||||
}
|
||||
}
|
||||
|
||||
style.font = [aFont cssString];
|
||||
|
||||
if (CPFeatureIsCompatible(CPJavascriptInnerTextFeature))
|
||||
CPStringReferenceElement.innerText = self;
|
||||
|
||||
else if (CPFeatureIsCompatible(CPJavascriptTextContentFeature))
|
||||
CPStringReferenceElement.textContent = self;
|
||||
|
||||
return CGSizeMake(CPStringReferenceElement.clientWidth, CPStringReferenceElement.clientHeight);
|
||||
return _CGSizeMake(CPStringReferenceElement.clientWidth, CPStringReferenceElement.clientHeight);
|
||||
#endif
|
||||
return _CGSizeMakeZero();
|
||||
}
|
||||
|
||||
+ (void)_resetSize
|
||||
{
|
||||
CPStringReferenceElement = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -69,7 +69,9 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
CPTabViewWillSelectTabViewItemSelector = 4,
|
||||
CPTabViewDidChangeNumberOfTabViewItemsSelector = 8;
|
||||
|
||||
/*! @class CPTabView
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPTabView
|
||||
|
||||
This class represents a view that has multiple subviews (CPTabViewItem) presented as individual tabs.
|
||||
Only one CPTabViewItem is shown at a time, and other CPTabViewItems can be made visible
|
||||
@@ -238,6 +240,9 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)insertTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(unsigned)anIndex
|
||||
{
|
||||
if (!_labelsView && _tabViewType == CPTopTabsBezelBorder)
|
||||
[self _createBezelBorder];
|
||||
|
||||
[_tabViewItems insertObject:aTabViewItem atIndex:anIndex];
|
||||
|
||||
[_labelsView tabView:self didAddTabViewItem:aTabViewItem];
|
||||
@@ -283,7 +288,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
count = [_tabViewItems count];
|
||||
|
||||
for (; index < count; ++index)
|
||||
if ([[_tabViewItems[index] identifier] isEqualTo:anIdentifier])
|
||||
if ([[_tabViewItems[index] identifier] isEqual:anIdentifier])
|
||||
return index;
|
||||
|
||||
return index;
|
||||
@@ -443,7 +448,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
if (_tabViewType == CPNoTabsBezelBorder || _tabViewType == CPNoTabsLineBorder || _tabViewType == CPNoTabsNoBorder)
|
||||
[_labelsView removeFromSuperview];
|
||||
else if (![_labelsView superview])
|
||||
[self addSubview:_lablesView];
|
||||
[self addSubview:_labelsView];
|
||||
|
||||
if (_tabViewType == CPNoTabsLineBorder || _tabViewType == CPNoTabsNoBorder)
|
||||
[_backgroundView removeFromSuperview];
|
||||
|
||||
@@ -44,7 +44,9 @@ CPBackgroundTab = 1;
|
||||
*/
|
||||
CPPressedTab = 2;
|
||||
|
||||
/*! @class CPTabView
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPTabViewItem
|
||||
|
||||
The class representation of an item in a CPTabView. One tab view item
|
||||
can be shown at a time in a CPTabView.
|
||||
@@ -182,8 +184,6 @@ var CPTabViewItemIdentifierKey = "CPTabViewItemIdentifierKey",
|
||||
|
||||
_view = [aCoder decodeObjectForKey:CPTabViewItemViewKey];
|
||||
_auxiliaryView = [aCoder decodeObjectForKey:CPTabViewItemAuxViewKey];
|
||||
|
||||
CPLog.warn("_identifier="+_identifier+" _label="+_label+" _view="+_view+" _auxiliaryView="+_auxiliaryView);
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
@@ -43,7 +43,13 @@ CPTableColumnAutoresizingMask = 1;
|
||||
*/
|
||||
CPTableColumnUserResizingMask = 2;
|
||||
|
||||
/*! @class CPTableColumn
|
||||
#define PurgableInfoMake(aView, aRow) { view:(aView), row:(aRow) }
|
||||
#define PurgableInfoView(anInfo) ((anInfo).view)
|
||||
#define PurgableInfoRow(anInfo) ((anInfo).row)
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPTableColumn
|
||||
|
||||
An CPTableColumn object mainly keeps information about the width of the column, its minimum and maximum width; whether the column can be edited or resized; and the cells used to draw the column header and the data in the column. You can change all these attributes of the column by calling the appropriate methods. Please note that the table column does not hold nor has access to the data to be displayed in the column; this data is maintained in the table view's data source.</p>
|
||||
|
||||
@@ -54,6 +60,7 @@ CPTableColumnUserResizingMask = 2;
|
||||
@implementation CPTableColumn : CPObject
|
||||
{
|
||||
CPString _identifier;
|
||||
CPView _headerView;
|
||||
|
||||
CPTableView _tableView;
|
||||
|
||||
@@ -62,6 +69,12 @@ CPTableColumnUserResizingMask = 2;
|
||||
float _maxWidth;
|
||||
|
||||
unsigned _resizingMask;
|
||||
|
||||
CPView _dataView; // default data view for this column
|
||||
|
||||
Object _dataViewData; // cache of data view archives (key=data view hash, value=data view archive)
|
||||
Object _dataViewForView; // mapping from view instances back to their data view prototype (key=view instance hash, value=data view)
|
||||
Object _purgableInfosForDataView; // (key=data view hash, value=)
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -75,19 +88,33 @@ CPTableColumnUserResizingMask = 2;
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self _init];
|
||||
|
||||
_identifier = anIdentifier;
|
||||
|
||||
_width = 40.0;
|
||||
_minWidth = 8.0;
|
||||
_maxWidth = 1000.0;
|
||||
|
||||
// FIXME
|
||||
_dataCell = [[CPTextField alloc] initWithFrame:CPRectMakeZero()];
|
||||
var dataView = [[CPTextField alloc] initWithFrame:CPRectMakeZero()];
|
||||
[dataView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateHighlighted];
|
||||
|
||||
[self setDataView:dataView];
|
||||
|
||||
_headerView = [[CPTextField alloc] initWithFrame:CPRectMakeZero()];
|
||||
[_headerView setBackgroundColor:[CPColor greenColor]];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_dataViewData = {};
|
||||
_dataViewForView = {};
|
||||
_purgableInfosForDataView = {};
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the table column's identifier
|
||||
@param anIdentifier the new identifier
|
||||
@@ -229,13 +256,16 @@ CPTableColumnUserResizingMask;
|
||||
return _isEditable;
|
||||
}
|
||||
|
||||
//Setting the column header view
|
||||
|
||||
/*!
|
||||
Sets the view that draws the column's header.
|
||||
@param aHeaderView the view that will draws the column header
|
||||
*/
|
||||
- (void)setHeaderView:(CPView)aHeaderView
|
||||
|
||||
- (void)setHeaderView:(CPView)aView
|
||||
{
|
||||
_headerView = aHeaderView;
|
||||
_headerView = aView;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -249,9 +279,21 @@ CPTableColumnUserResizingMask;
|
||||
/*!
|
||||
Sets the data cell that draws rows in this column.
|
||||
*/
|
||||
- (void)setDataCell:(CPCell)aDataCell
|
||||
- (void)setDataCell:(CPView <CPCoding>)aView
|
||||
{
|
||||
_dataCell = aDataCell;
|
||||
[self setDataView:aView];
|
||||
}
|
||||
|
||||
/*
|
||||
Sets the data view that draws rows in this column.
|
||||
*/
|
||||
- (void)setDataView:(CPView <CPCoding>)aView
|
||||
{
|
||||
if (_dataView)
|
||||
_dataViewData[[_dataView hash]] = nil;
|
||||
|
||||
_dataView = aView;
|
||||
_dataViewData[[aView hash]] = [CPKeyedArchiver archivedDataWithRootObject:aView];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -259,7 +301,15 @@ CPTableColumnUserResizingMask;
|
||||
*/
|
||||
- (CPCell)dataCell
|
||||
{
|
||||
return _dataCell;
|
||||
return _dataView;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the data view that draws rows in this column
|
||||
*/
|
||||
- (CPView)dataView
|
||||
{
|
||||
return [self dataCell];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -270,7 +320,152 @@ CPTableColumnUserResizingMask;
|
||||
*/
|
||||
- (CPCell)dataCellForRow:(int)aRowIndex
|
||||
{
|
||||
return [self dataCell];
|
||||
return [self dataView];
|
||||
}
|
||||
|
||||
- (CPView)dataViewForRow:(int)aRowIndex
|
||||
{
|
||||
return [self dataCellForRow:aRowIndex];
|
||||
}
|
||||
/*
|
||||
- (void)_markViewAsPurgable:(CPView)aView
|
||||
{
|
||||
var viewHash = [aView hash],
|
||||
dataViewHash = [_dataViewForView[viewHash] hash];
|
||||
|
||||
if (!_purgableInfosForDataView[dataViewHash])
|
||||
_purgableInfosForDataView[dataViewHash] = [CPDictionary dictionary];
|
||||
|
||||
[_purgableInfosForDataView[dataViewHash] setObject:aView forKey:viewHash];
|
||||
}
|
||||
*/
|
||||
- (void)_markView:(CPView)aView inRow:(unsigned)aRow asPurgable:(BOOL)isPurgable
|
||||
{
|
||||
var viewHash = [aView hash],
|
||||
dataViewHash = [_dataViewForView[viewHash] hash];
|
||||
|
||||
if (!_purgableInfosForDataView[dataViewHash])
|
||||
{
|
||||
if (!isPurgable)
|
||||
return;
|
||||
|
||||
_purgableInfosForDataView[dataViewHash] = {};
|
||||
}
|
||||
|
||||
if (!isPurgable) {
|
||||
if (_purgableInfosForDataView[dataViewHash][viewHash])
|
||||
CPLog.warn("removing unpurgable " + _purgableInfosForDataView[dataViewHash][viewHash]);
|
||||
delete _purgableInfosForDataView[dataViewHash][viewHash];
|
||||
}
|
||||
else
|
||||
_purgableInfosForDataView[dataViewHash][viewHash] = PurgableInfoMake(aView, aRow);
|
||||
}
|
||||
|
||||
- (CPView)_newDataViewForRow:(int)aRowIndex avoidingRows:(CPRange)rows
|
||||
{
|
||||
var view = [self dataViewForRow:aRowIndex],
|
||||
viewHash = [view hash],
|
||||
purgableInfos = _purgableInfosForDataView[viewHash];
|
||||
|
||||
if (purgableInfos)
|
||||
{
|
||||
for (var key in purgableInfos)
|
||||
{
|
||||
var info = purgableInfos[key];
|
||||
//if (!CPLocationInRange(PurgableInfoRow(info), rows))
|
||||
//{
|
||||
//CPLog.debug("yes, a purged view is usable, its called: " + PurgableInfoView(info));
|
||||
delete purgableInfos[key];
|
||||
return PurgableInfoView(info);
|
||||
//}
|
||||
//else
|
||||
// CPLog.warn("avoiding");
|
||||
}
|
||||
}
|
||||
|
||||
// if we haven't cached an archive of the data view, do it now
|
||||
if (!_dataViewData[viewHash])
|
||||
_dataViewData[viewHash] = [CPKeyedArchiver archivedDataWithRootObject:view];
|
||||
|
||||
// unarchive the data view cache
|
||||
var newView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[viewHash]];
|
||||
|
||||
// map the new view's hash to it's data view prototype
|
||||
_dataViewForView[[newView hash]] = view;
|
||||
|
||||
CPLog.warn("creating cell: %s", newView);
|
||||
|
||||
return newView;
|
||||
}
|
||||
|
||||
- (void)_purge
|
||||
{
|
||||
for (var viewHash in _purgableInfosForDataView)
|
||||
{
|
||||
var purgableInfos = _purgableInfosForDataView[viewHash];
|
||||
|
||||
for (var key in purgableInfos)
|
||||
{
|
||||
var view = PurgableInfoView(purgableInfos[key]);
|
||||
|
||||
if (!view)
|
||||
CPLog.info("key="+key+" view=" + view + " purgableInfos[key]="+purgableInfos[key])
|
||||
else if (view._superview) {
|
||||
//CPLog.error("PURGING: (removing)" + view);
|
||||
//[view removeFromSuperview];
|
||||
[view setHidden:YES];
|
||||
}
|
||||
//else
|
||||
// CPLog.warn("PURGING: (already removed)" + view);
|
||||
|
||||
//delete purgableInfos[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
||||
CPTableColumnHeaderViewKey = @"CPTableColumnHeaderViewKey",
|
||||
CPTableColumnDataViewKey = @"CPTableColumnDataViewKey",
|
||||
CPTableColumnWidthKey = @"CPTableColumnWidthKey",
|
||||
CPTableColumnMinWidthKey = @"CPTableColumnMinWidthKey",
|
||||
CPTableColumnMaxWidthKey = @"CPTableColumnMaxWidthKey",
|
||||
CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey";
|
||||
|
||||
@implementation CPTableColumn (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[self _init];
|
||||
|
||||
_identifier = [aCoder decodeObjectForKey:CPTableColumnIdentifierKey];
|
||||
|
||||
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
|
||||
[self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
|
||||
|
||||
_width = [aCoder decodeFloatForKey:CPTableColumnWidthKey];
|
||||
_minWidth = [aCoder decodeFloatForKey:CPTableColumnMinWidthKey];
|
||||
_maxWidth = [aCoder decodeFloatForKey:CPTableColumnMaxWidthKey];
|
||||
|
||||
_resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeObject:_identifier forKey:CPTableColumnIdentifierKey];
|
||||
|
||||
[aCoder encodeObject:_headerView forKey:CPTableColumnHeaderViewKey];
|
||||
[aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
|
||||
|
||||
[aCoder encodeObject:_width forKey:CPTableColumnWidthKey];
|
||||
[aCoder encodeObject:_minWidth forKey:CPTableColumnMinWidthKey];
|
||||
[aCoder encodeObject:_maxWidth forKey:CPTableColumnMaxWidthKey];
|
||||
|
||||
[aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,557 @@
|
||||
/*
|
||||
* CPTheme.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2009, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
|
||||
var CPThemesByName = { },
|
||||
CPThemeDefaultTheme = nil;
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
*/
|
||||
|
||||
@implementation CPTheme : CPObject
|
||||
{
|
||||
CPString _name;
|
||||
CPDictionary _attributes;
|
||||
}
|
||||
|
||||
+ (void)setDefaultTheme:(CPTheme)aTheme
|
||||
{
|
||||
CPThemeDefaultTheme = aTheme;
|
||||
}
|
||||
|
||||
+ (CPTheme)defaultTheme
|
||||
{
|
||||
return CPThemeDefaultTheme;
|
||||
}
|
||||
|
||||
+ (CPTheme)themeNamed:(CPString)aName
|
||||
{
|
||||
return CPThemesByName[aName];
|
||||
}
|
||||
|
||||
- (id)initWithName:(CPString)aName
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_name = aName;
|
||||
_attributes = [CPDictionary dictionary];
|
||||
|
||||
CPThemesByName[_name] = self;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPString)name
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
- (_CPThemeAttribute)_attributeWithName:(CPString)aName forClass:(CPString)aClass
|
||||
{
|
||||
var attributes = [_attributes objectForKey:aClass];
|
||||
|
||||
if (!attributes)
|
||||
return nil;
|
||||
|
||||
return [attributes objectForKey:aName];
|
||||
}
|
||||
|
||||
- (void)takeThemeFromObject:(id)anObject
|
||||
{
|
||||
var attributes = [anObject _themeAttributeDictionary],
|
||||
attributeName = nil,
|
||||
attributeNames = [attributes keyEnumerator],
|
||||
objectThemeClass = [[anObject class] themeClass];
|
||||
|
||||
while (attributeName = [attributeNames nextObject])
|
||||
[self _recordAttribute:[attributes objectForKey:attributeName] forClass:objectThemeClass];
|
||||
}
|
||||
|
||||
- (void)_recordAttribute:(_CPThemeAttribute)anAttribute forClass:(CPString)aClass
|
||||
{
|
||||
if (![anAttribute hasValues])
|
||||
return;
|
||||
|
||||
var attributes = [_attributes objectForKey:aClass];
|
||||
|
||||
if (!attributes)
|
||||
{
|
||||
attributes = [CPDictionary dictionary];
|
||||
|
||||
[_attributes setObject:attributes forKey:aClass];
|
||||
}
|
||||
|
||||
var name = [anAttribute name],
|
||||
existingAttribute = [attributes objectForKey:name];
|
||||
|
||||
if (existingAttribute)
|
||||
[attributes setObject:[existingAttribute attributeMergedWithAttribute:anAttribute] forKey:name];
|
||||
else
|
||||
[attributes setObject:anAttribute forKey:name];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPThemeNameKey = @"CPThemeNameKey",
|
||||
CPThemeAttributesKey = @"CPThemeAttributesKey";
|
||||
|
||||
@implementation CPTheme (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_name = [aCoder decodeObjectForKey:CPThemeNameKey];
|
||||
_attributes = [aCoder decodeObjectForKey:CPThemeAttributesKey];
|
||||
|
||||
CPThemesByName[_name] = self;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeObject:_name forKey:CPThemeNameKey];
|
||||
[aCoder encodeObject:_attributes forKey:CPThemeAttributesKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPThemeKeyedUnarchiver : CPKeyedUnarchiver
|
||||
{
|
||||
CPBundle _bundle;
|
||||
}
|
||||
|
||||
- (id)initForReadingWithData:(CPData)data bundle:(CPBundle)aBundle
|
||||
{
|
||||
self = [super initForReadingWithData:data];
|
||||
|
||||
if (self)
|
||||
_bundle = aBundle;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPBundle)bundle
|
||||
{
|
||||
return _bundle;
|
||||
}
|
||||
|
||||
- (BOOL)awakenCustomResources
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPThemeStates = {},
|
||||
CPThemeStateNames = {},
|
||||
CPThemeStateCount = 0;
|
||||
|
||||
function CPThemeState(aStateName)
|
||||
{
|
||||
var state = CPThemeStates[aStateName];
|
||||
|
||||
if (state === undefined)
|
||||
{
|
||||
if (aStateName.indexOf('+') === -1)
|
||||
state = 1 << CPThemeStateCount++;
|
||||
else
|
||||
{
|
||||
var state = 0,
|
||||
states = aStateName.split('+'),
|
||||
count = states.length;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var stateName = states[count],
|
||||
individualState = CPThemeStates[stateName];
|
||||
|
||||
if (individualState === undefined)
|
||||
{
|
||||
individualState = 1 << CPThemeStateCount++;
|
||||
CPThemeStates[stateName] = individualState;
|
||||
CPThemeStateNames[individualState] = stateName;
|
||||
}
|
||||
|
||||
state |= individualState;
|
||||
}
|
||||
}
|
||||
|
||||
CPThemeStates[aStateName] = state;
|
||||
CPThemeStateNames[state] = aStateName;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
function CPThemeStateName(aState)
|
||||
{
|
||||
var name = CPThemeStateNames[aState];
|
||||
|
||||
if (name !== undefined)
|
||||
return name;
|
||||
|
||||
if (!(aState & (aState - 1)))
|
||||
return "";
|
||||
|
||||
var state = 1,
|
||||
name = "";
|
||||
|
||||
for (; state < aState; state <<= 1)
|
||||
if (aState & state)
|
||||
name += (name.length === 0 ? '' : '+') + CPThemeStateNames[state];
|
||||
|
||||
CPThemeStateNames[aState] = name;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
CPThemeStateNames[0] = "normal";
|
||||
CPThemeStateNormal = CPThemeStates["normal"] = 0;
|
||||
CPThemeStateDisabled = CPThemeState("disabled");
|
||||
CPThemeStateHighlighted = CPThemeState("highlighted");
|
||||
CPThemeStateSelected = CPThemeState("selected");
|
||||
CPThemeStateBezeled = CPThemeState("bezeled");
|
||||
CPThemeStateBordered = CPThemeState("bordered");
|
||||
CPThemeStateEditable = CPThemeState("editable");
|
||||
CPThemeStateEditing = CPThemeState("editing");
|
||||
CPThemeStateVertical = CPThemeState("vertical");
|
||||
CPThemeStateDefault = CPThemeState("default");
|
||||
CPThemeStateCircular = CPThemeState("circular");
|
||||
|
||||
@implementation _CPThemeAttribute : CPObject
|
||||
{
|
||||
CPString _name;
|
||||
id _defaultValue;
|
||||
CPDictionary _values;
|
||||
|
||||
JSObject _cache;
|
||||
CPThemeAttribute _parentAttribute;
|
||||
}
|
||||
|
||||
- (id)initWithName:(CPString)aName defaultValue:(id)aDefaultValue
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_cache = { };
|
||||
_name = aName;
|
||||
_defaultValue = aDefaultValue;
|
||||
_values = [CPDictionary dictionary];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPString)name
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
- (id)defaultValue
|
||||
{
|
||||
return _defaultValue;
|
||||
}
|
||||
|
||||
- (BOOL)hasValues
|
||||
{
|
||||
return [_values count] > 0;
|
||||
}
|
||||
|
||||
- (BOOL)isTrivial
|
||||
{
|
||||
return ([_values count] === 1) && (Number([_values allKeys][0]) === CPThemeStateNormal);
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue
|
||||
{
|
||||
_cache = {};
|
||||
|
||||
if (aValue === undefined || aValue === nil)
|
||||
_values = [CPDictionary dictionary];
|
||||
else
|
||||
_values = [CPDictionary dictionaryWithObject:aValue forKey:String(CPThemeStateNormal)];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forState:(CPThemeState)aState
|
||||
{
|
||||
_cache = { };
|
||||
|
||||
if ((aValue === undefined) || (aValue === nil))
|
||||
[_values removeObjectForKey:String(aState)];
|
||||
else
|
||||
[_values setObject:aValue forKey:String(aState)];
|
||||
}
|
||||
|
||||
- (id)value
|
||||
{
|
||||
return [self valueForState:CPThemeStateNormal];
|
||||
}
|
||||
|
||||
- (id)valueForState:(CPThemeState)aState
|
||||
{
|
||||
var value = _cache[aState];
|
||||
|
||||
// This can be nil.
|
||||
if (value !== undefined)
|
||||
return value;
|
||||
|
||||
value = [_values objectForKey:String(aState)];
|
||||
|
||||
// If we don't have a value, and we have a non-normal state...
|
||||
if ((value === undefined || value === nil) && aState !== CPThemeStateNormal)
|
||||
{
|
||||
// If this is a composite state (not a power of 2), find the closest partial subset match.
|
||||
if (aState & (aState - 1))
|
||||
{
|
||||
var highestOneCount = 0,
|
||||
states = [_values allKeys],
|
||||
count = states.length;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
// states[count] is a string!
|
||||
var state = Number(states[count]);
|
||||
|
||||
// A & B = A iff A < B
|
||||
if ((state & aState) === state)
|
||||
{
|
||||
var oneCount = cachedNumberOfOnes[state];
|
||||
|
||||
if (oneCount === undefined)
|
||||
oneCount = numberOfOnes(state);
|
||||
|
||||
if (oneCount > highestOneCount)
|
||||
{
|
||||
highestOneCount = oneCount;
|
||||
value = [_values objectForKey:String(state)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Still don't have a value? OK, let's use the normal value.
|
||||
if (value === undefined || value === nil)
|
||||
value = [_values objectForKey:String(CPThemeStateNormal)];
|
||||
}
|
||||
|
||||
if (value === undefined || value === nil)
|
||||
value = [_parentAttribute valueForState:aState];
|
||||
|
||||
if (value === undefined || value === nil)
|
||||
value = _defaultValue;
|
||||
|
||||
_cache[aState] = value;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
- (void)setParentAttribute:(CPThemeAttribute)anAttribute
|
||||
{
|
||||
if (_parentAttribute === anAttribute)
|
||||
return;
|
||||
|
||||
_cache = { };
|
||||
_parentAttribute = anAttribute;
|
||||
}
|
||||
|
||||
- (CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
|
||||
{
|
||||
var mergedAttribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue];
|
||||
|
||||
mergedAttribute._values = [_values copy];
|
||||
[mergedAttribute._values addEntriesFromDictionary:anAttribute._values];
|
||||
|
||||
return mergedAttribute;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPThemeAttribute (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_cache = {};
|
||||
|
||||
_name = [aCoder decodeObjectForKey:@"name"];
|
||||
_values = [CPDictionary dictionary];
|
||||
|
||||
if ([aCoder containsValueForKey:@"value"])
|
||||
{
|
||||
var state = CPThemeStateNormal;
|
||||
|
||||
if ([aCoder containsValueForKey:@"state"])
|
||||
state = CPThemeState([aCoder decodeObjectForKey:@"state"]);
|
||||
|
||||
[_values setObject:[aCoder decodeObjectForKey:"value"] forKey:state];
|
||||
}
|
||||
else
|
||||
{
|
||||
var encodedValues = [aCoder decodeObjectForKey:@"values"],
|
||||
keys = [encodedValues allKeys],
|
||||
count = keys.length;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var key = keys[count];
|
||||
|
||||
[_values setObject:[encodedValues objectForKey:key] forKey:CPThemeState(key)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeObject:_name forKey:@"name"];
|
||||
|
||||
var keys = [_values allKeys],
|
||||
count = keys.length;
|
||||
|
||||
if (count === 1)
|
||||
{
|
||||
var onlyKey = keys[0];
|
||||
|
||||
if (Number(onlyKey) !== CPThemeStateNormal)
|
||||
[aCoder encodeObject:CPThemeStateName(Number(onlyKey)) forKey:@"state"];
|
||||
|
||||
[aCoder encodeObject:[_values objectForKey:onlyKey] forKey:@"value"];
|
||||
}
|
||||
else
|
||||
{
|
||||
var encodedValues = [CPDictionary dictionary];
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var key = keys[count];
|
||||
|
||||
[encodedValues setObject:[_values objectForKey:key] forKey:CPThemeStateName(Number(key))];
|
||||
}
|
||||
|
||||
[aCoder encodeObject:encodedValues forKey:@"values"];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var cachedNumberOfOnes = [ 0 /*000000*/, 1 /*000001*/, 1 /*000010*/, 2 /*000011*/, 1 /*000100*/, 2 /*000101*/, 2 /*000110*/,
|
||||
3 /*000111*/, 1 /*001000*/, 2 /*001001*/, 2 /*001010*/, 3 /*001011*/, 2 /*001100*/, 3 /*001101*/,
|
||||
3 /*001110*/, 4 /*001111*/, 1 /*010000*/, 2 /*010001*/, 2 /*010010*/, 3 /*010011*/, 2 /*010100*/,
|
||||
3 /*010101*/, 3 /*010110*/, 4 /*010111*/, 2 /*011000*/, 3 /*011001*/, 3 /*011010*/, 4 /*011011*/,
|
||||
3 /*011100*/, 4 /*011101*/, 4 /*011110*/, 5 /*011111*/, 1 /*100000*/, 2 /*100001*/, 2 /*100010*/,
|
||||
3 /*100011*/, 2 /*100100*/, 3 /*100101*/, 3 /*100110*/, 4 /*100111*/, 2 /*101000*/, 3 /*101001*/,
|
||||
3 /*101010*/, 4 /*101011*/, 3 /*101100*/, 4 /*101101*/, 4 /*101110*/, 5 /*101111*/, 2 /*110000*/,
|
||||
3 /*110001*/, 3 /*110010*/, 4 /*110011*/, 3 /*110100*/, 4 /*110101*/, 4 /*110110*/, 5 /*110111*/,
|
||||
3 /*111000*/, 4 /*111001*/, 4 /*111010*/, 5 /*111011*/, 4 /*111100*/, 5 /*111101*/, 5 /*111110*/,
|
||||
6 /*111111*/ ];
|
||||
|
||||
var numberOfOnes = function(aNumber)
|
||||
{
|
||||
var count = 0,
|
||||
slot = aNumber;
|
||||
|
||||
while (aNumber)
|
||||
{
|
||||
++count;
|
||||
aNumber &= (aNumber - 1);
|
||||
}
|
||||
|
||||
cachedNumberOfOnes[slot] = count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
numberOfOnes.displayName = "numberOfOnes";
|
||||
|
||||
function CPThemeAttributeEncode(aCoder, aThemeAttribute)
|
||||
{
|
||||
var values = aThemeAttribute._values,
|
||||
count = [values count],
|
||||
key = "$a" + [aThemeAttribute name];
|
||||
|
||||
if (count === 1)
|
||||
{
|
||||
var state = [values allKeys][0];
|
||||
|
||||
if (Number(state) === 0)
|
||||
{
|
||||
[aCoder encodeObject:[values objectForKey:state] forKey:key];
|
||||
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
if (count >= 1)
|
||||
{
|
||||
[aCoder encodeObject:aThemeAttribute forKey:key];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
function CPThemeAttributeDecode(aCoder, anAttributeName, aDefaultValue, aTheme, aClass)
|
||||
{
|
||||
var key = "$a" + anAttributeName;
|
||||
|
||||
if (![aCoder containsValueForKey:key])
|
||||
var attribute = [[_CPThemeAttribute alloc] initWithName:anAttributeName defaultValue:aDefaultValue];
|
||||
|
||||
else
|
||||
{
|
||||
var attribute = [aCoder decodeObjectForKey:key];
|
||||
|
||||
if (!attribute.isa || ![attribute isKindOfClass:[_CPThemeAttribute class]])
|
||||
{
|
||||
var themeAttribute = [[_CPThemeAttribute alloc] initWithName:anAttributeName defaultValue:aDefaultValue];
|
||||
|
||||
[themeAttribute setValue:attribute];
|
||||
|
||||
attribute = themeAttribute;
|
||||
}
|
||||
}
|
||||
|
||||
if (aTheme && aClass)
|
||||
[attribute setParentAttribute:[aTheme _attributeWithName:anAttributeName forClass:aClass]];
|
||||
|
||||
return attribute;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* CPThemeBlend.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2009, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
@import <AppKit/CPTheme.j>
|
||||
@import <AppKit/_CPCibCustomResource.j>
|
||||
@import <AppKit/_CPCibKeyedUnarchiver.j>
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
*/
|
||||
|
||||
@implementation CPThemeBlend : CPObject
|
||||
{
|
||||
CPBundle _bundle;
|
||||
CPArray _themes @accessors(readonly, getter=themes);
|
||||
id _loadDelegate;
|
||||
}
|
||||
|
||||
- (id)initWithContentsOfURL:(CPURL)aURL
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_bundle = [[CPBundle alloc] initWithPath:aURL + "/Info.plist"];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)loadWithDelegate:(id)aDelegate
|
||||
{
|
||||
_loadDelegate = aDelegate;
|
||||
|
||||
[_bundle loadWithDelegate:self];
|
||||
}
|
||||
|
||||
- (void)bundleDidFinishLoading:(CPBundle)aBundle
|
||||
{
|
||||
var paths = [_bundle objectForInfoDictionaryKey:@"CPBundleReplacedFiles"],
|
||||
index = 0,
|
||||
count = paths.length,
|
||||
bundlePath = [_bundle bundlePath];
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var path = paths[count];
|
||||
|
||||
if ([path pathExtension] === "keyedtheme")
|
||||
{
|
||||
var unarchiver = [[_CPThemeKeyedUnarchiver alloc]
|
||||
initForReadingWithData:[CPData dataWithString:objj_files[bundlePath + '/' + path].contents]
|
||||
bundle:_bundle];
|
||||
|
||||
[unarchiver decodeObjectForKey:@"root"];
|
||||
|
||||
[unarchiver finishDecoding];
|
||||
}
|
||||
}
|
||||
|
||||
[_loadDelegate blendDidFinishLoading:self];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -54,6 +54,7 @@ var CPToolbarsByIdentifier = nil;
|
||||
var CPToolbarConfigurationsByIdentifier = nil;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPToolbar
|
||||
|
||||
A CPToolbar is displayed at the top of a window with multiple
|
||||
@@ -100,6 +101,7 @@ var CPToolbarConfigurationsByIdentifier = nil;
|
||||
CPArray _itemsSortedByVisibilityPriority;
|
||||
|
||||
CPView _toolbarView;
|
||||
CPWindow _window;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
@@ -187,13 +189,22 @@ var CPToolbarConfigurationsByIdentifier = nil;
|
||||
*/
|
||||
- (void)setVisible:(BOOL)aFlag
|
||||
{
|
||||
if (_isVisible == aFlag)
|
||||
if (_isVisible === aFlag)
|
||||
return;
|
||||
|
||||
|
||||
_isVisible = aFlag;
|
||||
|
||||
[_window _setToolbarVisible:_isVisible];
|
||||
[self _reloadToolbarItems];
|
||||
[_window _noteToolbarChanged];
|
||||
}
|
||||
|
||||
- (CPWindow)_window
|
||||
{
|
||||
return _window;
|
||||
}
|
||||
|
||||
- (void)_setWindow:(CPWindow)aWindow
|
||||
{
|
||||
_window = aWindow;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -222,9 +233,10 @@ var CPToolbarConfigurationsByIdentifier = nil;
|
||||
if (!_toolbarView)
|
||||
{
|
||||
_toolbarView = [[_CPToolbarView alloc] initWithFrame:CPRectMake(0.0, 0.0, 1200.0, 59.0)];
|
||||
[_toolbarView setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
|
||||
[_toolbarView setToolbar:self];
|
||||
[_toolbarView setAutoresizingMask:CPViewWidthSizable];
|
||||
[_toolbarView reloadToolbarItems];
|
||||
}
|
||||
|
||||
return _toolbarView;
|
||||
@@ -233,9 +245,9 @@ var CPToolbarConfigurationsByIdentifier = nil;
|
||||
/* @ignore */
|
||||
- (void)_reloadToolbarItems
|
||||
{
|
||||
if (![_toolbarView superview] || !_delegate)
|
||||
if (!_delegate)
|
||||
return;
|
||||
|
||||
|
||||
var count = [_itemIdentifiers count];
|
||||
|
||||
if (!count)
|
||||
@@ -243,8 +255,6 @@ var CPToolbarConfigurationsByIdentifier = nil;
|
||||
_itemIdentifiers = [[_delegate toolbarDefaultItemIdentifiers:self] mutableCopy];
|
||||
count = [_itemIdentifiers count];
|
||||
}
|
||||
|
||||
[[_toolbarView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||
|
||||
_items = [];
|
||||
|
||||
@@ -256,8 +266,10 @@ var CPToolbarConfigurationsByIdentifier = nil;
|
||||
item = [CPToolbarItem _standardItemWithItemIdentifier:identifier];
|
||||
|
||||
if (!item)
|
||||
item = [[_delegate toolbar:self itemForItemIdentifier:identifier willBeInsertedIntoToolbar:YES] copy];
|
||||
|
||||
item = [_delegate toolbar:self itemForItemIdentifier:identifier willBeInsertedIntoToolbar:YES];
|
||||
|
||||
item = [item copy];
|
||||
|
||||
if (item == nil)
|
||||
[CPException raise:CPInvalidArgumentException
|
||||
reason:sprintf(@"_delegate %s returned nil toolbar item returned for identifier %s", _delegate, identifier)];
|
||||
@@ -436,6 +448,10 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
CPArray _invisibleItems;
|
||||
|
||||
CPPopUpButton _additionalItemsButton;
|
||||
CPColor _labelColor;
|
||||
CPColor _labelShadowColor;
|
||||
|
||||
float _minWidth;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
@@ -445,8 +461,6 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
_CPToolbarViewBackgroundColor = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPToolbarView/_CPToolbarViewBackground.png"] size:CGSizeMake(1.0, 59.0)]];
|
||||
|
||||
_CPToolbarViewExtraItemsImage = [[CPImage alloc] initWithContentsOfFile: [bundle pathForResource:"_CPToolbarView/_CPToolbarViewExtraItemsImage.png"] size: CPSizeMake(10.0, 15.0)];
|
||||
|
||||
_CPToolbarViewExtraItemsAlternateImage = [[CPImage alloc] initWithContentsOfFile: [bundle pathForResource:"_CPToolbarView/_CPToolbarViewExtraItemsAlternateImage.png"] size:CGSizeMake(10.0, 15.0)];
|
||||
@@ -460,7 +474,8 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
{
|
||||
_minWidth = 0;
|
||||
|
||||
[self setBackgroundColor:_CPToolbarViewBackgroundColor];
|
||||
_labelColor = [CPColor blackColor];
|
||||
_labelShadowColor = [CPColor colorWithWhite:1.0 alpha:0.75];
|
||||
|
||||
_additionalItemsButton = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 15.0) pullsDown:YES];
|
||||
[_additionalItemsButton setBordered:NO];
|
||||
@@ -484,6 +499,34 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
return _toolbar;
|
||||
}
|
||||
|
||||
- (void)setLabelColor:(CPColor)aColor
|
||||
{
|
||||
if (_labelColor === aColor)
|
||||
return;
|
||||
|
||||
_labelColor = aColor;
|
||||
|
||||
var items = [_toolbar items],
|
||||
count = [items count];
|
||||
|
||||
while (count--)
|
||||
[[self labelForItem:items[count]] setTextColor:_labelColor];
|
||||
}
|
||||
|
||||
- (void)setLabelShadowColor:(CPColor)aColor
|
||||
{
|
||||
if (_labelShadowColor === aColor)
|
||||
return;
|
||||
|
||||
_labelShadowColor = aColor;
|
||||
|
||||
var items = [_toolbar items],
|
||||
count = [items count];
|
||||
|
||||
while (count--)
|
||||
[[self labelForItem:items[count]] setTextShadowColor:_labelShadowColor];
|
||||
}
|
||||
|
||||
// This *should* be roughly O(3N) = O(N)
|
||||
- (void)resizeSubviewsWithOldSize:(CGSize)aSize
|
||||
{
|
||||
@@ -527,7 +570,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
[[self labelForItem:item] setHidden:YES];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Determine all the items that have flexible width.
|
||||
// Also determine the height of the toolbar.
|
||||
// NOTE: height is height without top margin, and bottom margin/label.
|
||||
@@ -717,8 +760,8 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
count = subviews.length;
|
||||
|
||||
while (count--)
|
||||
[subviews removeObjectAtIndex:count];
|
||||
|
||||
[subviews[count] removeFromSuperview];
|
||||
|
||||
// Populate with new subviews.
|
||||
var items = [_toolbar items],
|
||||
index = 0;
|
||||
@@ -745,10 +788,12 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
|
||||
[view setTarget:[item target]];
|
||||
[view setAction:[item action]];
|
||||
|
||||
[view setTag:[item tag]];
|
||||
|
||||
[view setImagePosition:CPImageOnly];
|
||||
}
|
||||
|
||||
|
||||
[self addSubview:view];
|
||||
|
||||
// Create a lable for this item.
|
||||
@@ -756,6 +801,9 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
|
||||
[label setStringValue:[item label]];
|
||||
[label setFont:[CPFont systemFontOfSize:11.0]];
|
||||
[label setTextColor:_labelColor];
|
||||
[label setTextShadowColor:_labelShadowColor];
|
||||
[label setTextShadowOffset:CGSizeMake(0, 1)];
|
||||
[label sizeToFit];
|
||||
|
||||
[label setTarget:[item target]];
|
||||
|
||||
@@ -56,9 +56,9 @@ CPToolbarShowFontsItemIdentifier = @"CPToolbarShowFontsItemIdentifier";
|
||||
CPToolbarCustomizeToolbarItemIdentifier = @"CPToolbarCustomizeToolbarItemIdentifier";
|
||||
CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
||||
|
||||
var _CPToolbarSeparatorItemView = nil;
|
||||
|
||||
/*! @class CPToolbarItem
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPToolbarItem
|
||||
|
||||
A representation of an item in a CPToolbar.
|
||||
*/
|
||||
@@ -479,8 +479,33 @@ CPToolbarItemVisibilityPriorityUser
|
||||
|
||||
// Standard toolbar identifiers
|
||||
|
||||
var _CPToolbarSeparatorItemView = nil,
|
||||
_CPToolbarSpaceItemView = nil;
|
||||
|
||||
@implementation CPToolbarItem (Standard)
|
||||
|
||||
+ (CPView)_separatorItemView
|
||||
{
|
||||
if (!_CPToolbarSeparatorItemView)
|
||||
{
|
||||
_CPToolbarSeparatorItemView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 2.0, 32.0)];
|
||||
|
||||
sizes = {};
|
||||
sizes[@"CPToolbarItemSeparator"] = [CGSizeMake(2.0, 26.0), CGSizeMake(2.0, 1.0), CGSizeMake(2.0, 26.0)];
|
||||
[_CPToolbarSeparatorItemView setBackgroundColor:_CPControlThreePartImagePattern(YES, sizes, @"CPToolbarItem", @"Separator")];
|
||||
}
|
||||
|
||||
return _CPToolbarSeparatorItemView;
|
||||
}
|
||||
|
||||
+ (CPView)_spaceItemView
|
||||
{
|
||||
if (!_CPToolbarSpaceItemView)
|
||||
_CPToolbarSpaceItemView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
return _CPToolbarSpaceItemView;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
+ (CPToolbarItem)_standardItemWithItemIdentifier:(CPString)anItemIdentifier
|
||||
{
|
||||
@@ -488,29 +513,23 @@ CPToolbarItemVisibilityPriorityUser
|
||||
|
||||
switch (anItemIdentifier)
|
||||
{
|
||||
case CPToolbarSeparatorItemIdentifier: [item setMinSize:CGSizeMake(2.0, 0.0)];
|
||||
case CPToolbarSeparatorItemIdentifier: [item setView:[self _separatorItemView]];
|
||||
|
||||
[item setMinSize:CGSizeMake(2.0, 0.0)];
|
||||
[item setMaxSize:CGSizeMake(2.0, 100000.0)];
|
||||
|
||||
if (!_CPToolbarSeparatorItemView)
|
||||
{
|
||||
_CPToolbarSeparatorItemView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 2.0, 32.0)];
|
||||
|
||||
sizes = {};
|
||||
sizes[@"CPToolbarItemSeparator"] = [CGSizeMake(2.0, 26.0), CGSizeMake(2.0, 1.0), CGSizeMake(2.0, 26.0)];
|
||||
[_CPToolbarSeparatorItemView setBackgroundColor:_CPControlThreePartImagePattern(YES, sizes, @"CPToolbarItem", @"Separator")];
|
||||
}
|
||||
|
||||
[item setView:_CPToolbarSeparatorItemView];
|
||||
|
||||
|
||||
return item;
|
||||
|
||||
case CPToolbarSpaceItemIdentifier: [item setMinSize:CGSizeMake(32.0, 32.0)];
|
||||
case CPToolbarSpaceItemIdentifier: [item setView:[self _spaceItemView]];
|
||||
|
||||
[item setMinSize:CGSizeMake(32.0, 32.0)];
|
||||
[item setMaxSize:CGSizeMake(32.0, 32.0)];
|
||||
|
||||
return item;
|
||||
|
||||
case CPToolbarFlexibleSpaceItemIdentifier: [item setMinSize:CGSizeMake(32.0, 32.0)];
|
||||
case CPToolbarFlexibleSpaceItemIdentifier: [item setView:[self _spaceItemView]];
|
||||
|
||||
[item setMinSize:CGSizeMake(32.0, 32.0)];
|
||||
[item setMaxSize:CGSizeMake(10000.0, 32.0)];
|
||||
|
||||
return item;
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPView.j"
|
||||
@import <AppKit/CPView.j>
|
||||
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
|
||||
// FIXME: implement these where possible:
|
||||
@@ -35,16 +37,27 @@ CPWebViewProgressEstimateChangedNotification = "CPWebViewProgressEstimateChan
|
||||
CPWebViewProgressStartedNotification = "CPWebViewProgressStartedNotification";
|
||||
CPWebViewProgressFinishedNotification = "CPWebViewProgressFinishedNotification";
|
||||
|
||||
CPWebViewScrollAppKit = 1;
|
||||
CPWebViewScrollNative = 2;
|
||||
|
||||
// FIXME: somehow make CPWebView work with CPScrollView instead of native scrollbars (is this even possible?)
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
*/
|
||||
|
||||
@implementation CPWebView : CPView
|
||||
{
|
||||
CPScrollView _scrollView;
|
||||
CPView _frameView;
|
||||
|
||||
IFrame _iframe;
|
||||
CPString _mainFrameURL;
|
||||
CPArray _backwardStack;
|
||||
CPArray _forwardStack;
|
||||
|
||||
BOOL _ignoreLoadEvent;
|
||||
BOOL _ignoreLoadStart;
|
||||
BOOL _ignoreLoadEnd;
|
||||
|
||||
id _downloadDelegate;
|
||||
id _frameLoadDelegate;
|
||||
@@ -53,6 +66,14 @@ CPWebViewProgressFinishedNotification = "CPWebViewProgressFinishedNoti
|
||||
id _UIDelegate;
|
||||
|
||||
CPWebScriptObject _wso;
|
||||
|
||||
CPString _url;
|
||||
CPString _html;
|
||||
|
||||
Function _loadCallback;
|
||||
|
||||
int _scrollMode;
|
||||
CGSize _scrollSize;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CPRect)frameRect frameName:(CPString)frameName groupName:(CPString)groupName
|
||||
@@ -68,9 +89,11 @@ CPWebViewProgressFinishedNotification = "CPWebViewProgressFinishedNoti
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
_mainFrameURL = nil;
|
||||
_backwardStack = [];
|
||||
_forwardStack = [];
|
||||
_mainFrameURL = nil;
|
||||
_backwardStack = [];
|
||||
_forwardStack = [];
|
||||
_scrollMode = CPWebViewScrollNative;
|
||||
|
||||
[self _initDOMWithFrame:aFrame];
|
||||
}
|
||||
|
||||
@@ -79,18 +102,20 @@ CPWebViewProgressFinishedNotification = "CPWebViewProgressFinishedNoti
|
||||
|
||||
- (id)_initDOMWithFrame:(CPRect)aFrame
|
||||
{
|
||||
_ignoreLoadEvent = NO;
|
||||
_ignoreLoadStart = YES;
|
||||
_ignoreLoadEnd = YES;
|
||||
|
||||
_iframe = document.createElement("iframe");
|
||||
_iframe.name = "iframe_" + Math.floor(Math.random()*10000);
|
||||
_iframe.style.width = "100%";
|
||||
_iframe.style.height = "100%";
|
||||
_iframe.style.borderWidth = "0px";
|
||||
|
||||
[self setDrawsBackground:YES];
|
||||
|
||||
var 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 (!_ignoreLoadEvent)
|
||||
if (!_ignoreLoadStart)
|
||||
{
|
||||
// post the start load notification
|
||||
[self _startedLoading];
|
||||
@@ -98,80 +123,184 @@ CPWebViewProgressFinishedNotification = "CPWebViewProgressFinishedNoti
|
||||
if (_mainFrameURL)
|
||||
[_backwardStack addObject:_mainFrameURL];
|
||||
|
||||
// FIXME: this doesn't actually get the right URL for different domains. Probably not be possible due to browser security restrictions.
|
||||
// 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];
|
||||
}
|
||||
_ignoreLoadEvent = NO;
|
||||
else
|
||||
_ignoreLoadStart = NO;
|
||||
|
||||
[self _finishedLoading]
|
||||
if (!_ignoreLoadEnd)
|
||||
{
|
||||
[self _finishedLoading];
|
||||
}
|
||||
else
|
||||
_ignoreLoadEnd = NO;
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
if (_iframe.addEventListener)
|
||||
_iframe.addEventListener("load", loadCallback, false);
|
||||
_iframe.addEventListener("load", _loadCallback, false);
|
||||
else if (_iframe.attachEvent)
|
||||
_iframe.attachEvent("onload", loadCallback);
|
||||
|
||||
_DOMElement.appendChild(_iframe);
|
||||
_iframe.attachEvent("onload", _loadCallback);
|
||||
|
||||
|
||||
_frameView = [[CPView alloc] initWithFrame:[self bounds]];
|
||||
|
||||
_scrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
|
||||
[_scrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||
[_scrollView setDocumentView:_frameView];
|
||||
|
||||
_frameView._DOMElement.appendChild(_iframe);
|
||||
|
||||
[self _setScrollMode:_scrollMode];
|
||||
|
||||
[self addSubview:_scrollView];
|
||||
}
|
||||
|
||||
// IBActions
|
||||
|
||||
- (IBAction)takeStringURLFrom:(id)sender
|
||||
{
|
||||
[self setMainFrameURL:[sender stringValue]];
|
||||
- (void)setFrameSize:(CPSize)aSize
|
||||
{
|
||||
[super setFrameSize:aSize];
|
||||
|
||||
[self _resizeWebFrame];
|
||||
}
|
||||
|
||||
- (IBAction)goBack:(id)sender
|
||||
- (BOOL)_resizeWebFrame
|
||||
{
|
||||
[self goBack];
|
||||
}
|
||||
|
||||
- (IBAction)goForward:(id)sender
|
||||
{
|
||||
[self goForward];
|
||||
}
|
||||
|
||||
- (IBAction)stopLoading:(id)sender
|
||||
{
|
||||
// FIXME: what to do?
|
||||
}
|
||||
|
||||
- (IBAction)reload:(id)sender
|
||||
{
|
||||
[self _loadMainFrameURL];
|
||||
}
|
||||
|
||||
- (IBAction)print:(id)sender
|
||||
{
|
||||
try
|
||||
if (_scrollMode === CPWebViewScrollAppKit)
|
||||
{
|
||||
[self window].print();
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
alert('Please click the webpage and select "Print" from the "File" menu');
|
||||
if (_scrollSize)
|
||||
{
|
||||
[_frameView setFrameSize:_scrollSize];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_frameView setFrameSize:[_scrollView bounds].size];
|
||||
|
||||
// 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)
|
||||
{
|
||||
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
|
||||
{
|
||||
CPLog.warn("using default size 800*1600");
|
||||
|
||||
[_frameView setFrameSize:CGSizeMake(800, 1600)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)drawsBackground
|
||||
- (void)setScrollMode:(int)aScrollMode
|
||||
{
|
||||
return _iframe.style.backgroundColor != "";
|
||||
if (_scrollMode == aScrollMode)
|
||||
return;
|
||||
|
||||
[self _setScrollMode:aScrollMode];
|
||||
}
|
||||
|
||||
- (void)setDrawsBackground:(BOOL)drawsBackround
|
||||
- (void)_setScrollMode:(int)aScrollMode
|
||||
{
|
||||
_iframe.style.backgroundColor = drawsBackround ? "white" : "";
|
||||
_scrollMode = aScrollMode;
|
||||
|
||||
_ignoreLoadStart = YES;
|
||||
_ignoreLoadEnd = YES;
|
||||
|
||||
var parent = _iframe.parentNode;
|
||||
parent.removeChild(_iframe);
|
||||
|
||||
if (_scrollMode === CPWebViewScrollAppKit)
|
||||
{
|
||||
[_scrollView setHasHorizontalScroller:YES];
|
||||
[_scrollView setHasVerticalScroller:YES];
|
||||
|
||||
_iframe.setAttribute("scrolling", "no");
|
||||
}
|
||||
else
|
||||
{
|
||||
[_scrollView setHasHorizontalScroller:NO];
|
||||
[_scrollView setHasVerticalScroller:NO];
|
||||
|
||||
_iframe.setAttribute("scrolling", "auto");
|
||||
|
||||
[_frameView setFrameSize:[_scrollView bounds].size];
|
||||
}
|
||||
|
||||
parent.appendChild(_iframe);
|
||||
}
|
||||
|
||||
- (void)loadHTMLString:(CPString)aString
|
||||
{
|
||||
[self loadHTMLString:aString baseURL:nil];
|
||||
}
|
||||
|
||||
- (void)loadHTMLString:(CPString)aString baseURL:(CPURL)URL
|
||||
{
|
||||
// FIXME: do something with baseURL?
|
||||
|
||||
[self _setScrollMode:CPWebViewScrollAppKit];
|
||||
|
||||
[self _startedLoading];
|
||||
|
||||
_ignoreLoadStart = YES;
|
||||
_ignoreLoadEnd = NO;
|
||||
|
||||
_url = null;
|
||||
_html = aString;
|
||||
|
||||
[self _load];
|
||||
}
|
||||
|
||||
- (void)_loadMainFrameURL
|
||||
{
|
||||
[self _setScrollMode:CPWebViewScrollNative];
|
||||
|
||||
[self _startedLoading];
|
||||
|
||||
_ignoreLoadEvent = YES;
|
||||
_iframe.src = _mainFrameURL;
|
||||
_ignoreLoadStart = YES;
|
||||
_ignoreLoadEnd = NO;
|
||||
|
||||
_url = _mainFrameURL;
|
||||
_html = null;
|
||||
|
||||
[self _load];
|
||||
}
|
||||
|
||||
- (void)_load
|
||||
{
|
||||
if (_url)
|
||||
{
|
||||
_iframe.src = _url;
|
||||
}
|
||||
else if (_html)
|
||||
{
|
||||
// clear the iframe
|
||||
_iframe.src = "";
|
||||
|
||||
// need to give the browser a chance to reset iframe, otherwise we'll be document.write()-ing the previous document
|
||||
window.setTimeout(function() {
|
||||
var win = [self DOMWindow];
|
||||
|
||||
win.document.write(_html);
|
||||
|
||||
window.setTimeout(_loadCallback, 1);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_startedLoading
|
||||
@@ -184,6 +313,8 @@ CPWebViewProgressFinishedNotification = "CPWebViewProgressFinishedNoti
|
||||
|
||||
- (void)_finishedLoading
|
||||
{
|
||||
[self _resizeWebFrame];
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPWebViewProgressFinishedNotification object:self];
|
||||
|
||||
if ([_frameLoadDelegate respondsToSelector:@selector(webView:didFinishLoadForFrame:)])
|
||||
@@ -255,17 +386,17 @@ CPWebViewProgressFinishedNotification = "CPWebViewProgressFinishedNoti
|
||||
|
||||
- (void)close
|
||||
{
|
||||
_DOMElement.removeChild(_iframe);
|
||||
_iframe.parentNode.removeChild(_iframe);
|
||||
}
|
||||
|
||||
- (Window)window
|
||||
- (DOMWindow)DOMWindow
|
||||
{
|
||||
return (_iframe.contentDocument && _iframe.contentDocument.defaultView) || _iframe.contentWindow;
|
||||
}
|
||||
|
||||
- (CPWebScriptObject)windowScriptObject
|
||||
{
|
||||
var win = [self window];
|
||||
var win = [self DOMWindow];
|
||||
if (!_wso || win != [_wso window])
|
||||
{
|
||||
if (win)
|
||||
@@ -298,6 +429,60 @@ CPWebViewProgressFinishedNotification = "CPWebViewProgressFinishedNoti
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (BOOL)drawsBackground
|
||||
{
|
||||
return _iframe.style.backgroundColor != "";
|
||||
}
|
||||
|
||||
- (void)setDrawsBackground:(BOOL)drawsBackround
|
||||
{
|
||||
_iframe.style.backgroundColor = drawsBackround ? "white" : "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
// IBActions
|
||||
|
||||
- (IBAction)takeStringURLFrom:(id)sender
|
||||
{
|
||||
[self setMainFrameURL:[sender stringValue]];
|
||||
}
|
||||
|
||||
- (IBAction)goBack:(id)sender
|
||||
{
|
||||
[self goBack];
|
||||
}
|
||||
|
||||
- (IBAction)goForward:(id)sender
|
||||
{
|
||||
[self goForward];
|
||||
}
|
||||
|
||||
- (IBAction)stopLoading:(id)sender
|
||||
{
|
||||
// FIXME: what to do?
|
||||
}
|
||||
|
||||
- (IBAction)reload:(id)sender
|
||||
{
|
||||
[self _loadMainFrameURL];
|
||||
}
|
||||
|
||||
- (IBAction)print:(id)sender
|
||||
{
|
||||
try
|
||||
{
|
||||
[self DOMWindow].print();
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
alert('Please click the webpage and select "Print" from the "File" menu');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Delegates:
|
||||
|
||||
// FIXME: implement more delegates, though most of these will likely never work with the iframe implementation
|
||||
@@ -343,26 +528,6 @@ CPWebViewProgressFinishedNotification = "CPWebViewProgressFinishedNoti
|
||||
_UIDelegate = anObject;
|
||||
}
|
||||
|
||||
|
||||
- (void)loadHTMLString:(CPString)aString
|
||||
{
|
||||
[self loadHTMLString:aString baseURL:nil];
|
||||
}
|
||||
|
||||
- (void)loadHTMLString:(CPString)aString baseURL:(CPURL)URL
|
||||
{
|
||||
// FIXME: do something with baseURL?
|
||||
|
||||
// clear the iframe
|
||||
_iframe.src = "";
|
||||
|
||||
// need to give the browser a chance to reset iframe, otherwise we'll be document.write()-ing the previous document
|
||||
window.setTimeout(function() {
|
||||
var win = [self window];
|
||||
win.document.write(aString);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -375,7 +540,7 @@ CPWebViewProgressFinishedNotification = "CPWebViewProgressFinishedNoti
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_window = aWindow
|
||||
_window = aWindow;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -424,11 +589,16 @@ CPWebViewProgressFinishedNotification = "CPWebViewProgressFinishedNoti
|
||||
if (self)
|
||||
{
|
||||
// FIXME: encode/decode these?
|
||||
_mainFrameURL = nil;
|
||||
_backwardStack = [];
|
||||
_forwardStack = [];
|
||||
_mainFrameURL = nil;
|
||||
_backwardStack = [];
|
||||
_forwardStack = [];
|
||||
_scrollMode = CPWebViewScrollNative;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
[self _initDOMWithFrame:[self frame]];
|
||||
#endif
|
||||
|
||||
[self setBackgroundColor:[CPColor whiteColor]];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -440,7 +610,10 @@ CPWebViewProgressFinishedNotification = "CPWebViewProgressFinishedNoti
|
||||
*/
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
var actualSubviews = _subviews;
|
||||
_subviews = [];
|
||||
[super encodeWithCoder:aCoder];
|
||||
_subviews = actualSubviews;
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPCountedSet.j>
|
||||
@import <Foundation/CPNotificationCenter.j>
|
||||
@import <Foundation/CPUndoManager.j>
|
||||
|
||||
@@ -27,10 +28,10 @@
|
||||
@import "CPAnimation.j"
|
||||
@import "CPResponder.j"
|
||||
|
||||
#include "Platform/Platform.h"
|
||||
#include "Platform/DOM/CPDOMDisplayServer.h"
|
||||
#include "../Platform/Platform.h"
|
||||
#include "../Platform/DOM/CPDOMDisplayServer.h"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
#include "../CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
/*
|
||||
@@ -88,6 +89,7 @@ CPWindowMinYMargin = 8;
|
||||
CPWindowHeightSizable = 16;
|
||||
CPWindowMaxYMargin = 32;
|
||||
|
||||
CPBackgroundWindowLevel = -1;
|
||||
/*
|
||||
Default level for windows
|
||||
@group CPWindowLevel
|
||||
@@ -171,6 +173,7 @@ CPWindowBelow = 2;
|
||||
CPWindowWillCloseNotification = @"CPWindowWillCloseNotification";
|
||||
CPWindowDidBecomeMainNotification = @"CPWindowDidBecomeMainNotification";
|
||||
CPWindowDidResignMainNotification = @"CPWindowDidResignMainNotification";
|
||||
CPWindowDidMoveNotification = @"CPWindowDidMoveNotification";
|
||||
|
||||
|
||||
var SHADOW_MARGIN_LEFT = 20.0,
|
||||
@@ -184,7 +187,9 @@ var SHADOW_MARGIN_LEFT = 20.0,
|
||||
var CPWindowSaveImage = nil,
|
||||
CPWindowSavingImage = nil;
|
||||
|
||||
/*! @class CPWindow
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPWindow
|
||||
|
||||
An CPWindow instance represents a window, panel or menu on the screen.</p>
|
||||
|
||||
@@ -230,55 +235,67 @@ var CPWindowSaveImage = nil,
|
||||
*/
|
||||
@implementation CPWindow : CPResponder
|
||||
{
|
||||
int _windowNumber;
|
||||
unsigned _styleMask;
|
||||
CGRect _frame;
|
||||
int _level;
|
||||
BOOL _isVisible;
|
||||
BOOL _isAnimating;
|
||||
BOOL _hasShadow;
|
||||
BOOL _isMovableByWindowBackground;
|
||||
|
||||
BOOL _isDocumentEdited;
|
||||
BOOL _isDocumentSaving;
|
||||
|
||||
CPNinePartImageView _shadowView;
|
||||
|
||||
CPView _windowView;
|
||||
CPView _contentView;
|
||||
CPView _toolbarView;
|
||||
|
||||
CPView _mouseOverView;
|
||||
CPView _leftMouseDownView;
|
||||
CPView _rightMouseDownView;
|
||||
|
||||
CPToolbar _toolbar;
|
||||
CPResponder _firstResponder;
|
||||
id _delegate;
|
||||
|
||||
CPString _title;
|
||||
|
||||
BOOL _acceptsMouseMovedEvents;
|
||||
|
||||
CPWindowController _windowController;
|
||||
|
||||
CGSize _minSize;
|
||||
CGSize _maxSize;
|
||||
|
||||
CGRect _resizeFrame;
|
||||
CGPoint _mouseDraggedPoint;
|
||||
|
||||
CPUndoManager _undoManager;
|
||||
CPURL _representedURL;
|
||||
|
||||
int _windowNumber;
|
||||
unsigned _styleMask;
|
||||
CGRect _frame;
|
||||
int _level;
|
||||
BOOL _isVisible;
|
||||
BOOL _isAnimating;
|
||||
BOOL _hasShadow;
|
||||
BOOL _isMovableByWindowBackground;
|
||||
|
||||
BOOL _isDocumentEdited;
|
||||
BOOL _isDocumentSaving;
|
||||
|
||||
CPImageView _shadowView;
|
||||
|
||||
CPView _windowView;
|
||||
CPView _contentView;
|
||||
CPView _toolbarView;
|
||||
|
||||
CPView _mouseOverView;
|
||||
CPView _leftMouseDownView;
|
||||
CPView _rightMouseDownView;
|
||||
|
||||
CPToolbar _toolbar;
|
||||
CPResponder _firstResponder;
|
||||
CPResponder _initialFirstResponder;
|
||||
id _delegate;
|
||||
|
||||
CPString _title;
|
||||
|
||||
BOOL _acceptsMouseMovedEvents;
|
||||
BOOL _ignoresMouseEvents;
|
||||
|
||||
CPWindowController _windowController;
|
||||
|
||||
CGSize _minSize;
|
||||
CGSize _maxSize;
|
||||
|
||||
CPUndoManager _undoManager;
|
||||
CPURL _representedURL;
|
||||
|
||||
CPSet _registeredDraggedTypes;
|
||||
CPArray _registeredDraggedTypesArray;
|
||||
CPCountedSet _inclusiveRegisteredDraggedTypes;
|
||||
|
||||
CPButton _defaultButton;
|
||||
BOOL _defaultButtonEnabled;
|
||||
|
||||
BOOL _autorecalculatesKeyViewLoop;
|
||||
BOOL _keyViewLoopIsDirty;
|
||||
|
||||
// Bridge Support
|
||||
#if PLATFORM(DOM)
|
||||
DOMElement _DOMElement;
|
||||
DOMElement _DOMElement;
|
||||
#endif
|
||||
CPDOMWindowBridge _bridge;
|
||||
unsigned _autoresizingMask;
|
||||
CPDOMWindowBridge _bridge;
|
||||
unsigned _autoresizingMask;
|
||||
|
||||
BOOL _delegateRespondsToWindowWillReturnUndoManagerSelector;
|
||||
BOOL _delegateRespondsToWindowWillReturnUndoManagerSelector;
|
||||
|
||||
BOOL _isFullBridge;
|
||||
_CPWindowFullBridgeSession _fullBridgeSession;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -292,8 +309,6 @@ var CPWindowSaveImage = nil,
|
||||
|
||||
var bundle = [CPBundle bundleForClass:[CPWindow class]];
|
||||
|
||||
CPWindowResizeIndicatorImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindowResizeIndicator.png"] size:CGSizeMake(12.0, 12.0)];
|
||||
|
||||
CPWindowSavingImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif"] size:CGSizeMake(16.0, 16.0)]
|
||||
}
|
||||
|
||||
@@ -314,7 +329,11 @@ CPTexturedBackgroundWindowMask
|
||||
*/
|
||||
- (id)initWithContentRect:(CGRect)aContentRect styleMask:(unsigned int)aStyleMask
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
return [self initWithContentRect:aContentRect styleMask:aStyleMask bridge:[CPDOMWindowBridge sharedDOMWindowBridge]];
|
||||
#else
|
||||
return [self initWithContentRect:aContentRect styleMask:aStyleMask bridge:nil];
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -340,34 +359,34 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
if (self)
|
||||
{
|
||||
_isFullBridge = NO;
|
||||
_registeredDraggedTypes = [CPSet set];
|
||||
_registeredDraggedTypesArray = [];
|
||||
|
||||
// Set up our window number.
|
||||
_windowNumber = [CPApp._windows count];
|
||||
CPApp._windows[_windowNumber] = self;
|
||||
|
||||
_styleMask = aStyleMask;
|
||||
|
||||
_frame = [self frameRectForContentRect:aContentRect];
|
||||
|
||||
_level = CPNormalWindowLevel;
|
||||
_hasShadow = NO;
|
||||
|
||||
_minSize = CGSizeMake(0.0, 0.0);
|
||||
_maxSize = CGSizeMake(1000000.0, 1000000.0);
|
||||
|
||||
if (_styleMask & CPBorderlessBridgeWindowMask)
|
||||
_autoresizingMask = CPWindowWidthSizable | CPWindowHeightSizable;
|
||||
|
||||
// Create our border view which is the actual root of our view hierarchy.
|
||||
_windowView = [[_CPWindowView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(_frame), CGRectGetHeight(_frame)) forStyleMask:_styleMask];
|
||||
var windowViewClass = [[self class] _windowViewClassForStyleMask:aStyleMask];
|
||||
|
||||
_frame = [windowViewClass frameRectForContentRect:aContentRect];
|
||||
_windowView = [[windowViewClass alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(_frame), CGRectGetHeight(_frame)) styleMask:aStyleMask];
|
||||
|
||||
[_windowView _setWindow:self];
|
||||
[_windowView setNextResponder:self];
|
||||
|
||||
|
||||
[self setMovableByWindowBackground:aStyleMask & CPHUDBackgroundWindowMask];
|
||||
|
||||
// Create a generic content view.
|
||||
[self setContentView:[[CPView alloc] initWithFrame:CGRectMakeZero()]];
|
||||
|
||||
|
||||
_firstResponder = self;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
@@ -384,13 +403,127 @@ CPTexturedBackgroundWindowMask
|
||||
#endif
|
||||
|
||||
[self setBridge:aBridge];
|
||||
|
||||
|
||||
[self setNextResponder:CPApp];
|
||||
|
||||
[self setHasShadow:aStyleMask !== CPBorderlessWindowMask];
|
||||
|
||||
if (aStyleMask & CPBorderlessBridgeWindowMask)
|
||||
[self setFullBridge:YES];
|
||||
|
||||
_defaultButtonEnabled = YES;
|
||||
_keyViewLoopIsDirty = YES;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
+ (Class)_windowViewClassForStyleMask:(unsigned)aStyleMask
|
||||
{
|
||||
if (aStyleMask & CPHUDBackgroundWindowMask)
|
||||
return _CPHUDWindowView;
|
||||
|
||||
else if (aStyleMask === CPBorderlessWindowMask)
|
||||
return _CPBorderlessWindowView;
|
||||
|
||||
return _CPStandardWindowView;
|
||||
}
|
||||
|
||||
+ (Class)_windowViewClassForFullBridgeStyleMask:(unsigned)aStyleMask
|
||||
{
|
||||
return _CPBorderlessBridgeWindowView;
|
||||
}
|
||||
|
||||
- (void)awakeFromCib
|
||||
{
|
||||
if (_initialFirstResponder)
|
||||
[self makeFirstResponder:_initialFirstResponder];
|
||||
|
||||
_keyViewLoopIsDirty = ![self _hasKeyViewLoop];
|
||||
}
|
||||
|
||||
- (void)_setWindowView:(CPView)aWindowView
|
||||
{
|
||||
if (_windowView === aWindowView)
|
||||
return;
|
||||
|
||||
var oldWindowView = _windowView;
|
||||
|
||||
_windowView = aWindowView;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
if (oldWindowView)
|
||||
{
|
||||
[oldWindowView _setWindow:nil];
|
||||
[oldWindowView noteToolbarChanged];
|
||||
|
||||
CPDOMDisplayServerRemoveChild(_DOMElement, oldWindowView._DOMElement);
|
||||
}
|
||||
|
||||
if (_windowView)
|
||||
{
|
||||
CPDOMDisplayServerAppendChild(_DOMElement, _windowView._DOMElement);
|
||||
|
||||
var contentRect = [_contentView convertRect:[_contentView bounds] toView:nil];
|
||||
|
||||
contentRect.origin = [self convertBaseToBridge:contentRect.origin];
|
||||
|
||||
[_windowView _setWindow:self];
|
||||
[_windowView setNextResponder:self];
|
||||
[_windowView addSubview:_contentView];
|
||||
[_windowView setTitle:_title];
|
||||
[_windowView noteToolbarChanged];
|
||||
|
||||
[self setFrame:[self frameRectForContentRect:contentRect]];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)setFullBridge:(BOOL)shouldBeFullBridge
|
||||
{
|
||||
shouldBeFullBridge = !!shouldBeFullBridge;
|
||||
|
||||
if (_isFullBridge === shouldBeFullBridge)
|
||||
return;
|
||||
|
||||
_isFullBridge = shouldBeFullBridge;
|
||||
|
||||
if (_isFullBridge)
|
||||
{
|
||||
_fullBridgeSession = _CPWindowFullBridgeSessionMake(_windowView, [self contentRectForFrameRect:[self frame]], [self hasShadow], [self level]);
|
||||
|
||||
var fullBridgeWindowViewClass = [[self class] _windowViewClassForFullBridgeStyleMask:_styleMask],
|
||||
windowView = [[fullBridgeWindowViewClass alloc] initWithFrame:CGRectMakeZero() styleMask:_styleMask];
|
||||
|
||||
[self _setWindowView:windowView];
|
||||
|
||||
[self setLevel:CPBackgroundWindowLevel];
|
||||
[self setHasShadow:NO];
|
||||
[self setAutoresizingMask:CPWindowWidthSizable | CPWindowHeightSizable];
|
||||
[self setFrame:[_bridge visibleFrame]];
|
||||
}
|
||||
else
|
||||
{
|
||||
var windowView = _fullBridgeSession.windowView;
|
||||
|
||||
[self _setWindowView:windowView];
|
||||
|
||||
[self setLevel:_fullBridgeSession.level];
|
||||
[self setHasShadow:_fullBridgeSession.hasShadow];
|
||||
[self setAutoresizingMask:CPWindowNotSizable];
|
||||
|
||||
[self setFrame:[windowView frameRectForContentRect:_fullBridgeSession.contentRect]];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isFullBridge
|
||||
{
|
||||
return _isFullBridge;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the window's style mask.
|
||||
*/
|
||||
@@ -407,9 +540,7 @@ CPTexturedBackgroundWindowMask
|
||||
*/
|
||||
+ (CGRect)frameRectForContentRect:(CGRect)aContentRect styleMask:(unsigned)aStyleMask
|
||||
{
|
||||
var frame = CGRectMakeCopy(aContentRect);
|
||||
|
||||
return frame;
|
||||
return [[[self class] _windowViewClassForStyleMask:_styleMask] frameRectForContentRect:aContentRect];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -418,31 +549,7 @@ CPTexturedBackgroundWindowMask
|
||||
*/
|
||||
- (CGRect)contentRectForFrameRect:(CGRect)aFrame
|
||||
{
|
||||
// FIXME: EXTRA RECT COPY
|
||||
var contentRect = CGRectMakeCopy([_windowView bounds]);
|
||||
|
||||
if (_styleMask & CPHUDBackgroundWindowMask)
|
||||
{
|
||||
contentRect.origin.x += 7.0;
|
||||
contentRect.origin.y += 30.0;
|
||||
contentRect.size.width -= 14.0;
|
||||
contentRect.size.height -= 40.0;
|
||||
}
|
||||
|
||||
else if (_styleMask & CPBorderlessBridgeWindowMask)
|
||||
{
|
||||
// The full width, like borderless.
|
||||
}
|
||||
|
||||
if ([_toolbar isVisible])
|
||||
{
|
||||
var toolbarHeight = CGRectGetHeight([_toolbarView frame]);
|
||||
|
||||
contentRect.origin.y += toolbarHeight;
|
||||
contentRect.size.height -= toolbarHeight;
|
||||
}
|
||||
|
||||
return contentRect;
|
||||
return [_windowView contentRectForFrameRect:aFrame];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -452,12 +559,7 @@ CPTexturedBackgroundWindowMask
|
||||
*/
|
||||
- (CGRect)frameRectForContentRect:(CGRect)aContentRect
|
||||
{
|
||||
if (_styleMask & CPBorderlessBridgeWindowMask)
|
||||
return _bridge ? [_bridge visibleFrame] : CGRectMakeZero();
|
||||
|
||||
var frame = [[self class] frameRectForContentRect:aContentRect styleMask:_styleMask];
|
||||
|
||||
return frame;
|
||||
return [_windowView frameRectForContentRect:aContentRect];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -515,6 +617,8 @@ CPTexturedBackgroundWindowMask
|
||||
#if PLATFORM(DOM)
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, origin.x, origin.y);
|
||||
#endif
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidMoveNotification object:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -539,51 +643,6 @@ CPTexturedBackgroundWindowMask
|
||||
[_delegate windowDidResize:self];
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
- (void)trackMoveWithEvent:(CPEvent)anEvent
|
||||
{
|
||||
var type = [anEvent type];
|
||||
|
||||
if (type == CPLeftMouseUp)
|
||||
return;
|
||||
|
||||
else if (type == CPLeftMouseDown)
|
||||
_mouseDraggedPoint = [self convertBaseToBridge:[anEvent locationInWindow]];
|
||||
|
||||
else if (type == CPLeftMouseDragged)
|
||||
{
|
||||
var location = [self convertBaseToBridge:[anEvent locationInWindow]];
|
||||
|
||||
[self setFrameOrigin:CGPointMake(_CGRectGetMinX(_frame) + (location.x - _mouseDraggedPoint.x), _CGRectGetMinY(_frame) + (location.y - _mouseDraggedPoint.y))];
|
||||
|
||||
_mouseDraggedPoint = location;
|
||||
}
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackMoveWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
- (void)trackResizeWithEvent:(CPEvent)anEvent
|
||||
{
|
||||
var location = [anEvent locationInWindow],
|
||||
type = [anEvent type];
|
||||
|
||||
if (type == CPLeftMouseUp)
|
||||
return;
|
||||
|
||||
else if (type == CPLeftMouseDown)
|
||||
_resizeFrame = CGRectMake(location.x, location.y, CGRectGetWidth(_frame), CGRectGetHeight(_frame));
|
||||
|
||||
else if (type == CPLeftMouseDragged)
|
||||
[self setFrameSize:CGSizeMake(CGRectGetWidth(_resizeFrame) + location.x - CGRectGetMinX(_resizeFrame), CGRectGetHeight(_resizeFrame) + location.y - CGRectGetMinY(_resizeFrame))];
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackResizeWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
Makes the receiver the front most window in the screen ordering.
|
||||
@param aSender the object that requested this
|
||||
@@ -701,11 +760,13 @@ CPTexturedBackgroundWindowMask
|
||||
if (_contentView)
|
||||
[_contentView removeFromSuperview];
|
||||
|
||||
var bounds = CGRectMake(0.0, 0.0, CGRectGetWidth(_frame), CGRectGetHeight(_frame));
|
||||
|
||||
_contentView = aView;
|
||||
[_contentView setFrame:[self contentRectForFrameRect:_frame]];
|
||||
[_contentView setFrame:[self contentRectForFrameRect:bounds]];
|
||||
|
||||
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
[_windowView addSubview:_contentView positioned:CPWindowBelow relativeTo:nil];
|
||||
[_windowView addSubview:_contentView];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -826,7 +887,7 @@ CPTexturedBackgroundWindowMask
|
||||
*/
|
||||
- (void)setHasShadow:(BOOL)shouldHaveShadow
|
||||
{
|
||||
if (_hasShadow == shouldHaveShadow)
|
||||
if (_hasShadow === shouldHaveShadow)
|
||||
return;
|
||||
|
||||
_hasShadow = shouldHaveShadow;
|
||||
@@ -840,7 +901,7 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
if (!_CPWindowShadowColor)
|
||||
{
|
||||
var bundle = [CPBundle bundleForClass:[self class]];
|
||||
var bundle = [CPBundle bundleForClass:[CPWindow class]];
|
||||
|
||||
_CPWindowShadowColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
@@ -865,7 +926,7 @@ CPTexturedBackgroundWindowMask
|
||||
CPDOMDisplayServerInsertBefore(_DOMElement, _shadowView._DOMElement, _windowView._DOMElement);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
else if (_shadowView)
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
CPDOMDisplayServerRemoveChild(_DOMElement, _shadowView._DOMElement);
|
||||
@@ -880,6 +941,8 @@ CPTexturedBackgroundWindowMask
|
||||
*/
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
{
|
||||
// FIXME: Unregister for notifications!
|
||||
|
||||
_delegate = aDelegate;
|
||||
|
||||
_delegateRespondsToWindowWillReturnUndoManagerSelector = [_delegate respondsToSelector:@selector(windowWillReturnUndoManager:)];
|
||||
@@ -899,6 +962,13 @@ CPTexturedBackgroundWindowMask
|
||||
selector:@selector(windowDidResignMain:)
|
||||
name:CPWindowDidResignMainNotification
|
||||
object:self];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(windowDidMove:)])
|
||||
[defaultCenter
|
||||
addObserver:_delegate
|
||||
selector:@selector(windowDidMove:)
|
||||
name:CPWindowDidMoveNotification
|
||||
object:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -984,6 +1054,16 @@ CPTexturedBackgroundWindowMask
|
||||
_acceptsMouseMovedEvents = shouldAcceptMouseMovedEvents;
|
||||
}
|
||||
|
||||
- (BOOL)ignoresMouseEvents
|
||||
{
|
||||
return _ignoresMouseEvents;
|
||||
}
|
||||
|
||||
- (void)setIgnoresMouseEvents:(BOOL)shouldIgnoreMouseEvents
|
||||
{
|
||||
_ignoresMouseEvents = shouldIgnoreMouseEvents;
|
||||
}
|
||||
|
||||
// Managing Titles
|
||||
|
||||
/*!
|
||||
@@ -1241,6 +1321,28 @@ CPTexturedBackgroundWindowMask
|
||||
[[CPDragServer sharedDragServer] dragImage:anImage fromWindow:self at:[self convertBaseToBridge:imageLocation] offset:mouseOffset event:anEvent pasteboard:aPasteboard source:aSourceObject slideBack:slideBack];
|
||||
}
|
||||
|
||||
- (void)_noteRegisteredDraggedTypes:(CPSet)pasteboardTypes
|
||||
{
|
||||
if (!pasteboardTypes)
|
||||
return;
|
||||
|
||||
if (!_inclusiveRegisteredDraggedTypes)
|
||||
_inclusiveRegisteredDraggedTypes = [CPCountedSet set];
|
||||
|
||||
[_inclusiveRegisteredDraggedTypes unionSet:pasteboardTypes];
|
||||
}
|
||||
|
||||
- (void)_noteUnregisteredDraggedTypes:(CPArray)pasteboardTypes
|
||||
{
|
||||
if (!pasteboardTypes)
|
||||
return;
|
||||
|
||||
[_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes]
|
||||
|
||||
if ([_inclusiveRegisteredDraggedTypes count] === 0)
|
||||
_inclusiveRegisteredDraggedTypes = nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
Initiates a drag operation from the receiver to another view that accepts dragged data.
|
||||
@param aView the view to be dragged
|
||||
@@ -1256,6 +1358,45 @@ CPTexturedBackgroundWindowMask
|
||||
[[CPDragServer sharedDragServer] dragView:aView fromWindow:self at:[self convertBaseToBridge:imageLocation] offset:mouseOffset event:anEvent pasteboard:aPasteboard source:aSourceObject slideBack:slideBack];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the receiver's list of acceptable data types for a dragging operation.
|
||||
@param pasteboardTypes an array of CPPasteboards
|
||||
*/
|
||||
- (void)registerForDraggedTypes:(CPArray)pasteboardTypes
|
||||
{
|
||||
if (!pasteboardTypes)
|
||||
return;
|
||||
|
||||
[self _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
|
||||
[_registeredDraggedTypes addObjectsFromArray:pasteboardTypes]
|
||||
[self _noteRegisteredDraggedTypes:_registeredDraggedTypes];
|
||||
|
||||
_registeredDraggedTypesArray = nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns an array of all types the receiver accepts for dragging operations.
|
||||
@return an array of CPPasteBoards
|
||||
*/
|
||||
- (CPArray)registeredDraggedTypes
|
||||
{
|
||||
if (!_registeredDraggedTypesArray)
|
||||
_registeredDraggedTypesArray = [_registeredDraggedTypes allObjects]
|
||||
|
||||
return _registeredDraggedTypesArray;
|
||||
}
|
||||
|
||||
/*!
|
||||
Resets the array of acceptable data types for a dragging operation.
|
||||
*/
|
||||
- (void)unregisterDraggedTypes
|
||||
{
|
||||
[self _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
|
||||
|
||||
_registeredDraggedTypes = [CPSet set];
|
||||
_registeredDraggedTypesArray = [];
|
||||
}
|
||||
|
||||
// Accessing Editing Status
|
||||
|
||||
/*!
|
||||
@@ -1434,49 +1575,54 @@ CPTexturedBackgroundWindowMask
|
||||
*/
|
||||
- (void)setToolbar:(CPToolbar)aToolbar
|
||||
{
|
||||
if (_toolbar == aToolbar)
|
||||
if (_toolbar === aToolbar)
|
||||
return;
|
||||
|
||||
// Cleanup old toolbar
|
||||
if (_toolbar)
|
||||
{
|
||||
[self _setToolbarVisible:NO];
|
||||
// If this has an owner, dump it!
|
||||
[[aToolbar _window] setToolbar:nil];
|
||||
|
||||
_toolbar._window = nil;
|
||||
_toolbarView = nil;
|
||||
}
|
||||
// This is no longer out toolbar.
|
||||
[_toolbar _setWindow:nil];
|
||||
|
||||
if (_toolbar = aToolbar)
|
||||
{
|
||||
// Set up new toolbar
|
||||
_toolbar = aToolbar;
|
||||
_toolbar._window = self;
|
||||
|
||||
if ([_toolbar isVisible])
|
||||
[self _setToolbarVisible:YES];
|
||||
|
||||
[_toolbar _reloadToolbarItems];
|
||||
}
|
||||
_toolbar = aToolbar;
|
||||
|
||||
// THIS is our toolbar.
|
||||
[_toolbar _setWindow:self];
|
||||
|
||||
[self _noteToolbarChanged];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)_setToolbarVisible:(BOOL)aFlag
|
||||
- (void)toggleToolbarShown:(id)aSender
|
||||
{
|
||||
if (aFlag)
|
||||
{
|
||||
if (!_toolbarView)
|
||||
_toolbarView = [_toolbar _toolbarView];
|
||||
|
||||
[_toolbarView setFrame:CGRectMake(0.0, 0.0, CGRectGetWidth([_windowView bounds]), CGRectGetHeight([_toolbarView frame]))];
|
||||
[_windowView addSubview:_toolbarView];
|
||||
}
|
||||
else
|
||||
[_toolbarView removeFromSuperview];
|
||||
var toolbar = [self toolbar];
|
||||
|
||||
[_contentView setFrame:[self contentRectForFrameRect:[_windowView bounds]]];
|
||||
[toolbar setVisible:![toolbar isVisible]];
|
||||
}
|
||||
|
||||
// Managing Sheets
|
||||
- (void)_noteToolbarChanged
|
||||
{
|
||||
var frame = CGRectMakeCopy([self frame]),
|
||||
newFrame;
|
||||
|
||||
[_windowView noteToolbarChanged];
|
||||
|
||||
if (_isFullBridge)
|
||||
newFrame = [_bridge visibleFrame];
|
||||
else
|
||||
{
|
||||
newFrame = CGRectMakeCopy([self frame]);
|
||||
|
||||
newFrame.origin = frame.origin;
|
||||
}
|
||||
|
||||
[self setFrame:newFrame];
|
||||
/*
|
||||
[_windowView setAnimatingToolbar:YES];
|
||||
[self setFrame:frame];
|
||||
[self setFrame:newFrame display:YES animate:YES];
|
||||
[_windowView setAnimatingToolbar:NO];
|
||||
*/
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)_setAttachedSheetFrameOrigin
|
||||
@@ -1566,8 +1712,174 @@ CPTexturedBackgroundWindowMask
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)keyDown:(CPEvent)event
|
||||
{
|
||||
if (![self performKeyEquivalent:event])
|
||||
[self interpretKeyEvents:[event]];
|
||||
}
|
||||
|
||||
- (void)insertNewline:(id)sender
|
||||
{
|
||||
if (_defaultButton && _defaultButtonEnabled)
|
||||
[_defaultButton performClick:nil];
|
||||
}
|
||||
|
||||
- (void)insertTab:(id)sender
|
||||
{
|
||||
[self selectNextKeyView:nil];
|
||||
}
|
||||
|
||||
- (void)_dirtyKeyViewLoop
|
||||
{
|
||||
if (_autorecalculatesKeyViewLoop)
|
||||
_keyViewLoopIsDirty = YES;
|
||||
}
|
||||
|
||||
- (BOOL)_hasKeyViewLoop
|
||||
{
|
||||
var subviews = [];
|
||||
|
||||
[self _appendSubviewsOf:_contentView toArray:subviews];
|
||||
|
||||
for (var i = 0, count = [subviews count]; i<count; i++)
|
||||
{
|
||||
if (subviews[i]._nextKeyView)
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)recalculateKeyViewLoop
|
||||
{
|
||||
var subviews = [];
|
||||
|
||||
[self _appendSubviewsOf:_contentView toArray:subviews];
|
||||
|
||||
var keyViewOrder = [subviews sortedArrayUsingFunction:keyViewComparator context:_contentView],
|
||||
count = [keyViewOrder count];
|
||||
|
||||
for (var i=0; i<count; i++)
|
||||
[keyViewOrder[i] setNextKeyView:keyViewOrder[(i+1)%count]];
|
||||
|
||||
_keyViewLoopIsDirty = NO;
|
||||
}
|
||||
|
||||
- (void)_appendSubviewsOf:(CPView)aView toArray:(CPArray)anArray
|
||||
{
|
||||
var subviews = [aView subviews],
|
||||
count = [subviews count];
|
||||
|
||||
while (count--)
|
||||
[self _appendSubviewsOf:subviews[count] toArray:anArray];
|
||||
|
||||
[anArray addObject:aView];
|
||||
}
|
||||
|
||||
- (void)setAutorecalculatesKeyViewLoop:(BOOL)shouldRecalculate
|
||||
{
|
||||
if (_autorecalculatesKeyViewLoop === shouldRecalculate)
|
||||
return;
|
||||
|
||||
_autorecalculatesKeyViewLoop = shouldRecalculate;
|
||||
|
||||
[self _dirtyKeyViewLoop];
|
||||
}
|
||||
|
||||
- (BOOL)autorecalculatesKeyViewLoop
|
||||
{
|
||||
return _autorecalculatesKeyViewLoop;
|
||||
}
|
||||
|
||||
- (void)selectNextKeyView:(id)sender
|
||||
{
|
||||
if ([_firstResponder isKindOfClass:[CPView class]])
|
||||
[self selectKeyViewFollowingView:_firstResponder];
|
||||
}
|
||||
|
||||
- (void)selectPreviousKeyView:(id)sender
|
||||
{
|
||||
if ([_firstResponder isKindOfClass:[CPView class]])
|
||||
[self selectKeyViewPrecedingView:_firstResponder];
|
||||
}
|
||||
|
||||
- (void)selectKeyViewFollowingView:(CPView)aView
|
||||
{
|
||||
if (_keyViewLoopIsDirty)
|
||||
[self recalculateKeyViewLoop];
|
||||
|
||||
[self makeFirstResponder:[aView nextValidKeyView]];
|
||||
}
|
||||
|
||||
- (void)selectKeyViewPrecedingView:(CPView)aView
|
||||
{
|
||||
if (_keyViewLoopIsDirty)
|
||||
[self recalculateKeyViewLoop];
|
||||
|
||||
[self makeFirstResponder:[aView previousValidKeyView]];
|
||||
}
|
||||
|
||||
- (void)setDefaultButtonCell:(CPButton)aButton
|
||||
{
|
||||
[self setDefaultButton:aButton];
|
||||
}
|
||||
|
||||
- (CPButton)defaultButtonCell
|
||||
{
|
||||
return [self defaultButton];
|
||||
}
|
||||
|
||||
- (void)setDefaultButton:(CPButton)aButton
|
||||
{
|
||||
[_defaultButton setDefaultButton:NO];
|
||||
|
||||
_defaultButton = aButton;
|
||||
|
||||
[_defaultButton setDefaultButton:YES];
|
||||
}
|
||||
|
||||
- (CPButton)defaultButton
|
||||
{
|
||||
return _defaultButton;
|
||||
}
|
||||
|
||||
- (void)enableKeyEquivalentForDefaultButton
|
||||
{
|
||||
_defaultButtonEnabled = YES;
|
||||
}
|
||||
|
||||
- (void)enableKeyEquivalentForDefaultButtonCell
|
||||
{
|
||||
[self enableKeyEquivalentForDefaultButton];
|
||||
}
|
||||
|
||||
- (void)disableKeyEquivalentForDefaultButton
|
||||
{
|
||||
_defaultButtonEnabled = NO;
|
||||
}
|
||||
|
||||
- (void)disableKeyEquivalentForDefaultButtonCell
|
||||
{
|
||||
[self disableKeyEquivalentForDefaultButton];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var keyViewComparator = function(a, b, context)
|
||||
{
|
||||
var viewBounds = [a convertRect:[a bounds] toView:nil],
|
||||
otherBounds = [b convertRect:[b bounds] toView:nil];
|
||||
|
||||
if (CGRectGetMinY(viewBounds) < CGRectGetMinY(otherBounds))
|
||||
return -1;
|
||||
else if (CGRectGetMinY(viewBounds) == CGRectGetMinY(otherBounds) && CGRectGetMinX(viewBounds) < CGRectGetMinX(otherBounds))
|
||||
return -1;
|
||||
else if (CGRectGetMinX(viewBounds) == CGRectGetMinX(otherBounds) && CGRectGetMinX(viewBounds) == CGRectGetMinX(otherBounds))
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
@implementation CPWindow (MenuBar)
|
||||
|
||||
- (void)_synchronizeMenuBarTitleWithWindowTitle
|
||||
@@ -1600,7 +1912,7 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
_bridge = aBridge;
|
||||
|
||||
if (_styleMask & CPBorderlessBridgeWindowMask)
|
||||
if ([self isFullBridge])
|
||||
[self setFrame:[aBridge contentBounds]];
|
||||
}
|
||||
|
||||
@@ -1609,7 +1921,7 @@ CPTexturedBackgroundWindowMask
|
||||
*/
|
||||
- (void)resizeWithOldBridgeSize:(CGSize)aSize
|
||||
{
|
||||
if (_styleMask & CPBorderlessBridgeWindowMask)
|
||||
if ([self isFullBridge])
|
||||
return [self setFrame:[_bridge visibleFrame]];
|
||||
|
||||
if (_autoresizingMask == CPWindowNotSizable)
|
||||
@@ -1704,6 +2016,11 @@ CPTexturedBackgroundWindowMask
|
||||
[[self undoManager] redo];
|
||||
}
|
||||
|
||||
- (BOOL)containsPoint:(CGPoint)aPoint
|
||||
{
|
||||
return CGRectContainsPoint(_frame, aPoint);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var interpolate = function(fromValue, toValue, progress)
|
||||
@@ -1757,7 +2074,16 @@ var interpolate = function(fromValue, toValue, progress)
|
||||
|
||||
@end
|
||||
|
||||
function _CPWindowFullBridgeSessionMake(aWindowView, aContentRect, hasShadow, aLevel)
|
||||
{
|
||||
return { windowView:aWindowView, contentRect:aContentRect, hasShadow:hasShadow, level:aLevel };
|
||||
}
|
||||
|
||||
@import "_CPWindowView.j"
|
||||
@import "_CPStandardWindowView.j"
|
||||
@import "_CPHUDWindowView.j"
|
||||
@import "_CPBorderlessWindowView.j"
|
||||
@import "_CPBorderlessBridgeWindowView.j"
|
||||
@import "CPDragServer.j"
|
||||
@import "CPDOMWindowBridge.j"
|
||||
@import "_CPWindowView.j"
|
||||
@import "CPView.j"
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* _CPBorderlessWindowView.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 "_CPWindowView.j"
|
||||
|
||||
|
||||
var _CPToolbarViewBackgroundColor = nil;
|
||||
|
||||
@implementation _CPBorderlessBridgeWindowView : _CPWindowView
|
||||
{
|
||||
CPView _toolbarBackgroundView;
|
||||
}
|
||||
|
||||
+ (CPColor)toolbarBackgroundColor
|
||||
{
|
||||
if (!_CPToolbarViewBackgroundColor)
|
||||
_CPToolbarViewBackgroundColor = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[_CPBorderlessBridgeWindowView class]] pathForResource:@"_CPToolbarView/_CPToolbarViewBackground.png"] size:CGSizeMake(1.0, 59.0)]];
|
||||
|
||||
return _CPToolbarViewBackgroundColor;
|
||||
}
|
||||
|
||||
- (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();
|
||||
|
||||
frame.origin = CGPointMakeCopy([self toolbarOffset]);
|
||||
frame.size = [_toolbarView frame].size;
|
||||
|
||||
[_toolbarBackgroundView setFrame:frame];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* _CPBorderlessWindowView.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 "_CPWindowView.j"
|
||||
|
||||
|
||||
@implementation _CPBorderlessWindowView : _CPWindowView
|
||||
{
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* _CPHUDWindowView.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
|
||||
*/
|
||||
|
||||
var _CPHUDWindowViewBackgroundColor = nil,
|
||||
|
||||
CPHUDCloseButtonImage = nil;
|
||||
|
||||
var HUD_TITLEBAR_HEIGHT = 26.0;
|
||||
|
||||
@implementation _CPHUDWindowView : _CPWindowView
|
||||
{
|
||||
CPView _toolbarView;
|
||||
|
||||
CPTextField _titleField;
|
||||
CPButton _closeButton;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self != [_CPHUDWindowView class])
|
||||
return;
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
_CPHUDWindowViewBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground0.png"] size:CPSizeMake(6.0, 78.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground1.png"] size:CPSizeMake(1.0, 78.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground2.png"] size:CPSizeMake(6.0, 78.0)],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground3.png"] size:CPSizeMake(6.0, 1.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground4.png"] size:CPSizeMake(1.0, 1.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground5.png"] size:CPSizeMake(6.0, 1.0)],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground6.png"] size:CPSizeMake(6.0, 6.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground7.png"] size:CPSizeMake(6.0, 6.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground8.png"] size:CPSizeMake(6.0, 6.0)]
|
||||
]]];
|
||||
|
||||
_CPHUDWindowViewCloseImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowClose.png"] size:CPSizeMake(20.0, 20.0)];
|
||||
_CPHUDWindowViewCloseActiveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowCloseActive.png"] size:CPSizeMake(20.0, 20.0)];
|
||||
}
|
||||
|
||||
+ (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
{
|
||||
var contentRect = CGRectMakeCopy(aFrameRect),
|
||||
titleBarHeight = HUD_TITLEBAR_HEIGHT;
|
||||
|
||||
contentRect.origin.y += titleBarHeight;
|
||||
contentRect.size.height -= titleBarHeight;
|
||||
|
||||
return contentRect;
|
||||
}
|
||||
|
||||
+ (CGRect)frameRectForContentRect:(CGRect)aContentRect
|
||||
{
|
||||
var frameRect = CGRectMakeCopy(aContentRect),
|
||||
titleBarHeight = HUD_TITLEBAR_HEIGHT;
|
||||
|
||||
frameRect.origin.y -= titleBarHeight;
|
||||
frameRect.size.height += titleBarHeight;
|
||||
|
||||
return frameRect;
|
||||
}
|
||||
|
||||
- (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
{
|
||||
var contentRect = [[self class] contentRectForFrameRect:aFrameRect];
|
||||
|
||||
if ([[[self window] toolbar] isVisible])
|
||||
{
|
||||
toolbarHeight = CGRectGetHeight([[self toolbarView] frame]);
|
||||
|
||||
contentRect.origin.y += toolbarHeight;
|
||||
contentRect.size.height -= toolbarHeight;
|
||||
}
|
||||
|
||||
return contentRect;
|
||||
}
|
||||
|
||||
- (CGRect)frameRectForContentRect:(CGRect)aContentRect
|
||||
{
|
||||
var frameRect = [[self class] frameRectForContentRect:aContentRect];
|
||||
|
||||
if ([[[self window] toolbar] isVisible])
|
||||
{
|
||||
toolbarHeight = CGRectGetHeight([[self toolbarView] frame]);
|
||||
|
||||
frameRect.origin.y -= toolbarHeight;
|
||||
frameRect.size.height += toolbarHeight;
|
||||
}
|
||||
|
||||
return frameRect;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CPRect)aFrame styleMask:(unsigned)aStyleMask
|
||||
{
|
||||
self = [super initWithFrame:aFrame styleMask:aStyleMask];
|
||||
|
||||
if (self)
|
||||
{
|
||||
var bounds = [self bounds];
|
||||
|
||||
[self setBackgroundColor:_CPHUDWindowViewBackgroundColor];
|
||||
|
||||
_titleField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[_titleField setHitTests:NO];
|
||||
[_titleField setFont:[CPFont systemFontOfSize:11.0]];
|
||||
[_titleField setTextColor:[CPColor whiteColor]];
|
||||
[_titleField setTextShadowColor:[CPColor blackColor]];
|
||||
[_titleField setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||
[_titleField setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
// FIXME: Make this to CPLineBreakByTruncatingMiddle once it's implemented.
|
||||
[_titleField setLineBreakMode:CPLineBreakByTruncatingTail];
|
||||
[_titleField setAlignment:CPCenterTextAlignment];
|
||||
|
||||
[_titleField setStringValue:@"Untitled"];
|
||||
[_titleField sizeToFit];
|
||||
[_titleField setAutoresizingMask:CPViewWidthSizable];
|
||||
[_titleField setStringValue:@""];
|
||||
|
||||
[_titleField setFrame:CGRectMake(20.0, 3.0, CGRectGetWidth([self bounds]) - 40.0, CGRectGetHeight([_titleField frame]))];
|
||||
|
||||
[self addSubview:_titleField];
|
||||
|
||||
if (_styleMask & CPClosableWindowMask)
|
||||
{
|
||||
var closeSize = [_CPHUDWindowViewCloseImage size];
|
||||
|
||||
_closeButton = [[CPButton alloc] initWithFrame:CGRectMake(4.0, 4.0, closeSize.width, closeSize.height)];
|
||||
|
||||
[_closeButton setBordered:NO];
|
||||
|
||||
[_closeButton setImage:_CPHUDWindowViewCloseImage];
|
||||
[_closeButton setAlternateImage:_CPHUDWindowViewCloseActiveImage];
|
||||
|
||||
[self addSubview:_closeButton];
|
||||
}
|
||||
|
||||
[self setResizeIndicatorOffset:CGSizeMake(5.0, 5.0)];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidMoveToWindow
|
||||
{
|
||||
[_closeButton setTarget:[self window]];
|
||||
[_closeButton setAction:@selector(performClose:)];
|
||||
}
|
||||
|
||||
- (void)setTitle:(CPString)aTitle
|
||||
{
|
||||
[_titleField setStringValue:aTitle];
|
||||
}
|
||||
|
||||
- (_CPToolbarView)toolbarView
|
||||
{
|
||||
return _toolbarView;
|
||||
}
|
||||
|
||||
- (CPColor)toolbarLabelColor
|
||||
{
|
||||
return [CPColor whiteColor];
|
||||
}
|
||||
|
||||
- (CPColor)toolbarLabelShadowColor
|
||||
{
|
||||
return [CPColor blackColor];
|
||||
}
|
||||
|
||||
- (CGSize)toolbarOffset
|
||||
{
|
||||
return CGSizeMake(0.0, HUD_TITLEBAR_HEIGHT);
|
||||
}
|
||||
|
||||
- (void)tile
|
||||
{
|
||||
[super tile];
|
||||
|
||||
var theWindow = [self window],
|
||||
bounds = [self bounds],
|
||||
width = CGRectGetWidth(bounds);
|
||||
|
||||
[_titleField setFrame:CGRectMake(20.0, 3.0, width - 40.0, CGRectGetHeight([_titleField frame]))];
|
||||
|
||||
var maxY = [self toolbarMaxY];
|
||||
|
||||
[[theWindow contentView] setFrameOrigin:CGPointMake(0.0, maxY, width, CGRectGetHeight(bounds) - maxY)];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
* _CPStandardWindowView.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 "_CPWindowView.j"
|
||||
|
||||
var GRADIENT_HEIGHT = 41.0;
|
||||
|
||||
var _CPTexturedWindowHeadGradientColor = nil,
|
||||
_CPTexturedWindowHeadSolidColor = nil;
|
||||
|
||||
@implementation _CPTexturedWindowHeadView : CPView
|
||||
{
|
||||
CPView _gradientView;
|
||||
CPView _solidView;
|
||||
CPView _dividerView;
|
||||
}
|
||||
|
||||
+ (CPColor)gradientColor
|
||||
{
|
||||
if (!_CPTexturedWindowHeadGradientColor)
|
||||
{
|
||||
var bundle = [CPBundle bundleForClass:[_CPWindowView class]];
|
||||
|
||||
_CPTexturedWindowHeadGradientColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/Standard/CPWindowStandardTop0.png"] size:CGSizeMake(6.0, 41.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/Standard/CPWindowStandardTop1.png"] size:CGSizeMake(1.0, 41.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/Standard/CPWindowStandardTop2.png"] size:CGSizeMake(6.0, 41.0)]
|
||||
]
|
||||
isVertical:NO
|
||||
]];
|
||||
}
|
||||
|
||||
return _CPTexturedWindowHeadGradientColor;
|
||||
}
|
||||
|
||||
+ (CPColor)solidColor
|
||||
{
|
||||
if (!_CPTexturedWindowHeadSolidColor)
|
||||
_CPTexturedWindowHeadSolidColor = [CPColor colorWithCalibratedRed:182.0 / 255.0 green:182.0 / 255.0 blue:182.0 / 255.0 alpha:1.0];
|
||||
|
||||
return _CPTexturedWindowHeadSolidColor;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
if (self)
|
||||
{
|
||||
var theClass = [self class],
|
||||
bounds = [self bounds];
|
||||
|
||||
_gradientView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(bounds), GRADIENT_HEIGHT)];
|
||||
[_gradientView setBackgroundColor:[theClass gradientColor]];
|
||||
|
||||
[self addSubview:_gradientView];
|
||||
|
||||
_solidView = [[CPView alloc] initWithFrame:CGRectMake(0.0, GRADIENT_HEIGHT, CGRectGetWidth(bounds), CGRectGetHeight(bounds) - GRADIENT_HEIGHT)];
|
||||
[_solidView setBackgroundColor:[theClass solidColor]];
|
||||
|
||||
[self addSubview:_solidView];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)resizeSubviewsWithOldSize:(CGSize)aSize
|
||||
{
|
||||
var bounds = [self bounds];
|
||||
|
||||
[_gradientView setFrameSize:CGSizeMake(CGRectGetWidth(bounds), GRADIENT_HEIGHT)];
|
||||
[_solidView setFrameSize:CGSizeMake(CGRectGetWidth(bounds), CGRectGetHeight(bounds) - GRADIENT_HEIGHT)];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var _CPStandardWindowViewBodyBackgroundColor = nil,
|
||||
_CPStandardWindowViewDividerBackgroundColor = nil,
|
||||
_CPStandardWindowViewTitleBackgroundColor = nil,
|
||||
_CPStandardWindowViewCloseButtonImage = nil,
|
||||
_CPStandardWindowViewCloseButtonHighlightedImage = nil;
|
||||
|
||||
var STANDARD_GRADIENT_HEIGHT = 41.0;
|
||||
STANDARD_TITLEBAR_HEIGHT = 25.0;
|
||||
|
||||
@implementation _CPStandardWindowView : _CPWindowView
|
||||
{
|
||||
_CPTexturedWindowHeadView _headView;
|
||||
CPView _dividerView;
|
||||
CPView _bodyView;
|
||||
CPView _toolbarView;
|
||||
|
||||
CPTextField _titleField;
|
||||
CPButton _closeButton;
|
||||
}
|
||||
|
||||
+ (CPColor)bodyBackgroundColor
|
||||
{
|
||||
if (!_CPStandardWindowViewBodyBackgroundColor)
|
||||
_CPStandardWindowViewBodyBackgroundColor = [CPColor colorWithWhite:0.96 alpha:1.0];
|
||||
|
||||
return _CPStandardWindowViewBodyBackgroundColor;
|
||||
}
|
||||
|
||||
+ (CPColor)dividerBackgroundColor
|
||||
{
|
||||
if (!_CPStandardWindowViewDividerBackgroundColor)
|
||||
_CPStandardWindowViewDividerBackgroundColor = [CPColor colorWithCalibratedRed:125.0 / 255.0 green:125.0 / 255.0 blue:125.0 / 255.0 alpha:1.0];
|
||||
|
||||
return _CPStandardWindowViewDividerBackgroundColor;
|
||||
}
|
||||
|
||||
+ (CPColor)titleColor
|
||||
{
|
||||
if (!_CPStandardWindowViewTitleBackgroundColor)
|
||||
_CPStandardWindowViewTitleBackgroundColor = [CPColor colorWithCalibratedRed:44.0 / 255.0 green:44.0 / 255.0 blue:44.0 / 255.0 alpha:1.0];
|
||||
|
||||
return _CPStandardWindowViewTitleBackgroundColor;
|
||||
}
|
||||
|
||||
+ (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
{
|
||||
var contentRect = CGRectMakeCopy(aFrameRect),
|
||||
titleBarHeight = [self titleBarHeight] + 1.0;
|
||||
|
||||
contentRect.origin.y += titleBarHeight;
|
||||
contentRect.size.height -= titleBarHeight;
|
||||
|
||||
return contentRect;
|
||||
}
|
||||
|
||||
+ (CGRect)frameRectForContentRect:(CGRect)aContentRect
|
||||
{
|
||||
var frameRect = CGRectMakeCopy(aContentRect),
|
||||
titleBarHeight = [self titleBarHeight] + 1.0;
|
||||
|
||||
frameRect.origin.y -= titleBarHeight;
|
||||
frameRect.size.height += titleBarHeight;
|
||||
|
||||
return frameRect;
|
||||
}
|
||||
|
||||
+ (float)titleBarHeight
|
||||
{
|
||||
return STANDARD_TITLEBAR_HEIGHT;
|
||||
}
|
||||
|
||||
- (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
{
|
||||
var contentRect = [[self class] contentRectForFrameRect:aFrameRect],
|
||||
theToolbar = [[self window] toolbar];
|
||||
|
||||
if ([theToolbar isVisible])
|
||||
{
|
||||
toolbarHeight = CGRectGetHeight([[theToolbar _toolbarView] frame]);
|
||||
|
||||
contentRect.origin.y += toolbarHeight;
|
||||
contentRect.size.height -= toolbarHeight;
|
||||
}
|
||||
|
||||
return contentRect;
|
||||
}
|
||||
|
||||
- (CGRect)frameRectForContentRect:(CGRect)aContentRect
|
||||
{
|
||||
var frameRect = [[self class] frameRectForContentRect:aContentRect],
|
||||
theToolbar = [[self window] toolbar];
|
||||
|
||||
if ([theToolbar isVisible])
|
||||
{
|
||||
toolbarHeight = CGRectGetHeight([[theToolbar _toolbarView] frame]);
|
||||
|
||||
frameRect.origin.y -= toolbarHeight;
|
||||
frameRect.size.height += toolbarHeight;
|
||||
}
|
||||
|
||||
return frameRect;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CPRect)aFrame styleMask:(unsigned)aStyleMask
|
||||
{
|
||||
self = [super initWithFrame:aFrame styleMask:aStyleMask];
|
||||
|
||||
if (self)
|
||||
{
|
||||
var theClass = [self class],
|
||||
bounds = [self bounds];
|
||||
|
||||
_headView = [[_CPTexturedWindowHeadView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(bounds), [[self class] titleBarHeight])];
|
||||
|
||||
[_headView setAutoresizingMask:CPViewWidthSizable];;
|
||||
[_headView setHitTests:NO];
|
||||
|
||||
[self addSubview:_headView];
|
||||
|
||||
_dividerView = [[CPView alloc] initWithFrame:CGRectMake(0.0, CGRectGetMaxY([_headView frame]), CGRectGetWidth(bounds), 1.0)];
|
||||
|
||||
[_dividerView setAutoresizingMask:CPViewWidthSizable];
|
||||
[_dividerView setBackgroundColor:[theClass dividerBackgroundColor]];
|
||||
[_dividerView setHitTests:NO];
|
||||
|
||||
[self addSubview:_dividerView];
|
||||
|
||||
var y = CGRectGetMaxY([_dividerView frame]);
|
||||
|
||||
_bodyView = [[CPView alloc] initWithFrame:CGRectMake(0.0, y, CGRectGetWidth(bounds), CGRectGetHeight(bounds) - y)];
|
||||
|
||||
[_bodyView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
[_bodyView setBackgroundColor:[theClass bodyBackgroundColor]];
|
||||
[_bodyView setHitTests:NO];
|
||||
|
||||
[self addSubview:_bodyView];
|
||||
|
||||
[self setResizeIndicatorOffset:CGSizeMake(2.0, 2.0)];
|
||||
|
||||
_titleField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[_titleField setFont:[CPFont boldSystemFontOfSize:12.0]];
|
||||
[_titleField setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
// FIXME: Make this to CPLineBreakByTruncatingMiddle once it's implemented.
|
||||
[_titleField setLineBreakMode:CPLineBreakByTruncatingTail];
|
||||
[_titleField setAlignment:CPCenterTextAlignment];
|
||||
[_titleField setTextShadowColor:[CPColor whiteColor]];
|
||||
[_titleField setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||
|
||||
[_titleField setStringValue:@"Untitled"];
|
||||
[_titleField sizeToFit];
|
||||
[_titleField setAutoresizingMask:CPViewWidthSizable];
|
||||
[_titleField setStringValue:@""];
|
||||
|
||||
[self addSubview:_titleField];
|
||||
|
||||
if (_styleMask & CPClosableWindowMask)
|
||||
{
|
||||
if (!_CPStandardWindowViewCloseButtonImage)
|
||||
{
|
||||
var bundle = [CPBundle bundleForClass:[CPWindow class]];
|
||||
|
||||
_CPStandardWindowViewCloseButtonImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/Standard/CPWindowStandardCloseButton.png"] size:CGSizeMake(16.0, 16.0)];
|
||||
_CPStandardWindowViewCloseButtonHighlightedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/Standard/CPWindowStandardCloseButtonHighlighted.png"] size:CGSizeMake(16.0, 16.0)];
|
||||
}
|
||||
|
||||
_closeButton = [[CPButton alloc] initWithFrame:CGRectMake(8.0, 7.0, 16.0, 16.0)];
|
||||
|
||||
[_closeButton setBordered:NO];
|
||||
|
||||
[_closeButton setImage:_CPStandardWindowViewCloseButtonImage];
|
||||
[_closeButton setAlternateImage:_CPStandardWindowViewCloseButtonHighlightedImage];
|
||||
|
||||
[self addSubview:_closeButton];
|
||||
}
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidMoveToWindow
|
||||
{
|
||||
[_closeButton setTarget:[self window]];
|
||||
[_closeButton setAction:@selector(performClose:)];
|
||||
}
|
||||
|
||||
- (CGSize)toolbarOffset
|
||||
{
|
||||
return CGSizeMake(0.0, [[self class] titleBarHeight]);
|
||||
}
|
||||
|
||||
- (void)tile
|
||||
{
|
||||
[super tile];
|
||||
|
||||
var theWindow = [self window],
|
||||
bounds = [self bounds],
|
||||
width = CGRectGetWidth(bounds);
|
||||
|
||||
[_headView setFrameSize:CGSizeMake(width, [self toolbarMaxY])];
|
||||
[_dividerView setFrame:CGRectMake(0.0, CGRectGetMaxY([_headView frame]), width, 1.0)];
|
||||
|
||||
var dividerMaxY = CGRectGetMaxY([_dividerView frame]);
|
||||
|
||||
[_bodyView setFrame:CGRectMake(0.0, dividerMaxY, width, CGRectGetHeight(bounds) - dividerMaxY)];
|
||||
|
||||
[_titleField setFrame:CGRectMake(10.0, 3.0, width - 20.0, CGRectGetHeight([_titleField frame]))];
|
||||
|
||||
[[theWindow contentView] setFrameOrigin:CGPointMake(0.0, CGRectGetMaxY([_dividerView frame]))];
|
||||
}
|
||||
/*
|
||||
- (void)setAnimatingToolbar:(BOOL)isAnimatingToolbar
|
||||
{
|
||||
[super setAnimatingToolbar:isAnimatingToolbar];
|
||||
|
||||
if ([self isAnimatingToolbar])
|
||||
{
|
||||
[[self toolbarView] setAutoresizingMask:CPViewHeightSizable];
|
||||
|
||||
[_headView setAutoresizingMask:CPViewHeightSizable];
|
||||
[_dividerView setAutoresizingMask:CPViewMinYMargin];
|
||||
[_bodyView setAutoresizingMask:CPViewMinYMargin];
|
||||
|
||||
[[[self window] contentView] setAutoresizingMask:CPViewNotSizable];
|
||||
}
|
||||
else
|
||||
{
|
||||
[[self toolbarView] setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
[_headView setAutoresizingMask:CPViewWidthSizable];
|
||||
[_dividerView setAutoresizingMask:CPViewWidthSizable];
|
||||
[_bodyView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
[[[self window] contentView] setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
}
|
||||
}
|
||||
*/
|
||||
- (void)setTitle:(CPString)aTitle
|
||||
{
|
||||
[_titleField setStringValue:aTitle];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
if (CGRectContainsPoint([_headView frame], [self convertPoint:[anEvent locationInWindow] fromView:nil]))
|
||||
return [self trackMoveWithEvent:anEvent];
|
||||
|
||||
[super mouseDown:anEvent];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
* _CPWindowView.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 "CPView.j"
|
||||
@import "CPImageView.j"
|
||||
|
||||
#include "../CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
var _CPWindowViewResizeIndicatorImage = nil;
|
||||
|
||||
@implementation _CPWindowView : CPView
|
||||
{
|
||||
unsigned _styleMask;
|
||||
|
||||
CPImageView _resizeIndicator;
|
||||
CGSize _resizeIndicatorOffset;
|
||||
|
||||
CPView _toolbarView;
|
||||
// BOOL _isAnimatingToolbar;
|
||||
|
||||
CGRect _resizeFrame;
|
||||
CGPoint _mouseDraggedPoint;
|
||||
|
||||
CGRect _cachedScreenFrame;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self != [_CPWindowView class])
|
||||
return;
|
||||
|
||||
_CPWindowViewResizeIndicatorImage = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPWindow class]] pathForResource:@"_CPWindowView/_CPWindowViewResizeIndicator.png"] size:CGSizeMake(12.0, 12.0)];
|
||||
}
|
||||
|
||||
+ (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
{
|
||||
return CGRectMakeCopy(aFrameRect);
|
||||
}
|
||||
|
||||
+ (CGRect)frameRectForContentRect:(CGRect)aContentRect
|
||||
{
|
||||
return CGRectMakeCopy(aContentRect);
|
||||
}
|
||||
|
||||
- (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
{
|
||||
return [[self class] contentRectForFrameRect:aFrameRect];
|
||||
}
|
||||
|
||||
- (CGRect)frameRectForContentRect:(CGRect)aContentRect
|
||||
{
|
||||
return [[self class] frameRectForContentRect:aContentRect];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CPRect)aFrame styleMask:(unsigned)aStyleMask
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_styleMask = aStyleMask;
|
||||
_resizeIndicatorOffset = CGSizeMake(0.0, 0.0);
|
||||
_toolbarOffset = CGSizeMake(0.0, 0.0);
|
||||
|
||||
[self setShowsResizeIndicator:!(_styleMask & CPBorderlessBridgeWindowMask) && (_styleMask & CPResizableWindowMask)];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setTitle:(CPString)aTitle
|
||||
{
|
||||
}
|
||||
|
||||
- (BOOL)acceptsFirstMouse:(CPEvent)anEvent
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
var theWindow = [self window];
|
||||
|
||||
if ((_styleMask & CPResizableWindowMask) && _resizeIndicator)
|
||||
{
|
||||
// FIXME: This should be better
|
||||
var frame = [_resizeIndicator frame];
|
||||
|
||||
if (CGRectContainsPoint(frame, [self convertPoint:[anEvent locationInWindow] fromView:nil]))
|
||||
return [self trackResizeWithEvent:anEvent];
|
||||
}
|
||||
|
||||
if ([theWindow isMovableByWindowBackground])
|
||||
[self trackMoveWithEvent:anEvent];
|
||||
|
||||
else
|
||||
[super mouseDown:anEvent];
|
||||
}
|
||||
|
||||
- (void)trackResizeWithEvent:(CPEvent)anEvent
|
||||
{
|
||||
var location = [anEvent locationInWindow],
|
||||
type = [anEvent type];
|
||||
|
||||
if (type === CPLeftMouseUp)
|
||||
return;
|
||||
|
||||
var theWindow = [self window];
|
||||
|
||||
if (type === CPLeftMouseDown)
|
||||
{
|
||||
var frame = [theWindow frame];
|
||||
|
||||
_resizeFrame = CGRectMake(location.x, location.y, CGRectGetWidth(frame), CGRectGetHeight(frame));
|
||||
}
|
||||
|
||||
else if (type === CPLeftMouseDragged)
|
||||
[theWindow setFrameSize:CGSizeMake(CGRectGetWidth(_resizeFrame) + location.x - CGRectGetMinX(_resizeFrame), CGRectGetHeight(_resizeFrame) + location.y - CGRectGetMinY(_resizeFrame))];
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackResizeWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
}
|
||||
|
||||
- (CGPoint)_pointWithinScreenFrame:(CGPoint)aPoint
|
||||
{
|
||||
var visibleFrame = _cachedScreenFrame;
|
||||
|
||||
if (!visibleFrame)
|
||||
visibleFrame = [[CPDOMWindowBridge sharedDOMWindowBridge] visibleFrame];
|
||||
|
||||
var restrictedPoint = CGPointMake(0, 0);
|
||||
|
||||
restrictedPoint.x = MIN(MAX(aPoint.x, -_frame.size.width + 4.0), CGRectGetMaxX(visibleFrame) - 4.0);
|
||||
restrictedPoint.y = MIN(MAX(aPoint.y, 0.0), CGRectGetMaxY(visibleFrame) - 8.0);
|
||||
|
||||
return restrictedPoint;
|
||||
}
|
||||
|
||||
- (void)trackMoveWithEvent:(CPEvent)anEvent
|
||||
{
|
||||
var type = [anEvent type];
|
||||
|
||||
if (type === CPLeftMouseUp)
|
||||
{
|
||||
_cachedScreenFrame = nil;
|
||||
return;
|
||||
}
|
||||
else if (type === CPLeftMouseDown)
|
||||
{
|
||||
_mouseDraggedPoint = [[self window] convertBaseToBridge:[anEvent locationInWindow]];
|
||||
_cachedScreenFrame = [[CPDOMWindowBridge sharedDOMWindowBridge] visibleFrame];
|
||||
}
|
||||
else if (type === CPLeftMouseDragged)
|
||||
{
|
||||
var theWindow = [self window],
|
||||
frame = [theWindow frame],
|
||||
location = [theWindow convertBaseToBridge:[anEvent locationInWindow]],
|
||||
origin = [self _pointWithinScreenFrame:CGPointMake(_CGRectGetMinX(frame) + (location.x - _mouseDraggedPoint.x),
|
||||
_CGRectGetMinY(frame) + (location.y - _mouseDraggedPoint.y))];
|
||||
|
||||
[theWindow setFrameOrigin:origin];
|
||||
|
||||
_mouseDraggedPoint = [self _pointWithinScreenFrame:location];
|
||||
}
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackMoveWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
}
|
||||
|
||||
- (void)setShowsResizeIndicator:(BOOL)shouldShowResizeIndicator
|
||||
{
|
||||
if (shouldShowResizeIndicator)
|
||||
{
|
||||
var size = [_CPWindowViewResizeIndicatorImage size],
|
||||
boundsSize = [self frame].size;
|
||||
|
||||
_resizeIndicator = [[CPImageView alloc] initWithFrame:CGRectMake(boundsSize.width - size.width - _resizeIndicatorOffset.width, boundsSize.height - size.height - _resizeIndicatorOffset.height, size.width, size.height)];
|
||||
|
||||
[_resizeIndicator setImage:_CPWindowViewResizeIndicatorImage];
|
||||
[_resizeIndicator setAutoresizingMask:CPViewMinXMargin | CPViewMinYMargin];
|
||||
|
||||
[self addSubview:_resizeIndicator];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_resizeIndicator removeFromSuperview];
|
||||
|
||||
_resizeIndicator = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (CPImage)showsResizeIndicator
|
||||
{
|
||||
return _resizeIndicator !== nil;
|
||||
}
|
||||
|
||||
- (void)setResizeIndicatorOffset:(CGSize)anOffset
|
||||
{
|
||||
if (CGSizeEqualToSize(_resizeIndicatorOffset, anOffset))
|
||||
return;
|
||||
|
||||
_resizeIndicatorOffset = anOffset;
|
||||
|
||||
if (!_resizeIndicator)
|
||||
return;
|
||||
|
||||
var size = [_resizeIndicator frame].size,
|
||||
boundsSize = [self frame].size;
|
||||
|
||||
[_resizeIndicator setFrameOrigin:CGPointMake(boundsSize.width - size.width - anOffset.width, boundsSize.height - size.height - anOffset.height)];
|
||||
}
|
||||
|
||||
- (CGSize)resizeIndicatorOffset
|
||||
{
|
||||
return _resizeIndicatorOffset;
|
||||
}
|
||||
|
||||
- (void)windowDidChangeDocumentEdited
|
||||
{
|
||||
}
|
||||
|
||||
- (void)windowDidChangeDocumentSaving
|
||||
{
|
||||
}
|
||||
|
||||
- (BOOL)showsToolbar
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CGSize)toolbarOffset
|
||||
{
|
||||
return CGSizeMakeZero();
|
||||
}
|
||||
|
||||
- (CPColor)toolbarLabelColor
|
||||
{
|
||||
return [CPColor blackColor];
|
||||
}
|
||||
|
||||
- (float)toolbarMaxY
|
||||
{
|
||||
if (!_toolbarView || [_toolbarView isHidden])
|
||||
return [self toolbarOffset].height;
|
||||
|
||||
return CGRectGetMaxY([_toolbarView frame]);
|
||||
}
|
||||
|
||||
- (_CPToolbarView)toolbarView
|
||||
{
|
||||
return _toolbarView;
|
||||
}
|
||||
|
||||
- (void)tile
|
||||
{
|
||||
var theWindow = [self window],
|
||||
bounds = [self bounds],
|
||||
width = CGRectGetWidth(bounds);
|
||||
|
||||
if ([[theWindow toolbar] isVisible])
|
||||
{
|
||||
var toolbarView = [self toolbarView],
|
||||
toolbarOffset = [self toolbarOffset];
|
||||
|
||||
[toolbarView setFrame:CGRectMake(toolbarOffset.width, toolbarOffset.height, width, CGRectGetHeight([toolbarView frame]))];
|
||||
}
|
||||
|
||||
if ([self showsResizeIndicator])
|
||||
{
|
||||
var size = [_resizeIndicator frame].size,
|
||||
boundsSize = [self bounds].size;
|
||||
|
||||
[_resizeIndicator setFrameOrigin:CGPointMake(boundsSize.width - size.width - _resizeIndicatorOffset.width, boundsSize.height - size.height - _resizeIndicatorOffset.height)];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)noteToolbarChanged
|
||||
{
|
||||
var theWindow = [self window],
|
||||
toolbar = [theWindow toolbar],
|
||||
toolbarView = [toolbar _toolbarView];
|
||||
|
||||
if (_toolbarView !== toolbarView)
|
||||
{
|
||||
[_toolbarView removeFromSuperview];
|
||||
|
||||
if (toolbarView)
|
||||
{
|
||||
[toolbarView removeFromSuperview];
|
||||
[toolbarView setLabelColor:[self toolbarLabelColor]];
|
||||
|
||||
if ([self respondsToSelector:@selector(toolbarLabelShadowColor)])
|
||||
[toolbarView setLabelShadowColor:[self toolbarLabelShadowColor]];
|
||||
|
||||
[self addSubview:toolbarView];
|
||||
}
|
||||
|
||||
_toolbarView = toolbarView;
|
||||
}
|
||||
|
||||
[toolbarView setHidden:![self showsToolbar] || ![toolbar isVisible]];
|
||||
|
||||
if (theWindow)
|
||||
{
|
||||
var contentRect = [self convertRect:[[theWindow contentView] frame] toView:nil];
|
||||
|
||||
contentRect.origin = [theWindow convertBaseToBridge:contentRect.origin];
|
||||
|
||||
[self setAutoresizesSubviews:NO];
|
||||
[theWindow setFrame:[theWindow frameRectForContentRect:contentRect]];
|
||||
[self setAutoresizesSubviews:YES];
|
||||
}
|
||||
|
||||
[self tile];
|
||||
}
|
||||
/*
|
||||
- (void)setAnimatingToolbar:(BOOL)isAnimatingToolbar
|
||||
{
|
||||
_isAnimatingToolbar = isAnimatingToolbar;
|
||||
}
|
||||
|
||||
- (BOOL)isAnimatingToolbar
|
||||
{
|
||||
return _isAnimatingToolbar;
|
||||
}
|
||||
*/
|
||||
|
||||
- (void)didAddSubview:(CPView)aView
|
||||
{
|
||||
if (!_resizeIndicator || aView === _resizeIndicator)
|
||||
return;
|
||||
|
||||
[self addSubview:_resizeIndicator];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -30,7 +30,9 @@
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
|
||||
/*! @class CPWindowController
|
||||
/*!
|
||||
@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
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
@import <Foundation/CPURLRequest.j>
|
||||
|
||||
@import "_CPCibCustomObject.j"
|
||||
@import "_CPCibCustomResource.j"
|
||||
@import "_CPCibCustomView.j"
|
||||
@import "_CPCibKeyedUnarchiver.j"
|
||||
@import "_CPCibObjectData.j"
|
||||
@@ -32,98 +33,149 @@
|
||||
|
||||
|
||||
CPCibOwner = @"CPCibOwner",
|
||||
CPCibTopLevelObjects = @"CPCibTopLevelObjects";
|
||||
CPCibTopLevelObjects = @"CPCibTopLevelObjects",
|
||||
CPCibReplacementClasses = @"CPCibReplacementClasses";
|
||||
|
||||
var CPCibObjectDataKey = @"CPCibObjectDataKey";
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
*/
|
||||
|
||||
@implementation CPCib : CPObject
|
||||
{
|
||||
CPData _data;
|
||||
CPData _data;
|
||||
CPBundle _bundle;
|
||||
BOOL _awakenCustomResources;
|
||||
|
||||
id _loadDelegate;
|
||||
}
|
||||
|
||||
- (id)initWithContentsOfURL:(CPURL)aURL
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_data = [CPURLConnection sendSynchronousRequest:[CPURLRequest requestWithURL:aURL] returningResponse:nil error:nil];
|
||||
|
||||
_awakenCustomResources = YES;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithContentsOfURL:(CPURL)aURL loadDelegate:(id)aLoadDelegate
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
[CPURLConnection connectionWithRequest:[CPURLRequest requestWithURL:aURL] delegate:self];
|
||||
|
||||
_awakenCustomResources = YES;
|
||||
|
||||
_loadDelegate = aLoadDelegate;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithCibNamed:(CPString)aName bundle:(CPBundle)aBundle loadDelegate:(id)aLoadDelegate
|
||||
{
|
||||
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] loadDelegate:aLoadDelegate];
|
||||
|
||||
if (self)
|
||||
_bundle = aBundle;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_setAwakenCustomResources:(BOOL)shouldAwakenCustomResources
|
||||
{
|
||||
_awakenCustomResources = shouldAwakenCustomResources;
|
||||
}
|
||||
|
||||
- (BOOL)_awakenCustomResources
|
||||
{
|
||||
return _awakenCustomResources;
|
||||
}
|
||||
|
||||
- (BOOL)instantiateCibWithExternalNameTable:(CPDictionary)anExternalNameTable
|
||||
{
|
||||
var unarchiver = [[_CPCibKeyedUnarchiver alloc] initForReadingWithData:_data],
|
||||
objectData = [unarchiver decodeObjectForKey:CPCibObjectDataKey];
|
||||
var bundle = _bundle,
|
||||
owner = [anExternalNameTable objectForKey:CPCibOwner];
|
||||
|
||||
if (!bundle && owner)
|
||||
bundle = [CPBundle bundleForClass:[owner class]];
|
||||
|
||||
var unarchiver = [[_CPCibKeyedUnarchiver alloc] initForReadingWithData:_data bundle:bundle awakenCustomResources:_awakenCustomResources],
|
||||
replacementClasses = [anExternalNameTable objectForKey:CPCibReplacementClasses];
|
||||
|
||||
if (replacementClasses)
|
||||
{
|
||||
var key = nil,
|
||||
keyEnumerator = [replacementClasses keyEnumerator];
|
||||
|
||||
while (key = [keyEnumerator nextObject])
|
||||
[unarchiver setClass:[replacementClasses objectForKey:key] forClassName:key];
|
||||
}
|
||||
|
||||
var objectData = [unarchiver decodeObjectForKey:CPCibObjectDataKey];
|
||||
|
||||
if (!objectData || ![objectData isKindOfClass:[_CPCibObjectData class]])
|
||||
return NO;
|
||||
|
||||
[objectData establishConnectionsWithExternalNameTable:anExternalNameTable];
|
||||
|
||||
var owner = [anExternalNameTable objectForKey:CPCibOwner],
|
||||
topLevelObjects = [anExternalNameTable objectForKey:CPCibTopLevelObjects];
|
||||
|
||||
|
||||
var topLevelObjects = [anExternalNameTable objectForKey:CPCibTopLevelObjects];
|
||||
|
||||
[objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects]
|
||||
[objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects];
|
||||
[objectData awakeWithOwner:owner topLevelObjects:topLevelObjects];
|
||||
|
||||
var menu;
|
||||
|
||||
if ((menu = [objectData mainMenu]) != nil)
|
||||
{
|
||||
[CPApp setMainMenu:menu];
|
||||
[CPMenu setMenuBarVisible:YES];
|
||||
}
|
||||
|
||||
/*
|
||||
// [objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects];
|
||||
// [objectData cibInstantiateWithOwner:owner topLevelObjects:topLevelObjects];
|
||||
// alert([objectData description]);
|
||||
// alert([unarchiver._archive description]);
|
||||
|
||||
NSMutableArray *t;
|
||||
NSEnumerator *e;
|
||||
id o;
|
||||
id owner;
|
||||
id rootObject;
|
||||
#if 0
|
||||
NSLog(@"instantiateCibWithExternalNameTable=%@", table);
|
||||
#endif
|
||||
if(![decoded isKindOfClass:[NSIBObjectData class]])
|
||||
return NO;
|
||||
owner=[table objectForKey:NSCibOwner];
|
||||
rootObject=[decoded rootObject];
|
||||
#if 0
|
||||
NSLog(@"establishConnections");
|
||||
#endif
|
||||
[decoded establishConnectionsWithExternalNameTable:table];
|
||||
#if 0
|
||||
NSLog(@"awakeFromCib %d objects", [decodedObjects count]);
|
||||
#endif
|
||||
#if 0
|
||||
NSLog(@"objects 2=%@", decodedObjects);
|
||||
#endif
|
||||
|
||||
// FIXME: shouldn't be accessing private variables.
|
||||
var objects = unarchiver._objects,
|
||||
count = [objects count];
|
||||
|
||||
// The order in which objects receive the awakeFromCib message is not guaranteed.
|
||||
while (count--)
|
||||
{
|
||||
var object = objects[count];
|
||||
|
||||
if ([object respondsToSelector:@selector(awakeFromCib)])
|
||||
[object awakeFromCib];
|
||||
}
|
||||
// Display Visible Windows.
|
||||
[objectData displayVisibleWindows];
|
||||
|
||||
// if ([owner respondsToSelector:@selector(awakeFromCib)])
|
||||
// [owner awakeFromCib];
|
||||
// Display visible windows.
|
||||
|
||||
return YES;*/
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)instantiateCibWithOwner:(id)anOwner topLevelObjects:(CPArray)topLevelObjects
|
||||
{
|
||||
[CPDictionary dictionaryWithObjectsAndKeys:anOwner, CPCibOwner, topLevelObjects, CPCibTopLevelObjects];
|
||||
return [self instantiate];
|
||||
return [self instantiateCibWithExternalNameTable:[CPDictionary dictionaryWithObjectsAndKeys:anOwner, CPCibOwner, topLevelObjects, CPCibTopLevelObjects]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPCib (CPURLConnectionDelegate)
|
||||
|
||||
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)data
|
||||
{
|
||||
_data = [CPData dataWithString:data];
|
||||
}
|
||||
|
||||
- (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError
|
||||
{
|
||||
alert("cib: connection failed.");
|
||||
|
||||
_loadDelegate = nil;
|
||||
}
|
||||
|
||||
- (void)connectionDidFinishLoading:(CPURLConnection)aConnection
|
||||
{
|
||||
if ([_loadDelegate respondsToSelector:@selector(cibDidFinishLoading:)])
|
||||
[_loadDelegate cibDidFinishLoading:self];
|
||||
|
||||
_loadDelegate = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* _CPCibLoading.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2008, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPBundle.j>
|
||||
@import <Foundation/CPDictionary.j>
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
|
||||
var CPCibOwner = @"CPCibOwner";
|
||||
|
||||
var LoadInfoForCib = {};
|
||||
|
||||
@implementation CPObject (CPCibLoading)
|
||||
|
||||
- (void)awakeFromCib
|
||||
{
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPBundle (CPCibLoading)
|
||||
|
||||
+ (void)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable loadDelegate:aDelegate
|
||||
{
|
||||
var cib = [[CPCib alloc] initWithContentsOfURL:anAbsolutePath loadDelegate:self];
|
||||
|
||||
LoadInfoForCib[[cib hash]] = { loadDelegate:aDelegate, externalNameTable:aNameTable };
|
||||
}
|
||||
|
||||
+ (void)loadCibNamed:(CPString)aName owner:(id)anOwner loadDelegate:(id)aDelegate
|
||||
{
|
||||
// Path is based solely on anOwner:
|
||||
var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle],
|
||||
path = [bundle pathForResource:aName];
|
||||
|
||||
[self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner] loadDelegate:aDelegate];
|
||||
}
|
||||
|
||||
- (void)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable loadDelegate:(id)aDelegate
|
||||
{
|
||||
var cib = [[CPCib alloc] initWithCibNamed:aFileName bundle:self loadDelegate:[self class]];
|
||||
|
||||
LoadInfoForCib[[cib hash]] = { loadDelegate:aDelegate, externalNameTable:aNameTable };
|
||||
}
|
||||
|
||||
+ (void)cibDidFinishLoading:(CPCib)aCib
|
||||
{
|
||||
var loadInfo = LoadInfoForCib[[aCib hash]];
|
||||
|
||||
delete LoadInfoForCib[[aCib hash]];
|
||||
|
||||
[aCib instantiateCibWithExternalNameTable:loadInfo.externalNameTable];
|
||||
|
||||
[loadInfo.loadDelegate cibDidFinishLoading:aCib];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -14,13 +14,17 @@ var _CPCibConnectorSourceKey = @"_CPCibConnectorSourceKey",
|
||||
CPString _label;
|
||||
}
|
||||
|
||||
- (void)replaceObject:(id)anObject withObject:(id)anotherObject
|
||||
- (void)replaceObjects:(JSObject)replacementObjects
|
||||
{
|
||||
if (_source == anObject)
|
||||
_source = anotherObject;
|
||||
|
||||
else if (_destination == anObject)
|
||||
_destination = anotherObject;
|
||||
var replacement = replacementObjects[[_source hash]];
|
||||
|
||||
if (replacement !== undefined)
|
||||
_source = replacement;
|
||||
|
||||
replacement = replacementObjects[[_destination hash]];
|
||||
|
||||
if (replacement !== undefined)
|
||||
_destination = replacement;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -36,10 +40,6 @@ var _CPCibConnectorSourceKey = @"_CPCibConnectorSourceKey",
|
||||
_source = [aCoder decodeObjectForKey:_CPCibConnectorSourceKey];
|
||||
_destination = [aCoder decodeObjectForKey:_CPCibConnectorDestinationKey];
|
||||
_label = [aCoder decodeObjectForKey:_CPCibConnectorLabelKey];
|
||||
|
||||
#if DEBUG
|
||||
CPLog("Connection from " + [_source description] + " to " + [_destination description] + " and label " + _label + " decoded.");
|
||||
#endif
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -60,11 +60,6 @@ var _CPCibConnectorSourceKey = @"_CPCibConnectorSourceKey",
|
||||
|
||||
- (void)establishConnection
|
||||
{
|
||||
#if DEBUG
|
||||
CPLog('[' + [_source description] + " setTarget: " + [_destination description] + ']');
|
||||
CPLog('[' + [_source description] + " setAction: " + _label + ']');
|
||||
#endif
|
||||
|
||||
var selectorName = _label;
|
||||
|
||||
if (![selectorName hasSuffix:@":"])
|
||||
@@ -102,10 +97,6 @@ var _CPCibConnectorSourceKey = @"_CPCibConnectorSourceKey",
|
||||
|
||||
- (void)establishConnection
|
||||
{
|
||||
#if DEBUG
|
||||
CPLog([_source description] + " setValue: " + [_destination description] + " forKey: " + _label);
|
||||
#endif
|
||||
|
||||
[_source setValue:_destination forKey:_label];
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,16 @@ var _CPCibCustomObjectClassName = @"_CPCibCustomObjectClassName";
|
||||
CPString _className;
|
||||
}
|
||||
|
||||
- (CPString)customClassName
|
||||
{
|
||||
return _className;
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
return [super description] + " (" + [self customClassName] + ')';
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPCibCustomObject (CPCoding)
|
||||
@@ -31,9 +41,14 @@ var _CPCibCustomObjectClassName = @"_CPCibCustomObjectClassName";
|
||||
- (id)_cibInstantiate
|
||||
{
|
||||
var theClass = CPClassFromString(_className);
|
||||
|
||||
|
||||
#if DEBUG
|
||||
if (!theClass)
|
||||
CPLog("Unknown class \"" + _className + "\" in cib file");
|
||||
#endif
|
||||
|
||||
if (theClass === [CPApplication class])
|
||||
return [CPApplication sharedApplication];
|
||||
|
||||
return [[theClass alloc] init];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* _CPCibCustomResource.j
|
||||
* AppKit
|
||||
*
|
||||
* Portions based on NSCustomResource.m (01/08/2009) in Cocotron (http://www.cocotron.org/)
|
||||
* Copyright (c) 2006-2007 Christopher J. W. Lloyd
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2009, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
|
||||
var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
|
||||
_CPCibCustomResourceResourceNameKey = @"_CPCibCustomResourceResourceNameKey",
|
||||
_CPCibCustomResourcePropertiesKey = @"_CPCibCustomResourcePropertiesKey";
|
||||
|
||||
@implementation _CPCibCustomResource : CPObject
|
||||
{
|
||||
CPString _className;
|
||||
CPString _resourceName;
|
||||
CPDictionary _properties;
|
||||
}
|
||||
|
||||
+ (id)imageResourceWithName:(CPString)aResourceName size:(CGSize)aSize
|
||||
{
|
||||
return [[self alloc] initWithClassName:@"CPImage" resourceName:aResourceName properties:[CPDictionary dictionaryWithObject:aSize forKey:@"size"]];
|
||||
}
|
||||
|
||||
- (id)initWithClassName:(CPString)aClassName resourceName:(CPString)aResourceName properties:(CPDictionary)properties
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_className = aClassName;
|
||||
_resourceName = aResourceName;
|
||||
_properties = properties;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_className = [aCoder decodeObjectForKey:_CPCibCustomResourceClassNameKey];
|
||||
_resourceName = [aCoder decodeObjectForKey:_CPCibCustomResourceResourceNameKey];
|
||||
_properties = [aCoder decodeObjectForKey:_CPCibCustomResourcePropertiesKey];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeObject:_className forKey:_CPCibCustomResourceClassNameKey];
|
||||
[aCoder encodeObject:_resourceName forKey:_CPCibCustomResourceResourceNameKey];
|
||||
[aCoder encodeObject:_properties forKey:_CPCibCustomResourcePropertiesKey];
|
||||
}
|
||||
|
||||
- (id)awakeAfterUsingCoder:(CPCoder)aCoder
|
||||
{
|
||||
if ([aCoder respondsToSelector:@selector(bundle)] &&
|
||||
(![aCoder respondsToSelector:@selector(awakenCustomResources)] || [aCoder awakenCustomResources]))
|
||||
if (_className === @"CPImage")
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[aCoder bundle] pathForResource:_resourceName] size:[_properties objectForKey:@"size"]];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPCibCustomResource (CPImage)
|
||||
|
||||
- (CPString)filename
|
||||
{
|
||||
return [[CPBundle mainBundle] pathForResource:_resourceName];
|
||||
}
|
||||
|
||||
- (CGSize)size
|
||||
{
|
||||
return [_properties objectForKey:@"size"];
|
||||
}
|
||||
|
||||
- (BOOL)isThreePartImage
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isNinePartImage
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -30,6 +30,11 @@
|
||||
CPString _className;
|
||||
}
|
||||
|
||||
- (CPString)customClassName
|
||||
{
|
||||
return _className;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var _CPCibCustomViewClassNameKey = @"_CPCibCustomViewClassNameKey";
|
||||
@@ -42,7 +47,7 @@ var _CPCibCustomViewClassNameKey = @"_CPCibCustomViewClassNameKey";
|
||||
|
||||
if (self)
|
||||
_className = [aCoder decodeObjectForKey:_CPCibCustomViewClassNameKey];
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -53,6 +58,18 @@ var _CPCibCustomViewClassNameKey = @"_CPCibCustomViewClassNameKey";
|
||||
[aCoder encodeObject:_className forKey:_CPCibCustomViewClassNameKey];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
var bounds = [self bounds],
|
||||
context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
CGContextSetLineWidth(context, 1.0);
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithCalibratedRed:169.0 / 255.0 green:173.0 / 255.0 blue:178.0 / 255.0 alpha:1.0]);
|
||||
CGContextStrokeRect(context, CGRectInset(CGRectIntegral(bounds), 0.5, 0.5));
|
||||
CGContextSetFillColor(context, [CPColor colorWithCalibratedRed:224.0 / 255.0 green:236.0 / 255.0 blue:250.0 / 255.0 alpha:1.0]);
|
||||
CGContextFillRect(context, CGRectInset(bounds, 2.0, 2.0));
|
||||
}
|
||||
|
||||
- (id)_cibInstantiate
|
||||
{
|
||||
var theClass = CPClassFromString(_className);
|
||||
@@ -61,10 +78,19 @@ var _CPCibCustomViewClassNameKey = @"_CPCibCustomViewClassNameKey";
|
||||
// FIXME: Should we instead throw an exception?
|
||||
if (!theClass)
|
||||
{
|
||||
#if DEBUG
|
||||
CPLog("Unknown class \"" + _className + "\" in cib file, using CPView instead.");
|
||||
|
||||
#endif
|
||||
theClass = [CPView class];
|
||||
}
|
||||
|
||||
// Hey this is us!
|
||||
if (theClass === [self class])
|
||||
{
|
||||
_className = @"CPView";
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
var view = [[theClass alloc] initWithFrame:[self frame]];
|
||||
|
||||
@@ -88,7 +114,9 @@ var _CPCibCustomViewClassNameKey = @"_CPCibCustomViewClassNameKey";
|
||||
[view setHitTests:[self hitTests]];
|
||||
[view setHidden:[self isHidden]];
|
||||
[view setAlphaValue:[self alphaValue]];
|
||||
|
||||
|
||||
[_superview replaceSubview:self with:view];
|
||||
|
||||
[view setBackgroundColor:[self backgroundColor]];
|
||||
}
|
||||
|
||||
|
||||
@@ -4,24 +4,33 @@
|
||||
|
||||
@implementation _CPCibKeyedUnarchiver : CPKeyedUnarchiver
|
||||
{
|
||||
CPBundle _bundle;
|
||||
BOOL _awakenCustomResources;
|
||||
}
|
||||
|
||||
- (id)initForReadingWithData:(CPData)data
|
||||
- (id)initForReadingWithData:(CPData)data bundle:(CPBundle)aBundle awakenCustomResources:(BOOL)shouldAwakenCustomResources
|
||||
{
|
||||
self = [super initForReadingWithData:data];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_bundle = aBundle;
|
||||
_awakenCustomResources = shouldAwakenCustomResources;
|
||||
|
||||
[self setDelegate:self];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)unarchiver:(CPKeyedUnarchiver)aKeyedUnarchiver didDecodeObject:(id)anObject
|
||||
- (CPBundle)bundle
|
||||
{
|
||||
if ([anObject respondsToSelector:@selector(_cibInstantiate)])
|
||||
return [anObject _cibInstantiate];
|
||||
return _bundle;
|
||||
}
|
||||
|
||||
return anObject;
|
||||
- (BOOL)awakenCustomResources
|
||||
{
|
||||
return _awakenCustomResources;
|
||||
}
|
||||
|
||||
- (void)replaceObjectAtUID:(int)aUID withObject:(id)anObject
|
||||
@@ -34,4 +43,4 @@
|
||||
return _objects[aUID];
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* _CPCibLoading.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2008, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPBundle.j>
|
||||
@import <Foundation/CPDictionary.j>
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
|
||||
var CPCibOwner = @"CPCibOwner";
|
||||
|
||||
@implementation CPObject (CPCibLoading)
|
||||
|
||||
-(void)awakeFromCib
|
||||
{
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPBundle (CPCibLoading)
|
||||
|
||||
+ (BOOL)loadCibFile:(CPString)aPath externalNameTable:(CPDictionary)aNameTable
|
||||
{
|
||||
return [[[CPCib alloc] initWithContentsOfFile:aPath] instantiateCibWithExternalNameTable:aNameTable];
|
||||
}
|
||||
|
||||
+ (BOOL)loadCibNamed:(CPString)aName owner:(id)anOwner
|
||||
{
|
||||
var bundle = [CPBundle bundleForClass:[anOwner class]];
|
||||
|
||||
/*NSString *path;
|
||||
|
||||
path=[bundle pathForResource:name ofType:@"cib"];
|
||||
if(path==nil)
|
||||
path=[[NSBundle mainBundle] pathForResource:name ofType:@"cib"];
|
||||
|
||||
if(path==nil)
|
||||
return NO;
|
||||
*/
|
||||
var path = [bundle pathForResource:aName];
|
||||
|
||||
return [CPBundle loadCibFile:aPath externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner]];
|
||||
}
|
||||
|
||||
- (BOOL)loadCibFile:(CPString)aPath externalNameTable:(CPDictionary)aNameTable
|
||||
{
|
||||
return [[[CPCib alloc] initWithContentsOfFile:aPath] instantiateCibWithExternalNameTable:aNameTable];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -57,38 +57,71 @@
|
||||
_CPCibCustomObject _fileOwner;
|
||||
|
||||
CPSet _visibleWindows;
|
||||
|
||||
JSObject _replacementObjects;
|
||||
}
|
||||
|
||||
- (CPArray)topLevelObjects
|
||||
- (id)init
|
||||
{
|
||||
var count = [_objectsValues count],
|
||||
topLevelObjects = [];
|
||||
|
||||
while (count--)
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
var eachObject = _objectsValues[count];
|
||||
|
||||
if (eachObject == _fileOwner)
|
||||
{
|
||||
var anObject = _objectsKeys[count];
|
||||
|
||||
if (anObject != _fileOwner)
|
||||
topLevelObjects.push(anObject);
|
||||
}
|
||||
_namesKeys = [];
|
||||
_namesValues = [];
|
||||
|
||||
//CPArray _accessibilityConnectors;
|
||||
//CPArray _accessibilityOidsKeys;
|
||||
//CPArray _accessibilityOidsValues;
|
||||
|
||||
_classesKeys = [];
|
||||
_classesValues = [];
|
||||
|
||||
_connections = [];
|
||||
//id _fontManager;
|
||||
|
||||
_framework = @"";
|
||||
|
||||
_nextOid = [];
|
||||
|
||||
_objectsKeys = [];
|
||||
_objectsValues = [];
|
||||
|
||||
_oidKeys = [];
|
||||
_oidValues = [];
|
||||
|
||||
_fileOwner = nil;
|
||||
|
||||
_visibleWindows = [CPSet set];
|
||||
}
|
||||
|
||||
return topLevelObjects;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPMenu)mainMenu
|
||||
{
|
||||
var index = [_namesValues indexOfObjectIdenticalTo:"MainMenu"];
|
||||
|
||||
if (index === CPNotFound)
|
||||
return nil;
|
||||
|
||||
{
|
||||
index = [_namesValues indexOfObjectIdenticalTo:"Main Menu"];
|
||||
|
||||
if (index === CPNotFound)
|
||||
return nil;
|
||||
}
|
||||
|
||||
return _namesKeys[index];
|
||||
}
|
||||
|
||||
- (void)displayVisibleWindows
|
||||
{
|
||||
var object = nil,
|
||||
objectEnumerator = [_visibleWindows objectEnumerator];
|
||||
|
||||
while (object = [objectEnumerator nextObject])
|
||||
[_replacementObjects[[object hash]] makeKeyAndOrderFront:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var _CPCibObjectDataNamesKeysKey = @"_CPCibObjectDataNamesKeysKey",
|
||||
@@ -123,9 +156,11 @@ var _CPCibObjectDataNamesKeysKey = @"_CPCibObjectDataNamesKeysKey
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_replacementObjects = {};
|
||||
|
||||
_namesKeys = [aCoder decodeObjectForKey:_CPCibObjectDataNamesKeysKey];
|
||||
_namesValues = [aCoder decodeObjectForKey:_CPCibObjectDataNamesValuesKey];
|
||||
|
||||
@@ -138,22 +173,22 @@ var _CPCibObjectDataNamesKeysKey = @"_CPCibObjectDataNamesKeysKey
|
||||
|
||||
_connections = [aCoder decodeObjectForKey:_CPCibObjectDataConnectionsKey];
|
||||
//id _fontManager;
|
||||
|
||||
|
||||
_framework = [aCoder decodeObjectForKey:_CPCibObjectDataFrameworkKey];
|
||||
|
||||
|
||||
_nextOid = [aCoder decodeIntForKey:_CPCibObjectDataNextOidKey];
|
||||
|
||||
|
||||
_objectsKeys = [aCoder decodeObjectForKey:_CPCibObjectDataObjectsKeysKey];
|
||||
_objectsValues = [aCoder decodeObjectForKey:_CPCibObjectDataObjectsValuesKey];
|
||||
|
||||
|
||||
_oidKeys = [aCoder decodeObjectForKey:_CPCibObjectDataOidKeysKey];
|
||||
_oidValues = [aCoder decodeObjectForKey:_CPCibObjectDataOidValuesKey];
|
||||
|
||||
_fileOwner = [aCoder decodeObjectForKey:_CPCibObjectDataFileOwnerKey];
|
||||
|
||||
// CPSet _visibleWindows;
|
||||
|
||||
_visibleWindows = [aCoder decodeObjectForKey:_CPCibObjectDataVisibleWindowsKey];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -161,16 +196,16 @@ var _CPCibObjectDataNamesKeysKey = @"_CPCibObjectDataNamesKeysKey
|
||||
{
|
||||
[aCoder encodeObject:_namesKeys forKey:_CPCibObjectDataNamesKeysKey];
|
||||
[aCoder encodeObject:_namesValues forKey:_CPCibObjectDataNamesValuesKey];
|
||||
|
||||
|
||||
//CPArray _accessibilityConnectors;
|
||||
//CPArray _accessibilityOidsKeys;
|
||||
//CPArray _accessibilityOidsValues;
|
||||
|
||||
|
||||
[aCoder encodeObject:_classesKeys forKey:_CPCibObjectDataClassesKeysKey];
|
||||
[aCoder encodeObject:_classesValues forKey:_CPCibObjectDataClassesValuesKey];
|
||||
|
||||
|
||||
[aCoder encodeObject:_connections forKey:_CPCibObjectDataConnectionsKey];
|
||||
|
||||
|
||||
//id _fontManager;
|
||||
|
||||
[aCoder encodeObject:_framework forKey:_CPCibObjectDataFrameworkKey];
|
||||
@@ -186,22 +221,84 @@ var _CPCibObjectDataNamesKeysKey = @"_CPCibObjectDataNamesKeysKey
|
||||
[aCoder encodeObject:_fileOwner forKey:_CPCibObjectDataFileOwnerKey];
|
||||
// CPCustomObject _fileOwner;
|
||||
|
||||
// CPSet _visibleWindows;
|
||||
[aCoder encodeObject:_visibleWindows forKey:_CPCibObjectDataVisibleWindowsKey];
|
||||
}
|
||||
|
||||
- (void)establishConnectionsWithExternalNameTable:(CPDictionary)anExternalNameTable
|
||||
- (void)instantiateWithOwner:(id)anOwner topLevelObjects:(CPMutableArray)topLevelObjects
|
||||
{
|
||||
// _objectsValues -> parent
|
||||
// _objectsKeys -> child
|
||||
var count = [_objectsKeys count];
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var object = _objectsKeys[count],
|
||||
parent = _objectsValues[count],
|
||||
instantiatedObject = object;
|
||||
|
||||
if ([object respondsToSelector:@selector(_cibInstantiate)])
|
||||
{
|
||||
var instantiatedObject = [object _cibInstantiate];
|
||||
|
||||
if (instantiatedObject !== object)
|
||||
{
|
||||
_replacementObjects[[object hash]] = instantiatedObject;
|
||||
|
||||
if ([instantiatedObject isKindOfClass:[CPView class]])
|
||||
{
|
||||
var clipView = [instantiatedObject superview];
|
||||
|
||||
if ([clipView isKindOfClass:[CPClipView class]])
|
||||
{
|
||||
var scrollView = [clipView superview];
|
||||
|
||||
if ([scrollView isKindOfClass:[CPScrollView class]])
|
||||
[scrollView setDocumentView:instantiatedObject];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (topLevelObjects && parent === _fileOwner && object !== _fileOwner)
|
||||
topLevelObjects.push(instantiatedObject);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)establishConnectionsWithOwner:(id)anOwner topLevelObjects:(CPMutableArray)topLevelObjects
|
||||
{
|
||||
_replacementObjects[[_fileOwner hash]] = anOwner;
|
||||
|
||||
var index = 0,
|
||||
count = _connections.length,
|
||||
cibOwner = [anExternalNameTable objectForKey:CPCibOwner];
|
||||
count = _connections.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var connection = _connections[index];
|
||||
|
||||
[connection replaceObject:_fileOwner withObject:cibOwner];
|
||||
|
||||
[connection replaceObjects:_replacementObjects];
|
||||
[connection establishConnection];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)awakeWithOwner:(id)anOwner topLevelObjects:(CPMutableArray)topLevelObjects
|
||||
{
|
||||
var count = [_objectsKeys count];
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var object = _objectsKeys[count],
|
||||
instantiatedObject = _replacementObjects[[object hash]];
|
||||
|
||||
if (instantiatedObject)
|
||||
object = instantiatedObject;
|
||||
|
||||
// Don't use _fileOwner, by this point its been replaced with anOwner.
|
||||
if (object !== anOwner && [object respondsToSelector:@selector(awakeFromCib)])
|
||||
[object awakeFromCib];
|
||||
}
|
||||
|
||||
if ([anOwner respondsToSelector:@selector(awakeFromCib)])
|
||||
[anOwner awakeFromCib];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -2,31 +2,35 @@
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
|
||||
var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey",
|
||||
_CPCibWindowTemplateMaxSizeKey = @"_CPCibWindowTemplateMaxSizeKey",
|
||||
var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey",
|
||||
_CPCibWindowTemplateMaxSizeKey = @"_CPCibWindowTemplateMaxSizeKey",
|
||||
|
||||
_CPCibWindowTemplateViewClassKey = @"_CPCibWindowTemplateViewClassKey",
|
||||
_CPCibWindowTemplateWindowClassKey = @"_CPCibWindowTemplateWindowClassKey",
|
||||
_CPCibWindowTemplateViewClassKey = @"_CPCibWindowTemplateViewClassKey",
|
||||
_CPCibWindowTemplateWindowClassKey = @"_CPCibWindowTemplateWindowClassKey",
|
||||
|
||||
_CPCibWindowTemplateWindowRectKey = @"_CPCibWindowTemplateWindowRectKey",
|
||||
_CPCibWindowTemplateWindowStyleMaskKey = @"_CPCibWindowTempatStyleMaskKey",
|
||||
_CPCibWindowTemplateWindowTitleKey = @"_CPCibWindowTemplateWindowTitleKey",
|
||||
_CPCibWindowTemplateWindowViewKey = @"_CPCibWindowTemplateWindowViewKey";
|
||||
_CPCibWindowTemplateWindowRectKey = @"_CPCibWindowTemplateWindowRectKey",
|
||||
_CPCibWindowTemplateWindowStyleMaskKey = @"_CPCibWindowTempatStyleMaskKey",
|
||||
_CPCibWindowTemplateWindowTitleKey = @"_CPCibWindowTemplateWindowTitleKey",
|
||||
_CPCibWindowTemplateWindowViewKey = @"_CPCibWindowTemplateWindowViewKey",
|
||||
|
||||
_CPCibWindowTemplateWindowIsFullBridgeKey = @"_CPCibWindowTemplateWindowIsFullBridgeKey";
|
||||
|
||||
@implementation _CPCibWindowTemplate : CPObject
|
||||
{
|
||||
CGSize _minSize;
|
||||
CGSize _maxSize;
|
||||
//CGSize _screenRect;
|
||||
|
||||
|
||||
id _viewClass;
|
||||
//unsigned _wtFlags;
|
||||
CPString _windowClass;
|
||||
CGRect _windowRect;
|
||||
unsigned _windowStyleMask;
|
||||
|
||||
|
||||
CPString _windowTitle;
|
||||
CPView _windowView;
|
||||
|
||||
BOOL _windowIsFullBridge;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
@@ -48,6 +52,8 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey",
|
||||
|
||||
_windowTitle = [aCoder decodeObjectForKey:_CPCibWindowTemplateWindowTitleKey];
|
||||
_windowView = [aCoder decodeObjectForKey:_CPCibWindowTemplateWindowViewKey];
|
||||
|
||||
_windowIsFullBridge = [aCoder decodeObjectForKey:_CPCibWindowTemplateWindowIsFullBridgeKey];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -68,11 +74,18 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey",
|
||||
|
||||
[aCoder encodeObject:_windowTitle forKey:_CPCibWindowTemplateWindowTitleKey];
|
||||
[aCoder encodeObject:_windowView forKey:_CPCibWindowTemplateWindowViewKey];
|
||||
|
||||
[aCoder encodeObject:_windowIsFullBridge forKey:_CPCibWindowTemplateWindowIsFullBridgeKey];
|
||||
}
|
||||
|
||||
- (CPString)windowClass
|
||||
{
|
||||
return _windowClass;
|
||||
}
|
||||
|
||||
- (id)_cibInstantiate
|
||||
{
|
||||
var windowClass = CPClassFromString(_windowClass);
|
||||
var windowClass = CPClassFromString([self windowClass]);
|
||||
|
||||
/* if (!windowClass)
|
||||
[NSException raise:NSInvalidArgumentException format:@"Unable to locate NSWindow class %@, using NSWindow",_windowClass];
|
||||
@@ -100,7 +113,9 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey",
|
||||
{
|
||||
[theWindow setToolbar:_viewClass];
|
||||
}
|
||||
|
||||
|
||||
[theWindow setFullBridge:_windowIsFullBridge];
|
||||
|
||||
return theWindow;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
@implementation CAAnimation : CPObject
|
||||
{
|
||||
BOOL _isRemovedOnCompletion;
|
||||
id _delegate;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -143,7 +144,7 @@
|
||||
{
|
||||
var animation = [self animation];
|
||||
|
||||
[animation setKeypath:aKeyPath];
|
||||
[animation setKeyPath:aKeyPath];
|
||||
|
||||
return animation;
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ var CAMediaNamedTimingFunctions = nil;
|
||||
else
|
||||
{
|
||||
reference[0] = 1.0;
|
||||
reference[0] = 1.0;
|
||||
reference[1] = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,147 +41,44 @@ kCGPathStroke = 2;
|
||||
kCGPathFillStroke = 3;
|
||||
kCGPathEOFillStroke = 4;
|
||||
|
||||
/*
|
||||
@global
|
||||
/*!
|
||||
@group CGBlendMode
|
||||
*/
|
||||
|
||||
kCGBlendModeNormal = 0;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeMultiply = 1;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeScreen = 2;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeOverlay = 3;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeDarken = 4;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeLighten = 5;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeColorDodge = 6;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeColorBurn = 7;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeSoftLight = 8;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeHardLight = 9;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeDifference = 10;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeExclusion = 11;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeHue = 12;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeSaturation = 13;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeColor = 14;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeLuminosity = 15;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeClear = 16;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeCopy = 17;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeSourceIn = 18;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeSourceOut = 19;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeSourceAtop = 20;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeDestinationOver = 21;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeDestinationIn = 22;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeDestinationOut = 23;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeDestinationAtop = 24;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModeXOR = 25;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModePlusDarker = 26;
|
||||
/*
|
||||
@global
|
||||
@group CGBlendMode
|
||||
*/
|
||||
kCGBlendModePlusLighter = 27;
|
||||
|
||||
/*!
|
||||
@defgroup coregraphics CoreGraphics
|
||||
@{
|
||||
*/
|
||||
|
||||
/*!
|
||||
This function is just here for source compatability.
|
||||
It does nothing.
|
||||
@@ -202,10 +99,20 @@ function CGContextRetain(aContext)
|
||||
return aContext;
|
||||
}
|
||||
|
||||
/*!
|
||||
@cond
|
||||
*/
|
||||
// BEGIN CANVAS IF
|
||||
if (!CPFeatureIsCompatible(CPHTMLCanvasFeature))
|
||||
{
|
||||
/*!
|
||||
@endcond
|
||||
*/
|
||||
|
||||
/*!
|
||||
Creates a new graphics state, which describes all the current values for drawing.
|
||||
@return a graphics state
|
||||
*/
|
||||
function CGGStateCreate()
|
||||
{
|
||||
return { alpha:1.0, strokeStyle:"#000", fillStyle:"#ccc", lineWidth:1.0, lineJoin:kCGLineJoinMiter, lineCap:kCGLineCapButt, miterLimit:10.0, globalAlpha:1.0,
|
||||
@@ -213,6 +120,11 @@ function CGGStateCreate()
|
||||
shadowOffset:_CGSizeMakeZero(), shadowBlur:0.0, shadowColor:NULL, CTM:_CGAffineTransformMakeIdentity() };
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a copy of the given graphics state.
|
||||
@param aGState the graphics state to copy
|
||||
@return a copy of the given graphics state
|
||||
*/
|
||||
function CGGStateCreateCopy(aGState)
|
||||
{
|
||||
return { alpha:aGState.alpha, strokeStyle:aGState.strokeStyle, fillStyle:aGState.fillStyle, lineWidth:aGState.lineWidth,
|
||||
@@ -221,16 +133,30 @@ function CGGStateCreateCopy(aGState)
|
||||
shadowOffset:aGState.shadowOffset, shadowBlur:aGState.shadowBlur, shadowColor:aGState.shadowColor, CTM:_CGAffineTransformMakeCopy(aGState.CTM) };
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a new graphics context.
|
||||
@return CGContext a new graphics context which can be drawn into
|
||||
*/
|
||||
function CGBitmapGraphicsContextCreate()
|
||||
{
|
||||
return { DOMElement:document.createElement("div"), path:NULL, gState:CGGStateCreate(), gStateStack:[] };
|
||||
}
|
||||
|
||||
/*!
|
||||
Pushes the current graphics state of aContext onto the top of a stack.
|
||||
@param aContext the CGContext to edit
|
||||
@return void
|
||||
*/
|
||||
function CGContextSaveGState(aContext)
|
||||
{
|
||||
aContext.gStateStack.push(CGGStateCreateCopy(aContext.gState));
|
||||
}
|
||||
|
||||
/*!
|
||||
Pops the most recent graphics state of the top of the graphics stack and restores it.
|
||||
@param aContext the CGContext to edit
|
||||
@return void
|
||||
*/
|
||||
function CGContextRestoreGState(aContext)
|
||||
{
|
||||
aContext.gState = aContext.gStateStack.pop();
|
||||
@@ -266,26 +192,67 @@ function CGContextAddArc(aContext, x, y, radius, startAngle, endAngle, clockwise
|
||||
CGPathAddArc(aContext.path, aContext.gState.CTM, x, y, radius, startAngle, endAngle, clockwise);
|
||||
}
|
||||
|
||||
/*!
|
||||
Adds an arc to the current context that ends in the specified point.
|
||||
@param aContext the CGContext to edit
|
||||
@param x1 the x coordinate of the beginning of the arc
|
||||
@param y1 the y coordinate of the beginning of the arc
|
||||
@param x2 the x coordinate of the end of the arc
|
||||
@param y2 the y coordinate of the end of the arc
|
||||
@param radius the radius of the arc to be drawn
|
||||
@return void
|
||||
*/
|
||||
function CGContextAddArcToPoint(aContext, x1, y1, x2, y2, radius)
|
||||
{
|
||||
CGPathAddArcToPoint(aContext.path, aContext.gState.CTM, x1, y1, x2, y2, radius);
|
||||
}
|
||||
|
||||
/*!
|
||||
Adds a cubic curve to the current context
|
||||
@param aContext the CGContext to edit
|
||||
@param cp1x the x coordinate of the first control point
|
||||
@param cp1y the y coordinate of the first control point
|
||||
@param cp2x the x coordinate of the second control point
|
||||
@param cp2y the y coordinate of the second control point
|
||||
@param x the x coordinate of the end of the curve
|
||||
@param y the y coordinate of the end of the curve
|
||||
@return void
|
||||
*/
|
||||
function CGContextAddCurveToPoint(aContext, cp1x, cp1y, cp2x, cp2y, x, y)
|
||||
{
|
||||
CGPathAddCurveToPoint(aContext.path, aContext.gState.CTM, cp1x, cp1y, cp2x, cp2y, x, y);
|
||||
}
|
||||
|
||||
/*!
|
||||
Adds a line to each element in the points array
|
||||
@param aContext the CGContext to move
|
||||
@param points an array of points that are to be consecutively executed as if they were individual addToPoint calls
|
||||
@param count an upper bound on the number of points to use
|
||||
@return void
|
||||
*/
|
||||
function CGContextAddLines(aContext, points, count)
|
||||
{
|
||||
CGPathAddLines(aContext.path, aContext.gState.CTM, points, count);
|
||||
}
|
||||
|
||||
/*!
|
||||
Adds a line from the current point to the x/y
|
||||
@param aContext the CGContext to move
|
||||
@param x the x coordinate of the end point of the line
|
||||
@param y the y coordinate of the end point of the line
|
||||
@return void
|
||||
*/
|
||||
function CGContextAddLineToPoint(aContext, x, y)
|
||||
{
|
||||
CGPathAddLineToPoint(aContext.path, aContext.gState.CTM, x, y);
|
||||
}
|
||||
|
||||
/*!
|
||||
Adds aPath to the current path in aContext
|
||||
@param aContext the CGContext to add to
|
||||
@param aPath the path to be added
|
||||
@return void
|
||||
*/
|
||||
function CGContextAddPath(aContext, aPath)
|
||||
{
|
||||
if (!aContext || CGPathIsEmpty(aPath))
|
||||
@@ -297,32 +264,71 @@ function CGContextAddPath(aContext, aPath)
|
||||
CGPathAddPath(aContext.path, aContext.gState.CTM, aPath);
|
||||
}
|
||||
|
||||
/*!
|
||||
Adds a quadratic curve from the current point to the point specified by x/y, using the control point specified by cpx/cpy
|
||||
@param aContext the CGContext to add the curve to
|
||||
@param cpx the x coordinate for the curve's control point
|
||||
@param cpy the y coordinate for the curve's control point
|
||||
@param x the x coordinate for the end point of the curve
|
||||
@param y the y coordinate for the end point of the curve
|
||||
@return void
|
||||
*/
|
||||
function CGContextAddQuadCurveToPoint(aContext, cpx, cpy, x, y)
|
||||
{
|
||||
CGPathAddQuadCurveToPoint(aContext.path, aContext.gState.CTM, cpx, cpy, x, y);
|
||||
}
|
||||
|
||||
/*!
|
||||
Adds aRect to the current path in the given context
|
||||
@param aContext the CGContext to add to
|
||||
@param aRect the dimensions of the rectangle to add
|
||||
@return void
|
||||
*/
|
||||
function CGContextAddRect(aContext, aRect)
|
||||
{
|
||||
CGPathAddRect(aContext.path, aContext.gState.CTM, aRect);
|
||||
}
|
||||
|
||||
/*!
|
||||
Adds up to count elements from rects to the current path in aContext
|
||||
@param aContext the CGContext to add to
|
||||
@param rects an array of CGRects to be added to the context's path
|
||||
@param the upper bound of elements to be added
|
||||
@return void
|
||||
*/
|
||||
function CGContextAddRects(aContext, rects, count)
|
||||
{
|
||||
CGPathAddRects(aContext.path, aContext.gState.CTM, rects, count);
|
||||
}
|
||||
|
||||
/*!
|
||||
Begins a new subpath in the given context
|
||||
@param aContext the CGContext to create a new path in
|
||||
@return void
|
||||
*/
|
||||
function CGContextBeginPath(aContext)
|
||||
{
|
||||
// This clears any previous path.
|
||||
aContext.path = CGPathCreateMutable();
|
||||
}
|
||||
|
||||
/*!
|
||||
Closes the currently open subpath, if any, in aContext
|
||||
@param aContext the CGContext to close a path in
|
||||
@return void
|
||||
*/
|
||||
function CGContextClosePath(aContext)
|
||||
{
|
||||
CGPathCloseSubpath(aContext.path);
|
||||
}
|
||||
|
||||
/*!
|
||||
Moves the current location of aContext to the given x and y coordinates
|
||||
@param aContext the CGContext to move
|
||||
@param x the x location to move the context to
|
||||
@param y the y location to move the context to
|
||||
@return void
|
||||
*/
|
||||
function CGContextMoveToPoint(aContext, x, y)
|
||||
{
|
||||
if (!aContext.path)
|
||||
@@ -331,14 +337,27 @@ function CGContextMoveToPoint(aContext, x, y)
|
||||
CGPathMoveToPoint(aContext.path, aContext.gState.CTM, x, y);
|
||||
}
|
||||
|
||||
/*!
|
||||
Fills a rectangle in the given context with aRect dimensions, using the context's current fill color
|
||||
@param aContext the CGContext to draw into
|
||||
@param aRect the dimensions of the rectangle to fill
|
||||
@return void
|
||||
*/
|
||||
function CGContextFillRect(aContext, aRect)
|
||||
{
|
||||
CGContextFillRects(aContext, [aRect], 1);
|
||||
}
|
||||
|
||||
/*!
|
||||
Fills a rectangle in the given context for each CGRect in the given array, up to a total of count rects
|
||||
@param aContext the CGContext to draw into
|
||||
@param rects an array of rects to fill
|
||||
@param count the maximum number of rects from the given array to fill
|
||||
@return void
|
||||
*/
|
||||
function CGContextFillRects(aContext, rects, count)
|
||||
{
|
||||
if (arguments["count"] == NULL)
|
||||
if (arguments[2] === undefined)
|
||||
var count = rects.length;
|
||||
|
||||
CGContextBeginPath(aContext);
|
||||
@@ -348,6 +367,12 @@ function CGContextFillRects(aContext, rects, count)
|
||||
CGContextDrawPath(aContext, kCGPathFill);
|
||||
}
|
||||
|
||||
/*!
|
||||
Strokes a rectangle with the given location into the given context, using the context's current width and color
|
||||
@param aContext the CGContext to draw into
|
||||
@param aRect a CGRect indicating the dimensions of the rectangle to be drawn
|
||||
@return void
|
||||
*/
|
||||
function CGContextStrokeRect(aContext, aRect)
|
||||
{
|
||||
CGContextBeginPath(aContext);
|
||||
@@ -357,6 +382,13 @@ function CGContextStrokeRect(aContext, aRect)
|
||||
CGContextDrawPath(aContext, kCGPathStroke);
|
||||
}
|
||||
|
||||
/*!
|
||||
Strokes a rectangle with the given dimensions and the given stroke width
|
||||
@param aContext the CGContext to draw into
|
||||
@param aRect the CGRect indicating the bounds of the rect to be drawn
|
||||
@param aWidth the width with which to stroke the rect
|
||||
@return void
|
||||
*/
|
||||
function CGContextStrokeRectWithWidth(aContext, aRect, aWidth)
|
||||
{
|
||||
CGContextSaveGState(aContext);
|
||||
@@ -367,6 +399,12 @@ function CGContextStrokeRectWithWidth(aContext, aRect, aWidth)
|
||||
CGContextRestoreGState(aContext);
|
||||
}
|
||||
|
||||
/*!
|
||||
Concatenates the given transformation matrix onto the current transformation matrix in aContext
|
||||
@param aContext the CGContext to transform
|
||||
@param aTransform the CGAffineTransform to apply to the given context
|
||||
@return void
|
||||
*/
|
||||
function CGContextConcatCTM(aContext, aTransform)
|
||||
{
|
||||
var CTM = aContext.gState.CTM;
|
||||
@@ -374,11 +412,23 @@ function CGContextConcatCTM(aContext, aTransform)
|
||||
_CGAffineTransformConcatTo(CTM, aTransform, CTM);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the current transformation matrix for the given context
|
||||
@param aContext the CGContext for which we are asking for the transform
|
||||
@return CGAffineTransform the current transformation matrix of the given context
|
||||
*/
|
||||
function CGContextGetCTM(aContext)
|
||||
{
|
||||
return aContext.gState.CTM;
|
||||
}
|
||||
|
||||
/*!
|
||||
Rotates the current context by anAngle radians
|
||||
@param aContext the CGContext to rotate
|
||||
@param anAngle the amount to rotate, in radians
|
||||
@return void
|
||||
*/
|
||||
|
||||
function CGContextRotateCTM(aContext, anAngle)
|
||||
{
|
||||
var gState = aContext.gState;
|
||||
@@ -386,6 +436,13 @@ function CGContextRotateCTM(aContext, anAngle)
|
||||
gState.CTM = CGAffineTransformRotate(gState.CTM, anAngle);
|
||||
}
|
||||
|
||||
/*!
|
||||
Scales the current context by sx/sy
|
||||
@param aContext the CGContext to scale
|
||||
@param sx the amount to scale in the x direction
|
||||
@param sy the amount to scale in the y direction
|
||||
@return void
|
||||
*/
|
||||
function CGContextScaleCTM(aContext, sx, sy)
|
||||
{
|
||||
var gState = aContext.gState;
|
||||
@@ -393,6 +450,13 @@ function CGContextScaleCTM(aContext, sx, sy)
|
||||
gState.CTM = _CGAffineTransformScale(gState.CTM, sx, sy);
|
||||
}
|
||||
|
||||
/*!
|
||||
Translates the given context by tx in the x direction and ty in the y direction
|
||||
@param aContext the CGContext to translate
|
||||
@param tx the amount to move in the x direction
|
||||
@param ty the amount to move in the y direction
|
||||
@return void
|
||||
*/
|
||||
function CGContextTranslateCTM(aContext, tx, ty)
|
||||
{
|
||||
var gState = aContext.gState;
|
||||
@@ -400,6 +464,14 @@ function CGContextTranslateCTM(aContext, tx, ty)
|
||||
gState.CTM = _CGAffineTransformTranslate(gState.CTM, tx, ty);
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the current offset, and blur for shadows in core graphics drawing operations
|
||||
@param aContext the CGContext of the shadow
|
||||
@param aSize a CGSize indicating the offset of the shaodw
|
||||
@param aBlur a float indicating the blur radius
|
||||
@return void
|
||||
*/
|
||||
|
||||
function CGContextSetShadow(aContext, aSize, aBlur)
|
||||
{
|
||||
var gState = aContext.gState;
|
||||
@@ -409,6 +481,14 @@ function CGContextSetShadow(aContext, aSize, aBlur)
|
||||
gState.shadowColor = [CPColor shadowColor];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the current offset, blur, and color for shadows in core graphics drawing operations
|
||||
@param aContext the CGContext of the shadow
|
||||
@param aSize a CGSize indicating the offset of the shaodw
|
||||
@param aBlur a float indicating the blur radius
|
||||
@param aColor a CPColor object indicating the color of the shadow
|
||||
@return void
|
||||
*/
|
||||
function CGContextSetShadowWithColor(aContext, aSize, aBlur, aColor)
|
||||
{
|
||||
var gState = aContext.gState;
|
||||
@@ -418,19 +498,30 @@ function CGContextSetShadowWithColor(aContext, aSize, aBlur, aColor)
|
||||
gState.shadowColor = aColor;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the current alpha value for core graphics drawing operations in the given context .
|
||||
@param aContext the CGContext who's alpha value should be updated
|
||||
@param anAlpha the new alpha value. 1.0 is completely opaque, 0.0 is completely transparent.
|
||||
@return void
|
||||
*/
|
||||
function CGContextSetAlpha(aContext, anAlpha)
|
||||
{
|
||||
aContext.gState.alpha = MAX(MIN(anAlpha, 1.0), 0.0);
|
||||
}
|
||||
|
||||
/*!
|
||||
@cond
|
||||
*/
|
||||
} // END CANVAS IF
|
||||
/*!
|
||||
@endcond
|
||||
*/
|
||||
|
||||
// GOOD.
|
||||
/*!
|
||||
Fills in the area of the current path, using the even-odd fill rule.
|
||||
@param aContext the CGContext of the path
|
||||
@return void
|
||||
@group CGContext
|
||||
*/
|
||||
function CGContextEOFillPath(aContext)
|
||||
{
|
||||
@@ -441,7 +532,6 @@ function CGContextEOFillPath(aContext)
|
||||
Fills in the area of the current path, using the non-zero winding number rule.
|
||||
@param aContext the CGContext of the path
|
||||
@return void
|
||||
@group CGContext
|
||||
*/
|
||||
function CGContextFillPath(aContext)
|
||||
{
|
||||
@@ -455,28 +545,10 @@ var KAPPA = 4.0 * ((SQRT2 - 1.0) / 3.0);
|
||||
@param aContext CGContext to draw on
|
||||
@param aRect the rectangle bounding the ellipse
|
||||
@return void
|
||||
@group CGContext
|
||||
*/
|
||||
function CGContextAddEllipseInRect(aContext, aRect)
|
||||
{
|
||||
CGContextBeginPath(aContext);
|
||||
|
||||
if (_CGRectGetWidth(aRect) == _CGRectGetHeight(aRect))
|
||||
CGContextAddArc(aContext, _CGRectGetMidX(aRect), _CGRectGetMidY(aRect), _CGRectGetWidth(aRect) / 2.0, 0.0, 2 * PI, YES);
|
||||
else
|
||||
{
|
||||
var axis = _CGSizeMake(_CGRectGetWidth(aRect) / 2.0, _CGRectGetHeight(aRect) / 2.0),
|
||||
center = _CGPointMake(_CGRectGetMinX(aRect) + axis.width, _CGRectGetMinY(aRect) + axis.height);
|
||||
|
||||
CGContextMoveToPoint(aContext, center.x, center.y - axis.height);
|
||||
|
||||
CGContextAddCurveToPoint(aContext, center.x + (KAPPA * axis.width), center.y - axis.height, center.x + axis.width, center.y - (KAPPA * axis.height), center.x + axis.width, center.y);
|
||||
CGContextAddCurveToPoint(aContext, center.x + axis.width, center.y + (KAPPA * axis.height), center.x + (KAPPA * axis.width), center.y + axis.height, center.x, center.y + axis.height);
|
||||
CGContextAddCurveToPoint(aContext, center.x - (KAPPA * axis.width), center.y + axis.height, center.x - axis.width, center.y + (KAPPA * axis.height), center.x - axis.width, center.y);
|
||||
CGContextAddCurveToPoint(aContext, center.x - axis.width, center.y - (KAPPA * axis.height), center.x - (KAPPA * axis.width), center.y - axis.height, center.x, center.y - axis.height);
|
||||
}
|
||||
|
||||
CGContextClosePath(aContext);
|
||||
CGContextAddPath(aContext, CGPathWithEllipseInRect(aRect));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -484,11 +556,12 @@ function CGContextAddEllipseInRect(aContext, aRect)
|
||||
@param aContext CGContext to draw on
|
||||
@param aRect the rectangle bounding the ellipse
|
||||
@return void
|
||||
@group CGContext
|
||||
*/
|
||||
function CGContextFillEllipseInRect(aContext, aRect)
|
||||
{
|
||||
CGContextBeginPath(aContext);
|
||||
CGContextAddEllipseInRect(aContext, aRect);
|
||||
CGContextClosePath(aContext);
|
||||
CGContextFillPath(aContext);
|
||||
}
|
||||
|
||||
@@ -497,11 +570,12 @@ function CGContextFillEllipseInRect(aContext, aRect)
|
||||
@param aContext CGContext to draw on
|
||||
@param aRect the rectangle bounding the ellipse
|
||||
@return void
|
||||
@group CGContext
|
||||
*/
|
||||
function CGContextStrokeEllipseInRect(aContext, aRect)
|
||||
{
|
||||
CGContextBeginPath(aContext);
|
||||
CGContextAddEllipseInRect(aContext, aRect);
|
||||
CGContextClosePath(aContext);
|
||||
CGContextStrokePath(aContext);
|
||||
}
|
||||
|
||||
@@ -509,7 +583,6 @@ function CGContextStrokeEllipseInRect(aContext, aRect)
|
||||
Paints a line in the current path of the current context.
|
||||
@param aContext CGContext to draw on
|
||||
@return void
|
||||
@group CGContext
|
||||
*/
|
||||
function CGContextStrokePath(aContext)
|
||||
{
|
||||
@@ -525,7 +598,6 @@ function CGContextStrokePath(aContext)
|
||||
the beginning of second line segment, etc.
|
||||
@param count the number of points in the array
|
||||
@return void
|
||||
@group CGContext
|
||||
*/
|
||||
function CGContextStrokeLineSegments(aContext, points, count)
|
||||
{
|
||||
@@ -553,7 +625,6 @@ function CGContextStrokeLineSegments(aContext, points, count)
|
||||
@param aContext the CGContext
|
||||
@param aColor the new color for the fill
|
||||
@return void
|
||||
@group CGContext
|
||||
*/
|
||||
|
||||
function CGContextSetFillColor(aContext, aColor)
|
||||
@@ -567,7 +638,6 @@ function CGContextSetFillColor(aContext, aColor)
|
||||
@param aContext the CGContext
|
||||
@param aColor the new color for the stroke
|
||||
@return void
|
||||
@group CGContext
|
||||
*/
|
||||
function CGContextSetStrokeColor(aContext, aColor)
|
||||
{
|
||||
@@ -585,54 +655,37 @@ function CGContextSetStrokeColor(aContext, aColor)
|
||||
@param sw set it to <code>YES</code> for a rounded southwest corner
|
||||
@param nw set it to <code>YES</code> for a rounded northwest corner
|
||||
@return void
|
||||
@group CGContext
|
||||
*/
|
||||
function CGContextFillRoundedRectangleInRect(aContext, aRect, aRadius, ne, se, sw, nw)
|
||||
{
|
||||
var xMin = _CGRectGetMinX(aRect),
|
||||
xMax = _CGRectGetMaxX(aRect),
|
||||
yMin = _CGRectGetMinY(aRect),
|
||||
yMax = _CGRectGetMaxY(aRect);
|
||||
|
||||
CGContextBeginPath(aContext);
|
||||
CGContextMoveToPoint(aContext, xMin + aRadius, yMin);
|
||||
|
||||
if (ne)
|
||||
{
|
||||
CGContextAddLineToPoint(aContext, xMax - aRadius, yMin);
|
||||
CGContextAddCurveToPoint(aContext, xMax - aRadius, yMin, xMax, yMin, xMax, yMin + aRadius);
|
||||
}
|
||||
else
|
||||
CGContextAddLineToPoint(aContext, xMax, yMin);
|
||||
|
||||
if (se)
|
||||
{
|
||||
CGContextAddLineToPoint(aContext, xMax, yMax - aRadius);
|
||||
CGContextAddCurveToPoint(aContext, xMax, yMax - aRadius, xMax, yMax, xMax - aRadius, yMax);
|
||||
}
|
||||
else
|
||||
CGContextAddLineToPoint(aContext, xMax, yMax);
|
||||
|
||||
if (sw)
|
||||
{
|
||||
CGContextAddLineToPoint(aContext, xMin + aRadius, yMax);
|
||||
CGContextAddCurveToPoint(aContext, xMin + aRadius, yMax, xMin, yMax, xMin, yMax - aRadius);
|
||||
}
|
||||
else
|
||||
CGContextAddLineToPoint(aContext, xMin, yMax);
|
||||
|
||||
if (nw)
|
||||
{
|
||||
CGContextAddLineToPoint(aContext, xMin, yMin + aRadius);
|
||||
CGContextAddCurveToPoint(aContext, xMin, yMin + aRadius, xMin, yMin, xMin + aRadius, yMin);
|
||||
} else
|
||||
CGContextAddLineToPoint(aContext, xMin, yMin);
|
||||
|
||||
CGContextClosePath(aContext);
|
||||
|
||||
CGContextAddPath(aContext, CGPathWithRoundedRectangleInRect(aRect, aRadius, aRadius, ne, se, sw, nw));
|
||||
CGContextFillPath(aContext);
|
||||
}
|
||||
|
||||
/*!
|
||||
Strokes a rounded rectangle.
|
||||
@param aContext the CGContext to draw into
|
||||
@param aRect the base rectangle
|
||||
@param aRadius the distance from the rectange corner to the rounded corner
|
||||
@param ne set it to <code>YES</code> for a rounded northeast corner
|
||||
@param se set it to <code>YES</code> for a rounded southeast corner
|
||||
@param sw set it to <code>YES</code> for a rounded southwest corner
|
||||
@param nw set it to <code>YES</code> for a rounded northwest corner
|
||||
@return void
|
||||
*/
|
||||
function CGContextStrokeRoundedRectangleInRect(aContext, aRect, aRadius, ne, se, sw, nw)
|
||||
{
|
||||
CGContextAddPath(aContext, CGPathWithRoundedRectangleInRect(aRect, aRadius, aRadius, ne, se, sw, nw));
|
||||
CGContextStrokePath(aContext);
|
||||
}
|
||||
|
||||
/*!
|
||||
@}
|
||||
*/
|
||||
|
||||
/*!
|
||||
@cond
|
||||
*/
|
||||
if (CPFeatureIsCompatible(CPHTMLCanvasFeature))
|
||||
{
|
||||
#include "CGContextCanvas.j"
|
||||
@@ -641,3 +694,6 @@ else if (CPFeatureIsCompatible(CPVMLFeature))
|
||||
{
|
||||
#include "CGContextVML.j"
|
||||
}
|
||||
/*!
|
||||
@endcond
|
||||
*/
|
||||
|
||||
@@ -229,7 +229,10 @@ function CGContextDrawPath(aContext, aMode)
|
||||
|
||||
vml.push("\">");
|
||||
|
||||
if (fill)
|
||||
if (gState.gradient)
|
||||
vml.push(gState.gradient)
|
||||
|
||||
else if (fill)
|
||||
vml.push("<cg_vml_:fill color=\"", gState.fillStyle, "\" opacity=\"", opacity, "\" />");
|
||||
|
||||
if (stroke)
|
||||
@@ -260,3 +263,59 @@ function CGContextDrawPath(aContext, aMode)
|
||||
aContext.DOMElement.insertAdjacentHTML("BeforeEnd", vml.join(""));
|
||||
}
|
||||
|
||||
function to_string(aColor)
|
||||
{
|
||||
return "rgb(" + ROUND(aColor.components[0] * 255) + ", " + ROUND(aColor.components[1] * 255) + ", " + ROUND(255 * aColor.components[2]) + ")";
|
||||
}
|
||||
|
||||
function CGContextDrawLinearGradient(aContext, aGradient, aStartPoint, anEndPoint, options)
|
||||
{
|
||||
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("colors=\"");
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
vml.push(([stops[i] position]*100).toFixed(0)+"% ");
|
||||
vml.push([[[stops[i] color] colorForSlideBase:nil] cssString]);
|
||||
|
||||
if (i < count-1)
|
||||
vml.push(",");
|
||||
}
|
||||
|
||||
vml.push("\" />");
|
||||
}
|
||||
else
|
||||
{
|
||||
var colors = aGradient.colors,
|
||||
count = colors.length;
|
||||
|
||||
vml = ["<cg_vml_:fill type=\"gradient\" "];
|
||||
|
||||
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("\" />");
|
||||
}
|
||||
|
||||
aContext.gState.gradient = vml.join("");
|
||||
console.log(vml.join(""));
|
||||
|
||||
// if (aContext.buffer != nil)
|
||||
// aContext.buffer += vml.join("");
|
||||
// else
|
||||
// aContext.DOMElement.innerHTML = vml.join("");
|
||||
}
|
||||
@@ -59,6 +59,11 @@
|
||||
|
||||
#define _CGRectContainsPoint(aRect, aPoint) (aPoint.x >= _CGRectGetMinX(aRect) && aPoint.y >= _CGRectGetMinY(aRect) && aPoint.x < _CGRectGetMaxX(aRect) && aPoint.y < _CGRectGetMaxY(aRect))
|
||||
|
||||
#define _CGInsetMake(_top, _right, _bottom, _left) { top:(_top), right:(_right), bottom:(_bottom), left:(_left) }
|
||||
#define _CGInsetMakeCopy(anInset) _CGInsetMake(anInset.top, anInset.right, anInset.bottom, anInset.left)
|
||||
#define _CGInsetMakeZero() _CGInsetMake(0, 0, 0, 0)
|
||||
#define _CGInsetIsEmpty(anInset) ((anInset).top === 0 && (anInset).right === 0 && (anInset).bottom === 0 && (anInset).left === 0)
|
||||
|
||||
// DEPRECATED
|
||||
#define _CGPointCreateCopy(aPoint) _CGPointMake(aPoint.x, aPoint.y)
|
||||
#define _CGSizeCreateCopy(aSize) _CGSizeMake(aSize.width, aSize.height)
|
||||
|
||||
@@ -65,6 +65,16 @@ _function(CGRectIsNull(aRect))
|
||||
|
||||
_function(CGRectContainsPoint(aRect, aPoint))
|
||||
|
||||
_function(CGInsetMake(top, right, bottom, left))
|
||||
_function(CGInsetMakeZero())
|
||||
_function(CGInsetMakeCopy(anInset))
|
||||
_function(CGInsetIsEmpty(anInset))
|
||||
|
||||
/*!
|
||||
@addtogroup appkit
|
||||
@{
|
||||
*/
|
||||
|
||||
/*!
|
||||
Returns a <code>BOOL</code> indicating whether CGRect <code>lhsRect</code>
|
||||
contains CGRect <code>rhsRect</code>.
|
||||
@@ -203,3 +213,21 @@ function CGPointFromEvent(anEvent)
|
||||
{
|
||||
return _CGPointMake(anEvent.clientX, anEvent.clientY);
|
||||
}
|
||||
|
||||
function CGInsetFromString(aString)
|
||||
{
|
||||
var numbers = aString.substr(1, aString.length - 2).split(',');
|
||||
|
||||
return _CGInsetMake(parseFloat(numbers[0]), parseFloat(numbers[1]), parseFloat(numbers[2]), parseFloat(numbers[3]));
|
||||
}
|
||||
|
||||
CGInsetFromCPString = CGInsetFromString;
|
||||
|
||||
function CPStringFromCGInset(anInset)
|
||||
{
|
||||
return '{' + anInset.top + ", " + anInset.left + ", " + anInset.bottom + ", " + anInset.right + '}';
|
||||
}
|
||||
|
||||
/*!
|
||||
@}
|
||||
*/
|
||||
|
||||
@@ -36,11 +36,23 @@ kCGPathElementCloseSubpath = 4;
|
||||
kCGPathElementAddArc = 5;
|
||||
kCGPathElementAddArcToPoint = 6;
|
||||
|
||||
/*!
|
||||
@addtogroup coregraphics
|
||||
@{
|
||||
*/
|
||||
|
||||
/*!
|
||||
Returns a new CGPath object.
|
||||
*/
|
||||
function CGPathCreateMutable()
|
||||
{
|
||||
return { count:0, start:NULL, current:NULL, elements:[] };
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a copy of the given path object.
|
||||
*/
|
||||
|
||||
function CGPathCreateMutableCopy(aPath)
|
||||
{
|
||||
var path = CGPathCreateMutable();
|
||||
@@ -50,6 +62,10 @@ function CGPathCreateMutableCopy(aPath)
|
||||
return path;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a copy of the given path object.
|
||||
*/
|
||||
|
||||
function CGPathCreateCopy(aPath)
|
||||
{
|
||||
return CGPathCreateMutableCopy(aPath);
|
||||
@@ -158,12 +174,15 @@ function CGPathAddPath(aPath, aTransform, anotherPath)
|
||||
|
||||
for (; i < count; ++i)
|
||||
{
|
||||
var element = anotherPath[i];
|
||||
var element = anotherPath.elements[i];
|
||||
|
||||
aPath.elements[aPath.count++] = { type:element.type, points:element.point.slice() };
|
||||
aPath.elements[aPath.count] = { type:element.type, x:element.x, y:element.y,
|
||||
cpx:element.cpx, cpy:element.cpy,
|
||||
radius:element.radius, startAngle:element.startAngle, endAngle:element.endAngle,
|
||||
cp1x:element.cp1x, cp1y:element.cp1y, cp2x:element.cp2x, cp2y:element.cp2y,
|
||||
points: element.points ? element.points.slice() : nil};
|
||||
|
||||
if (element.type == kCGPathElementAddArc || element.type == kCGPathElementAddArcToPoint)
|
||||
aPath.elements[aPath.count - 1].radius = element.radius;
|
||||
aPath.count++
|
||||
}
|
||||
|
||||
aPath.current = anotherPath.current;
|
||||
@@ -231,6 +250,76 @@ function CGPathMoveToPoint(aPath, aTransform, x, y)
|
||||
aPath.elements[aPath.count++] = { type:kCGPathElementMoveToPoint, x:point.x, y:point.y };
|
||||
}
|
||||
|
||||
function CGPathWithEllipseInRect(aRect)
|
||||
{
|
||||
var path = CGPathCreateMutable();
|
||||
|
||||
if (_CGRectGetWidth(aRect) == _CGRectGetHeight(aRect))
|
||||
CGPathAddArc(path, nil, _CGRectGetMidX(aRect), _CGRectGetMidY(aRect), _CGRectGetWidth(aRect) / 2.0, 0.0, 2 * PI, YES);
|
||||
else
|
||||
{
|
||||
var axis = _CGSizeMake(_CGRectGetWidth(aRect) / 2.0, _CGRectGetHeight(aRect) / 2.0),
|
||||
center = _CGPointMake(_CGRectGetMinX(aRect) + axis.width, _CGRectGetMinY(aRect) + axis.height);
|
||||
|
||||
CGPathMoveToPoint(path, nil, center.x, center.y - axis.height);
|
||||
|
||||
CGPathAddCurveToPoint(path, nil, center.x + (KAPPA * axis.width), center.y - axis.height, center.x + axis.width, center.y - (KAPPA * axis.height), center.x + axis.width, center.y);
|
||||
CGPathAddCurveToPoint(path, nil, center.x + axis.width, center.y + (KAPPA * axis.height), center.x + (KAPPA * axis.width), center.y + axis.height, center.x, center.y + axis.height);
|
||||
CGPathAddCurveToPoint(path, nil, center.x - (KAPPA * axis.width), center.y + axis.height, center.x - axis.width, center.y + (KAPPA * axis.height), center.x - axis.width, center.y);
|
||||
CGPathAddCurveToPoint(path, nil, center.x - axis.width, center.y - (KAPPA * axis.height), center.x - (KAPPA * axis.width), center.y - axis.height, center.x, center.y - axis.height);
|
||||
}
|
||||
|
||||
CGPathCloseSubpath(path);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
function CGPathWithRoundedRectangleInRect(aRect, xRadius, yRadius/*not currently supported*/, ne, se, sw, nw)
|
||||
{
|
||||
var path = CGPathCreateMutable(),
|
||||
xMin = _CGRectGetMinX(aRect),
|
||||
xMax = _CGRectGetMaxX(aRect),
|
||||
yMin = _CGRectGetMinY(aRect),
|
||||
yMax = _CGRectGetMaxY(aRect);
|
||||
|
||||
CGPathMoveToPoint(path, nil, xMin + xRadius, yMin);
|
||||
|
||||
if (ne)
|
||||
{
|
||||
CGPathAddLineToPoint(path, nil, xMax - xRadius, yMin);
|
||||
CGPathAddCurveToPoint(path, nil, xMax - xRadius, yMin, xMax, yMin, xMax, yMin + xRadius);
|
||||
}
|
||||
else
|
||||
CGPathAddLineToPoint(path, nil, xMax, yMin);
|
||||
|
||||
if (se)
|
||||
{
|
||||
CGPathAddLineToPoint(path, nil, xMax, yMax - xRadius);
|
||||
CGPathAddCurveToPoint(path, nil, xMax, yMax - xRadius, xMax, yMax, xMax - xRadius, yMax);
|
||||
}
|
||||
else
|
||||
CGPathAddLineToPoint(path, nil, xMax, yMax);
|
||||
|
||||
if (sw)
|
||||
{
|
||||
CGPathAddLineToPoint(path, nil, xMin + xRadius, yMax);
|
||||
CGPathAddCurveToPoint(path, nil, xMin + xRadius, yMax, xMin, yMax, xMin, yMax - xRadius);
|
||||
}
|
||||
else
|
||||
CGPathAddLineToPoint(path, nil, xMin, yMax);
|
||||
|
||||
if (nw)
|
||||
{
|
||||
CGPathAddLineToPoint(path, nil, xMin, yMin + xRadius);
|
||||
CGPathAddCurveToPoint(path, nil, xMin, yMin + xRadius, xMin, yMin, xMin + xRadius, yMin);
|
||||
} else
|
||||
CGPathAddLineToPoint(path, nil, xMin, yMin);
|
||||
|
||||
CGPathCloseSubpath(path);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
function CGPathCloseSubpath(aPath)
|
||||
{
|
||||
var count = aPath.count;
|
||||
@@ -284,3 +373,8 @@ function CGPathIsEmpty(aPath)
|
||||
{
|
||||
return !aPath || aPath.count == 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
@}
|
||||
*/
|
||||
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
<dict>
|
||||
<key>CPBundleIdentifier</key>
|
||||
<string>com.280n.AppKit</string>
|
||||
<key>Default Themes Path</key>
|
||||
<string>Default.cptheme</string>
|
||||
<key>Default Theme Name</key>
|
||||
<string>Default</string>
|
||||
<key>CPBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CPBundleName</key>
|
||||
|
||||
@@ -152,6 +152,7 @@ CPDOMDisplayServerViewsContext = {};
|
||||
|
||||
delete CPDOMDisplayServerViewsContext[[view hash]];
|
||||
|
||||
[view layoutIfNeeded];
|
||||
[view displayIfNeeded];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,8 +59,6 @@ var CPDOMWindowGetFrame,
|
||||
CPTimeInterval _lastMouseUp;
|
||||
CPTimeInterval _lastMouseDown;
|
||||
|
||||
CPPoint _currentMousePosition;
|
||||
|
||||
JSObject _charCodes;
|
||||
unsigned _keyCode;
|
||||
|
||||
@@ -105,7 +103,10 @@ var CPDOMWindowGetFrame,
|
||||
_DOMBodyElement = document.getElementsByTagName("body")[0];
|
||||
_DOMBodyElement.innerHTML = ""; // Get rid of anything that might be lingering in the body element.
|
||||
_DOMBodyElement.style.overflow = "hidden";
|
||||
_DOMBodyElement.style.webkitTouchCallout = "none";
|
||||
|
||||
[CPString _resetSize];
|
||||
|
||||
if (document.documentElement)
|
||||
document.documentElement.style.overflow = "hidden";
|
||||
|
||||
@@ -151,6 +152,10 @@ var CPDOMWindowGetFrame,
|
||||
resizeEventImplementation = class_getMethodImplementation(theClass, resizeEventSelector),
|
||||
resizeEventCallback = function (anEvent) { resizeEventImplementation(self, nil, anEvent); },
|
||||
|
||||
touchEventSelector = @selector(_bridgeTouchEvent:),
|
||||
touchEventImplementation = class_getMethodImplementation(theClass, touchEventSelector),
|
||||
touchEventCallback = function (anEvent) { touchEventImplementation(self, nil, anEvent); },
|
||||
|
||||
theDocument = _DOMWindow.document;
|
||||
|
||||
if (document.addEventListener)
|
||||
@@ -165,6 +170,12 @@ var CPDOMWindowGetFrame,
|
||||
theDocument.addEventListener(CPDOMEventKeyDown, keyEventCallback, NO);
|
||||
theDocument.addEventListener(CPDOMEventKeyPress, keyEventCallback, NO);
|
||||
|
||||
|
||||
theDocument.addEventListener(CPDOMEventTouchStart, touchEventCallback, NO);
|
||||
theDocument.addEventListener(CPDOMEventTouchEnd, touchEventCallback, NO);
|
||||
theDocument.addEventListener(CPDOMEventTouchMove, touchEventCallback, NO);
|
||||
theDocument.addEventListener(CPDOMEventTouchCancel, touchEventCallback, NO);
|
||||
|
||||
//FIXME: does firefox really need a different value?
|
||||
_DOMWindow.addEventListener("DOMMouseScroll", scrollEventCallback, NO);
|
||||
_DOMWindow.addEventListener(CPDOMEventScrollWheel, scrollEventCallback, NO);
|
||||
@@ -225,6 +236,16 @@ var CPDOMWindowGetFrame,
|
||||
return CPRectCreateCopy(_contentBounds);
|
||||
}
|
||||
|
||||
- (CPArray)orderedWindowsAtLevel:(int)aLevel
|
||||
{
|
||||
var layer = [self layerAtLevel:aLevel create:NO];
|
||||
|
||||
if (!layer)
|
||||
return [];
|
||||
|
||||
return [layer orderedWindows];
|
||||
}
|
||||
|
||||
- (CPDOMWindowLayer)layerAtLevel:(int)aLevel create:(BOOL)aFlag
|
||||
{
|
||||
var layer = [_windowLayers objectForKey:aLevel];
|
||||
@@ -277,14 +298,13 @@ var CPDOMWindowGetFrame,
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (CPView)_dragHitTest:(CPPoint)aPoint pasteboard:(CPPasteboard)aPasteboard
|
||||
- (id)_dragHitTest:(CPPoint)aPoint pasteboard:(CPPasteboard)aPasteboard
|
||||
{
|
||||
var view = nil,
|
||||
levels = _windowLevels,
|
||||
var levels = _windowLevels,
|
||||
layers = _windowLayers,
|
||||
levelCount = levels.length;
|
||||
|
||||
while (levelCount-- && !view)
|
||||
while (levelCount--)
|
||||
{
|
||||
// Skip any windows above or at the dragging level.
|
||||
if (levels[levelCount] >= CPDraggingWindowLevel)
|
||||
@@ -295,18 +315,14 @@ var CPDOMWindowGetFrame,
|
||||
|
||||
while (windowCount--)
|
||||
{
|
||||
var theWindow = windows[windowCount],
|
||||
frame = theWindow._frame;
|
||||
var theWindow = windows[windowCount];
|
||||
|
||||
if (CPRectContainsPoint(frame, aPoint))
|
||||
if (view = [theWindow._windowView _dragHitTest:CGPointMake(aPoint.x - frame.origin.x, aPoint.y - frame.origin.y) pasteboard:aPasteboard])
|
||||
return view;
|
||||
else
|
||||
return nil;
|
||||
if ([theWindow containsPoint:aPoint])
|
||||
return [theWindow _dragHitTest:aPoint pasteboard:aPasteboard];
|
||||
}
|
||||
}
|
||||
|
||||
return view;
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
@@ -328,8 +344,12 @@ var CPDOMWindowGetFrame,
|
||||
windowCount = windows.length;
|
||||
|
||||
while (windowCount-- && !theWindow)
|
||||
if (CPRectContainsPoint(windows[windowCount]._frame, location))
|
||||
theWindow = windows[windowCount];
|
||||
{
|
||||
var candidateWindow = windows[windowCount];
|
||||
|
||||
if (!candidateWindow._ignoresMouseEvents && [candidateWindow containsPoint:location])
|
||||
theWindow = candidateWindow;
|
||||
}
|
||||
}
|
||||
|
||||
return theWindow;
|
||||
@@ -542,8 +562,6 @@ var CTRL_KEY_CODE = 17;
|
||||
event = [CPEvent mouseEventWithType:_mouseIsDown ? CPLeftMouseDragged : CPMouseMoved
|
||||
location:location modifierFlags:modifierFlags timestamp:timestamp
|
||||
windowNumber:windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0];
|
||||
|
||||
_currentMousePosition = _CGPointMake(aDOMEvent.clientX, aDOMEvent.clientY);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -649,7 +667,7 @@ var CTRL_KEY_CODE = 17;
|
||||
{
|
||||
_pasteboardKeyDownEvent = event;
|
||||
|
||||
window.setTimeout(function () { [self _checkPasteboardElement] }, 0);
|
||||
window.setNativeTimeout(function () { [self _checkPasteboardElement] }, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -694,7 +712,7 @@ var CTRL_KEY_CODE = 17;
|
||||
|
||||
_DOMPasteboardElement.select();
|
||||
|
||||
window.setTimeout(function() { [self _clearPasteboardElement]; }, 0);
|
||||
window.setNativeTimeout(function() { [self _clearPasteboardElement]; }, 0);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -720,10 +738,32 @@ var CTRL_KEY_CODE = 17;
|
||||
|
||||
try
|
||||
{
|
||||
if (CPFeatureIsCompatible(CPJavaScriptMouseWheelValues_8_15))
|
||||
{
|
||||
var x = 0.0,
|
||||
y = 0.0,
|
||||
element = aDOMEvent.target;
|
||||
|
||||
while (element.nodeType !== 1)
|
||||
element = element.parentNode;
|
||||
|
||||
if (element.offsetParent)
|
||||
{
|
||||
do
|
||||
{
|
||||
x += element.offsetLeft;
|
||||
y += element.offsetTop;
|
||||
|
||||
} while (element = element.offsetParent);
|
||||
}
|
||||
|
||||
var location = _CGPointMake((x + ((aDOMEvent.clientX - 8) / 15)), (y + ((aDOMEvent.clientY - 8) / 15)));}
|
||||
else
|
||||
var location = _CGPointMake(aDOMEvent.clientX, aDOMEvent.clientY);
|
||||
|
||||
var deltaX = 0.0,
|
||||
deltaY = 0.0,
|
||||
windowNumber = 0,
|
||||
location = CGPointMake(_currentMousePosition.x, _currentMousePosition.y),
|
||||
timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(),
|
||||
modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) |
|
||||
(aDOMEvent.ctrlKey ? CPControlKeyMask : 0) |
|
||||
@@ -807,7 +847,7 @@ var CTRL_KEY_CODE = 17;
|
||||
{
|
||||
var windows = [layers objectForKey:levels[levelCount]]._windows,
|
||||
windowCount = windows.length;
|
||||
|
||||
|
||||
while (windowCount--)
|
||||
[windows[windowCount] resizeWithOldBridgeSize:oldSize];
|
||||
}
|
||||
@@ -822,13 +862,77 @@ var CTRL_KEY_CODE = 17;
|
||||
}
|
||||
}
|
||||
|
||||
// DOM event properties used in mouse bridge code
|
||||
|
||||
// type
|
||||
// clientX
|
||||
// clientY
|
||||
// timestamp
|
||||
// target/srcElement
|
||||
// shiftKey,ctrlKey,altKey,metaKey
|
||||
|
||||
/* @ignore */
|
||||
- (void)_bridgeTouchEvent:(DOMEvent)aDOMEvent
|
||||
{
|
||||
try
|
||||
{
|
||||
if (aDOMEvent.touches && (aDOMEvent.touches.length == 1 || (aDOMEvent.touches.length == 0 && aDOMEvent.changedTouches.length == 1)))
|
||||
{
|
||||
var newEvent = {};
|
||||
|
||||
switch(aDOMEvent.type)
|
||||
{
|
||||
case CPDOMEventTouchStart: newEvent.type = CPDOMEventMouseDown;
|
||||
break;
|
||||
case CPDOMEventTouchEnd: newEvent.type = CPDOMEventMouseUp;
|
||||
break;
|
||||
case CPDOMEventTouchMove: newEvent.type = CPDOMEventMouseMoved;
|
||||
break;
|
||||
case CPDOMEventTouchCancel: newEvent.type = CPDOMEventMouseUp;
|
||||
break;
|
||||
}
|
||||
|
||||
var touch = aDOMEvent.touches.length ? aDOMEvent.touches[0] : aDOMEvent.changedTouches[0];
|
||||
|
||||
newEvent.clientX = touch.clientX;
|
||||
newEvent.clientY = touch.clientY;
|
||||
|
||||
newEvent.timestamp = aDOMEvent.timestamp;
|
||||
newEvent.target = aDOMEvent.target;
|
||||
|
||||
newEvent.shiftKey = newEvent.ctrlKey = newEvent.altKey = newEvent.metaKey = false;
|
||||
|
||||
newEvent.preventDefault = function(){if(aDOMEvent.preventDefault) aDOMEvent.preventDefault()};
|
||||
newEvent.stopPropagation = function(){if(aDOMEvent.stopPropagation) aDOMEvent.stopPropagation()};
|
||||
|
||||
[self _bridgeMouseEvent:newEvent];
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (aDOMEvent.preventDefault)
|
||||
aDOMEvent.preventDefault();
|
||||
|
||||
if (aDOMEvent.stopPropagation)
|
||||
aDOMEvent.stopPropagation();
|
||||
}
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
objj_exception_report(e, {path:@"CPDOMWindowBridge.j"});
|
||||
}
|
||||
|
||||
// handle touch cases specifically
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)_checkPasteboardElement
|
||||
{
|
||||
try
|
||||
{
|
||||
var value = _DOMPasteboardElement.value;
|
||||
|
||||
|
||||
if ([value length])
|
||||
{
|
||||
var pasteboard = [CPPasteboard generalPasteboard];
|
||||
@@ -898,7 +1002,3 @@ var CPDOMEventStop = function(aDOMEvent)
|
||||
CPSharedDOMWindowBridge._DOMFocusElement.blur();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
*/
|
||||
@@ -61,6 +61,9 @@
|
||||
|
||||
- (void)removeWindow:(CPWindow)aWindow
|
||||
{
|
||||
if (!aWindow._isVisible)
|
||||
return;
|
||||
|
||||
var index = aWindow._index,
|
||||
count = _windows.length - 1;
|
||||
|
||||
@@ -111,9 +114,14 @@
|
||||
|
||||
aWindow._isVisible = YES;
|
||||
|
||||
if ([aWindow styleMask] & CPBorderlessBridgeWindowMask)
|
||||
[aWindow setFrame:[aWindow._bridge contentBounds]];
|
||||
if ([aWindow isFullBridge])
|
||||
[aWindow setFrame:[aWindow._bridge visibleFrame]];
|
||||
}
|
||||
}
|
||||
|
||||
- (CPArray)orderedWindows
|
||||
{
|
||||
return _windows;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'rake'
|
||||
require '../common'
|
||||
require 'objective-j'
|
||||
require 'objective-j/bundletask'
|
||||
|
||||
|
||||
$BUILD_PATH = File.join($BUILD_DIR, $CONFIGURATION, 'AppKit')
|
||||
$ENVIRONMENT_PRODUCT = File.join($ENVIRONMENT_FRAMEWORKS_DIR, 'AppKit')
|
||||
|
||||
$THEME_PRODUCT = File.join($BUILD_PATH, 'Resources', 'Aristo.blend')
|
||||
$ENVIRONMENT_THEME_PRODUCT = File.join($ENVIRONMENT_PRODUCT, 'Resources', 'Aristo.blend')
|
||||
|
||||
AppKitFiles = FileList['**/*.j'].exclude('CoreGraphics/CGContextCanvas.j', 'CoreGraphics/CGContextVML.j', 'Themes/**', 'Tools/**')
|
||||
|
||||
ObjectiveJ::BundleTask.new(:AppKit) do |t|
|
||||
t.name = 'AppKit'
|
||||
t.identifier = 'com.280n.AppKit'
|
||||
t.version = '0.7.0'
|
||||
t.author = '280 North, Inc.'
|
||||
t.email = 'feedback @nospam@ 280north.com'
|
||||
t.summary = 'AppKit classes for Cappuccino'
|
||||
t.sources = AppKitFiles
|
||||
t.resources = FileList['Resources/*']
|
||||
t.license = ObjectiveJ::License::LGPL_v2_1
|
||||
t.build_path = $BUILD_PATH
|
||||
t.flag = '-DDEBUG -g' if $CONFIGURATION == 'Debug'
|
||||
t.flag = '-O' if $CONFIGURATION == 'Release'
|
||||
t.platforms = [ObjectiveJ::Platform::Browser, ObjectiveJ::Platform::Rhino]
|
||||
t.type = ObjectiveJ::Bundle::Type::Framework
|
||||
end
|
||||
|
||||
# It would be nice to just have ENVIRONMENT_PRODUCT depend on THEME_PRODUCT,
|
||||
# but this would be a circular dependency because THEME_PRODUCT needs
|
||||
# ENVIRONMENT_PRODUCT up-to-date since it runs an objj application that uses
|
||||
# AppKit.
|
||||
file_d $ENVIRONMENT_PRODUCT => [:AppKit] do
|
||||
cp_r(File.join($BUILD_PATH, '.'), $ENVIRONMENT_PRODUCT)
|
||||
end
|
||||
|
||||
file_d $ENVIRONMENT_THEME_PRODUCT => $THEME_PRODUCT do
|
||||
cp_r(File.join($THEME_PRODUCT, '.'), $ENVIRONMENT_THEME_PRODUCT)
|
||||
end
|
||||
|
||||
ThemeFiles = FileList['Themes/Aristo/*']
|
||||
|
||||
file_d $THEME_PRODUCT => ThemeFiles << $ENVIRONMENT_PRODUCT do
|
||||
File.popen("blend -d Themes/Aristo/ThemeDescriptors.j -o #{$THEME_PRODUCT} -R Themes/Aristo/Resources") do |blend|
|
||||
blend.sync = true
|
||||
|
||||
while str = blend.gets
|
||||
puts str
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
task :build => [:build_subprojects, :AppKit, $ENVIRONMENT_PRODUCT, $THEME_PRODUCT, $ENVIRONMENT_THEME_PRODUCT]
|
||||
|
||||
task :clean => :clean_suprojects
|
||||
|
||||
task :clobber => :clobber_subprojects
|
||||
|
||||
subprojects = %w{Tools}
|
||||
|
||||
task :build_subprojects do
|
||||
subrake(subprojects, :build)
|
||||
end
|
||||
|
||||
task :clean_suprojects do
|
||||
subrake(subprojects, :clean)
|
||||
end
|
||||
|
||||
task :clobber_subprojects do
|
||||
subrake(subprojects, :clobber)
|
||||
end
|
||||
|
||||
CLOBBER.include($ENVIRONMENT_PRODUCT)
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 497 B |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 486 B |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 617 B |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 578 B |
|
Before Width: | Height: | Size: 437 B After Width: | Height: | Size: 438 B |
|
Before Width: | Height: | Size: 471 B After Width: | Height: | Size: 462 B |
|
Before Width: | Height: | Size: 3.2 KiB |