mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-09-10 12:47:13 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80097ea2a2 | ||
|
|
b85e9d83b8 | ||
|
|
2e9684e9a7 | ||
|
|
a80a0d0a13 | ||
|
|
885eff1f9b | ||
|
|
706e80362d | ||
|
|
7bf2297125 | ||
|
|
99c1d18d95 | ||
|
|
a45668e7cb | ||
|
|
f46bbf83a8 | ||
|
|
52f7844aee | ||
|
|
64aeea0f08 | ||
|
|
06db60d7df | ||
|
|
eb39e2e81a | ||
|
|
0867ccdc73 | ||
|
|
8ead5f63da | ||
|
|
a80732f13a | ||
|
|
923d7c63b5 | ||
|
|
7626af00e7 | ||
|
|
1d647fab10 | ||
|
|
c9fcbe0e93 | ||
|
|
6d9d443d0a | ||
|
|
2a95523577 | ||
|
|
0fa149b74f | ||
|
|
c7fdad883a | ||
|
|
6e9f82212b | ||
|
|
22e2bdcd25 | ||
|
|
85c9ca518f | ||
|
|
29a93b20f4 | ||
|
|
b95bdca2a3 | ||
|
|
6fd5f66a15 | ||
|
|
9e235f7236 | ||
|
|
90d12ef77e | ||
|
|
0c2301766a | ||
|
|
8a7b6054ef | ||
|
|
7037151bfc | ||
|
|
ba26b19567 | ||
|
|
6587014014 | ||
|
|
80b16ae9ab | ||
|
|
07330a0ca8 | ||
|
|
c735399ca5 | ||
|
|
d68f4359ac | ||
|
|
d4cfa4b24f | ||
|
|
2912acb4f5 | ||
|
|
85683d8f18 | ||
|
|
8ca2a1bf5b | ||
|
|
8427697a4b | ||
|
|
275f89a340 | ||
|
|
49c8a02b5f | ||
|
|
1165e569d2 | ||
|
|
e66f22d094 | ||
|
|
d0b29fd38c | ||
|
|
28378ff19b | ||
|
|
b4f2f15698 | ||
|
|
2210c1f4c5 | ||
|
|
7be6352531 | ||
|
|
f2391cb150 | ||
|
|
09c02c5884 | ||
|
|
71d02abc28 | ||
|
|
367efe590e | ||
|
|
afcce49455 | ||
|
|
d63e4f8021 | ||
|
|
c9a4821d15 | ||
|
|
696990f035 | ||
|
|
ad0867ba7d | ||
|
|
48ebd2e954 | ||
|
|
3d82203893 | ||
|
|
a3766a0f96 | ||
|
|
2eb27a6492 | ||
|
|
991e213d02 | ||
|
|
834480ff68 | ||
|
|
678563a970 | ||
|
|
00e638f406 | ||
|
|
6b37bae2c2 | ||
|
|
a3a4aed0d2 | ||
|
|
8ec78f20d1 | ||
|
|
a821614939 | ||
|
|
e13d771560 | ||
|
|
49a0a3d86e | ||
|
|
56bc94f98c | ||
|
|
f0b527b680 | ||
|
|
58494c5c2a | ||
|
|
c72e136370 | ||
|
|
b4c8da8f3d | ||
|
|
612e8c3f0b | ||
|
|
9763cef196 | ||
|
|
ebd83b4941 | ||
|
|
48d3ae61c5 | ||
|
|
cfba019e3d | ||
|
|
2037ab9a5e | ||
|
|
3287b02816 | ||
|
|
12deb6859e | ||
|
|
98393c66fc | ||
|
|
74bedf6dcd | ||
|
|
b5d0054f94 | ||
|
|
560c971aeb | ||
|
|
8fc465b63a | ||
|
|
ca0c68c9bf | ||
|
|
6c663ddf32 | ||
|
|
7129094e26 | ||
|
|
802d7d53b0 | ||
|
|
c4a074a92d | ||
|
|
fe35823b46 | ||
|
|
8439dc1c0f | ||
|
|
db8e132ef2 | ||
|
|
7e0c61bef0 | ||
|
|
2c4bb019ba | ||
|
|
0bd03b8d58 | ||
|
|
e62af384ea | ||
|
|
e23c70b5c4 | ||
|
|
c8639cc8cd | ||
|
|
87c9f9ef03 | ||
|
|
ab430b3574 | ||
|
|
b8ae14d3a8 | ||
|
|
ca0ed0ccb9 | ||
|
|
99201dc3db | ||
|
|
5074938437 | ||
|
|
637b8bed33 | ||
|
|
fcd75d72e0 | ||
|
|
5b82417698 | ||
|
|
45ebe2c905 | ||
|
|
ff2aa51a68 | ||
|
|
b6491f7bb8 | ||
|
|
e78200838f | ||
|
|
01852d8075 | ||
|
|
0ce115bc9c | ||
|
|
b430e2ef65 | ||
|
|
a99e976610 | ||
|
|
9b4807de26 | ||
|
|
56a0184258 | ||
|
|
b64390077a | ||
|
|
e7e9c24aaa | ||
|
|
9eba3c0cec | ||
|
|
69b30df8e6 | ||
|
|
ca2aab1198 | ||
|
|
1b45f621a7 | ||
|
|
421a51f008 | ||
|
|
cce21e7e87 | ||
|
|
f6236ca317 | ||
|
|
77e10c94e9 | ||
|
|
38cc1943ee | ||
|
|
3b1047e97d | ||
|
|
34c1a1ce10 | ||
|
|
b0e3e38791 | ||
|
|
124a63736f | ||
|
|
656e0eb28e | ||
|
|
688c46c793 | ||
|
|
ee2228a83c | ||
|
|
9f4dd3c2b8 | ||
|
|
c80a28077a | ||
|
|
47c631c58e | ||
|
|
ed4235d2f9 | ||
|
|
16e9fce5b5 | ||
|
|
2e22a0d5e8 | ||
|
|
1ae31c9374 | ||
|
|
973c43843d | ||
|
|
90709156c6 | ||
|
|
0d15e59d0a | ||
|
|
60fcb24159 | ||
|
|
a175e71906 | ||
|
|
c3b5dc747a | ||
|
|
e527c7e19f | ||
|
|
790327fbe8 | ||
|
|
d18bba6b03 | ||
|
|
0a752be53c | ||
|
|
b221cc1853 | ||
|
|
2935651578 | ||
|
|
ca2ae22f15 | ||
|
|
1c597eb0df | ||
|
|
28dd74444f | ||
|
|
28cf834e0b | ||
|
|
4dc102a3cf | ||
|
|
23a654d57a | ||
|
|
ffcbf87858 | ||
|
|
32a0e950fe | ||
|
|
f21ec37531 | ||
|
|
a8d02f43e2 | ||
|
|
7e863e7e96 | ||
|
|
588577bd96 | ||
|
|
ee64c5d832 | ||
|
|
e55cbbdc0e | ||
|
|
65c48004ba | ||
|
|
4211abd0b0 | ||
|
|
cf6dc3fa5e | ||
|
|
fb3da5c5bd | ||
|
|
e6bd921746 | ||
|
|
40dcfbd72c | ||
|
|
48d14840ee | ||
|
|
c9e0ab654f | ||
|
|
d8c0d2da8e | ||
|
|
e59f20668b | ||
|
|
8fe67b73da | ||
|
|
2fba03dc75 | ||
|
|
71f8d1db74 | ||
|
|
098131e252 | ||
|
|
afc5b72092 | ||
|
|
14f494a25d | ||
|
|
8bc665f355 | ||
|
|
6dd872f2d2 | ||
|
|
461bb65263 | ||
|
|
266bed7dc9 | ||
|
|
9777e4c52f | ||
|
|
dd89a98242 | ||
|
|
9b57d04181 | ||
|
|
8e74418a5c | ||
|
|
3350579675 | ||
|
|
46c14f3766 | ||
|
|
0aa65de6df | ||
|
|
ea7257c00d | ||
|
|
06bb1a96f3 | ||
|
|
2f0de57c92 | ||
|
|
70e4dd16df | ||
|
|
b66034ef38 | ||
|
|
d3c86aeefd | ||
|
|
212feff636 | ||
|
|
b1b0cea27e | ||
|
|
5742608595 | ||
|
|
f46f97f8b6 | ||
|
|
7692f80f64 | ||
|
|
bb811238f3 | ||
|
|
68c657eb66 | ||
|
|
b5bae40a0c | ||
|
|
f7c68736f0 | ||
|
|
7d855a9c09 | ||
|
|
d59d141302 | ||
|
|
0c4ce1e756 | ||
|
|
9b8cadb91c | ||
|
|
9c9d6a7fdc | ||
|
|
fb31267cc1 | ||
|
|
b194d407d3 | ||
|
|
57813ea3fb | ||
|
|
bce89ca75b | ||
|
|
7204e73c22 | ||
|
|
541f5b8948 | ||
|
|
c5d471b31b | ||
|
|
ac26827f32 | ||
|
|
677cb4638f | ||
|
|
32348148b8 | ||
|
|
f79edc7bfb | ||
|
|
f7c7ee447d | ||
|
|
1220555936 | ||
|
|
032639234e | ||
|
|
cdf9a8c2a7 | ||
|
|
6fbdf7b400 | ||
|
|
4983e97884 | ||
|
|
cc7d50f505 | ||
|
|
f2f737fcd3 | ||
|
|
c47e6af6e4 | ||
|
|
5e6485b622 | ||
|
|
bb2ec9098b | ||
|
|
4e4cc65645 | ||
|
|
ddfac8d717 | ||
|
|
009683ddd4 | ||
|
|
8eefb90944 | ||
|
|
6bc8a53618 | ||
|
|
de73c05316 | ||
|
|
fba8b85c90 | ||
|
|
20557190d9 | ||
|
|
4e4e7ae015 | ||
|
|
36c3c94d3b | ||
|
|
64b733b1ea | ||
|
|
67a023a992 | ||
|
|
b6e7d4149d | ||
|
|
bcacee2147 | ||
|
|
b75dcd7ac4 | ||
|
|
e77d28f761 | ||
|
|
bc9645aa4f | ||
|
|
d52cbb7077 | ||
|
|
ba9df402b0 | ||
|
|
c78b5e580a | ||
|
|
ce2c662872 | ||
|
|
04b331ad55 | ||
|
|
35c026f92c | ||
|
|
6680a1f2a7 | ||
|
|
1ffbf7857f | ||
|
|
e2741ba604 | ||
|
|
5b7497093c | ||
|
|
b092ed8c2c | ||
|
|
2dd1a1b54d | ||
|
|
1952bc2b76 | ||
|
|
b6da0fdf06 | ||
|
|
7f7571a2d1 | ||
|
|
e704d42adb | ||
|
|
5ff9683cd7 | ||
|
|
7d36daa5b7 | ||
|
|
46956dbe9e | ||
|
|
586e18f1a7 | ||
|
|
c489909542 | ||
|
|
ad679e7c34 | ||
|
|
75f6db436b | ||
|
|
bdcef193b7 | ||
|
|
d377790e9d | ||
|
|
9a31297249 | ||
|
|
b4f7df4786 | ||
|
|
18d7dcc226 | ||
|
|
f7ef182d33 | ||
|
|
be36e17bd8 | ||
|
|
6b940116be | ||
|
|
da8ea72593 | ||
|
|
5effa853a3 | ||
|
|
0780a68fba | ||
|
|
b61192a050 | ||
|
|
9bc9a49b8f | ||
|
|
547f1fb786 | ||
|
|
b27560c51e | ||
|
|
8dd1d20a2d | ||
|
|
ad5badb0d7 | ||
|
|
18696e6bc2 | ||
|
|
4f2914a123 | ||
|
|
431c6522a6 | ||
|
|
b823eb7fe0 | ||
|
|
f8ceaf62b7 | ||
|
|
213fde04fe | ||
|
|
ddad10b615 | ||
|
|
f4e7386a0a | ||
|
|
9a42e12985 | ||
|
|
86ee790ea1 | ||
|
|
b21eab1bf1 | ||
|
|
c9752195ac | ||
|
|
64000215a4 | ||
|
|
65d957f9f5 | ||
|
|
aef19c3b13 | ||
|
|
9968896bbd | ||
|
|
1a27ae39a3 | ||
|
|
ee4802e513 | ||
|
|
60dd1863b3 | ||
|
|
71408e7c3a | ||
|
|
659543461b | ||
|
|
50b7f02470 | ||
|
|
febdf4092e | ||
|
|
a3d89c8d78 | ||
|
|
c9b02603bc | ||
|
|
b9086f134a | ||
|
|
447c33b806 | ||
|
|
ae47ba78cd | ||
|
|
2f51358ea0 | ||
|
|
c91c513b60 | ||
|
|
189d90da91 | ||
|
|
5e20a6d9ef | ||
|
|
05edec8a8b | ||
|
|
75cc0be52a | ||
|
|
a9e59e1e87 | ||
|
|
e766a2c945 | ||
|
|
fbd5a78cf0 | ||
|
|
f39c1a2eb8 | ||
|
|
5335a611a0 | ||
|
|
c06068c931 | ||
|
|
62f81f2601 | ||
|
|
077e548219 | ||
|
|
d56bc733ad | ||
|
|
8fbd24c861 | ||
|
|
98049aeb78 | ||
|
|
c9718783af | ||
|
|
bfe01badc1 | ||
|
|
111ac84a65 | ||
|
|
d7540eea84 | ||
|
|
88408fc0ea | ||
|
|
6e796d7a22 | ||
|
|
f587713795 | ||
|
|
66fcba846b | ||
|
|
bdf20b0267 | ||
|
|
0292203ec0 | ||
|
|
112ad65882 | ||
|
|
6bc0880a0d | ||
|
|
90a63e1b14 | ||
|
|
6ce45d32da | ||
|
|
4eaf560ee6 | ||
|
|
4c0057e66a | ||
|
|
bcb22c7e46 | ||
|
|
0683b46239 | ||
|
|
61ccc39f81 | ||
|
|
533e1a1846 | ||
|
|
6afe22f351 | ||
|
|
039f2ce449 | ||
|
|
494f39dd86 | ||
|
|
c851522536 | ||
|
|
9b37ba20a3 | ||
|
|
6310bfe084 | ||
|
|
1a9670ae9c | ||
|
|
ee9da8e31e | ||
|
|
23e9fd927c | ||
|
|
22c481ff27 | ||
|
|
14fb769582 | ||
|
|
da0af13142 | ||
|
|
44fb4a9b83 | ||
|
|
1e6f6879ff | ||
|
|
ba33bb56d0 | ||
|
|
ab5e2dd774 | ||
|
|
0b1b1bbe0b | ||
|
|
1aebc8942d | ||
|
|
233df3bdab | ||
|
|
dd9c085ae3 | ||
|
|
1fed798120 | ||
|
|
fcf9c0bc84 | ||
|
|
fd9a753170 | ||
|
|
2a5f4b98ed | ||
|
|
ad33d1648c | ||
|
|
1f784f46c7 | ||
|
|
ed52b44f8b | ||
|
|
4b8cc3e6d1 | ||
|
|
6b8e10cb2e | ||
|
|
952bb4bb7c | ||
|
|
a0bcae2404 | ||
|
|
567f54c9f9 | ||
|
|
66f84ede6e | ||
|
|
5b1ca8a7f9 | ||
|
|
4fc894e430 | ||
|
|
15356b617b | ||
|
|
c8f6e12586 | ||
|
|
102cc92991 | ||
|
|
1e490f1796 | ||
|
|
088a5c7166 | ||
|
|
5837533678 | ||
|
|
20ec557655 | ||
|
|
b7d1dfa75f | ||
|
|
33e4a082d6 | ||
|
|
dd49ef51d5 | ||
|
|
13b2a886f3 | ||
|
|
c1dfb315a9 | ||
|
|
96958d26c7 | ||
|
|
8d635c7a5a | ||
|
|
627c300b4a | ||
|
|
00812025c2 | ||
|
|
0b21b8bab1 | ||
|
|
271bb00147 | ||
|
|
b346d761d8 | ||
|
|
21614e15b2 | ||
|
|
998c2f19cf | ||
|
|
750cd3c258 | ||
|
|
df358ccc42 | ||
|
|
1b5efdfc5b | ||
|
|
63dfb8a227 | ||
|
|
a3c0590218 | ||
|
|
c694c96a32 | ||
|
|
30bc304a20 | ||
|
|
974cf64e1d | ||
|
|
fce726a031 | ||
|
|
7187ba3074 | ||
|
|
bfbf8fb841 | ||
|
|
4ea0d4d043 | ||
|
|
8c13204afa | ||
|
|
e4c79d2101 | ||
|
|
90a45dca29 | ||
|
|
bcff25b959 | ||
|
|
dff6203fb3 | ||
|
|
b4dd6b670b | ||
|
|
f028533c07 | ||
|
|
dac61a14cd | ||
|
|
6884f93d76 | ||
|
|
17cc77e816 | ||
|
|
7ac59dd142 | ||
|
|
c277ae7f68 | ||
|
|
7c78753865 | ||
|
|
9fc07ac622 | ||
|
|
364a11491d | ||
|
|
0a26288d88 | ||
|
|
dcfb916d30 | ||
|
|
d1c7dab356 | ||
|
|
0e5b5c844c | ||
|
|
3eea14abe4 | ||
|
|
a7ca917abf | ||
|
|
9ca80df67a | ||
|
|
48a89fd828 | ||
|
|
1002f80617 | ||
|
|
fc51bead8e | ||
|
|
cea663f4eb | ||
|
|
8ecac8d03c | ||
|
|
f26d2f4ebf | ||
|
|
cb7f60aba8 | ||
|
|
b4dbe422ff | ||
|
|
aea19c5cd0 | ||
|
|
edc5542ee6 | ||
|
|
eb99b7d7ca | ||
|
|
006f709d37 | ||
|
|
f5322b39bc | ||
|
|
8702b1421f | ||
|
|
3070634aab | ||
|
|
b65041a780 | ||
|
|
6426c8aee2 | ||
|
|
16b6753f1d | ||
|
|
b96db40e3d | ||
|
|
7caf5fe20a | ||
|
|
44a958d3f8 | ||
|
|
4c562048dc | ||
|
|
f3b92c7445 | ||
|
|
675e9829bd | ||
|
|
4c0dbda558 | ||
|
|
e586273a3f | ||
|
|
d4a0f0cd21 | ||
|
|
8cfba4c242 | ||
|
|
cce13b4b45 | ||
|
|
05e435633f | ||
|
|
6ff3fa0e52 | ||
|
|
c3c996f1f7 | ||
|
|
ff98a9be5a | ||
|
|
96cef81267 | ||
|
|
75ceeffab8 | ||
|
|
71fffb6b68 | ||
|
|
e066228015 | ||
|
|
48a5d55af7 | ||
|
|
b9c2becd3e | ||
|
|
24f72c0b73 | ||
|
|
90e9b86497 | ||
|
|
560ea75a25 | ||
|
|
78fd972312 | ||
|
|
d947c849c8 | ||
|
|
8ce63a244c | ||
|
|
0306c35b54 | ||
|
|
ff8e5ae42e | ||
|
|
acf5e5b75f | ||
|
|
4f946f267e | ||
|
|
abfe2b4be6 | ||
|
|
bb3c08ce0b | ||
|
|
138888e620 | ||
|
|
4e1b429913 | ||
|
|
51f780b5f5 | ||
|
|
cffbf86351 | ||
|
|
709a9b3c61 | ||
|
|
c35621b669 | ||
|
|
4d1baac4db | ||
|
|
474623feb3 | ||
|
|
c17a3533ec | ||
|
|
85f3691432 | ||
|
|
2ae8d25d18 | ||
|
|
780bdc4421 | ||
|
|
a2e6f8f964 | ||
|
|
564668587c | ||
|
|
023cf46041 | ||
|
|
36bb41a945 | ||
|
|
0cbdb3b2d1 | ||
|
|
70f2d86b58 | ||
|
|
914175de70 | ||
|
|
7696b30067 | ||
|
|
478b5eaba3 | ||
|
|
52f0c0f587 | ||
|
|
2a4d3507b8 | ||
|
|
78a75924de | ||
|
|
a34dfee752 | ||
|
|
5ca9b4f370 | ||
|
|
2a2b320be3 | ||
|
|
071ab7d555 | ||
|
|
9738bbfbe5 | ||
|
|
e385321f95 | ||
|
|
21a9ae4c45 | ||
|
|
6a689dc3df | ||
|
|
af0ca52739 | ||
|
|
83ea50a836 | ||
|
|
2022eb5c12 | ||
|
|
6b132c4d3b | ||
|
|
f34775b038 | ||
|
|
f73d8a55de | ||
|
|
3d39bf8720 | ||
|
|
9a302328c6 | ||
|
|
cdb1ac32fa | ||
|
|
74af0dc93a | ||
|
|
2da1dc31fb | ||
|
|
6b55c81462 | ||
|
|
07630964c1 | ||
|
|
a6b7d456f4 | ||
|
|
7c5a07f709 | ||
|
|
7e25166ce1 | ||
|
|
10df31cbf9 | ||
|
|
10c067e44f | ||
|
|
f81e97726a | ||
|
|
8f040d6ff1 | ||
|
|
32fb13a9a9 | ||
|
|
4b86115d30 | ||
|
|
12a49d0ee1 | ||
|
|
b37f5b4143 | ||
|
|
cbb9602f9e | ||
|
|
997a305d35 | ||
|
|
f09193ce07 | ||
|
|
96fc34c00e | ||
|
|
bd06b8a867 | ||
|
|
7414d1407f | ||
|
|
19d5431f60 | ||
|
|
f2c01cbbbd | ||
|
|
c807358216 | ||
|
|
685c3c9853 | ||
|
|
db3514a2c1 | ||
|
|
6a43c544eb | ||
|
|
1b174b86ca | ||
|
|
f40fc321fe | ||
|
|
eaf4fa240f | ||
|
|
17a8be1ae6 | ||
|
|
16be03b162 | ||
|
|
2f58517ce5 | ||
|
|
9a3c2d5311 | ||
|
|
fed39694f6 | ||
|
|
bb659e3c06 | ||
|
|
5c5412db67 | ||
|
|
1c35bd22f8 | ||
|
|
c28222e04d | ||
|
|
854481e395 | ||
|
|
44555ac724 | ||
|
|
dcec14decd | ||
|
|
f62d81e79f | ||
|
|
9ff056f073 | ||
|
|
1edb0bcc4a | ||
|
|
1899250a53 | ||
|
|
443e23e348 | ||
|
|
1e6595fca7 | ||
|
|
5ed475eedd | ||
|
|
17669fd09d | ||
|
|
51825db716 | ||
|
|
421ae6b316 | ||
|
|
3c98ed78ee | ||
|
|
9ab446b790 | ||
|
|
c65e3d4e6d | ||
|
|
10fad00c1e | ||
|
|
478f2d8134 | ||
|
|
a49b01d396 | ||
|
|
c26ebe0bd2 | ||
|
|
381a44148e | ||
|
|
c1f16de441 | ||
|
|
4a048657c5 | ||
|
|
44f5086600 | ||
|
|
ddddc3330d | ||
|
|
39ba9b9a4f | ||
|
|
bdb36f35cf | ||
|
|
0c9b4da473 | ||
|
|
935f1084d6 | ||
|
|
c8759babae | ||
|
|
ab3d648244 | ||
|
|
57dc0460a3 | ||
|
|
d5ee07fe1b | ||
|
|
89e3618d85 | ||
|
|
162381a73f | ||
|
|
08db857334 | ||
|
|
bb651d0c70 | ||
|
|
d9c094f644 | ||
|
|
32040bdd7e | ||
|
|
43f0e43de7 | ||
|
|
5122b15ffb | ||
|
|
468d8e7c33 | ||
|
|
93b1d1e591 | ||
|
|
1642149228 | ||
|
|
8fd564b034 | ||
|
|
7c3f94dd87 | ||
|
|
eacd408ce8 | ||
|
|
084da71420 | ||
|
|
3fa47ee9ec | ||
|
|
e811895570 | ||
|
|
47e890b8e1 | ||
|
|
f2bb27dc32 | ||
|
|
ef9d2d1775 | ||
|
|
be13a14330 | ||
|
|
45a2bcb71a | ||
|
|
48fb660e66 | ||
|
|
218919a8ba | ||
|
|
79ed04e403 | ||
|
|
3c995fe17b | ||
|
|
5ff8ddf5f3 | ||
|
|
8b2350fb22 | ||
|
|
15be647c16 | ||
|
|
8a8af0e4a9 | ||
|
|
4ff89eab04 | ||
|
|
ec032cb739 | ||
|
|
2b287a85e5 | ||
|
|
6ea2b4e0e2 | ||
|
|
f7e2e9c2ee | ||
|
|
5463e5ca55 | ||
|
|
396d4218f0 | ||
|
|
e3a07845d4 | ||
|
|
341a42bddd | ||
|
|
573444e640 | ||
|
|
ed9c6d7959 | ||
|
|
ed2c65dd6f | ||
|
|
0062caafdf | ||
|
|
b98f0b1427 | ||
|
|
b6a3d2b283 | ||
|
|
0d848e3d93 | ||
|
|
065197980b | ||
|
|
2a36488db7 | ||
|
|
3cd44284c4 | ||
|
|
bc0fa6a62e | ||
|
|
51c90223fc | ||
|
|
df1b56becf | ||
|
|
5a77c19791 | ||
|
|
eae3270385 | ||
|
|
daee101005 | ||
|
|
b32d503d65 | ||
|
|
ca7af88c59 | ||
|
|
6bd8e96ac0 | ||
|
|
d06d69966b | ||
|
|
004829ac9e | ||
|
|
0009603098 | ||
|
|
5479c77ae6 | ||
|
|
1f97616f3c | ||
|
|
e65fcdab42 | ||
|
|
428f5a656d | ||
|
|
0315ad38f9 | ||
|
|
6c1a6a2033 | ||
|
|
2a630a7210 | ||
|
|
528203d8e5 | ||
|
|
fd5a0cc468 | ||
|
|
359a29874b | ||
|
|
f9da7f73b3 | ||
|
|
49ae82d96a | ||
|
|
fbd23fb2c3 | ||
|
|
252b258159 | ||
|
|
dfcef3ca2d | ||
|
|
3d4a33d373 | ||
|
|
28397e672e | ||
|
|
bbbf439028 | ||
|
|
3c5dab1f34 | ||
|
|
e8499e1751 | ||
|
|
be26ab9201 | ||
|
|
7519b7ab63 | ||
|
|
aaf5c7581c | ||
|
|
ce4e8dc8b7 | ||
|
|
5c2e6c8ed8 | ||
|
|
4020f9c6c2 | ||
|
|
16bf635aca | ||
|
|
99bc5a018e | ||
|
|
06a553ba85 | ||
|
|
08b06b8632 | ||
|
|
79e8b6e242 | ||
|
|
6a34329765 | ||
|
|
f7dd6e4387 | ||
|
|
6a33acbb7c | ||
|
|
97e4b69eaa | ||
|
|
e96678eebc | ||
|
|
1bc8536f0e | ||
|
|
76df9be4fb | ||
|
|
322d8c67b3 | ||
|
|
d6ac30be75 | ||
|
|
a9f970459b | ||
|
|
76443a5d7f | ||
|
|
f0501f8494 | ||
|
|
efb752f1f4 | ||
|
|
d252e94892 | ||
|
|
0be23981f3 | ||
|
|
a4cadc5fb3 | ||
|
|
f902223597 | ||
|
|
9b926be557 | ||
|
|
db568af302 | ||
|
|
e7cf20a723 | ||
|
|
202243f711 | ||
|
|
c5f51ae826 | ||
|
|
61b9c7a1ee | ||
|
|
4520715b5b | ||
|
|
6ef829e9ec | ||
|
|
791e65c88b | ||
|
|
fddcde757f | ||
|
|
66180f8de4 | ||
|
|
bc5a21d545 | ||
|
|
fc8525e4d8 | ||
|
|
8dd61155bf | ||
|
|
5a89dfe8f4 | ||
|
|
80b70ec6b9 | ||
|
|
ac81ab458c | ||
|
|
23b76874df | ||
|
|
bc54fcf6c0 | ||
|
|
e0a3a683a5 | ||
|
|
c31786c4c1 | ||
|
|
13a5c7f215 | ||
|
|
ee2f361425 | ||
|
|
9eab2071dc | ||
|
|
61d7fe04e8 | ||
|
|
d3161422db | ||
|
|
d1ae1bd41f | ||
|
|
6384bed9cc | ||
|
|
be75e4948d | ||
|
|
337f5d9e73 | ||
|
|
4afa2bfada | ||
|
|
b94174f9e1 | ||
|
|
bf71045381 | ||
|
|
0ade0e1361 | ||
|
|
0f02e0d8dd | ||
|
|
7c786407a5 | ||
|
|
79ba8fecd5 | ||
|
|
213c81ed4d | ||
|
|
d7432c376d | ||
|
|
b8c7d6ea86 | ||
|
|
983f0a92b2 | ||
|
|
256cc902eb | ||
|
|
f7b766cc4a | ||
|
|
dca66f300d | ||
|
|
fd9dac8122 | ||
|
|
8b168e76af | ||
|
|
5b518797d7 | ||
|
|
e5275514dd | ||
|
|
0d35b38282 | ||
|
|
837dcbf19d | ||
|
|
e68d70cf1d | ||
|
|
1171e2c9af | ||
|
|
e5873caf04 | ||
|
|
34ee33aea0 | ||
|
|
2d93d12cad | ||
|
|
c43b80cb91 | ||
|
|
542e491bb4 | ||
|
|
9c9eb519df | ||
|
|
0a96cb8eb3 | ||
|
|
90975c96f9 | ||
|
|
2fd85ab78f | ||
|
|
a0cf7d5787 | ||
|
|
e7fc9d9912 | ||
|
|
bdb0fb1310 | ||
|
|
006f7e0c15 | ||
|
|
93afa11ef9 | ||
|
|
040e7bc9ee | ||
|
|
6bb8514253 | ||
|
|
85283cff38 | ||
|
|
ef68408fff | ||
|
|
71104e4902 | ||
|
|
65362e727a | ||
|
|
5044ce4236 | ||
|
|
b4aca3410f | ||
|
|
b5971eae95 | ||
|
|
4b775796be | ||
|
|
e97af776a0 | ||
|
|
e83e5b7c29 | ||
|
|
179ef85f4e | ||
|
|
5b4603b6a7 | ||
|
|
fc2560eb32 | ||
|
|
2c23c0ffa7 | ||
|
|
fda974458e | ||
|
|
efe4d5f339 | ||
|
|
032fe7cc0c | ||
|
|
50c519ec69 | ||
|
|
af566ec08a | ||
|
|
cb7879eecf | ||
|
|
b1825334dd | ||
|
|
09727909b3 | ||
|
|
f98d3bd44b | ||
|
|
1545f7b60a | ||
|
|
2453e403ef | ||
|
|
2bb16c3617 | ||
|
|
4ef9202e92 | ||
|
|
22668b6b43 | ||
|
|
f9c786f3eb | ||
|
|
0f2ee1966e | ||
|
|
62e520a6a5 | ||
|
|
2f9cf6bc9b | ||
|
|
e03cfe8287 | ||
|
|
0d97dfacd6 | ||
|
|
6ac0191451 | ||
|
|
f5b360f66c | ||
|
|
1d5c21fa72 | ||
|
|
015aca9165 | ||
|
|
d3e1c39e35 | ||
|
|
ae47509aa7 | ||
|
|
5ff798306f | ||
|
|
c41ffc14c7 | ||
|
|
1e7a3bef0d | ||
|
|
243f564396 | ||
|
|
dae1e44a8f | ||
|
|
67bcc29baf | ||
|
|
cdb089778c | ||
|
|
5e43a02ffa | ||
|
|
7395d13c3e | ||
|
|
f6000468db | ||
|
|
09e52d82bf | ||
|
|
0e98f44a93 | ||
|
|
6d595c1344 | ||
|
|
5f6f997095 | ||
|
|
6662fabcb8 | ||
|
|
7577cf8645 | ||
|
|
8340791824 | ||
|
|
14f0d16fae | ||
|
|
e1ad4a2fce | ||
|
|
f67580e2b2 | ||
|
|
31f408478a | ||
|
|
fd93b6e5f7 | ||
|
|
39bb8e3418 | ||
|
|
ab6d5d6a90 | ||
|
|
6b3600d67b | ||
|
|
bf8ff44b84 | ||
|
|
72a3888062 | ||
|
|
4479233bea | ||
|
|
a7021e6b66 | ||
|
|
0f5dd9d469 | ||
|
|
388f008189 | ||
|
|
639a32ea7e | ||
|
|
5838f1aec8 | ||
|
|
d2399b6157 | ||
|
|
b1282b4362 | ||
|
|
bbd402fcff | ||
|
|
6f0ca9d94c | ||
|
|
a18fb1b686 | ||
|
|
6a72e1b6ff | ||
|
|
b3141f1a62 | ||
|
|
aea8f1f0dc | ||
|
|
8aecf880e5 | ||
|
|
7d5ce51910 | ||
|
|
cfc8ccafce | ||
|
|
e11dfc2875 | ||
|
|
b3ef31ad05 | ||
|
|
70410d6311 | ||
|
|
4cc7dec35b | ||
|
|
47ecd40c4f | ||
|
|
489f2bcfa0 | ||
|
|
16590e0603 | ||
|
|
f50cda9abc | ||
|
|
7543968203 | ||
|
|
54685b1f36 | ||
|
|
abdc601d92 | ||
|
|
9f50f08065 | ||
|
|
aabb1fa6f2 | ||
|
|
4b770714bd | ||
|
|
8175dbca53 | ||
|
|
c91332afb4 | ||
|
|
08fb1b33b4 | ||
|
|
cd6b6afc65 | ||
|
|
cd4a70ea78 | ||
|
|
eb24ba9835 | ||
|
|
468869821f | ||
|
|
0c85dbf9b0 | ||
|
|
2db47e413e | ||
|
|
b8fddc98bf | ||
|
|
467f798147 | ||
|
|
374f3d13f1 | ||
|
|
b0a35a183f | ||
|
|
74e349ed33 | ||
|
|
c57aa2ac5e | ||
|
|
acac29dcda | ||
|
|
675969af6d | ||
|
|
ce32177e1d | ||
|
|
e956d61a08 | ||
|
|
068cdb9817 | ||
|
|
0ec7d4cd9a | ||
|
|
6a8126337c | ||
|
|
12db25a829 | ||
|
|
a347bfb8b1 | ||
|
|
9255af210c | ||
|
|
0b3264a99d | ||
|
|
2bf16da441 | ||
|
|
5c4d890100 | ||
|
|
99282026fa | ||
|
|
8f4b2a7cfd | ||
|
|
c78feda3d6 | ||
|
|
a279d62c88 | ||
|
|
8d1f787179 | ||
|
|
7ab41cf195 | ||
|
|
df728b7a21 | ||
|
|
cba26faf9b | ||
|
|
c4c1cffc01 | ||
|
|
321706e5c6 | ||
|
|
47bf4c0baa | ||
|
|
fc628c1221 | ||
|
|
eb6a03704a | ||
|
|
7b855e6c68 | ||
|
|
fe0818c612 | ||
|
|
74dabcae8a | ||
|
|
daf7870bab | ||
|
|
64da7f8775 | ||
|
|
6cfa11a94d | ||
|
|
db3c6c1463 | ||
|
|
65a669a9a1 | ||
|
|
33f56bb203 | ||
|
|
1ff873e170 | ||
|
|
b0e0156880 | ||
|
|
896f36dffb | ||
|
|
eae975652e | ||
|
|
e46d1a793c | ||
|
|
1c9763eaa8 | ||
|
|
686370ac0e | ||
|
|
e4ca057e4c | ||
|
|
ac5a0e3dfc | ||
|
|
a580b522e3 | ||
|
|
af53c271c7 | ||
|
|
4476dad395 | ||
|
|
b7b2dd2915 | ||
|
|
efb6a0f5c6 | ||
|
|
deba653661 | ||
|
|
eb831dc4ac | ||
|
|
b0d355a71c | ||
|
|
af11b4e423 | ||
|
|
0cf86318ce | ||
|
|
4175b762c3 | ||
|
|
3ddcb5f118 | ||
|
|
d0ad865976 | ||
|
|
7013b34897 | ||
|
|
bbbae36e6a | ||
|
|
34c3a9530b | ||
|
|
78cb522874 | ||
|
|
e8a0d2acf6 | ||
|
|
f8c13f1e30 | ||
|
|
4b272a76fd | ||
|
|
f73d96af08 | ||
|
|
bb0835e2f3 | ||
|
|
ef4c108b9e | ||
|
|
319b9ed00f | ||
|
|
35b62ca53f | ||
|
|
4e1e6f3c0b | ||
|
|
c8f3445fa6 | ||
|
|
7aa1ae6bd4 | ||
|
|
58179939bb | ||
|
|
5d3eae9022 | ||
|
|
05f8a10b3d | ||
|
|
6843df410a | ||
|
|
f324577014 | ||
|
|
df8357e1fc | ||
|
|
35d14939c4 | ||
|
|
f2c19ad403 | ||
|
|
ed9fee3038 | ||
|
|
58e31b9cb4 | ||
|
|
401ee3fd94 | ||
|
|
43b601af9b | ||
|
|
5581dd71fa | ||
|
|
d8fb849691 | ||
|
|
5f4281b851 | ||
|
|
24ab176236 | ||
|
|
9c342ca19c | ||
|
|
3ee3acc948 | ||
|
|
9bdc5fa0fe | ||
|
|
d7a7d8e2ae | ||
|
|
5a9682b1bd | ||
|
|
3c97903ed0 | ||
|
|
c9cf21be80 | ||
|
|
f0818d94e9 | ||
|
|
831555cf5a | ||
|
|
e0483e316e | ||
|
|
c1fe45cbcd | ||
|
|
ef7ad8ee8e | ||
|
|
0ed7d46926 | ||
|
|
ac69879fba | ||
|
|
50e779ef5a | ||
|
|
0032af1468 | ||
|
|
cf1c369dc3 | ||
|
|
ece7996895 | ||
|
|
3cdfc1192a | ||
|
|
8b8998a2b9 | ||
|
|
677cf9e1df | ||
|
|
a08d4c6a06 | ||
|
|
e1e344dad1 | ||
|
|
b9427f84ae | ||
|
|
dc9d79bc3d | ||
|
|
503ce5502e | ||
|
|
0e4d476d76 | ||
|
|
cc2d579bc9 | ||
|
|
94bf2a36cf | ||
|
|
63127bf9c3 | ||
|
|
033765e866 | ||
|
|
1634e4562a | ||
|
|
ed66d78585 | ||
|
|
39e1514620 | ||
|
|
10b7eb83f1 | ||
|
|
672be3991d | ||
|
|
b350c2be91 | ||
|
|
68ab5bd4e7 | ||
|
|
bd21153300 | ||
|
|
9cca7ead17 | ||
|
|
4b1bf1fe65 | ||
|
|
6d353f378d | ||
|
|
cc2bb8f496 | ||
|
|
20853e3ad7 | ||
|
|
67def34e29 | ||
|
|
54549b61e1 | ||
|
|
3e7c3e952b | ||
|
|
e6411d7d90 | ||
|
|
9e7d0d3183 | ||
|
|
3ae4b1cf19 | ||
|
|
2841223c9d | ||
|
|
ba713b8b06 | ||
|
|
c53bff288a | ||
|
|
d85e8798c2 | ||
|
|
6dbb4eedb7 | ||
|
|
33b4b94426 | ||
|
|
3fc99095e2 | ||
|
|
8410198c37 | ||
|
|
d1b325052d | ||
|
|
4c4b42833a | ||
|
|
519a9300e2 | ||
|
|
91dda1f759 | ||
|
|
65e12269d1 | ||
|
|
9d2474b142 | ||
|
|
e804d44934 | ||
|
|
961628d8d3 | ||
|
|
7522751fd2 | ||
|
|
e3dc9fd96b | ||
|
|
c3ac076d13 | ||
|
|
1e02511022 | ||
|
|
071a772208 | ||
|
|
78711163c5 | ||
|
|
3f005ff476 | ||
|
|
ddd399631f | ||
|
|
c0ce830456 | ||
|
|
481555f11f | ||
|
|
20327d8fb6 | ||
|
|
a377e15368 | ||
|
|
52ca9628fd | ||
|
|
db1454c4fe | ||
|
|
6845bd4598 | ||
|
|
f02286e3f5 | ||
|
|
d473c251e6 | ||
|
|
64a401125d | ||
|
|
68ae1af13f | ||
|
|
f2165af48f | ||
|
|
62b1dbbc74 | ||
|
|
0881d86998 | ||
|
|
aff4883222 | ||
|
|
fbed77fc64 | ||
|
|
276e8b948d | ||
|
|
2edcfbda35 | ||
|
|
22cdd6e04d | ||
|
|
3518813145 | ||
|
|
a453412d5b | ||
|
|
55b438e8c1 | ||
|
|
ce749302a5 | ||
|
|
3356175f3e | ||
|
|
50ff20ba33 | ||
|
|
d3ba51104e | ||
|
|
981c184c20 | ||
|
|
e3a65a1847 | ||
|
|
64eb440ea3 | ||
|
|
994383f73a | ||
|
|
89bd5f5b93 | ||
|
|
ae25f489ad | ||
|
|
510eaabcfb | ||
|
|
875e177219 | ||
|
|
f8f62e1473 | ||
|
|
c1a70a3aa2 | ||
|
|
c514fd7a08 | ||
|
|
3cefc86fbf | ||
|
|
0c66606d1d | ||
|
|
05fc35a5b9 | ||
|
|
2425838ea6 | ||
|
|
20d117e129 | ||
|
|
8f08c33bcc | ||
|
|
d7f0bf6a24 | ||
|
|
5afe6fea3c | ||
|
|
9441739839 | ||
|
|
8727d96a06 | ||
|
|
b2ffe7e509 | ||
|
|
119c950b53 | ||
|
|
29a0de3636 | ||
|
|
aa3e3c7e71 | ||
|
|
eb00953c60 | ||
|
|
c4b255ae46 | ||
|
|
d3547dd892 | ||
|
|
7d1c7b2907 | ||
|
|
d0999fa5d5 | ||
|
|
c478afee0f | ||
|
|
ab196e75c1 | ||
|
|
50b5c21fcf | ||
|
|
47bc7e812d | ||
|
|
ad5f574fb7 | ||
|
|
9537a62ab1 | ||
|
|
dc7bd3355d | ||
|
|
d76d9bcfad | ||
|
|
440eed77cf | ||
|
|
b906fbea29 | ||
|
|
af148137d6 | ||
|
|
64357fde0d | ||
|
|
7512a45cda | ||
|
|
e034abef82 | ||
|
|
0b5db9c4bd | ||
|
|
3cd763aabb | ||
|
|
1a881fb501 | ||
|
|
2f68804279 | ||
|
|
60d15e2983 | ||
|
|
628488f7aa | ||
|
|
149308bc89 | ||
|
|
b4fa971007 | ||
|
|
b30f10ca46 | ||
|
|
da725f6ffc | ||
|
|
b0d62a8608 | ||
|
|
3da2d3718b | ||
|
|
4bd6aca0c0 | ||
|
|
e90c84ee81 | ||
|
|
45b8f83cdd | ||
|
|
c8e0aa9cb4 | ||
|
|
7a486db45f | ||
|
|
4634c6cf3b | ||
|
|
eb57d14673 | ||
|
|
cb939baca0 | ||
|
|
db8a277960 | ||
|
|
398d61097c | ||
|
|
4a43e4fda6 | ||
|
|
783159ee44 | ||
|
|
fa63551b42 | ||
|
|
18a0deb678 | ||
|
|
f7c46855b8 | ||
|
|
e67539c3b1 | ||
|
|
b8d06521b2 | ||
|
|
3225d980c5 | ||
|
|
9c3a579ff8 | ||
|
|
92b5b34d17 | ||
|
|
47e8696b9f | ||
|
|
7938384162 | ||
|
|
01aec1f78e | ||
|
|
67f35c7b74 | ||
|
|
d600df4585 | ||
|
|
f3a0710059 | ||
|
|
203e0d150b | ||
|
|
efd699a044 | ||
|
|
dbe0ca0adc | ||
|
|
5316cabf30 | ||
|
|
9a16921a32 | ||
|
|
f5edf2a4c2 | ||
|
|
cfdcfdbc99 | ||
|
|
ad99dca6ac | ||
|
|
fbcc81056b | ||
|
|
756877b94c | ||
|
|
68d30c8802 | ||
|
|
555b83a359 | ||
|
|
ff43be6d7b | ||
|
|
7defbce1dd | ||
|
|
ef5aead17d | ||
|
|
585b70a6a9 | ||
|
|
b24a78bdd5 | ||
|
|
f305621ade | ||
|
|
24198a7890 | ||
|
|
2d477b38bc | ||
|
|
48afc5639e | ||
|
|
7b932fbf4a | ||
|
|
39f3e7b292 | ||
|
|
49f3038737 | ||
|
|
f7a40a071b | ||
|
|
3a1ebcaf3f | ||
|
|
3da1c4381c | ||
|
|
9ff73e5e63 | ||
|
|
f3633c050b | ||
|
|
1ba828da18 | ||
|
|
109725d613 | ||
|
|
4bc8f01376 | ||
|
|
df20a6d6df | ||
|
|
e32963384e | ||
|
|
03a9865ccb | ||
|
|
7674b3aec6 | ||
|
|
9c9a5bcd51 | ||
|
|
8948f7f43c | ||
|
|
ef4e86a124 | ||
|
|
b9edc357f3 | ||
|
|
9353d0f95c | ||
|
|
7defdd2a00 | ||
|
|
621e79fe33 | ||
|
|
e759c5343b | ||
|
|
458481af4e | ||
|
|
d879b25458 | ||
|
|
ccffde6966 | ||
|
|
1524f80418 | ||
|
|
bcbeb888f6 | ||
|
|
7730aeb652 | ||
|
|
272f938f2e | ||
|
|
5570a346c4 | ||
|
|
2b90652a16 | ||
|
|
a58dd4678c | ||
|
|
25f4574093 | ||
|
|
733b9b731d | ||
|
|
20637fc5e0 | ||
|
|
c33e2ee51f | ||
|
|
7ef59418dd | ||
|
|
0805e58a94 | ||
|
|
6ddeff2b21 | ||
|
|
7433c38d92 | ||
|
|
5f930ec840 | ||
|
|
0dd36b2275 | ||
|
|
629428739d | ||
|
|
7d7281480a | ||
|
|
666e2c0190 | ||
|
|
3968d35cac | ||
|
|
551677d6fd | ||
|
|
85b029fad0 | ||
|
|
841ed9ea89 | ||
|
|
74fd7eb793 | ||
|
|
26df9e861f | ||
|
|
338860d05b | ||
|
|
b7df6c1480 | ||
|
|
b2179f14ab | ||
|
|
99b43fed7f | ||
|
|
25dfcd38a7 | ||
|
|
a6d2c42402 | ||
|
|
fd8271396d | ||
|
|
19ca6a342e | ||
|
|
7819e174f1 | ||
|
|
7cd6d026a2 | ||
|
|
c48d306195 | ||
|
|
3a9845f784 | ||
|
|
94d3053232 | ||
|
|
b078169adf | ||
|
|
38c4dd408c | ||
|
|
8beb9dfed0 | ||
|
|
eef9549e96 | ||
|
|
82ac98ddc7 | ||
|
|
3d52ffcbdc | ||
|
|
3fad4635b0 | ||
|
|
b0b19328a8 | ||
|
|
9fd79488f8 | ||
|
|
cebe31857a | ||
|
|
1961829414 | ||
|
|
3e5bdec033 | ||
|
|
5789021a76 | ||
|
|
6bf0319c51 | ||
|
|
8f519caa77 | ||
|
|
a38be80a86 | ||
|
|
81b72fc571 | ||
|
|
91681d7846 | ||
|
|
d40619aca0 | ||
|
|
1328bc732f | ||
|
|
060f65b27e | ||
|
|
364669f527 | ||
|
|
f4042b9d4b | ||
|
|
c750b696d2 | ||
|
|
02cdee6c75 | ||
|
|
c4a824b5db | ||
|
|
7f31c0632d | ||
|
|
96ee92695c | ||
|
|
80b252a744 | ||
|
|
4f50f8b83f | ||
|
|
df895b9529 | ||
|
|
f9e9e51352 | ||
|
|
27e99344bd | ||
|
|
32572844fd | ||
|
|
a77e67e578 | ||
|
|
fb9cd1ef93 | ||
|
|
93722f6a7d | ||
|
|
76da7466ec | ||
|
|
6b3c95f09f | ||
|
|
81110ddba7 | ||
|
|
64fd9f615c | ||
|
|
213df88766 | ||
|
|
a26750d4f4 | ||
|
|
72edd7376e | ||
|
|
948e9ae139 | ||
|
|
ae357d1a2b | ||
|
|
59756ff1b3 | ||
|
|
2908e453e8 | ||
|
|
7b1ffc885f | ||
|
|
95364b1d31 | ||
|
|
f3257c0847 | ||
|
|
eb0fc35c8f | ||
|
|
3dccd93093 | ||
|
|
8929199082 | ||
|
|
20f6a57b3a | ||
|
|
db949728dd | ||
|
|
92d28e468e | ||
|
|
f95c3ca46a | ||
|
|
477b6bcdc5 | ||
|
|
3e40deba5f | ||
|
|
7d9bd25270 | ||
|
|
c201990cb0 | ||
|
|
289df53fb4 | ||
|
|
62788423a1 | ||
|
|
8617990206 | ||
|
|
2d8f2b328f | ||
|
|
833896e267 | ||
|
|
f12b4520f6 | ||
|
|
2564003c85 | ||
|
|
c36b8f2257 | ||
|
|
d413fbe0ed | ||
|
|
4237000fc9 | ||
|
|
5131aff352 | ||
|
|
f77f52802c | ||
|
|
d52ab34421 | ||
|
|
81e4c26b38 | ||
|
|
1eed1901e9 | ||
|
|
a8b1c7bce1 | ||
|
|
ac3d035ce7 | ||
|
|
c8575cac05 | ||
|
|
8d63c059c5 | ||
|
|
bc53288fca | ||
|
|
474d4281f1 | ||
|
|
73babcd7d6 | ||
|
|
5fe208d6a0 | ||
|
|
94ca0ed71b | ||
|
|
a323cfe08c | ||
|
|
29c3654928 | ||
|
|
27fefed0d8 | ||
|
|
235d974ce1 | ||
|
|
cb1d3168e3 | ||
|
|
64dc25dfb6 | ||
|
|
9a7484e57d | ||
|
|
b89ee3e4c1 | ||
|
|
ec5645d380 | ||
|
|
a0abf1e221 | ||
|
|
0e558d54e5 | ||
|
|
004cc5fe5a | ||
|
|
0b22b1d022 | ||
|
|
24ecf31bd3 | ||
|
|
c37c80771c | ||
|
|
a017c0c4a8 | ||
|
|
3a35ab449b | ||
|
|
da84964a33 | ||
|
|
65051855ee | ||
|
|
72c36789c6 | ||
|
|
bc07bd16bd | ||
|
|
bf691fa552 | ||
|
|
47ddfec1f9 | ||
|
|
fb8ba655e1 | ||
|
|
d64f56817d | ||
|
|
9363708e49 | ||
|
|
65a2e4d6b0 | ||
|
|
138d7bd9a2 | ||
|
|
97fe09fbdd | ||
|
|
487412fa22 | ||
|
|
ea47baa1fc | ||
|
|
90cd519916 | ||
|
|
669d18b218 | ||
|
|
fbcd2b3174 | ||
|
|
99a839456d | ||
|
|
0d9d60466d | ||
|
|
5a031efa7a | ||
|
|
1f64fce47c | ||
|
|
04529897dc | ||
|
|
7837e1ad81 | ||
|
|
c7c60b2b94 | ||
|
|
f9c2805379 | ||
|
|
035d772a4a | ||
|
|
f89c2e0ba9 | ||
|
|
94ce055bc2 | ||
|
|
9b3d4d4453 | ||
|
|
329e4dc3c3 | ||
|
|
d96e939eed | ||
|
|
c8437895dc | ||
|
|
95ba648dae | ||
|
|
9f847e5a24 | ||
|
|
a4eec5fef8 | ||
|
|
e51bf3f0c1 | ||
|
|
b907ea59f4 | ||
|
|
cebff75992 | ||
|
|
a3f9b65501 | ||
|
|
1f7afe7a49 | ||
|
|
ceecaa0184 | ||
|
|
78b4bbb06e | ||
|
|
0375e7a881 | ||
|
|
ebc831663b | ||
|
|
65ceb96e4f | ||
|
|
57ef2d2229 | ||
|
|
8759b175bd | ||
|
|
13f86b0cd4 | ||
|
|
c0fad49375 | ||
|
|
579cc98e4f | ||
|
|
4a98417ee8 | ||
|
|
4a5e90b5cb | ||
|
|
36a85e935b | ||
|
|
9034203a4f | ||
|
|
24e8f8aa43 | ||
|
|
632251b16c | ||
|
|
2406cbe7ed | ||
|
|
e6a0caa164 | ||
|
|
cd3e2fbbb8 | ||
|
|
47bd6e5ce3 | ||
|
|
f590c63e33 | ||
|
|
e8b74ece72 | ||
|
|
3d45699bc7 | ||
|
|
ae987f19dc | ||
|
|
09786cb8d2 | ||
|
|
17072f9ed4 | ||
|
|
82d3d1abc5 | ||
|
|
2cc40a7961 | ||
|
|
c523e706e9 | ||
|
|
cdca8047b9 | ||
|
|
09b8a3394e | ||
|
|
ed1a7a4bc9 | ||
|
|
0696fb405e | ||
|
|
265a410342 | ||
|
|
cbd0d6e6a2 | ||
|
|
25e0a59d5b | ||
|
|
ab34ee882e | ||
|
|
4f05657236 | ||
|
|
7720200679 | ||
|
|
117ec9970c | ||
|
|
766073f77a | ||
|
|
5f0a60f61c | ||
|
|
d608d34166 | ||
|
|
8bc1c7445d | ||
|
|
985b906c94 | ||
|
|
e8ac94f8da | ||
|
|
9465dd6941 | ||
|
|
28a00fff23 | ||
|
|
c418481981 | ||
|
|
2b87b9f3fc | ||
|
|
683eb993e8 | ||
|
|
e19d6a58c9 | ||
|
|
2dccee05bc | ||
|
|
ac2885afc6 | ||
|
|
972909902e | ||
|
|
b07f2ed186 | ||
|
|
ee6160e796 | ||
|
|
5940e6913d | ||
|
|
c85e33c034 | ||
|
|
21ef259e1f | ||
|
|
2b66683167 | ||
|
|
851a0e3d24 | ||
|
|
8b32f561ec | ||
|
|
1571b6daa2 | ||
|
|
2d69509d5e | ||
|
|
8edf05c000 | ||
|
|
0e6cef0268 | ||
|
|
60e4d8e080 | ||
|
|
6b58986ec3 | ||
|
|
e88ec01fca | ||
|
|
8284498722 | ||
|
|
e088280a5f | ||
|
|
7f78c323e9 | ||
|
|
77303c1aeb | ||
|
|
cc74f941c6 | ||
|
|
775c1c1c8b | ||
|
|
35a7456302 | ||
|
|
4006b35a5e | ||
|
|
b562280503 | ||
|
|
e3a075a6a6 | ||
|
|
8c534c6d33 | ||
|
|
82be6c243c | ||
|
|
5b8ee5dd1b | ||
|
|
050a132bd5 | ||
|
|
146bff6766 | ||
|
|
cd98bce331 | ||
|
|
a2d3723c7a | ||
|
|
ecb88a87ad | ||
|
|
3f2813932a | ||
|
|
c2223e3942 | ||
|
|
2dc0839d36 | ||
|
|
97ef1d1781 | ||
|
|
e64a9a7ab9 | ||
|
|
d4f3f83212 | ||
|
|
1488f3ed58 | ||
|
|
26945bde42 | ||
|
|
c911dd8aa6 | ||
|
|
1c81e0eee0 | ||
|
|
5366713790 | ||
|
|
e9940d060a | ||
|
|
605e905f3e | ||
|
|
11d30566bf | ||
|
|
0942f9fac3 | ||
|
|
7b303b6529 | ||
|
|
6a9040989d | ||
|
|
840e9c7671 | ||
|
|
1d9e2f8169 | ||
|
|
8c9f302b67 | ||
|
|
44f23cd8ac | ||
|
|
c88f781509 | ||
|
|
3dc578d585 | ||
|
|
238d8ff0be | ||
|
|
ca5dd0071c | ||
|
|
86fa759f9f | ||
|
|
0bcf8a6626 | ||
|
|
d735cd98e7 | ||
|
|
e25a550d3f | ||
|
|
8a2206656d | ||
|
|
ac68d670a2 | ||
|
|
e6539bbed5 | ||
|
|
9db0694677 | ||
|
|
a4d73330cc | ||
|
|
ea6a983e9b | ||
|
|
79cd8603a2 | ||
|
|
02cb054b71 | ||
|
|
007cfd589f | ||
|
|
90d24fd6bf | ||
|
|
4b7310d0cb | ||
|
|
59660032e1 | ||
|
|
d9c47ec763 | ||
|
|
a18ea750a6 | ||
|
|
c423411639 | ||
|
|
b5ad030e40 | ||
|
|
bfdbe2a34a | ||
|
|
ec5dcb47c9 | ||
|
|
436f1d1541 | ||
|
|
05873a030f | ||
|
|
78083eea48 | ||
|
|
7715da02e7 | ||
|
|
6798a5777a | ||
|
|
2f3ad961e7 | ||
|
|
dba047187f | ||
|
|
03e63f29dc | ||
|
|
b4cd9c4c45 | ||
|
|
b9b2649db9 | ||
|
|
df98483b06 | ||
|
|
37fbeaad02 | ||
|
|
794d8a754c | ||
|
|
b081debf88 | ||
|
|
36c6c9bfa6 | ||
|
|
bda5ea1c59 | ||
|
|
5ccf6eefc0 | ||
|
|
06261559fc | ||
|
|
477d2f9d82 | ||
|
|
0cb66ddc6e | ||
|
|
99df7f6acb | ||
|
|
0791fa0ad3 | ||
|
|
9811327672 | ||
|
|
60f2eaadf5 | ||
|
|
5478c640cc | ||
|
|
7fe3b115f1 | ||
|
|
3ee63b754c | ||
|
|
378b6c12f3 | ||
|
|
ee5817e480 | ||
|
|
a354b4acd5 | ||
|
|
8e87a4a941 | ||
|
|
42712166e9 | ||
|
|
2bc31de69d | ||
|
|
fcfeb29be5 | ||
|
|
a64a270e25 | ||
|
|
96eebc7d1d | ||
|
|
38fd675f51 | ||
|
|
35adaee1bb | ||
|
|
def314b5ad | ||
|
|
913a18eaaf | ||
|
|
d82b39de19 | ||
|
|
cde5d8709c | ||
|
|
ec210c49c5 | ||
|
|
07f320def9 | ||
|
|
f5fe15d6cb | ||
|
|
da146b0873 | ||
|
|
3b7a77ae0c | ||
|
|
9cb1e28ad1 | ||
|
|
9db7701691 | ||
|
|
27aca4c84a | ||
|
|
4e50244dca | ||
|
|
0c21724270 | ||
|
|
09306aa2cd | ||
|
|
1170673b92 | ||
|
|
712a991c86 | ||
|
|
e3cdcbc5ab | ||
|
|
62379b21c1 | ||
|
|
cfde67742c | ||
|
|
9b01561127 | ||
|
|
fb89450b90 | ||
|
|
5a8d491f10 | ||
|
|
7ffb44e394 | ||
|
|
34a5d9e61b | ||
|
|
e1d43e3651 | ||
|
|
c291ad83f1 | ||
|
|
c6a4eb28a8 | ||
|
|
dd4735026a | ||
|
|
dc0439227e | ||
|
|
00f470763f | ||
|
|
05b1cfca31 | ||
|
|
e40696a7af | ||
|
|
bc030c42d9 | ||
|
|
7ce72a31c5 | ||
|
|
cf8989938c | ||
|
|
e09b63183c | ||
|
|
76717c7177 | ||
|
|
6749fa57ad | ||
|
|
050b75a2df | ||
|
|
3f730c94ce | ||
|
|
22c931729b | ||
|
|
cb658826a3 | ||
|
|
3f8c311ea2 | ||
|
|
22aa4d359e | ||
|
|
c2880ec8e4 | ||
|
|
108822d4e1 | ||
|
|
f79a926b10 | ||
|
|
4eef234736 | ||
|
|
5abbdfc094 | ||
|
|
c44715bef4 | ||
|
|
b5f55100e9 | ||
|
|
4e0404fce6 | ||
|
|
f1874eca8a | ||
|
|
2e1d6f2412 | ||
|
|
0395287906 | ||
|
|
bda8a5fd6c | ||
|
|
ded413481c | ||
|
|
a5a6c07b08 | ||
|
|
204df99375 | ||
|
|
55dd67a0ad | ||
|
|
6040ee4ffc | ||
|
|
544ed99d98 | ||
|
|
7546640fba | ||
|
|
daf5b88834 | ||
|
|
c36f975bbf | ||
|
|
a5e34d9153 | ||
|
|
57a63440f9 | ||
|
|
e25a227e4d | ||
|
|
db7b340b32 | ||
|
|
7683755137 | ||
|
|
8de71663c2 | ||
|
|
211a7c7939 | ||
|
|
82ce66af16 | ||
|
|
df4bc13122 | ||
|
|
8f3661d5a4 | ||
|
|
bb31ac11ca | ||
|
|
4ef0065c66 | ||
|
|
476d168a46 | ||
|
|
093c6cdca3 | ||
|
|
345f5e14de | ||
|
|
5ddfef7eb7 | ||
|
|
81d784b5dc | ||
|
|
b0b9a7a294 | ||
|
|
e76ee3c96e | ||
|
|
24b495ca43 | ||
|
|
ff4fd1411e | ||
|
|
03eed5f4f9 | ||
|
|
1c89968b69 | ||
|
|
01ce469a0f | ||
|
|
c6347a3cf1 | ||
|
|
bf7e581445 | ||
|
|
0fe9253d3b | ||
|
|
6a9042fd9c | ||
|
|
9e62fdc0b8 | ||
|
|
a33b70f8bd | ||
|
|
bfc06ed81f | ||
|
|
c3c8ac7ff0 | ||
|
|
bfd0c00708 | ||
|
|
ef0c84072b | ||
|
|
066972ff75 | ||
|
|
608853d4fa | ||
|
|
1774305c2d | ||
|
|
3295966022 | ||
|
|
8f43f5a4a1 | ||
|
|
379f40c1be | ||
|
|
c2282af879 | ||
|
|
d057b1909f | ||
|
|
3cb3bfc008 | ||
|
|
2ba4e99114 | ||
|
|
f61a6ba5ff | ||
|
|
34a6389a92 | ||
|
|
b675adbbb0 | ||
|
|
e46da0e2f2 | ||
|
|
44b257a749 | ||
|
|
fe2599eb35 | ||
|
|
d791a189bc | ||
|
|
bbc521a2f3 | ||
|
|
56f6da606c | ||
|
|
3e098b7479 | ||
|
|
7e2fe6d5be | ||
|
|
c4b2cf9394 | ||
|
|
9ac823833a | ||
|
|
60132c085c | ||
|
|
5e14e65eb0 | ||
|
|
64063fb77d | ||
|
|
aa309ef27c | ||
|
|
4c81c9e21e | ||
|
|
f4912eb23b | ||
|
|
7f85b8b33f | ||
|
|
85c68f78da | ||
|
|
af03085d5f | ||
|
|
b7d747ee17 | ||
|
|
b6f100888a | ||
|
|
3cfd392e3e | ||
|
|
7ed98a8655 | ||
|
|
d78eb4a4e5 | ||
|
|
a3d168b646 | ||
|
|
5018df511b | ||
|
|
09345a9d53 | ||
|
|
8b17cd3cde | ||
|
|
403fcd8fff | ||
|
|
409be4020b | ||
|
|
24801a220c | ||
|
|
19b9f4e1c1 | ||
|
|
48d584df58 | ||
|
|
dd999a29fd | ||
|
|
75fdfb5a0b | ||
|
|
6b4db4e9ae | ||
|
|
2571b24f22 | ||
|
|
855a9eea44 | ||
|
|
189e299592 | ||
|
|
6cbaa35849 | ||
|
|
cb1cfa4d94 | ||
|
|
5bbf893a37 | ||
|
|
3ddbfb5dea | ||
|
|
5352d062d5 | ||
|
|
e15cbfca33 | ||
|
|
51b58f911e | ||
|
|
7acfbb9eed | ||
|
|
4bf9853a25 | ||
|
|
58c6db0a8f | ||
|
|
aed52a7829 | ||
|
|
a1e24a3f95 | ||
|
|
11cff29916 | ||
|
|
f184b9bcc4 | ||
|
|
bab0024e0c | ||
|
|
deed92cff7 | ||
|
|
a9bc949679 | ||
|
|
1411410f4e | ||
|
|
648fbe1b10 | ||
|
|
7042f89620 | ||
|
|
e235fffb5e | ||
|
|
6aadd13450 | ||
|
|
349de098af | ||
|
|
5527e585f6 | ||
|
|
a6e9814dfc | ||
|
|
f01a7d3933 | ||
|
|
d2cd3b899f | ||
|
|
ac2c0d5d84 | ||
|
|
f0d0b512ca | ||
|
|
c859ffd0f7 | ||
|
|
4eb57f3cc5 | ||
|
|
6218bfaf9e | ||
|
|
4d5cdcaeae | ||
|
|
6ad62a6f2f | ||
|
|
37d4b151d7 | ||
|
|
37c1d804f6 | ||
|
|
d200df3e9c | ||
|
|
eb43e416ae | ||
|
|
e6244f71bd | ||
|
|
403277ed06 | ||
|
|
dbe8a59c3c | ||
|
|
a98de54db4 | ||
|
|
7edb7266f2 | ||
|
|
d14e077511 | ||
|
|
211c14e316 | ||
|
|
4fbc140551 | ||
|
|
ee8e65c80d | ||
|
|
3635d0ec26 | ||
|
|
105bb7512f | ||
|
|
b63e50dacb | ||
|
|
417b5c8b97 | ||
|
|
08ed16c493 | ||
|
|
734efdf343 | ||
|
|
1195678893 | ||
|
|
4ad2c2221f | ||
|
|
18cf198592 | ||
|
|
9bbe51fa64 | ||
|
|
4de3a34a3e | ||
|
|
c028425f14 | ||
|
|
7d03d8a58f | ||
|
|
db0e88d8a7 | ||
|
|
1b8aca26a3 | ||
|
|
b239053810 | ||
|
|
1acb130be1 |
@@ -4,3 +4,4 @@ Build
|
|||||||
Demos
|
Demos
|
||||||
./Aristo
|
./Aristo
|
||||||
WebSite
|
WebSite
|
||||||
|
.push-package
|
||||||
|
|||||||
+13
-4
@@ -26,6 +26,7 @@
|
|||||||
@import "CPApplication.j"
|
@import "CPApplication.j"
|
||||||
@import "CPBezierPath.j"
|
@import "CPBezierPath.j"
|
||||||
@import "CPBox.j"
|
@import "CPBox.j"
|
||||||
|
@import "CPBrowser.j"
|
||||||
@import "CPButton.j"
|
@import "CPButton.j"
|
||||||
@import "CPButtonBar.j"
|
@import "CPButtonBar.j"
|
||||||
@import "CPCheckBox.j"
|
@import "CPCheckBox.j"
|
||||||
@@ -35,8 +36,8 @@
|
|||||||
@import "CPCibLoading.j"
|
@import "CPCibLoading.j"
|
||||||
@import "CPCibOutletConnector.j"
|
@import "CPCibOutletConnector.j"
|
||||||
@import "CPClipView.j"
|
@import "CPClipView.j"
|
||||||
@import "CPCollectionViewItem.j"
|
|
||||||
@import "CPCollectionView.j"
|
@import "CPCollectionView.j"
|
||||||
|
@import "CPCollectionViewItem.j"
|
||||||
@import "CPColor.j"
|
@import "CPColor.j"
|
||||||
@import "CPColorPanel.j"
|
@import "CPColorPanel.j"
|
||||||
@import "CPColorWell.j"
|
@import "CPColorWell.j"
|
||||||
@@ -52,33 +53,41 @@
|
|||||||
@import "CPFont.j"
|
@import "CPFont.j"
|
||||||
@import "CPFontManager.j"
|
@import "CPFontManager.j"
|
||||||
@import "CPGeometry.j"
|
@import "CPGeometry.j"
|
||||||
|
@import "CPGraphics.j"
|
||||||
@import "CPImage.j"
|
@import "CPImage.j"
|
||||||
@import "CPImageView.j"
|
@import "CPImageView.j"
|
||||||
|
@import "CPKeyBinding.j"
|
||||||
@import "CPMenu.j"
|
@import "CPMenu.j"
|
||||||
@import "CPMenuItem.j"
|
@import "CPMenuItem.j"
|
||||||
@import "CPOpenPanel.j"
|
@import "CPOpenPanel.j"
|
||||||
|
@import "CPOutlineView.j"
|
||||||
@import "CPPanel.j"
|
@import "CPPanel.j"
|
||||||
@import "CPPasteboard.j"
|
@import "CPPasteboard.j"
|
||||||
@import "CPPopUpButton.j"
|
@import "CPPopUpButton.j"
|
||||||
@import "CPProgressIndicator.j"
|
@import "CPProgressIndicator.j"
|
||||||
@import "CPRadio.j"
|
@import "CPRadio.j"
|
||||||
@import "CPResponder.j"
|
@import "CPResponder.j"
|
||||||
@import "CPSearchField.j"
|
|
||||||
@import "CPScrollView.j"
|
|
||||||
@import "CPScroller.j"
|
@import "CPScroller.j"
|
||||||
|
@import "CPScrollView.j"
|
||||||
|
@import "CPSearchField.j"
|
||||||
@import "CPSecureTextField.j"
|
@import "CPSecureTextField.j"
|
||||||
@import "CPSegmentedControl.j"
|
@import "CPSegmentedControl.j"
|
||||||
@import "CPShadow.j"
|
@import "CPShadow.j"
|
||||||
@import "CPSlider.j"
|
@import "CPSlider.j"
|
||||||
@import "CPSplitView.j"
|
@import "CPSplitView.j"
|
||||||
@import "CPTabView.j"
|
|
||||||
@import "CPTableColumn.j"
|
@import "CPTableColumn.j"
|
||||||
@import "CPTableView.j"
|
@import "CPTableView.j"
|
||||||
|
@import "CPTabView.j"
|
||||||
|
@import "CPText.j"
|
||||||
@import "CPTextField.j"
|
@import "CPTextField.j"
|
||||||
@import "CPToolbar.j"
|
@import "CPToolbar.j"
|
||||||
@import "CPToolbarItem.j"
|
@import "CPToolbarItem.j"
|
||||||
|
@import "CPTokenField.j"
|
||||||
|
@import "CPTreeNode.j"
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
@import "CPViewAnimation.j"
|
||||||
@import "CPViewController.j"
|
@import "CPViewController.j"
|
||||||
@import "CPWebView.j"
|
@import "CPWebView.j"
|
||||||
@import "CPWindow.j"
|
@import "CPWindow.j"
|
||||||
@import "CPWindowController.j"
|
@import "CPWindowController.j"
|
||||||
|
@import "CPArrayController.j"
|
||||||
|
|||||||
@@ -26,11 +26,16 @@
|
|||||||
@import <Foundation/CPIndexSet.j>
|
@import <Foundation/CPIndexSet.j>
|
||||||
@import <Foundation/CPString.j>
|
@import <Foundation/CPString.j>
|
||||||
|
|
||||||
@import <AppKit/CPView.j>
|
@import "CPView.j"
|
||||||
|
@import "CPButton.j"
|
||||||
#import "CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ingroup appkit
|
||||||
|
@class CPAccordionViewItem
|
||||||
|
|
||||||
|
<p>A CPAccordionViewItem represents a single section of a CPAccordionView.</p>
|
||||||
|
*/
|
||||||
@implementation CPAccordionViewItem : CPObject
|
@implementation CPAccordionViewItem : CPObject
|
||||||
{
|
{
|
||||||
CPString _identifier @accessors(property=identifier);
|
CPString _identifier @accessors(property=identifier);
|
||||||
@@ -43,6 +48,10 @@
|
|||||||
return [self initWithIdentifier:@""];
|
return [self initWithIdentifier:@""];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Initializes a new CPAccordionViewItem with the specified identifier. This identifier may
|
||||||
|
then be used in subsequent methods to provide abstract introspection of the CPAccordionView.
|
||||||
|
*/
|
||||||
- (id)initWithIdentifier:(CPString)anIdentifier
|
- (id)initWithIdentifier:(CPString)anIdentifier
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
@@ -55,6 +64,25 @@
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ingroup appkit
|
||||||
|
@class CPAccordionView
|
||||||
|
|
||||||
|
<p>CPAccordionView provides a container for CPAccordionViewItem objects and manages layout state
|
||||||
|
for all sublayout items.</p>
|
||||||
|
|
||||||
|
<strong>Example</strong><br />
|
||||||
|
<pre>
|
||||||
|
var myAccordionView = [[CPAccordionView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
var firstItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"firstSection"]];
|
||||||
|
[firstItem setView:[[CPView alloc] initWithFrame:CGRectMakeZero()]];
|
||||||
|
var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection"]];
|
||||||
|
[secondItem setView:[[CPView alloc] initWithFrame:CGRectMakeZero()]];
|
||||||
|
[myAccordionView addItem:firstItem];
|
||||||
|
[myAccordionView addItem:secondItem];
|
||||||
|
[myAccordionView setAutoresizingMask: CPViewWidthSizable | CPViewHeightSizable];
|
||||||
|
</pre>
|
||||||
|
*/
|
||||||
@implementation CPAccordionView : CPView
|
@implementation CPAccordionView : CPView
|
||||||
{
|
{
|
||||||
CPInteger _dirtyItemIndex;
|
CPInteger _dirtyItemIndex;
|
||||||
@@ -64,7 +92,10 @@
|
|||||||
CPMutableArray _itemViews;
|
CPMutableArray _itemViews;
|
||||||
CPIndexSet _expandedItemIndexes;
|
CPIndexSet _expandedItemIndexes;
|
||||||
}
|
}
|
||||||
|
/*!
|
||||||
|
Initializes the receiver for usage with the specified bounding rectangle
|
||||||
|
@return the initialized view
|
||||||
|
*/
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
{
|
{
|
||||||
self = [super initWithFrame:aFrame];
|
self = [super initWithFrame:aFrame];
|
||||||
@@ -95,13 +126,17 @@
|
|||||||
{
|
{
|
||||||
return _items;
|
return _items;
|
||||||
}
|
}
|
||||||
|
/*!
|
||||||
- (void)addItem:(CPAccordionItem)anItem
|
Append a CPAccordionViewItem to the receiver. Note that the CPAccordionViewItem must contain
|
||||||
|
a valid CPView derived component or a TypeError will be generated when the contents of the
|
||||||
|
ViewItem are disclosed.
|
||||||
|
*/
|
||||||
|
- (void)addItem:(CPAccordionViewItem)anItem
|
||||||
{
|
{
|
||||||
[self insertItem:anItem atIndex:_items.length];
|
[self insertItem:anItem atIndex:_items.length];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)insertItem:(CPAccordionItem)anItem atIndex:(CPInteger)anIndex
|
- (void)insertItem:(CPAccordionViewItem)anItem atIndex:(CPInteger)anIndex
|
||||||
{
|
{
|
||||||
// FIXME: SHIFT ITEMS RIGHT
|
// FIXME: SHIFT ITEMS RIGHT
|
||||||
[_expandedItemIndexes addIndex:anIndex];
|
[_expandedItemIndexes addIndex:anIndex];
|
||||||
@@ -122,7 +157,7 @@
|
|||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)removeItem:(CPAccordionItem)anItem
|
- (void)removeItem:(CPAccordionViewItem)anItem
|
||||||
{
|
{
|
||||||
[self removeItemAtIndex:[_items indexOfObjectIdenticalTo:anItem]];
|
[self removeItemAtIndex:[_items indexOfObjectIdenticalTo:anItem]];
|
||||||
}
|
}
|
||||||
@@ -197,6 +232,20 @@
|
|||||||
return indexSet;
|
return indexSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setEnabled:(BOOL)isEnabled forItemAtIndex:(CPInteger)anIndex
|
||||||
|
{
|
||||||
|
var itemView = _itemViews[anIndex];
|
||||||
|
if (!itemView)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!isEnabled)
|
||||||
|
[self collapseItemAtIndex:anIndex];
|
||||||
|
else
|
||||||
|
[self expandItemAtIndex:anIndex];
|
||||||
|
|
||||||
|
[itemView setEnabled:isEnabled];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)_invalidateItemsStartingAtIndex:(CPInteger)anIndex
|
- (void)_invalidateItemsStartingAtIndex:(CPInteger)anIndex
|
||||||
{
|
{
|
||||||
if (_dirtyItemIndex === CPNotFound)
|
if (_dirtyItemIndex === CPNotFound)
|
||||||
@@ -301,6 +350,12 @@
|
|||||||
[_headerView setStringValue:aLabel];
|
[_headerView setStringValue:aLabel];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setEnabled:(BOOL)isEnabled
|
||||||
|
{
|
||||||
|
if ([_headerView respondsToSelector:@selector(setEnabled:)])
|
||||||
|
[_headerView setEnabled:isEnabled];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setContentView:(CPView)aView
|
- (void)setContentView:(CPView)aView
|
||||||
{
|
{
|
||||||
if (_contentView === aView)
|
if (_contentView === aView)
|
||||||
@@ -312,7 +367,7 @@
|
|||||||
|
|
||||||
_contentView = aView;
|
_contentView = aView;
|
||||||
|
|
||||||
[_contentView addObserver:self forKeyPath:@"frame" options:0 context:NULL];
|
[_contentView addObserver:self forKeyPath:@"frame" options:CPKeyValueObservingOptionOld | CPKeyValueObservingOptionNew context:NULL];
|
||||||
|
|
||||||
[self addSubview:_contentView];
|
[self addSubview:_contentView];
|
||||||
|
|
||||||
|
|||||||
+240
-85
@@ -26,14 +26,14 @@
|
|||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
@import <Foundation/CPString.j>
|
@import <Foundation/CPString.j>
|
||||||
|
|
||||||
@import <AppKit/CPApplication.j>
|
@import "CPApplication.j"
|
||||||
@import <AppKit/CPButton.j>
|
@import "CPButton.j"
|
||||||
@import <AppKit/CPColor.j>
|
@import "CPColor.j"
|
||||||
@import <AppKit/CPFont.j>
|
@import "CPFont.j"
|
||||||
@import <AppKit/CPImage.j>
|
@import "CPImage.j"
|
||||||
@import <AppKit/CPImageView.j>
|
@import "CPImageView.j"
|
||||||
@import <AppKit/CPPanel.j>
|
@import "CPPanel.j"
|
||||||
@import <AppKit/CPTextField.j>
|
@import "CPTextField.j"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@global
|
@global
|
||||||
@@ -51,11 +51,6 @@ CPInformationalAlertStyle = 1;
|
|||||||
*/
|
*/
|
||||||
CPCriticalAlertStyle = 2;
|
CPCriticalAlertStyle = 2;
|
||||||
|
|
||||||
|
|
||||||
var CPAlertWarningImage,
|
|
||||||
CPAlertInformationImage,
|
|
||||||
CPAlertErrorImage;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
|
|
||||||
@@ -78,37 +73,47 @@ var CPAlertWarningImage,
|
|||||||
representing the first button added to the alert which appears on the
|
representing the first button added to the alert which appears on the
|
||||||
right, 1 representing the next button to the left and so on)
|
right, 1 representing the next button to the left and so on)
|
||||||
*/
|
*/
|
||||||
@implementation CPAlert : CPObject
|
@implementation CPAlert : CPView
|
||||||
{
|
{
|
||||||
CPPanel _alertPanel;
|
CPPanel _alertPanel;
|
||||||
|
|
||||||
CPTextField _messageLabel;
|
CPTextField _messageLabel;
|
||||||
|
CPTextField _informativeLabel;
|
||||||
CPImageView _alertImageView;
|
CPImageView _alertImageView;
|
||||||
|
|
||||||
CPAlertStyle _alertStyle;
|
CPAlertStyle _alertStyle;
|
||||||
CPString _windowTitle;
|
CPString _windowTitle;
|
||||||
int _windowStyle;
|
int _windowStyle;
|
||||||
int _buttonCount;
|
|
||||||
CPArray _buttons;
|
CPArray _buttons;
|
||||||
|
|
||||||
id _delegate;
|
id _delegate;
|
||||||
|
SEL _didEndSelector;
|
||||||
|
id _modalDelegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)initialize
|
+ (CPString)defaultThemeClass
|
||||||
{
|
{
|
||||||
if (self != CPAlert)
|
return @"alert";
|
||||||
return;
|
}
|
||||||
|
|
||||||
var bundle = [CPBundle bundleForClass:[self class]];
|
+ (id)themeAttributes
|
||||||
|
{
|
||||||
CPAlertWarningImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-warning.png"]
|
return [CPDictionary dictionaryWithObjects:[CGSizeMake(400.0, 110.0), CGInsetMake(15, 15, 15, 50), 6, 10,
|
||||||
size:CGSizeMake(32.0, 32.0)];
|
CPJustifiedTextAlignment, [CPColor blackColor], [CPFont boldSystemFontOfSize:13.0], [CPNull null], CGSizeMakeZero(),
|
||||||
|
CPJustifiedTextAlignment, [CPColor blackColor], [CPFont systemFontOfSize:12.0], [CPNull null], CGSizeMakeZero(),
|
||||||
CPAlertInformationImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-information.png"]
|
CGPointMake(15, 12),
|
||||||
size:CGSizeMake(32.0, 32.0)];
|
[CPNull null],
|
||||||
|
[CPNull null],
|
||||||
CPAlertErrorImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-error.png"]
|
[CPNull null]
|
||||||
size:CGSizeMake(32.0, 32.0)];
|
]
|
||||||
|
forKeys:[@"size", @"content-inset", @"informative-offset", @"button-offset",
|
||||||
|
@"message-text-alignment", @"message-text-color", @"message-text-font", @"message-text-shadow-color", @"message-text-shadow-offset",
|
||||||
|
@"informative-text-alignment", @"informative-text-color", @"informative-text-font", @"informative-text-shadow-color", @"informative-text-shadow-offset",
|
||||||
|
@"image-offset",
|
||||||
|
@"information-image",
|
||||||
|
@"warning-image",
|
||||||
|
@"error-image"
|
||||||
|
]];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -118,56 +123,56 @@ var CPAlertWarningImage,
|
|||||||
{
|
{
|
||||||
if (self = [super init])
|
if (self = [super init])
|
||||||
{
|
{
|
||||||
_buttonCount = 0;
|
|
||||||
_buttons = [CPArray array];
|
_buttons = [CPArray array];
|
||||||
_alertStyle = CPWarningAlertStyle;
|
_alertStyle = CPWarningAlertStyle;
|
||||||
|
_alertPanel = nil;
|
||||||
|
_windowStyle = nil;
|
||||||
|
_didEndSelector = nil;
|
||||||
|
|
||||||
[self setWindowStyle:nil];
|
_messageLabel = [CPTextField labelWithTitle:@"Alert"];
|
||||||
|
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
_informativeLabel = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the window appearance.
|
Sets the window appearance. If CPHUDBackgroundWindowMask is set, the default HUD theme
|
||||||
|
will be activated.
|
||||||
|
|
||||||
@param styleMask - Either CPHUDBackgroundWindowMask or nil for standard.
|
@param styleMask - Either CPHUDBackgroundWindowMask or nil for standard.
|
||||||
*/
|
*/
|
||||||
- (void)setWindowStyle:(int)styleMask
|
- (void)setWindowStyle:(int)styleMask
|
||||||
{
|
{
|
||||||
_windowStyle = styleMask;
|
_windowStyle = styleMask;
|
||||||
|
|
||||||
_alertPanel = [[CPPanel alloc] initWithContentRect:CGRectMake(0.0, 0.0, 400.0, 110.0) styleMask:styleMask ? styleMask | CPTitledWindowMask : CPTitledWindowMask];
|
[self setTheme:(_windowStyle & CPHUDBackgroundWindowMask) ? [CPTheme defaultHudTheme] : [CPTheme defaultTheme]];
|
||||||
[_alertPanel setFloatingPanel:YES];
|
|
||||||
[_alertPanel center];
|
|
||||||
|
|
||||||
[_messageLabel setTextColor:(styleMask & CPHUDBackgroundWindowMask) ? [CPColor whiteColor] : [CPColor blackColor]];
|
// We'll need to recreate the panel to get the new window style.
|
||||||
|
_alertPanel = nil;
|
||||||
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 setTheme:[CPTheme themeNamed: _windowStyle === CPHUDBackgroundWindowMask ? "Aristo-HUD" : "Aristo"]];
|
|
||||||
|
|
||||||
[[_alertPanel contentView] addSubview:button];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_messageLabel)
|
- (void)_createPanel
|
||||||
{
|
{
|
||||||
var bounds = [[_alertPanel contentView] bounds];
|
var frame = CGRectMakeZero();
|
||||||
|
frame.size = [self currentValueForThemeAttribute:@"size"];
|
||||||
|
_alertPanel = [[CPPanel alloc] initWithContentRect:frame styleMask:_windowStyle ? _windowStyle | CPTitledWindowMask : CPTitledWindowMask];
|
||||||
|
|
||||||
_messageLabel = [[CPTextField alloc] initWithFrame:CGRectMake(57.0, 10.0, CGRectGetWidth(bounds) - 73.0, 62.0)];
|
var contentView = [_alertPanel contentView],
|
||||||
[_messageLabel setFont:[CPFont boldSystemFontOfSize:13.0]];
|
count = [_buttons count];
|
||||||
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
|
|
||||||
[_messageLabel setAlignment:CPJustifiedTextAlignment];
|
|
||||||
[_messageLabel setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
|
||||||
|
|
||||||
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMake(15.0, 12.0, 32.0, 32.0)];
|
if (count)
|
||||||
|
{
|
||||||
|
while (count--)
|
||||||
|
[contentView addSubview:_buttons[count]];
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
[self addButtonWithTitle:@"OK"];
|
||||||
|
|
||||||
[[_alertPanel contentView] addSubview:_messageLabel];
|
[contentView addSubview:_messageLabel];
|
||||||
[[_alertPanel contentView] addSubview:_alertImageView];
|
[contentView addSubview:_alertImageView];
|
||||||
|
[contentView addSubview:_informativeLabel];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -230,7 +235,7 @@ var CPAlertWarningImage,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Set’s the receiver’s message text, or title, to a given text.
|
Sets the receiver’s message text, or title, to a given text.
|
||||||
@param messageText - Message text for the alert.
|
@param messageText - Message text for the alert.
|
||||||
*/
|
*/
|
||||||
- (void)setMessageText:(CPString)messageText
|
- (void)setMessageText:(CPString)messageText
|
||||||
@@ -239,40 +244,156 @@ var CPAlertWarningImage,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Return's the receiver's message text body.
|
Returns the receiver's message text body.
|
||||||
*/
|
*/
|
||||||
- (CPString)messageText
|
- (CPString)messageText
|
||||||
{
|
{
|
||||||
return [_messageLabel stringValue];
|
return [_messageLabel stringValue];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the receiver's informative text, shown below the message text.
|
||||||
|
@param informativeText - The informative text.
|
||||||
|
*/
|
||||||
|
- (void)setInformativeText:(CPString)informativeText
|
||||||
|
{
|
||||||
|
[_informativeLabel setStringValue:informativeText];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the receiver's informative text.
|
||||||
|
*/
|
||||||
|
- (CPString)informativeText
|
||||||
|
{
|
||||||
|
return [_informativeLabel stringValue];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Adds a button with a given title to the receiver.
|
Adds a button with a given title to the receiver.
|
||||||
Buttons will be added starting from the right hand side of the \c CPAlert panel.
|
Buttons will be added starting from the right hand side of the \c CPAlert panel.
|
||||||
The first button will have the index 0, the second button 1 and so on.
|
The first button will have the index 0, the second button 1 and so on.
|
||||||
|
|
||||||
|
The first button will automatically be given a key equivalent of Return,
|
||||||
|
and any button titled "Cancel" will be given a key equivalent of Escape.
|
||||||
|
|
||||||
You really shouldn't need more than 3 buttons.
|
You really shouldn't need more than 3 buttons.
|
||||||
*/
|
*/
|
||||||
- (void)addButtonWithTitle:(CPString)title
|
- (void)addButtonWithTitle:(CPString)title
|
||||||
{
|
{
|
||||||
var bounds = [[_alertPanel contentView] bounds],
|
var bounds = [[_alertPanel contentView] bounds],
|
||||||
button = [[CPButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(bounds) - ((_buttonCount + 1) * 90.0), CGRectGetHeight(bounds) - 34.0, 80.0, (_windowStyle == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)];
|
button = [[CPButton alloc] initWithFrame:CGRectMakeZero()],
|
||||||
|
_buttonCount = [_buttons count];
|
||||||
|
|
||||||
[button setTitle:title];
|
[button setTitle:title];
|
||||||
[button setTarget:self];
|
[button setTarget:self];
|
||||||
[button setTag:_buttonCount];
|
[button setTag:_buttonCount];
|
||||||
[button setAction:@selector(_notifyDelegate:)];
|
[button setAction:@selector(_dismissAlert:)];
|
||||||
|
|
||||||
[button setTheme:[CPTheme themeNamed: _windowStyle === CPHUDBackgroundWindowMask ? "Aristo-HUD" : "Aristo"]];
|
|
||||||
[button setAutoresizingMask:CPViewMinXMargin|CPViewMinYMargin];
|
|
||||||
|
|
||||||
[[_alertPanel contentView] addSubview:button];
|
[[_alertPanel contentView] addSubview:button];
|
||||||
|
|
||||||
if (_buttonCount == 0)
|
if (_buttonCount == 0)
|
||||||
[_alertPanel setDefaultButton:button];
|
[button setKeyEquivalent:CPCarriageReturnCharacter];
|
||||||
|
else if ([title lowercaseString] === "cancel")
|
||||||
|
[button setKeyEquivalent:CPEscapeFunctionKey];
|
||||||
|
else
|
||||||
|
[button setKeyEquivalent:nil];
|
||||||
|
|
||||||
_buttonCount++;
|
[_buttons insertObject:button atIndex:0];
|
||||||
[_buttons addObject:button];
|
}
|
||||||
|
|
||||||
|
- (void)layoutPanel
|
||||||
|
{
|
||||||
|
if (!_alertPanel)
|
||||||
|
[self _createPanel];
|
||||||
|
|
||||||
|
var inset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||||
|
iconOffset = [self currentValueForThemeAttribute:@"image-offset"],
|
||||||
|
theTitle,
|
||||||
|
theImage;
|
||||||
|
|
||||||
|
switch (_alertStyle)
|
||||||
|
{
|
||||||
|
case CPWarningAlertStyle: theImage = [self currentValueForThemeAttribute:@"warning-image"];
|
||||||
|
theTitle = @"Warning";
|
||||||
|
break;
|
||||||
|
case CPInformationalAlertStyle: theImage = [self currentValueForThemeAttribute:@"information-image"];
|
||||||
|
theTitle = @"Information";
|
||||||
|
break;
|
||||||
|
case CPCriticalAlertStyle: theImage = [self currentValueForThemeAttribute:@"error-image"];
|
||||||
|
theTitle = @"Error";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
[_alertImageView setImage:theImage];
|
||||||
|
|
||||||
|
var imageSize = theImage ? [theImage size] : CGSizeMakeZero();
|
||||||
|
[_alertImageView setFrame:CGRectMake(iconOffset.x, iconOffset.y, imageSize.width, imageSize.height)];
|
||||||
|
|
||||||
|
[_alertPanel setTitle:_windowTitle ? _windowTitle : theTitle];
|
||||||
|
[_alertPanel setFloatingPanel:YES];
|
||||||
|
[_alertPanel center];
|
||||||
|
|
||||||
|
[_messageLabel setTextColor:[self currentValueForThemeAttribute:@"message-text-color"]];
|
||||||
|
[_messageLabel setFont:[self currentValueForThemeAttribute:@"message-text-font"]];
|
||||||
|
[_messageLabel setTextShadowColor:[self currentValueForThemeAttribute:@"message-text-shadow-color"]];
|
||||||
|
[_messageLabel setTextShadowOffset:[self currentValueForThemeAttribute:@"message-text-shadow-offset"]];
|
||||||
|
[_messageLabel setAlignment:[self currentValueForThemeAttribute:@"message-text-alignment"]];
|
||||||
|
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
|
||||||
|
|
||||||
|
[_informativeLabel setTextColor:[self currentValueForThemeAttribute:@"informative-text-color"]];
|
||||||
|
[_informativeLabel setFont:[self currentValueForThemeAttribute:@"informative-text-font"]];
|
||||||
|
[_informativeLabel setTextShadowColor:[self currentValueForThemeAttribute:@"informative-text-shadow-color"]];
|
||||||
|
[_informativeLabel setTextShadowOffset:[self currentValueForThemeAttribute:@"informative-text-shadow-offset"]];
|
||||||
|
[_informativeLabel setLineBreakMode:CPLineBreakByWordWrapping];
|
||||||
|
|
||||||
|
// FIXME sizeWithFontCorrection shouldn't be needed.
|
||||||
|
var bounds = [[_alertPanel contentView] bounds],
|
||||||
|
offsetX = CGRectGetWidth(bounds) - inset.right,
|
||||||
|
informativeOffset = [self currentValueForThemeAttribute:@"informative-offset"],
|
||||||
|
buttonOffset = [self currentValueForThemeAttribute:@"button-offset"],
|
||||||
|
|
||||||
|
textWidth = offsetX - inset.left,
|
||||||
|
messageSize = [([_messageLabel stringValue] || " ") sizeWithFont:[_messageLabel font] inWidth:textWidth],
|
||||||
|
informationString = [_informativeLabel stringValue],
|
||||||
|
informativeSize = [(informationString || " ") sizeWithFont:[_informativeLabel font] inWidth:textWidth],
|
||||||
|
sizeWithFontCorrection = 6.0;
|
||||||
|
|
||||||
|
[_messageLabel setFrame:CGRectMake(inset.left, inset.top, textWidth, messageSize.height + sizeWithFontCorrection)];
|
||||||
|
[_informativeLabel setFrame:CGRectMake(inset.left, CGRectGetMaxY([_messageLabel frame]) + informativeOffset, textWidth, informativeSize.height + sizeWithFontCorrection)];
|
||||||
|
// Don't let an empty informative label partially cover the buttons.
|
||||||
|
[_informativeLabel setHidden:!informationString];
|
||||||
|
|
||||||
|
var aRepresentativeButton = _buttons[0],
|
||||||
|
buttonY = MAX(CGRectGetMaxY([_alertImageView frame]), CGRectGetMaxY(informationString ? [_informativeLabel frame] : [_messageLabel frame])) + buttonOffset; // the lower of the bottom of the text and the bottom of the icon.
|
||||||
|
|
||||||
|
[aRepresentativeButton setTheme:[self theme]];
|
||||||
|
[aRepresentativeButton sizeToFit];
|
||||||
|
|
||||||
|
// Make the window just tall enough to fit everything. Bit of a hack really.
|
||||||
|
var minimumSize = [self currentValueForThemeAttribute:@"size"],
|
||||||
|
desiredHeight = MAX(minimumSize.height, buttonY + CGRectGetHeight([aRepresentativeButton bounds]) + inset.bottom),
|
||||||
|
deltaY = desiredHeight - CGRectGetHeight(bounds),
|
||||||
|
frameSize = CGSizeMakeCopy([_alertPanel frame].size);
|
||||||
|
|
||||||
|
frameSize.height += deltaY;
|
||||||
|
[_alertPanel setFrameSize:frameSize];
|
||||||
|
|
||||||
|
var count = [_buttons count];
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
{
|
||||||
|
var button = _buttons[count];
|
||||||
|
[button setTheme:[self theme]];
|
||||||
|
[button sizeToFit];
|
||||||
|
|
||||||
|
var buttonBounds = [button bounds],
|
||||||
|
width = MAX(80.0, CGRectGetWidth(buttonBounds)),
|
||||||
|
height = CGRectGetHeight(buttonBounds);
|
||||||
|
|
||||||
|
offsetX -= width;
|
||||||
|
[button setFrame:CGRectMake(offsetX, buttonY, width, height)];
|
||||||
|
offsetX -= 10;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -282,34 +403,68 @@ var CPAlertWarningImage,
|
|||||||
*/
|
*/
|
||||||
- (void)runModal
|
- (void)runModal
|
||||||
{
|
{
|
||||||
var theTitle;
|
[self layoutPanel];
|
||||||
|
|
||||||
switch (_alertStyle)
|
|
||||||
{
|
|
||||||
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];
|
[CPApp runModalForWindow:_alertPanel];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Runs the receiver modally as an alert sheet attached to a specified window.
|
||||||
|
|
||||||
|
@param window The parent window for the sheet.
|
||||||
|
@param modalDelegate The delegate for the modal-dialog session.
|
||||||
|
@param alertDidEndSelector Message the alert sends to modalDelegate after the sheet is dismissed.
|
||||||
|
@param contextInfo Contextual data passed to modalDelegate in didEndSelector message.
|
||||||
|
*/
|
||||||
|
- (void)beginSheetModalForWindow:(CPWindow)window modalDelegate:(id)modalDelegate didEndSelector:(SEL)alertDidEndSelector contextInfo:(void)contextInfo
|
||||||
|
{
|
||||||
|
if (!(_windowStyle & CPDocModalWindowMask))
|
||||||
|
[self setWindowStyle:CPDocModalWindowMask];
|
||||||
|
[self layoutPanel];
|
||||||
|
|
||||||
|
_didEndSelector = alertDidEndSelector;
|
||||||
|
_modalDelegate = modalDelegate;
|
||||||
|
|
||||||
|
[CPApp beginSheet:_alertPanel modalForWindow:window modalDelegate:self didEndSelector:@selector(_alertDidEnd:returnCode:contextInfo:) contextInfo:contextInfo];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Runs the receiver modally as an alert sheet attached to a specified window.
|
||||||
|
|
||||||
|
@param window The parent window for the sheet.
|
||||||
|
*/
|
||||||
|
- (void)beginSheetModalForWindow:(CPWindow)window
|
||||||
|
{
|
||||||
|
if (!(_windowStyle & CPDocModalWindowMask))
|
||||||
|
[self setWindowStyle:CPDocModalWindowMask];
|
||||||
|
[self layoutPanel];
|
||||||
|
|
||||||
|
[CPApp beginSheet:_alertPanel modalForWindow:window modalDelegate:self didEndSelector:@selector(_alertDidEnd:returnCode:contextInfo:) contextInfo:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_alertDidEnd:(CPWindow)aSheet returnCode:(CPInteger)returnCode contextInfo:(id)contextInfo
|
||||||
|
{
|
||||||
|
if ([_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
|
||||||
|
[_delegate alertDidEnd:self returnCode:returnCode];
|
||||||
|
|
||||||
|
if (_didEndSelector)
|
||||||
|
objj_msgSend(_modalDelegate, _didEndSelector, self, returnCode, contextInfo);
|
||||||
|
|
||||||
|
_didEndSelector = nil;
|
||||||
|
_modalDelegate = nil;
|
||||||
|
}
|
||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
- (void)_notifyDelegate:(id)button
|
- (void)_dismissAlert:(CPButton)button
|
||||||
|
{
|
||||||
|
if ([_alertPanel isSheet])
|
||||||
|
[CPApp endSheet:_alertPanel returnCode:[button tag]];
|
||||||
|
else
|
||||||
{
|
{
|
||||||
[CPApp abortModal];
|
[CPApp abortModal];
|
||||||
[_alertPanel close];
|
[_alertPanel close];
|
||||||
|
|
||||||
if (_delegate && [_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
|
[self _alertDidEnd:nil returnCode:[button tag] contextInfo:nil];
|
||||||
[_delegate alertDidEnd:self returnCode:[button tag]];
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+248
-119
@@ -40,6 +40,10 @@ CPApp = nil;
|
|||||||
CPApplicationWillFinishLaunchingNotification = @"CPApplicationWillFinishLaunchingNotification";
|
CPApplicationWillFinishLaunchingNotification = @"CPApplicationWillFinishLaunchingNotification";
|
||||||
CPApplicationDidFinishLaunchingNotification = @"CPApplicationDidFinishLaunchingNotification";
|
CPApplicationDidFinishLaunchingNotification = @"CPApplicationDidFinishLaunchingNotification";
|
||||||
CPApplicationWillTerminateNotification = @"CPApplicationWillTerminateNotification";
|
CPApplicationWillTerminateNotification = @"CPApplicationWillTerminateNotification";
|
||||||
|
CPApplicationWillBecomeActiveNotification = @"CPApplicationWillBecomeActiveNotification";
|
||||||
|
CPApplicationDidBecomeActiveNotification = @"CPApplicationDidBecomeActiveNotification";
|
||||||
|
CPApplicationWillResignActiveNotification = @"CPApplicationWillResignActiveNotification";
|
||||||
|
CPApplicationDidResignActiveNotification = @"CPApplicationDidResignActiveNotification";
|
||||||
|
|
||||||
CPTerminateNow = YES;
|
CPTerminateNow = YES;
|
||||||
CPTerminateCancel = NO;
|
CPTerminateCancel = NO;
|
||||||
@@ -83,6 +87,8 @@ CPRunContinuesResponse = -1002;
|
|||||||
CPArray _windows;
|
CPArray _windows;
|
||||||
CPWindow _keyWindow;
|
CPWindow _keyWindow;
|
||||||
CPWindow _mainWindow;
|
CPWindow _mainWindow;
|
||||||
|
CPWindow _previousKeyWindow;
|
||||||
|
CPWindow _previousMainWindow;
|
||||||
|
|
||||||
CPMenu _mainMenu;
|
CPMenu _mainMenu;
|
||||||
CPDocumentController _documentController;
|
CPDocumentController _documentController;
|
||||||
@@ -92,6 +98,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
//
|
//
|
||||||
id _delegate;
|
id _delegate;
|
||||||
BOOL _finishedLaunching;
|
BOOL _finishedLaunching;
|
||||||
|
BOOL _isActive;
|
||||||
|
|
||||||
CPDictionary _namedArgs;
|
CPDictionary _namedArgs;
|
||||||
CPArray _args;
|
CPArray _args;
|
||||||
@@ -100,6 +107,8 @@ CPRunContinuesResponse = -1002;
|
|||||||
CPImage _applicationIconImage;
|
CPImage _applicationIconImage;
|
||||||
|
|
||||||
CPPanel _aboutPanel;
|
CPPanel _aboutPanel;
|
||||||
|
|
||||||
|
CPThemeBlend _themeBlend @accessors(property=themeBlend);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -124,6 +133,8 @@ CPRunContinuesResponse = -1002;
|
|||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
|
|
||||||
|
CPApp = self;
|
||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_eventListeners = [];
|
_eventListeners = [];
|
||||||
@@ -131,63 +142,6 @@ CPRunContinuesResponse = -1002;
|
|||||||
_windows = [];
|
_windows = [];
|
||||||
|
|
||||||
[_windows addObject:nil];
|
[_windows addObject:nil];
|
||||||
|
|
||||||
// FIXME: This should be read from the cib.
|
|
||||||
_mainMenu = [[CPMenu alloc] initWithTitle:@"MainMenu"];
|
|
||||||
|
|
||||||
// FIXME: We should implement autoenabling.
|
|
||||||
[_mainMenu setAutoenablesItems:NO];
|
|
||||||
|
|
||||||
var bundle = [CPBundle bundleForClass:[CPApplication class]],
|
|
||||||
newMenuItem = [[CPMenuItem alloc] initWithTitle:@"New" action:@selector(newDocument:) keyEquivalent:@"N"];
|
|
||||||
|
|
||||||
[newMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/New.png"] size:CGSizeMake(16.0, 16.0)]];
|
|
||||||
[newMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/NewHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
|
||||||
|
|
||||||
[_mainMenu addItem:newMenuItem];
|
|
||||||
|
|
||||||
var openMenuItem = [[CPMenuItem alloc] initWithTitle:@"Open" action:@selector(openDocument:) keyEquivalent:@"O"];
|
|
||||||
|
|
||||||
[openMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Open.png"] size:CGSizeMake(16.0, 16.0)]];
|
|
||||||
[openMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/OpenHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
|
||||||
|
|
||||||
[_mainMenu addItem:openMenuItem];
|
|
||||||
|
|
||||||
var saveMenu = [[CPMenu alloc] initWithTitle:@"Save"],
|
|
||||||
saveMenuItem = [[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:nil];
|
|
||||||
|
|
||||||
[saveMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Save.png"] size:CGSizeMake(16.0, 16.0)]];
|
|
||||||
[saveMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/SaveHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
|
||||||
|
|
||||||
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:@"S"]];
|
|
||||||
[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:nil],
|
|
||||||
editMenu = [[CPMenu alloc] initWithTitle:@"Edit"],
|
|
||||||
|
|
||||||
undoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Undo" action:@selector(undo:) keyEquivalent:CPUndoKeyEquivalent],
|
|
||||||
redoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Redo" action:@selector(redo:) keyEquivalent:CPRedoKeyEquivalent];
|
|
||||||
|
|
||||||
[undoMenuItem setKeyEquivalentModifierMask:CPUndoKeyEquivalentModifierMask];
|
|
||||||
[redoMenuItem setKeyEquivalentModifierMask:CPRedoKeyEquivalentModifierMask];
|
|
||||||
|
|
||||||
[editMenu addItem:undoMenuItem];
|
|
||||||
[editMenu addItem:redoMenuItem];
|
|
||||||
|
|
||||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"X"]],
|
|
||||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"C"]],
|
|
||||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"V"]];
|
|
||||||
|
|
||||||
[editMenuItem setSubmenu:editMenu];
|
|
||||||
[editMenuItem setHidden:YES];
|
|
||||||
|
|
||||||
[_mainMenu addItem:editMenuItem];
|
|
||||||
|
|
||||||
[_mainMenu addItem:[CPMenuItem separatorItem]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -206,36 +160,45 @@ CPRunContinuesResponse = -1002;
|
|||||||
if (_delegate == aDelegate)
|
if (_delegate == aDelegate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
var defaultCenter = [CPNotificationCenter defaultCenter],
|
||||||
|
delegateNotifications =
|
||||||
|
[
|
||||||
|
CPApplicationWillFinishLaunchingNotification, @selector(applicationWillFinishLaunching:),
|
||||||
|
CPApplicationDidFinishLaunchingNotification, @selector(applicationDidFinishLaunching:),
|
||||||
|
CPApplicationWillBecomeActiveNotification, @selector(applicationWillBecomeActive:),
|
||||||
|
CPApplicationDidBecomeActiveNotification, @selector(applicationDidBecomeActive:),
|
||||||
|
CPApplicationWillResignActiveNotification, @selector(applicationWillResignActive:),
|
||||||
|
CPApplicationDidResignActiveNotification, @selector(applicationDidResignActive:),
|
||||||
|
CPApplicationWillTerminateNotification, @selector(applicationWillTerminate:)
|
||||||
|
],
|
||||||
|
count = [delegateNotifications count];
|
||||||
|
|
||||||
if (_delegate)
|
if (_delegate)
|
||||||
{
|
{
|
||||||
[defaultCenter
|
var index = 0;
|
||||||
removeObserver:_delegate
|
|
||||||
name:CPApplicationWillFinishLaunchingNotification
|
|
||||||
object:self];
|
|
||||||
|
|
||||||
[defaultCenter
|
for (; index < count; index += 2)
|
||||||
removeObserver:_delegate
|
{
|
||||||
name:CPApplicationDidFinishLaunchingNotification
|
var notificationName = delegateNotifications[index],
|
||||||
object:self];
|
selector = delegateNotifications[index + 1];
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:selector])
|
||||||
|
[defaultCenter removeObserver:_delegate name:notificationName object:self];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_delegate = aDelegate;
|
_delegate = aDelegate;
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(applicationWillFinishLaunching:)])
|
var index = 0;
|
||||||
[defaultCenter
|
|
||||||
addObserver:_delegate
|
|
||||||
selector:@selector(applicationWillFinishLaunching:)
|
|
||||||
name:CPApplicationWillFinishLaunchingNotification
|
|
||||||
object:self];
|
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(applicationDidFinishLaunching:)])
|
for (; index < count; index += 2)
|
||||||
[defaultCenter
|
{
|
||||||
addObserver:_delegate
|
var notificationName = delegateNotifications[index],
|
||||||
selector:@selector(applicationDidFinishLaunching:)
|
selector = delegateNotifications[index + 1];
|
||||||
name:CPApplicationDidFinishLaunchingNotification
|
|
||||||
object:self];
|
if ([_delegate respondsToSelector:selector])
|
||||||
|
[defaultCenter addObserver:_delegate selector:selector name:notificationName object:self];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -314,6 +277,10 @@ CPRunContinuesResponse = -1002;
|
|||||||
|
|
||||||
- (void)terminate:(id)aSender
|
- (void)terminate:(id)aSender
|
||||||
{
|
{
|
||||||
|
[[CPNotificationCenter defaultCenter]
|
||||||
|
postNotificationName:CPApplicationWillTerminateNotification
|
||||||
|
object:self];
|
||||||
|
|
||||||
if (![CPPlatform isBrowser])
|
if (![CPPlatform isBrowser])
|
||||||
{
|
{
|
||||||
[[CPDocumentController sharedDocumentController] closeAllDocumentsWithDelegate:self
|
[[CPDocumentController sharedDocumentController] closeAllDocumentsWithDelegate:self
|
||||||
@@ -359,7 +326,9 @@ CPRunContinuesResponse = -1002;
|
|||||||
applicationVersion = [options objectForKey:@"ApplicationVersion"] || [mainInfo objectForKey:@"CPBundleShortVersionString"],
|
applicationVersion = [options objectForKey:@"ApplicationVersion"] || [mainInfo objectForKey:@"CPBundleShortVersionString"],
|
||||||
copyright = [options objectForKey:@"Copyright"] || [mainInfo objectForKey:@"CPHumanReadableCopyright"];
|
copyright = [options objectForKey:@"Copyright"] || [mainInfo objectForKey:@"CPHumanReadableCopyright"];
|
||||||
|
|
||||||
var aboutPanelController = [[CPWindowController alloc] initWithWindowCibName:@"AboutPanel"],
|
var aboutPanelPath = [[CPBundle bundleForClass:[CPWindowController class]] pathForResource:@"AboutPanel.cib"],
|
||||||
|
aboutPanelController = [CPWindowController alloc],
|
||||||
|
aboutPanelController = [aboutPanelController initWithWindowCibPath:aboutPanelPath owner:aboutPanelController],
|
||||||
aboutPanel = [aboutPanelController window],
|
aboutPanel = [aboutPanelController window],
|
||||||
contentView = [aboutPanel contentView],
|
contentView = [aboutPanel contentView],
|
||||||
imageView = [contentView viewWithTag:1],
|
imageView = [contentView viewWithTag:1],
|
||||||
@@ -379,10 +348,10 @@ CPRunContinuesResponse = -1002;
|
|||||||
|
|
||||||
[applicationLabel setStringValue:applicationTitle || ""];
|
[applicationLabel setStringValue:applicationTitle || ""];
|
||||||
|
|
||||||
if (version && applicationVersion)
|
if (applicationVersion && version)
|
||||||
[versionLabel setStringValue:sprintf(@"Version %@ (%@)", applicationVersion, version)];
|
[versionLabel setStringValue:@"Version " + applicationVersion + " (" + version + ")"];
|
||||||
else if (applicationVersion || version)
|
else if (applicationVersion || version)
|
||||||
[versionLabel setStringValue:sprintf(@"Version %@", applicationVersion || version)];
|
[versionLabel setStringValue:@"Version " + (applicationVersion || version)];
|
||||||
else
|
else
|
||||||
[versionLabel setStringValue:@""];
|
[versionLabel setStringValue:@""];
|
||||||
|
|
||||||
@@ -419,7 +388,27 @@ CPRunContinuesResponse = -1002;
|
|||||||
|
|
||||||
- (void)activateIgnoringOtherApps:(BOOL)shouldIgnoreOtherApps
|
- (void)activateIgnoringOtherApps:(BOOL)shouldIgnoreOtherApps
|
||||||
{
|
{
|
||||||
|
[self _willBecomeActive];
|
||||||
|
|
||||||
[CPPlatform activateIgnoringOtherApps:shouldIgnoreOtherApps];
|
[CPPlatform activateIgnoringOtherApps:shouldIgnoreOtherApps];
|
||||||
|
_isActive = YES;
|
||||||
|
|
||||||
|
[self _willResignActive];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)deactivate
|
||||||
|
{
|
||||||
|
[self _willResignActive];
|
||||||
|
|
||||||
|
[CPPlatform deactivate];
|
||||||
|
_isActive = NO;
|
||||||
|
|
||||||
|
[self _didResignActive];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)isActive
|
||||||
|
{
|
||||||
|
return _isActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)hideOtherApplications:(id)aSender
|
- (void)hideOtherApplications:(id)aSender
|
||||||
@@ -517,7 +506,8 @@ CPRunContinuesResponse = -1002;
|
|||||||
var theWindow = aModalSession._window;
|
var theWindow = aModalSession._window;
|
||||||
|
|
||||||
[theWindow center];
|
[theWindow center];
|
||||||
[theWindow makeKeyAndOrderFront:self];
|
[theWindow makeKeyWindow];
|
||||||
|
[theWindow orderFront:self];
|
||||||
|
|
||||||
// [theWindow._bridge _obscureWindowsBelowModalWindow];
|
// [theWindow._bridge _obscureWindowsBelowModalWindow];
|
||||||
|
|
||||||
@@ -624,6 +614,18 @@ CPRunContinuesResponse = -1002;
|
|||||||
return _windows;
|
return _windows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns an array of visible CPWindow objects, ordered by their front to back order on the screen.
|
||||||
|
*/
|
||||||
|
- (CPArray)orderedWindows
|
||||||
|
{
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
return CPWindowObjectList();
|
||||||
|
#else
|
||||||
|
return [];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
- (void)hide:(id)aSender
|
- (void)hide:(id)aSender
|
||||||
{
|
{
|
||||||
[CPPlatform hide:self];
|
[CPPlatform hide:self];
|
||||||
@@ -779,8 +781,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
return windowController;
|
return windowController;
|
||||||
|
|
||||||
var theDocument = [windowController document];
|
var theDocument = [windowController document];
|
||||||
|
if (theDocument !== delegate && [theDocument respondsToSelector:anAction])
|
||||||
if (theDocument != delegate && [theDocument respondsToSelector:anAction])
|
|
||||||
return theDocument;
|
return theDocument;
|
||||||
|
|
||||||
return nil;
|
return nil;
|
||||||
@@ -791,7 +792,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
Checks for a target in the following order:
|
Checks for a target in the following order:
|
||||||
<ol>
|
<ol>
|
||||||
<li>a responder from the key window</li>
|
<li>a responder from the key window</li>
|
||||||
<li>a responder frmo the main window</li>
|
<li>a responder from the main window</li>
|
||||||
<li>the CPApplication instance</li>
|
<li>the CPApplication instance</li>
|
||||||
<li>the application delegate</li>
|
<li>the application delegate</li>
|
||||||
<li>the document controller</li>
|
<li>the document controller</li>
|
||||||
@@ -830,8 +831,6 @@ CPRunContinuesResponse = -1002;
|
|||||||
- (void)setCallback:(Function)aCallback forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
|
- (void)setCallback:(Function)aCallback forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
|
||||||
{
|
{
|
||||||
_eventListeners.push(_CPEventListenerMake(aMask, aCallback));
|
_eventListeners.push(_CPEventListenerMake(aMask, aCallback));
|
||||||
|
|
||||||
if (_eventListeners.length == 3) objj_debug_print_backtrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPEvent)setTarget:(id)aTarget selector:(SEL)aSelector forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
|
- (CPEvent)setTarget:(id)aTarget selector:(SEL)aSelector forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
|
||||||
@@ -863,6 +862,8 @@ CPRunContinuesResponse = -1002;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[aWindow orderFront:self];
|
||||||
|
[aSheet setPlatformWindow:[aWindow platformWindow]];
|
||||||
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo];
|
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -872,8 +873,8 @@ CPRunContinuesResponse = -1002;
|
|||||||
|
|
||||||
while (--count >= 0)
|
while (--count >= 0)
|
||||||
{
|
{
|
||||||
var aWindow = [_windows objectAtIndex:count];
|
var aWindow = [_windows objectAtIndex:count],
|
||||||
var context = aWindow._sheetContext;
|
context = aWindow._sheetContext;
|
||||||
|
|
||||||
if (context != nil && context["sheet"] === sheet)
|
if (context != nil && context["sheet"] === sheet)
|
||||||
{
|
{
|
||||||
@@ -889,10 +890,9 @@ CPRunContinuesResponse = -1002;
|
|||||||
[self endSheet:sheet returnCode:0];
|
[self endSheet:sheet returnCode:0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (CPArray)arguments
|
- (CPArray)arguments
|
||||||
{
|
{
|
||||||
if(_fullArgsString != window.location.hash)
|
if (_fullArgsString !== window.location.hash)
|
||||||
[self _reloadArguments];
|
[self _reloadArguments];
|
||||||
|
|
||||||
return _args;
|
return _args;
|
||||||
@@ -925,13 +925,19 @@ CPRunContinuesResponse = -1002;
|
|||||||
- (void)_reloadArguments
|
- (void)_reloadArguments
|
||||||
{
|
{
|
||||||
_fullArgsString = window.location.hash;
|
_fullArgsString = window.location.hash;
|
||||||
var args = _fullArgsString.replace("#", "").split("/").slice(0);
|
|
||||||
|
if (_fullArgsString.length)
|
||||||
|
{
|
||||||
|
var args = _fullArgsString.substring(1).split("/");
|
||||||
|
|
||||||
for (var i = 0, count = args.length; i < count; i++)
|
for (var i = 0, count = args.length; i < count; i++)
|
||||||
args[i] = decodeURIComponent(args[i]);
|
args[i] = decodeURIComponent(args[i]);
|
||||||
|
|
||||||
_args = args;
|
_args = args;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
_args = [];
|
||||||
|
}
|
||||||
|
|
||||||
- (CPDictionary)namedArguments
|
- (CPDictionary)namedArguments
|
||||||
{
|
{
|
||||||
@@ -952,10 +958,70 @@ CPRunContinuesResponse = -1002;
|
|||||||
return !![_documentController openDocumentWithContentsOfURL:aURL display:YES error:NULL];
|
return !![_documentController openDocumentWithContentsOfURL:aURL display:YES error:NULL];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)_willBecomeActive
|
||||||
|
{
|
||||||
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillBecomeActiveNotification
|
||||||
|
object:self
|
||||||
|
userInfo:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_didBecomeActive
|
||||||
|
{
|
||||||
|
if (![self keyWindow] && _previousKeyWindow &&
|
||||||
|
[[self windows] indexOfObjectIdenticalTo:_previousKeyWindow] !== CPNotFound)
|
||||||
|
[_previousKeyWindow makeKeyWindow];
|
||||||
|
|
||||||
|
if (![self mainWindow] && _previousMainWindow &&
|
||||||
|
[[self windows] indexOfObjectIdenticalTo:_previousMainWindow] !== CPNotFound)
|
||||||
|
[_previousMainWindow makeMainWindow];
|
||||||
|
|
||||||
|
if ([self keyWindow])
|
||||||
|
[[self keyWindow] orderFront:self];
|
||||||
|
else if ([self mainWindow])
|
||||||
|
[[self mainWindow] makeKeyAndOrderFront:self];
|
||||||
|
else
|
||||||
|
[[self mainMenu]._menuWindow makeKeyWindow]; //FIXME this may not actually work
|
||||||
|
|
||||||
|
_previousKeyWindow = nil;
|
||||||
|
_previousMainWindow = nil;
|
||||||
|
|
||||||
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidBecomeActiveNotification
|
||||||
|
object:self
|
||||||
|
userInfo:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_willResignActive
|
||||||
|
{
|
||||||
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillResignActiveNotification
|
||||||
|
object:self
|
||||||
|
userInfo:nil];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)_didResignActive
|
- (void)_didResignActive
|
||||||
{
|
{
|
||||||
if (self._activeMenu)
|
if (self._activeMenu)
|
||||||
[self._activeMenu cancelTracking];
|
[self._activeMenu cancelTracking];
|
||||||
|
|
||||||
|
if ([self keyWindow])
|
||||||
|
{
|
||||||
|
_previousKeyWindow = [self keyWindow];
|
||||||
|
[_previousKeyWindow resignKeyWindow];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([self mainWindow])
|
||||||
|
{
|
||||||
|
_previousMainWindow = [self mainWindow];
|
||||||
|
[_previousMainWindow resignMainWindow];
|
||||||
|
}
|
||||||
|
|
||||||
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidResignActiveNotification
|
||||||
|
object:self
|
||||||
|
userInfo:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPString)defaultThemeName
|
||||||
|
{
|
||||||
|
return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo");
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -970,7 +1036,8 @@ var _CPEventListenerMake = function(anEventMask, aCallback)
|
|||||||
return { _mask:anEventMask, _callback:aCallback };
|
return { _mask:anEventMask, _callback:aCallback };
|
||||||
}
|
}
|
||||||
|
|
||||||
var _CPRunModalLoop = function(anEvent)
|
// Make this a global for use in CPPlatformWindow+DOM.j.
|
||||||
|
_CPRunModalLoop = function(anEvent)
|
||||||
{
|
{
|
||||||
[CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO];
|
[CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO];
|
||||||
|
|
||||||
@@ -990,6 +1057,13 @@ var _CPRunModalLoop = function(anEvent)
|
|||||||
|
|
||||||
function CPApplicationMain(args, namedArgs)
|
function CPApplicationMain(args, namedArgs)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
// hook to allow recorder, etc to manipulate things before starting AppKit
|
||||||
|
if (window.parent !== window && typeof window.parent._childAppIsStarting === "function")
|
||||||
|
window.parent._childAppIsStarting(window);
|
||||||
|
#endif
|
||||||
|
|
||||||
var mainBundle = [CPBundle mainBundle],
|
var mainBundle = [CPBundle mainBundle],
|
||||||
principalClass = [mainBundle principalClass];
|
principalClass = [mainBundle principalClass];
|
||||||
|
|
||||||
@@ -998,29 +1072,8 @@ function CPApplicationMain(args, namedArgs)
|
|||||||
|
|
||||||
[principalClass sharedApplication];
|
[principalClass sharedApplication];
|
||||||
|
|
||||||
//FIXME?
|
|
||||||
if (!args)
|
|
||||||
{
|
|
||||||
var args = [CPApp arguments];
|
|
||||||
|
|
||||||
if ([args containsObject:"debug"])
|
if ([args containsObject:"debug"])
|
||||||
CPLogRegister(CPLogPopup);
|
CPLogRegister(CPLogPopup);
|
||||||
}
|
|
||||||
|
|
||||||
if (!namedArgs)
|
|
||||||
{
|
|
||||||
var searchParams = window.location.search.substring(1).split("&");
|
|
||||||
namedArgs = [CPDictionary dictionary];
|
|
||||||
|
|
||||||
for(var i=0; i<searchParams.length; i++)
|
|
||||||
{
|
|
||||||
var index = searchParams[i].indexOf('=');
|
|
||||||
if(index == -1)
|
|
||||||
[namedArgs setObject: "" forKey:searchParams[i]];
|
|
||||||
else
|
|
||||||
[namedArgs setObject: searchParams[i].substring(index+1) forKey: searchParams[i].substring(0, index)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CPApp._args = args;
|
CPApp._args = args;
|
||||||
CPApp._namedArgs = namedArgs;
|
CPApp._namedArgs = namedArgs;
|
||||||
@@ -1034,7 +1087,7 @@ var _CPAppBootstrapperActions = nil;
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)actions
|
+ (CPArray)actions
|
||||||
{
|
{
|
||||||
return [@selector(bootstrapPlatform), @selector(loadDefaultTheme), @selector(loadMainCibFile)];
|
return [@selector(bootstrapPlatform), @selector(loadDefaultTheme), @selector(loadMainCibFile)];
|
||||||
}
|
}
|
||||||
@@ -1062,16 +1115,24 @@ var _CPAppBootstrapperActions = nil;
|
|||||||
|
|
||||||
+ (BOOL)loadDefaultTheme
|
+ (BOOL)loadDefaultTheme
|
||||||
{
|
{
|
||||||
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:[[CPBundle bundleForClass:[CPApplication class]] pathForResource:@"Aristo.blend"]];
|
var defaultThemeName = [CPApplication defaultThemeName],
|
||||||
|
themeURL = nil;
|
||||||
|
|
||||||
|
if (defaultThemeName === @"Aristo")
|
||||||
|
themeURL = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:defaultThemeName + @".blend"];
|
||||||
|
else
|
||||||
|
themeURL = [[CPBundle mainBundle] pathForResource:defaultThemeName + @".blend"];
|
||||||
|
|
||||||
|
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:themeURL];
|
||||||
[blend loadWithDelegate:self];
|
[blend loadWithDelegate:self];
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)blendDidFinishLoading:(CPBundle)aBundle
|
+ (void)blendDidFinishLoading:(CPThemeBlend)aThemeBlend
|
||||||
{
|
{
|
||||||
[CPTheme setDefaultTheme:[CPTheme themeNamed:@"Aristo"]];
|
[[CPApplication sharedApplication] setThemeBlend:aThemeBlend];
|
||||||
|
[CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]];
|
||||||
|
|
||||||
[self performActions];
|
[self performActions];
|
||||||
}
|
}
|
||||||
@@ -1089,15 +1150,83 @@ var _CPAppBootstrapperActions = nil;
|
|||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
[self loadCiblessBrowserMainMenu];
|
||||||
|
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (void)loadCiblessBrowserMainMenu
|
||||||
|
{
|
||||||
|
var mainMenu = [[CPMenu alloc] initWithTitle:@"MainMenu"];
|
||||||
|
|
||||||
|
// FIXME: We should implement autoenabling.
|
||||||
|
[mainMenu setAutoenablesItems:NO];
|
||||||
|
|
||||||
|
var bundle = [CPBundle bundleForClass:[CPApplication class]],
|
||||||
|
newMenuItem = [[CPMenuItem alloc] initWithTitle:@"New" action:@selector(newDocument:) keyEquivalent:@"n"];
|
||||||
|
|
||||||
|
[newMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/New.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||||
|
[newMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/NewHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||||
|
|
||||||
|
[mainMenu addItem:newMenuItem];
|
||||||
|
|
||||||
|
var openMenuItem = [[CPMenuItem alloc] initWithTitle:@"Open" action:@selector(openDocument:) keyEquivalent:@"o"];
|
||||||
|
|
||||||
|
[openMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Open.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||||
|
[openMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/OpenHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||||
|
|
||||||
|
[mainMenu addItem:openMenuItem];
|
||||||
|
|
||||||
|
var saveMenu = [[CPMenu alloc] initWithTitle:@"Save"],
|
||||||
|
saveMenuItem = [[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:nil];
|
||||||
|
|
||||||
|
[saveMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Save.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||||
|
[saveMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/SaveHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||||
|
|
||||||
|
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:@"s"]];
|
||||||
|
[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:nil],
|
||||||
|
editMenu = [[CPMenu alloc] initWithTitle:@"Edit"],
|
||||||
|
|
||||||
|
undoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Undo" action:@selector(undo:) keyEquivalent:CPUndoKeyEquivalent],
|
||||||
|
redoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Redo" action:@selector(redo:) keyEquivalent:CPRedoKeyEquivalent];
|
||||||
|
|
||||||
|
[undoMenuItem setKeyEquivalentModifierMask:CPUndoKeyEquivalentModifierMask];
|
||||||
|
[redoMenuItem setKeyEquivalentModifierMask:CPRedoKeyEquivalentModifierMask];
|
||||||
|
|
||||||
|
[editMenu addItem:undoMenuItem];
|
||||||
|
[editMenu addItem:redoMenuItem];
|
||||||
|
|
||||||
|
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"]],
|
||||||
|
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"]],
|
||||||
|
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"v"]];
|
||||||
|
|
||||||
|
[editMenuItem setSubmenu:editMenu];
|
||||||
|
[editMenuItem setHidden:YES];
|
||||||
|
|
||||||
|
[mainMenu addItem:editMenuItem];
|
||||||
|
|
||||||
|
[mainMenu addItem:[CPMenuItem separatorItem]];
|
||||||
|
|
||||||
|
[CPApp setMainMenu:mainMenu];
|
||||||
|
}
|
||||||
|
|
||||||
+ (void)cibDidFinishLoading:(CPCib)aCib
|
+ (void)cibDidFinishLoading:(CPCib)aCib
|
||||||
{
|
{
|
||||||
[self performActions];
|
[self performActions];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (void)cibDidFailToLoad:(CPCib)aCib
|
||||||
|
{
|
||||||
|
throw new Error("Could not load main cib file (Did you forget to nib2cib it?).");
|
||||||
|
}
|
||||||
|
|
||||||
+ (void)reset
|
+ (void)reset
|
||||||
{
|
{
|
||||||
_CPAppBootstrapperActions = nil;
|
_CPAppBootstrapperActions = nil;
|
||||||
|
|||||||
@@ -0,0 +1,675 @@
|
|||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CPArrayController.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Adapted from Cocotron, by Johannes Fortmann
|
||||||
|
*
|
||||||
|
* Created by Ross Boucher.
|
||||||
|
* Copyright 2009, 280 North, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import <Foundation/CPIndexSet.j>
|
||||||
|
|
||||||
|
@import "CPObjectController.j"
|
||||||
|
@import "CPKeyValueBinding.j"
|
||||||
|
|
||||||
|
|
||||||
|
@implementation CPArrayController : CPObjectController
|
||||||
|
{
|
||||||
|
BOOL _avoidsEmptySelection;
|
||||||
|
BOOL _clearsFilterPredicateOnInsertion;
|
||||||
|
BOOL _filterRestrictsInsertion;
|
||||||
|
BOOL _preservesSelection;
|
||||||
|
BOOL _selectsInsertedObjects;
|
||||||
|
BOOL _alwaysUsesMultipleValuesMarker;
|
||||||
|
|
||||||
|
id _selectionIndexes;
|
||||||
|
id _sortDescriptors;
|
||||||
|
id _filterPredicate;
|
||||||
|
id _arrangedObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
if (self !== [CPArrayController class])
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self exposeBinding:@"contentArray"];
|
||||||
|
[self exposeBinding:@"contentSet"];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPSet)keyPathsForValuesAffectingContentArray
|
||||||
|
{
|
||||||
|
return [CPSet setWithObjects:"content"];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPSet)keyPathsForValuesAffectingArrangedObjects
|
||||||
|
{
|
||||||
|
return [CPSet setWithObjects:"content", "filterPredicate", "sortDescriptors"];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPSet)keyPathsForValuesAffectingSelection
|
||||||
|
{
|
||||||
|
return [CPSet setWithObjects:"selectionIndexes"];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPSet)keyPathsForValuesAffectingSelectionIndex
|
||||||
|
{
|
||||||
|
return [CPSet setWithObjects:"selectionIndexes"];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPSet)keyPathsForValuesAffectingSelectionIndexes
|
||||||
|
{
|
||||||
|
// When the arranged objects change, selection preservation may cause the indexes
|
||||||
|
// to change.
|
||||||
|
return [CPSet setWithObjects:"arrangedObjects"];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPSet)keyPathsForValuesAffectingSelectedObjects
|
||||||
|
{
|
||||||
|
// Don't need to depend on arrangedObjects here because selectionIndexes already does.
|
||||||
|
return [CPSet setWithObjects:"selectionIndexes"];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPSet)keyPathsForValuesAffectingCanRemove
|
||||||
|
{
|
||||||
|
return [CPSet setWithObjects:"selectionIndexes"];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPSet)keyPathsForValuesAffectingCanSelectNext
|
||||||
|
{
|
||||||
|
return [CPSet setWithObjects:"selectionIndexes"];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPSet)keyPathsForValuesAffectingCanSelectPrevious
|
||||||
|
{
|
||||||
|
return [CPSet setWithObjects:"selectionIndexes"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_selectionIndexes = [CPIndexSet indexSet];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)prepareContent
|
||||||
|
{
|
||||||
|
[self _setContentArray:[[self newObject]]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)preservesSelection
|
||||||
|
{
|
||||||
|
return _preservesSelection;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setPreservesSelection:(BOOL)value
|
||||||
|
{
|
||||||
|
_preservesSelection = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)selectsInsertedObjects
|
||||||
|
{
|
||||||
|
return _selectsInsertedObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setSelectsInsertedObjects:(BOOL)value
|
||||||
|
{
|
||||||
|
_selectsInsertedObjects = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)avoidsEmptySelection
|
||||||
|
{
|
||||||
|
return _avoidsEmptySelection;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setAvoidsEmptySelection:(BOOL)value
|
||||||
|
{
|
||||||
|
_avoidsEmptySelection = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setContent:(id)value
|
||||||
|
{
|
||||||
|
if (value === nil)
|
||||||
|
value = [];
|
||||||
|
|
||||||
|
if (![value isKindOfClass:[CPArray class]])
|
||||||
|
value = [value];
|
||||||
|
|
||||||
|
var oldSelectedObjects = nil,
|
||||||
|
oldSelectionIndexes = nil;
|
||||||
|
|
||||||
|
if ([self preservesSelection])
|
||||||
|
oldSelectedObjects = [self selectedObjects];
|
||||||
|
else
|
||||||
|
oldSelectionIndexes = [self selectionIndexes];
|
||||||
|
|
||||||
|
/*
|
||||||
|
When the contents are changed, the selected indexes may no longer refer to the
|
||||||
|
same items. This would cause problems when setSelectedObjects is called below.
|
||||||
|
Any KVO observation would try to retrieve the 'before' value which could be
|
||||||
|
wrong or even throw an exception for no longer existing indexes.
|
||||||
|
|
||||||
|
To avoid that, use the internal __setSelectedObjects which fires no notifications.
|
||||||
|
The selectionIndexes notifications will fire later since they depend on the
|
||||||
|
content key. This pattern is also applied for many other methods throughout this
|
||||||
|
class.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (_clearsFilterPredicateOnInsertion)
|
||||||
|
[self willChangeValueForKey:@"filterPredicate"];
|
||||||
|
|
||||||
|
// Don't use [super setContent:] as that would fire the contentObject change.
|
||||||
|
// We need to be in control of when notifications fire.
|
||||||
|
_contentObject = value;
|
||||||
|
|
||||||
|
if (_clearsFilterPredicateOnInsertion)
|
||||||
|
[self __setFilterPredicate:nil]; // Causes a _rearrangeObjects.
|
||||||
|
else
|
||||||
|
[self _rearrangeObjects];
|
||||||
|
|
||||||
|
if ([self preservesSelection])
|
||||||
|
[self __setSelectedObjects:oldSelectedObjects];
|
||||||
|
else
|
||||||
|
[self __setSelectionIndexes:oldSelectionIndexes];
|
||||||
|
|
||||||
|
if (_clearsFilterPredicateOnInsertion)
|
||||||
|
[self didChangeValueForKey:@"filterPredicate"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_setContentArray:(id)anArray
|
||||||
|
{
|
||||||
|
[self setContent:anArray];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_setContentSet:(id)aSet
|
||||||
|
{
|
||||||
|
[self setContent:aSet];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)contentArray
|
||||||
|
{
|
||||||
|
return [self content];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)contentSet
|
||||||
|
{
|
||||||
|
return [self content];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPArray)arrangeObjects:(CPArray)objects
|
||||||
|
{
|
||||||
|
var filterPredicate = [self filterPredicate],
|
||||||
|
sortDescriptors = [self sortDescriptors];
|
||||||
|
|
||||||
|
if (filterPredicate && sortDescriptors)
|
||||||
|
{
|
||||||
|
var sortedObjects = [objects filteredArrayUsingPredicate:filterPredicate];
|
||||||
|
[sortedObjects sortUsingDescriptors:sortDescriptors];
|
||||||
|
return sortedObjects;
|
||||||
|
}
|
||||||
|
else if (filterPredicate)
|
||||||
|
return [objects filteredArrayUsingPredicate:filterPredicate];
|
||||||
|
else if (sortDescriptors)
|
||||||
|
return [objects sortedArrayUsingDescriptors:sortDescriptors];
|
||||||
|
|
||||||
|
return [objects copy];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)rearrangeObjects
|
||||||
|
{
|
||||||
|
[self willChangeValueForKey:@"arrangedObjects"];
|
||||||
|
[self _rearrangeObjects];
|
||||||
|
[self didChangeValueForKey:@"arrangedObjects"];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Like rearrangeObjects but don't fire any change notifications.
|
||||||
|
@ignore
|
||||||
|
*/
|
||||||
|
- (void)_rearrangeObjects
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Rearranging reapplies the selection criteria and may cause objects to disappear,
|
||||||
|
so take care of the selection.
|
||||||
|
*/
|
||||||
|
var oldSelectedObjects = nil,
|
||||||
|
oldSelectionIndexes = nil;
|
||||||
|
|
||||||
|
if ([self preservesSelection])
|
||||||
|
oldSelectedObjects = [self selectedObjects];
|
||||||
|
else
|
||||||
|
oldSelectionIndexes = [self selectionIndexes];
|
||||||
|
|
||||||
|
[self __setArrangedObjects:[self arrangeObjects:[self contentArray]]];
|
||||||
|
|
||||||
|
if ([self preservesSelection])
|
||||||
|
[self __setSelectedObjects:oldSelectedObjects];
|
||||||
|
else
|
||||||
|
[self __setSelectionIndexes:oldSelectionIndexes];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)__setArrangedObjects:(id)value
|
||||||
|
{
|
||||||
|
if (_arrangedObjects === value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_arrangedObjects = [[_CPObservableArray alloc] initWithArray:value];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)arrangedObjects
|
||||||
|
{
|
||||||
|
return _arrangedObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPArray)sortDescriptors
|
||||||
|
{
|
||||||
|
return _sortDescriptors;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setSortDescriptors:(CPArray)value
|
||||||
|
{
|
||||||
|
if (_sortDescriptors === value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_sortDescriptors = [value copy];
|
||||||
|
// Use the non-notification version since arrangedObjects already depends
|
||||||
|
// on sortDescriptors.
|
||||||
|
[self _rearrangeObjects];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPPredicate)filterPredicate
|
||||||
|
{
|
||||||
|
return _filterPredicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFilterPredicate:(CPPredicate)value
|
||||||
|
{
|
||||||
|
[self __setFilterPredicate:value];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Like setFilterPredicate but don't fire any change notifications.
|
||||||
|
@ignore
|
||||||
|
*/
|
||||||
|
- (void)__setFilterPredicate:(CPPredicate)value
|
||||||
|
{
|
||||||
|
if (_filterPredicate === value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_filterPredicate = value;
|
||||||
|
// Use the non-notification version since arrangedObjects already depends
|
||||||
|
// on filterPredicate.
|
||||||
|
[self _rearrangeObjects];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)alwaysUsesMultipleValuesMarker
|
||||||
|
{
|
||||||
|
return _alwaysUsesMultipleValuesMarker;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Selection
|
||||||
|
|
||||||
|
- (unsigned)selectionIndex
|
||||||
|
{
|
||||||
|
return [_selectionIndexes firstIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)setSelectionIndex:(unsigned)index
|
||||||
|
{
|
||||||
|
return [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPIndexSet)selectionIndexes
|
||||||
|
{
|
||||||
|
return _selectionIndexes;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)setSelectionIndexes:(CPIndexSet)indexes
|
||||||
|
{
|
||||||
|
[self _selectionWillChange]
|
||||||
|
[self __setSelectionIndexes:indexes];
|
||||||
|
[self _selectionDidChange];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Like setSelectionIndex but don't fire any change notifications.
|
||||||
|
@ignore
|
||||||
|
*/
|
||||||
|
- (BOOL)__setSelectionIndex:(int)theIndex
|
||||||
|
{
|
||||||
|
[self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:theIndex]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Like setSelectionIndexes but don't fire any change notifications.
|
||||||
|
@ignore
|
||||||
|
*/
|
||||||
|
- (BOOL)__setSelectionIndexes:(CPIndexSet)indexes
|
||||||
|
{
|
||||||
|
if (!indexes)
|
||||||
|
indexes = [CPIndexSet indexSet];
|
||||||
|
|
||||||
|
if (![indexes count])
|
||||||
|
{
|
||||||
|
if (_avoidsEmptySelection && [[self arrangedObjects] count])
|
||||||
|
indexes = [CPIndexSet indexSetWithIndex:0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var objectsCount = [[self arrangedObjects] count];
|
||||||
|
// Remove out of bounds indexes.
|
||||||
|
[indexes removeIndexesInRange:CPMakeRange(objectsCount, [indexes lastIndex] + 1)];
|
||||||
|
// When avoiding empty selection and the deleted selection was at the bottom, select the last item.
|
||||||
|
if (![indexes count] && _avoidsEmptySelection && objectsCount)
|
||||||
|
indexes = [CPIndexSet indexSetWithIndex:objectsCount - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([_selectionIndexes isEqualToIndexSet:indexes])
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
_selectionIndexes = [indexes copy];
|
||||||
|
|
||||||
|
// Push back the new selection to the model for selectionIndexes if we have one.
|
||||||
|
// There won't be an infinite loop because of the equality check above.
|
||||||
|
[[CPKeyValueBinding getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPArray)selectedObjects
|
||||||
|
{
|
||||||
|
var objects = [[self arrangedObjects] objectsAtIndexes:[self selectionIndexes]];
|
||||||
|
|
||||||
|
return [_CPObservableArray arrayWithArray:(objects || [])];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)setSelectedObjects:(CPArray)objects
|
||||||
|
{
|
||||||
|
[self willChangeValueForKey:@"selectionIndexes"];
|
||||||
|
[self _selectionWillChange];
|
||||||
|
|
||||||
|
[self __setSelectedObjects:objects];
|
||||||
|
|
||||||
|
[self didChangeValueForKey:@"selectionIndexes"];
|
||||||
|
[self _selectionDidChange];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Like setSelectedObjects but don't fire any change notifications.
|
||||||
|
@ignore
|
||||||
|
*/
|
||||||
|
- (BOOL)__setSelectedObjects:(CPArray)objects
|
||||||
|
{
|
||||||
|
var set = [CPIndexSet indexSet],
|
||||||
|
count = [objects count],
|
||||||
|
arrangedObjects = [self arrangedObjects];
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var index = [arrangedObjects indexOfObject:[objects objectAtIndex:i]];
|
||||||
|
|
||||||
|
if (index !== CPNotFound)
|
||||||
|
[set addIndex:index];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self __setSelectionIndexes:set];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Moving selection
|
||||||
|
|
||||||
|
- (BOOL)canSelectPrevious
|
||||||
|
{
|
||||||
|
return [[self selectionIndexes] firstIndex] > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)selectPrevious:(id)sender
|
||||||
|
{
|
||||||
|
var index = [[self selectionIndexes] firstIndex] - 1;
|
||||||
|
|
||||||
|
if (index >= 0)
|
||||||
|
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)canSelectNext
|
||||||
|
{
|
||||||
|
return [[self selectionIndexes] firstIndex] < [[self arrangedObjects] count] - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)selectNext:(id)sender
|
||||||
|
{
|
||||||
|
var index = [[self selectionIndexes] firstIndex] + 1;
|
||||||
|
|
||||||
|
if (index < [[self arrangedObjects] count])
|
||||||
|
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add/Remove
|
||||||
|
|
||||||
|
- (void)addObject:(id)object
|
||||||
|
{
|
||||||
|
if (![self canAdd])
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_clearsFilterPredicateOnInsertion)
|
||||||
|
[self willChangeValueForKey:@"filterPredicate"];
|
||||||
|
|
||||||
|
[self willChangeValueForKey:@"content"];
|
||||||
|
[_contentObject addObject:object];
|
||||||
|
|
||||||
|
if (_clearsFilterPredicateOnInsertion)
|
||||||
|
[self __setFilterPredicate:nil];
|
||||||
|
|
||||||
|
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
|
||||||
|
{
|
||||||
|
var pos = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors];
|
||||||
|
|
||||||
|
// selectionIndexes change notification will be fired as a result of the
|
||||||
|
// content change. Don't fire manually.
|
||||||
|
if (_selectsInsertedObjects)
|
||||||
|
[self __setSelectionIndex:pos];
|
||||||
|
else
|
||||||
|
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[self _rearrangeObjects];
|
||||||
|
|
||||||
|
[self didChangeValueForKey:@"content"];
|
||||||
|
if (_clearsFilterPredicateOnInsertion)
|
||||||
|
[self didChangeValueForKey:@"filterPredicate"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)insertObject:(id)anObject atArrangedObjectIndex:(int)anIndex
|
||||||
|
{
|
||||||
|
if (![self canAdd])
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_clearsFilterPredicateOnInsertion)
|
||||||
|
[self willChangeValueForKey:@"filterPredicate"];
|
||||||
|
|
||||||
|
[self willChangeValueForKey:@"content"];
|
||||||
|
[_contentObject insertObject:anObject atIndex:anIndex];
|
||||||
|
|
||||||
|
if (_clearsFilterPredicateOnInsertion)
|
||||||
|
[self __setFilterPredicate:nil];
|
||||||
|
|
||||||
|
[[self arrangedObjects] insertObject:anObject atIndex:anIndex];
|
||||||
|
|
||||||
|
// selectionIndexes change notification will be fired as a result of the
|
||||||
|
// content change. Don't fire manually.
|
||||||
|
if ([self selectsInsertedObjects])
|
||||||
|
[self __setSelectionIndex:anIndex];
|
||||||
|
else
|
||||||
|
[[self selectionIndexes] shiftIndexesStartingAtIndex:anIndex by:1];
|
||||||
|
|
||||||
|
if ([self avoidsEmptySelection] && [[self selectionIndexes] count] <= 0 && [_contentObject count] > 0)
|
||||||
|
[self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:0]];
|
||||||
|
|
||||||
|
[self didChangeValueForKey:@"content"];
|
||||||
|
if (_clearsFilterPredicateOnInsertion)
|
||||||
|
[self didChangeValueForKey:@"filterPredicate"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeObject:(id)object
|
||||||
|
{
|
||||||
|
if (![self canRemove])
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self willChangeValueForKey:@"content"];
|
||||||
|
[_contentObject removeObject:object];
|
||||||
|
|
||||||
|
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
|
||||||
|
{
|
||||||
|
// selectionIndexes change notification will be fired as a result of the
|
||||||
|
// content change. Don't fire manually.
|
||||||
|
var pos = [_arrangedObjects indexOfObject:object];
|
||||||
|
|
||||||
|
[_arrangedObjects removeObjectAtIndex:pos];
|
||||||
|
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self didChangeValueForKey:@"content"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)add:(id)sender
|
||||||
|
{
|
||||||
|
if (![self canAdd])
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self insert:sender];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)insert:(id)sender
|
||||||
|
{
|
||||||
|
if (![self canInsert])
|
||||||
|
return;
|
||||||
|
|
||||||
|
var newObject = [self automaticallyPreparesContent] ? [self newObject] : [self _defaultNewObject];
|
||||||
|
|
||||||
|
[self addObject:newObject];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)remove:(id)sender
|
||||||
|
{
|
||||||
|
[self removeObjects:[[self arrangedObjects] objectsAtIndexes:[self selectionIndexes]]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeObjectsAtArrangedObjectIndexes:(CPIndexSet)indexes
|
||||||
|
{
|
||||||
|
[self _removeObjects:[[self arrangedObjects] objectsAtIndexes:indexes]];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)addObjects:(CPArray)objects
|
||||||
|
{
|
||||||
|
if (![self canAdd])
|
||||||
|
return;
|
||||||
|
|
||||||
|
var contentArray = [self contentArray],
|
||||||
|
count = [objects count];
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
[contentArray addObject:[objects objectAtIndex:i]];
|
||||||
|
|
||||||
|
[self setContent:contentArray];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeObjects:(CPArray)objects
|
||||||
|
{
|
||||||
|
if (![self canRemove])
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self _removeObjects:objects];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_removeObjects:(CPArray)objects
|
||||||
|
{
|
||||||
|
[self willChangeValueForKey:@"content"];
|
||||||
|
[_contentObject removeObjectsInArray:objects];
|
||||||
|
|
||||||
|
var arrangedObjects = [self arrangedObjects],
|
||||||
|
position = [arrangedObjects indexOfObject:[objects objectAtIndex:0]];
|
||||||
|
|
||||||
|
[arrangedObjects removeObjectsInArray:objects];
|
||||||
|
|
||||||
|
var objectsCount = [arrangedObjects count],
|
||||||
|
selectionIndexes = [CPIndexSet indexSet];
|
||||||
|
|
||||||
|
if ([self preservesSelection] || [self avoidsEmptySelection])
|
||||||
|
{
|
||||||
|
selectionIndexes = [CPIndexSet indexSetWithIndex:position];
|
||||||
|
|
||||||
|
// Remove the selection if there are no objects
|
||||||
|
if (objectsCount <= 0)
|
||||||
|
selectionIndexes = [CPIndexSet indexSet];
|
||||||
|
|
||||||
|
// Shift selection to last object if position is out of bounds
|
||||||
|
else if (position >= objectsCount)
|
||||||
|
selectionIndexes = [CPIndexSet indexSetWithIndex:objectsCount - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
_selectionIndexes = selectionIndexes;
|
||||||
|
|
||||||
|
[self didChangeValueForKey:@"content"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)canInsert
|
||||||
|
{
|
||||||
|
return [self isEditable];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation CPArrayController (CPCoding)
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
self = [super initWithCoder:coder];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_avoidsEmptySelection = [coder decodeBoolForKey:@"CPArrayControllerAvoidsEmptySelection"];
|
||||||
|
_clearsFilterPredicateOnInsertion = [coder decodeBoolForKey:@"CPClearsFilterPredicateOnInsertion"];
|
||||||
|
_filterRestrictsInsertion = [coder decodeBoolForKey:@"CPArrayControllerFilterRestrictsInsertion"];
|
||||||
|
_preservesSelection = [coder decodeBoolForKey:@"CPArrayControllerPreservesSelection"];
|
||||||
|
_selectsInsertedObjects = [coder decodeBoolForKey:@"CPArrayControllerSelectsInsertedObjects"];
|
||||||
|
_alwaysUsesMultipleValuesMarker = [coder decodeBoolForKey:@"CPArrayControllerAlwaysUsesMultipleValuesMarker"];
|
||||||
|
|
||||||
|
if ([self automaticallyPreparesContent])
|
||||||
|
[self prepareContent];
|
||||||
|
else
|
||||||
|
[self _setContentArray:[]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)awakeFromCib
|
||||||
|
{
|
||||||
|
[self _selectionWillChange];
|
||||||
|
[self _selectionDidChange];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -23,9 +23,10 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@import <AppKit/CPGraphicsContext.j>
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
|
@import "CPGraphicsContext.j"
|
||||||
|
|
||||||
|
|
||||||
// Class defaults
|
// Class defaults
|
||||||
|
|
||||||
|
|||||||
+157
-33
@@ -22,6 +22,13 @@
|
|||||||
|
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
|
||||||
|
// CPBoxType
|
||||||
|
CPBoxPrimary = 0;
|
||||||
|
CPBoxSecondary = 1;
|
||||||
|
CPBoxSeperator = 2;
|
||||||
|
CPBoxOldStyle = 3;
|
||||||
|
CPBoxCustom = 4;
|
||||||
|
|
||||||
// CPBorderType
|
// CPBorderType
|
||||||
CPNoBorder = 0;
|
CPNoBorder = 0;
|
||||||
CPLineBorder = 1;
|
CPLineBorder = 1;
|
||||||
@@ -30,6 +37,7 @@ CPGrooveBorder = 3;
|
|||||||
|
|
||||||
@implementation CPBox : CPView
|
@implementation CPBox : CPView
|
||||||
{
|
{
|
||||||
|
CPBoxType _boxType;
|
||||||
CPBorderType _borderType;
|
CPBorderType _borderType;
|
||||||
|
|
||||||
CPColor _borderColor;
|
CPColor _borderColor;
|
||||||
@@ -62,6 +70,7 @@ CPGrooveBorder = 3;
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
|
_borderType = CPBezelBorder;
|
||||||
_fillColor = [CPColor clearColor];
|
_fillColor = [CPColor clearColor];
|
||||||
_borderColor = [CPColor blackColor];
|
_borderColor = [CPColor blackColor];
|
||||||
|
|
||||||
@@ -69,7 +78,9 @@ CPGrooveBorder = 3;
|
|||||||
_contentMargin = CGSizeMake(0.0, 0.0);
|
_contentMargin = CGSizeMake(0.0, 0.0);
|
||||||
|
|
||||||
_contentView = [[CPView alloc] initWithFrame:[self bounds]];
|
_contentView = [[CPView alloc] initWithFrame:[self bounds]];
|
||||||
|
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||||
|
|
||||||
|
[self setAutoresizesSubviews:YES];
|
||||||
[self addSubview:_contentView];
|
[self addSubview:_contentView];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,9 +99,26 @@ CPGrooveBorder = 3;
|
|||||||
return _borderType;
|
return _borderType;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setBorderType:(CPBorderType)value
|
- (void)setBorderType:(CPBorderType)aBorderType
|
||||||
{
|
{
|
||||||
_borderType = value;
|
if (_borderType === aBorderType)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_borderType = aBorderType;
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPBoxType)boxType
|
||||||
|
{
|
||||||
|
return _boxType;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setBoxType:(CPBoxType)aBoxType
|
||||||
|
{
|
||||||
|
if (_boxType === aBoxType)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_boxType = aBoxType;
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,6 +189,7 @@ CPGrooveBorder = 3;
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
[aView setFrame:CGRectInset([self bounds], _contentMargin.width + _borderWidth, _contentMargin.height + _borderWidth)];
|
[aView setFrame:CGRectInset([self bounds], _contentMargin.width + _borderWidth, _contentMargin.height + _borderWidth)];
|
||||||
|
[aView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||||
[self replaceSubview:_contentView with:aView];
|
[self replaceSubview:_contentView with:aView];
|
||||||
|
|
||||||
_contentView = aView;
|
_contentView = aView;
|
||||||
@@ -198,47 +227,142 @@ CPGrooveBorder = 3;
|
|||||||
|
|
||||||
- (void)drawRect:(CPRect)rect
|
- (void)drawRect:(CPRect)rect
|
||||||
{
|
{
|
||||||
var bounds = [self bounds],
|
if (_borderType === CPNoBorder)
|
||||||
aContext = [[CPGraphicsContext currentContext] graphicsPort],
|
return;
|
||||||
border2 = _borderWidth/2,
|
|
||||||
|
|
||||||
strokeRect = CGRectMake(bounds.origin.x + border2,
|
var bounds = [self bounds];
|
||||||
bounds.origin.y + border2,
|
|
||||||
bounds.size.width - _borderWidth,
|
|
||||||
bounds.size.height - _borderWidth),
|
|
||||||
|
|
||||||
fillRect = CGRectMake(bounds.origin.x + border2,
|
switch (_boxType)
|
||||||
bounds.origin.y + border2,
|
{
|
||||||
bounds.size.width - _borderWidth,
|
case CPBoxSeperator:
|
||||||
bounds.size.height - _borderWidth);
|
// NSBox does not include a horitontal flag for the seperator type. We have to determine
|
||||||
|
// the type of seperator to draw by the width and height of the frame.
|
||||||
|
if (CGRectGetWidth(bounds) === 5.0)
|
||||||
|
return [self _drawVerticalSeperatorInRect:bounds];
|
||||||
|
else if (CGRectGetHeight(bounds) === 5.0)
|
||||||
|
return [self _drawHorizontalSeperatorInRect:bounds];
|
||||||
|
|
||||||
CGContextSetFillColor(aContext, [self fillColor]);
|
break;
|
||||||
CGContextSetStrokeColor(aContext, [self borderColor]);
|
}
|
||||||
CGContextSetLineWidth(aContext, _borderWidth);
|
|
||||||
|
|
||||||
switch (_borderType)
|
switch (_borderType)
|
||||||
{
|
{
|
||||||
case CPLineBorder: CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES);
|
case CPBezelBorder:
|
||||||
CGContextStrokeRoundedRectangleInRect(aContext, strokeRect, _cornerRadius, YES, YES, YES, YES);
|
[self _drawBezelBorderInRect:bounds];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPBezelBorder: CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES);
|
default:
|
||||||
CGContextSetStrokeColor(aContext, [CPColor colorWithWhite:190.0/255.0 alpha:1.0]);
|
case CPLineBorder:
|
||||||
CGContextBeginPath(aContext);
|
[self _drawLineBorderInRect:bounds];
|
||||||
CGContextMoveToPoint(aContext, strokeRect.origin.x, strokeRect.origin.y);
|
|
||||||
CGContextAddLineToPoint(aContext, CGRectGetMinX(strokeRect), CGRectGetMaxY(strokeRect)),
|
|
||||||
CGContextAddLineToPoint(aContext, CGRectGetMaxX(strokeRect), CGRectGetMaxY(strokeRect)),
|
|
||||||
CGContextAddLineToPoint(aContext, CGRectGetMaxX(strokeRect), CGRectGetMinY(strokeRect)),
|
|
||||||
CGContextStrokePath(aContext);
|
|
||||||
CGContextSetStrokeColor(aContext, [CPColor colorWithWhite:142.0/255.0 alpha:1.0]);
|
|
||||||
CGContextBeginPath(aContext);
|
|
||||||
CGContextMoveToPoint(aContext, bounds.origin.x, strokeRect.origin.y);
|
|
||||||
CGContextAddLineToPoint(aContext, CGRectGetMaxX(bounds), CGRectGetMinY(strokeRect));
|
|
||||||
CGContextStrokePath(aContext);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)_drawHorizontalSeperatorInRect:(CGRect)aRect
|
||||||
|
{
|
||||||
|
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||||
|
|
||||||
|
CGContextSetStrokeColor(context, [self borderColor]);
|
||||||
|
CGContextSetLineWidth(context, 1.0);
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, CGRectGetMinX(aRect), CGRectGetMinY(aRect));
|
||||||
|
CGContextAddLineToPoint(context, CGRectGetWidth(aRect), CGRectGetMinY(aRect));
|
||||||
|
CGContextStrokePath(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_drawVerticalSeperatorInRect:(CGRect)aRect
|
||||||
|
{
|
||||||
|
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||||
|
|
||||||
|
CGContextSetStrokeColor(context, [self borderColor]);
|
||||||
|
CGContextSetLineWidth(context, 1.0);
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, CGRectGetMinX(aRect), CGRectGetMinY(aRect));
|
||||||
|
CGContextAddLineToPoint(context, CGRectGetMinX(aRect), CGRectGetHeight(aRect));
|
||||||
|
CGContextStrokePath(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_drawBezelBorderInRect:(CGRect)aRect
|
||||||
|
{
|
||||||
|
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||||
|
sides = [CPMinYEdge, CPMaxXEdge, CPMaxYEdge, CPMinXEdge],
|
||||||
|
sideGray = 190.0 / 255.0,
|
||||||
|
grays = [142.0 / 255.0, sideGray, sideGray, sideGray],
|
||||||
|
borderWidth = _borderWidth;
|
||||||
|
|
||||||
|
while (borderWidth--)
|
||||||
|
aRect = CPDrawTiledRects(aRect, aRect, sides, grays);
|
||||||
|
|
||||||
|
CGContextSetFillColor(context, [self fillColor]);
|
||||||
|
CGContextFillRect(context, aRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_drawLineBorderInRect:(CGRect)aRect
|
||||||
|
{
|
||||||
|
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||||
|
|
||||||
|
aRect = CGRectInset(aRect, _borderWidth / 2.0, _borderWidth / 2.0);
|
||||||
|
|
||||||
|
CGContextSetFillColor(context, [self fillColor]);
|
||||||
|
CGContextSetStrokeColor(context, [self borderColor]);
|
||||||
|
|
||||||
|
CGContextSetLineWidth(context, _borderWidth);
|
||||||
|
CGContextFillRoundedRectangleInRect(context, aRect, _cornerRadius, YES, YES, YES, YES);
|
||||||
|
CGContextStrokeRoundedRectangleInRect(context, aRect, _cornerRadius, YES, YES, YES, YES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var CPBoxTypeKey = @"CPBoxTypeKey",
|
||||||
|
CPBoxBorderTypeKey = @"CPBoxBorderTypeKey",
|
||||||
|
CPBoxBorderColorKey = @"CPBoxBorderColorKey",
|
||||||
|
CPBoxFillColorKey = @"CPBoxFillColorKey",
|
||||||
|
CPBoxCornerRadiusKey = @"CPBoxCornerRadiusKey",
|
||||||
|
CPBoxBorderWidthKey = @"CPBoxBorderWidthKey",
|
||||||
|
CPBoxContentMarginKey = @"CPBoxContentMarginKey";
|
||||||
|
|
||||||
|
@implementation CPBox (CPCoding)
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
self = [super initWithCoder:aCoder];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_boxType = [aCoder decodeIntForKey:CPBoxTypeKey];
|
||||||
|
_borderType = [aCoder decodeIntForKey:CPBoxBorderTypeKey];
|
||||||
|
|
||||||
|
_borderColor = [aCoder decodeObjectForKey:CPBoxBorderColorKey];
|
||||||
|
_fillColor = [aCoder decodeObjectForKey:CPBoxFillColorKey];
|
||||||
|
|
||||||
|
_cornerRadius = [aCoder decodeFloatForKey:CPBoxCornerRadiusKey];
|
||||||
|
_borderWidth = [aCoder decodeFloatForKey:CPBoxBorderWidthKey];
|
||||||
|
|
||||||
|
_contentMargin = [aCoder decodeSizeForKey:CPBoxContentMarginKey];
|
||||||
|
|
||||||
|
_contentView = [self subviews][0];
|
||||||
|
|
||||||
|
[self setAutoresizesSubviews:YES];
|
||||||
|
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
[super encodeWithCoder:aCoder];
|
||||||
|
|
||||||
|
[aCoder encodeInt:_boxType forKey:CPBoxTypeKey];
|
||||||
|
[aCoder encodeInt:_borderType forKey:CPBoxBorderTypeKey];
|
||||||
|
|
||||||
|
[aCoder encodeObject:_borderColor forKey:CPBoxBorderColorKey];
|
||||||
|
[aCoder encodeObject:_fillColor forKey:CPBoxFillColorKey];
|
||||||
|
|
||||||
|
[aCoder encodeFloat:_cornerRadius forKey:CPBoxCornerRadiusKey];
|
||||||
|
[aCoder encodeFloat:_borderWidth forKey:CPBoxBorderWidthKey];
|
||||||
|
|
||||||
|
[aCoder encodeSize:_contentMargin forKey:CPBoxContentMarginKey];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -0,0 +1,955 @@
|
|||||||
|
/*
|
||||||
|
* CPBrowser.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Ross Boucher.
|
||||||
|
* Copyright 2010, 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/CPIndexSet.j>
|
||||||
|
|
||||||
|
@import "CPControl.j"
|
||||||
|
@import "CPImage.j"
|
||||||
|
@import "CPTableView.j"
|
||||||
|
@import "CPTextField.j"
|
||||||
|
@import "CPScrollView.j"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ingroup appkit
|
||||||
|
@class CPBrowser
|
||||||
|
*/
|
||||||
|
|
||||||
|
@implementation CPBrowser : CPControl
|
||||||
|
{
|
||||||
|
id _delegate;
|
||||||
|
CPString _pathSeparator;
|
||||||
|
|
||||||
|
CPView _contentView;
|
||||||
|
CPScrollView _horizontalScrollView;
|
||||||
|
CPView _prototypeView;
|
||||||
|
|
||||||
|
CPArray _tableViews;
|
||||||
|
CPArray _tableDelegates;
|
||||||
|
|
||||||
|
id _rootItem;
|
||||||
|
|
||||||
|
BOOL _delegateSupportsImages;
|
||||||
|
|
||||||
|
SEL _doubleAction @accessors(property=doubleAction);
|
||||||
|
|
||||||
|
BOOL _allowsMultipleSelection;
|
||||||
|
BOOL _allowsEmptySelection;
|
||||||
|
|
||||||
|
Class _tableViewClass @accessors(property=tableViewClass);
|
||||||
|
|
||||||
|
float _rowHeight;
|
||||||
|
float _imageWidth;
|
||||||
|
float _leafWidth;
|
||||||
|
float _minColumnWidth;
|
||||||
|
float _defaultColumnWidth @accessors(property=defaultColumnWidth);
|
||||||
|
|
||||||
|
CPArray _columnWidths;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPImage)branchImage
|
||||||
|
{
|
||||||
|
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPBrowser class]]
|
||||||
|
pathForResource:"browser-leaf.png"]
|
||||||
|
size:CGSizeMake(9,9)];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPImage)highlightedBranchImage
|
||||||
|
{
|
||||||
|
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPBrowser class]]
|
||||||
|
pathForResource:"browser-leaf-highlighted.png"]
|
||||||
|
size:CGSizeMake(9,9)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
|
{
|
||||||
|
if (self = [super initWithFrame:aFrame])
|
||||||
|
{
|
||||||
|
_rowHeight = 23.0;
|
||||||
|
_defaultColumnWidth = 140.0;
|
||||||
|
_minColumnWidth = 80.0;
|
||||||
|
_imageWidth = 23.0;
|
||||||
|
_leafWidth = 13.0;
|
||||||
|
_columnWidths = [];
|
||||||
|
|
||||||
|
_pathSeparator = "/";
|
||||||
|
_tableViews = [];
|
||||||
|
_tableDelegates = [];
|
||||||
|
_allowsMultipleSelection = YES;
|
||||||
|
_allowsEmptySelection = YES;
|
||||||
|
_tableViewClass = [_CPBrowserTableView class];
|
||||||
|
|
||||||
|
_prototypeView = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
[_prototypeView setVerticalAlignment:CPCenterVerticalTextAlignment];
|
||||||
|
[_prototypeView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateSelectedDataView];
|
||||||
|
[_prototypeView setLineBreakMode:CPLineBreakByTruncatingTail];
|
||||||
|
|
||||||
|
_horizontalScrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
|
||||||
|
|
||||||
|
[_horizontalScrollView setHasVerticalScroller:NO];
|
||||||
|
[_horizontalScrollView setAutohidesScrollers:YES];
|
||||||
|
[_horizontalScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||||
|
|
||||||
|
_contentView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, 0, CGRectGetHeight([self bounds]))];
|
||||||
|
[_contentView setAutoresizingMask:CPViewHeightSizable];
|
||||||
|
|
||||||
|
[_horizontalScrollView setDocumentView:_contentView];
|
||||||
|
|
||||||
|
[self addSubview:_horizontalScrollView];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setPrototypeView:(CPView)aPrototypeView
|
||||||
|
{
|
||||||
|
_prototypeView = [CPKeyedUnarchiver unarchiveObjectWithData:
|
||||||
|
[CPKeyedArchiver archivedDataWithRootObject:aPrototypeView]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPView)prototypeView
|
||||||
|
{
|
||||||
|
return [CPKeyedUnarchiver unarchiveObjectWithData:
|
||||||
|
[CPKeyedArchiver archivedDataWithRootObject:_prototypeView]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDelegate:(id)anObject
|
||||||
|
{
|
||||||
|
_delegate = anObject;
|
||||||
|
_delegateSupportsImages = [_delegate respondsToSelector:@selector(browser:imageValueForItem:)];
|
||||||
|
|
||||||
|
[self loadColumnZero];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)delegate
|
||||||
|
{
|
||||||
|
return _delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPTableView)tableViewInColumn:(unsigned)index
|
||||||
|
{
|
||||||
|
return _tableViews[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (unsigned)columnOfTableView:(CPTableView)aTableView
|
||||||
|
{
|
||||||
|
return [_tableViews indexOfObject:aTableView];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)loadColumnZero
|
||||||
|
{
|
||||||
|
if ([_delegate respondsToSelector:@selector(rootItemForBrowser:)])
|
||||||
|
_rootItem = [_delegate rootItemForBrowser:self];
|
||||||
|
else
|
||||||
|
_rootItem = nil;
|
||||||
|
|
||||||
|
[self setLastColumn:-1];
|
||||||
|
[self addColumn];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setLastColumn:(int)columnIndex
|
||||||
|
{
|
||||||
|
if (columnIndex >= _tableViews.length)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var oldValue = _tableViews.length - 1,
|
||||||
|
indexPlusOne = columnIndex + 1; // unloads all later columns.
|
||||||
|
|
||||||
|
[[_tableViews.slice(indexPlusOne) valueForKey:"enclosingScrollView"]
|
||||||
|
makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||||
|
|
||||||
|
_tableViews = _tableViews.slice(0, indexPlusOne);
|
||||||
|
_tableDelegates = _tableDelegates.slice(0, indexPlusOne);
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:didChangeLastColumn:toColumn:)])
|
||||||
|
[_delegate browser:self didChangeLastColumn:oldValue toColumn:columnIndex];
|
||||||
|
|
||||||
|
[self tile];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int)lastColumn
|
||||||
|
{
|
||||||
|
return _tableViews.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)addColumn
|
||||||
|
{
|
||||||
|
var lastIndex = [self lastColumn],
|
||||||
|
lastColumn = _tableViews[lastIndex],
|
||||||
|
selectionIndexes = [lastColumn selectedRowIndexes];
|
||||||
|
|
||||||
|
if (lastIndex >= 0 && [selectionIndexes count] > 1)
|
||||||
|
[CPException raise:CPInvalidArgumentException
|
||||||
|
reason:"Can't add column, column "+lastIndex+" has invalid selection."];
|
||||||
|
|
||||||
|
var index = lastIndex + 1,
|
||||||
|
item = index === 0 ? _rootItem : [_tableDelegates[lastIndex] childAtIndex:[selectionIndexes firstIndex]];
|
||||||
|
|
||||||
|
if (index > 0 && item && [self isLeafItem:item])
|
||||||
|
return;
|
||||||
|
|
||||||
|
var table = [[_tableViewClass alloc] initWithFrame:CGRectMakeZero() browser:self];
|
||||||
|
|
||||||
|
[table setHeaderView:nil];
|
||||||
|
[table setCornerView:nil];
|
||||||
|
[table setAllowsMultipleSelection:_allowsMultipleSelection];
|
||||||
|
[table setAllowsEmptySelection:_allowsEmptySelection];
|
||||||
|
[table registerForDraggedTypes:[self registeredDraggedTypes]];
|
||||||
|
|
||||||
|
[self _addTableColumnsToTableView:table forColumnIndex:index];
|
||||||
|
|
||||||
|
var delegate = [[_CPBrowserTableDelegate alloc] init];
|
||||||
|
|
||||||
|
[delegate _setDelegate:_delegate];
|
||||||
|
[delegate _setBrowser:self];
|
||||||
|
[delegate _setIndex:index];
|
||||||
|
[delegate _setItem:item];
|
||||||
|
|
||||||
|
_tableViews[index] = table;
|
||||||
|
_tableDelegates[index] = delegate;
|
||||||
|
|
||||||
|
[table setDelegate:delegate];
|
||||||
|
[table setDataSource:delegate];
|
||||||
|
[table setTarget:delegate];
|
||||||
|
[table setAction:@selector(_tableViewClicked:)];
|
||||||
|
[table setDoubleAction:@selector(_tableViewDoubleClicked:)];
|
||||||
|
[table setDraggingDestinationFeedbackStyle:CPTableViewDraggingDestinationFeedbackStyleRegular];
|
||||||
|
|
||||||
|
var scrollView = [[_CPBrowserScrollView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
[scrollView _setBrowser:self];
|
||||||
|
[scrollView setDocumentView:table];
|
||||||
|
[scrollView setHasHorizontalScroller:NO];
|
||||||
|
[scrollView setAutoresizingMask:CPViewHeightSizable];
|
||||||
|
|
||||||
|
[_contentView addSubview:scrollView];
|
||||||
|
|
||||||
|
[self tile];
|
||||||
|
|
||||||
|
[self scrollColumnToVisible:index];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_addTableColumnsToTableView:(CPTableView)aTableView forColumnIndex:(unsigned)index
|
||||||
|
{
|
||||||
|
if (_delegateSupportsImages)
|
||||||
|
{
|
||||||
|
var column = [[CPTableColumn alloc] initWithIdentifier:@"Image"],
|
||||||
|
view = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
|
[view setImageScaling:CPScaleProportionally];
|
||||||
|
|
||||||
|
[column setDataView:view];
|
||||||
|
[column setResizingMask:CPTableColumnNoResizing];
|
||||||
|
|
||||||
|
[aTableView addTableColumn:column];
|
||||||
|
}
|
||||||
|
|
||||||
|
var column = [[CPTableColumn alloc] initWithIdentifier:@"Content"];
|
||||||
|
|
||||||
|
[column setDataView:_prototypeView];
|
||||||
|
[column setResizingMask:CPTableColumnNoResizing];
|
||||||
|
|
||||||
|
[aTableView addTableColumn:column];
|
||||||
|
|
||||||
|
var column = [[CPTableColumn alloc] initWithIdentifier:@"Leaf"],
|
||||||
|
view = [[_CPBrowserLeafView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
|
[view setBranchImage:[[self class] branchImage]];
|
||||||
|
[view setHighlightedBranchImage:[[self class] highlightedBranchImage]];
|
||||||
|
|
||||||
|
[column setDataView:view];
|
||||||
|
[column setResizingMask:CPTableColumnNoResizing];
|
||||||
|
|
||||||
|
[aTableView addTableColumn:column];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reloadColumn:(int)column
|
||||||
|
{
|
||||||
|
[[self tableViewInColumn:column] reloadData];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tile
|
||||||
|
{
|
||||||
|
var xOrigin = 0,
|
||||||
|
scrollerWidth = [CPScroller scrollerWidth],
|
||||||
|
height = CGRectGetHeight([_contentView bounds]);
|
||||||
|
|
||||||
|
for (var i = 0, count = _tableViews.length; i < count; i++)
|
||||||
|
{
|
||||||
|
var tableView = _tableViews[i],
|
||||||
|
scrollView = [tableView enclosingScrollView],
|
||||||
|
width = [self widthOfColumn:i],
|
||||||
|
tableHeight = CGRectGetHeight([tableView bounds]);
|
||||||
|
|
||||||
|
[[tableView tableColumnWithIdentifier:"Image"] setWidth:_imageWidth];
|
||||||
|
[[tableView tableColumnWithIdentifier:"Content"] setWidth:width - (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) - scrollerWidth - scrollerWidth];
|
||||||
|
[[tableView tableColumnWithIdentifier:"Leaf"] setWidth:_leafWidth];
|
||||||
|
|
||||||
|
[tableView setRowHeight:_rowHeight];
|
||||||
|
[tableView setFrameSize:CGSizeMake(width - scrollerWidth, tableHeight)];
|
||||||
|
[scrollView setFrameOrigin:CGPointMake(xOrigin, 0)];
|
||||||
|
[scrollView setFrameSize:CGSizeMake(width, height)];
|
||||||
|
|
||||||
|
xOrigin += width;
|
||||||
|
}
|
||||||
|
|
||||||
|
[_contentView setFrameSize:CGSizeMake(xOrigin, height)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (unsigned)rowAtPoint:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
var column = [self columnAtPoint:aPoint];
|
||||||
|
if (column === -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
var tableView = _tableViews[column];
|
||||||
|
return [tableView rowAtPoint:[tableView convertPoint:aPoint fromView:self]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (unsigned)columnAtPoint:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
var adjustedPoint = [_contentView convertPoint:aPoint fromView:self];
|
||||||
|
|
||||||
|
for (var i = 0, count = _tableViews.length; i < count; i++)
|
||||||
|
{
|
||||||
|
var frame = [[_tableViews[i] enclosingScrollView] frame];
|
||||||
|
if (CGRectContainsPoint(frame, adjustedPoint))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)rectOfRow:(unsigned)aRow inColumn:(unsigned)aColumn
|
||||||
|
{
|
||||||
|
var tableView = _tableViews[aColumn],
|
||||||
|
rect = [tableView rectOfRow:aRow];
|
||||||
|
|
||||||
|
rect.origin = [self convertPoint:rect.origin fromView:tableView];
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ITEMS
|
||||||
|
|
||||||
|
- (id)itemAtRow:(int)row inColumn:(int)column
|
||||||
|
{
|
||||||
|
return [_tableDelegates[column] childAtIndex:row];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isLeafItem:(id)item
|
||||||
|
{
|
||||||
|
return [_delegate respondsToSelector:@selector(browser:isLeafItem:)] && [_delegate browser:self isLeafItem:item];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)parentForItemsInColumn:(int)column
|
||||||
|
{
|
||||||
|
return [_tableDelegates[column] _item];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPSet)selectedItems
|
||||||
|
{
|
||||||
|
var selectedColumn = [self selectedColumn],
|
||||||
|
selectedIndexes = [self selectedRowIndexesInColumn:selectedColumn],
|
||||||
|
set = [CPSet set],
|
||||||
|
index = [selectedIndexes firstIndex];
|
||||||
|
|
||||||
|
while (index !== CPNotFound)
|
||||||
|
{
|
||||||
|
[set addObject:[self itemAtRow:index inColumn:selectedColumn]];
|
||||||
|
index = [selectedIndexes indexGreaterThanIndex:index];
|
||||||
|
}
|
||||||
|
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)selectedItem
|
||||||
|
{
|
||||||
|
var selectedColumn = [self selectedColumn],
|
||||||
|
selectedRow = [self selectedRowInColumn:selectedColumn];
|
||||||
|
|
||||||
|
return [self itemAtRow:selectedRow inColumn:selectedColumn];
|
||||||
|
}
|
||||||
|
|
||||||
|
// CLICK EVENTS
|
||||||
|
|
||||||
|
- (void)trackMouse:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_column:(unsigned)columnIndex clickedRow:(unsigned)rowIndex
|
||||||
|
{
|
||||||
|
[self setLastColumn:columnIndex];
|
||||||
|
|
||||||
|
if (rowIndex >= 0)
|
||||||
|
[self addColumn];
|
||||||
|
|
||||||
|
[self doClick:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sendAction
|
||||||
|
{
|
||||||
|
[self sendAction:_action to:_target];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)doClick:(id)sender
|
||||||
|
{
|
||||||
|
[self sendAction:_action to:_target];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)doDoubleClick:(id)sender
|
||||||
|
{
|
||||||
|
[self sendAction:_doubleAction to:_target];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)keyDown:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
var column = [self selectedColumn];
|
||||||
|
if (column === -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_tableViews[column] keyDown:anEvent];
|
||||||
|
}
|
||||||
|
|
||||||
|
// SIZING
|
||||||
|
|
||||||
|
- (float)columnContentWidthForColumnWidth:(float)aWidth
|
||||||
|
{
|
||||||
|
return aWidth - (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) - [CPScroller scrollerWidth];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (float)columnWidthForColumnContentWidth:(float)aWidth
|
||||||
|
{
|
||||||
|
return aWidth + (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) + [CPScroller scrollerWidth];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setImageWidth:(float)aWidth
|
||||||
|
{
|
||||||
|
_imageWidth = aWidth;
|
||||||
|
[self tile];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (float)imageWidth
|
||||||
|
{
|
||||||
|
return _imageWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setMinColumnWidth:(float)minWidth
|
||||||
|
{
|
||||||
|
_minColumnWidth = minWidth;
|
||||||
|
[self tile];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (float)minColumnWidth
|
||||||
|
{
|
||||||
|
return _minColumnWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setWidth:(float)aWidth ofColumn:(unsigned)column
|
||||||
|
{
|
||||||
|
_columnWidths[column] = aWidth;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:didResizeColumn:)])
|
||||||
|
[_delegate browser:self didResizeColumn:column];
|
||||||
|
|
||||||
|
[self tile];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (float)widthOfColumn:(unsigned)column
|
||||||
|
{
|
||||||
|
var width = _columnWidths[column];
|
||||||
|
|
||||||
|
if (width == null)
|
||||||
|
width = _defaultColumnWidth;
|
||||||
|
|
||||||
|
return MAX([CPScroller scrollerWidth], MAX(_minColumnWidth, width));
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setRowHeight:(float)aHeight
|
||||||
|
{
|
||||||
|
_rowHeight = aHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (float)rowHeight
|
||||||
|
{
|
||||||
|
return _rowHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SCROLLERS
|
||||||
|
|
||||||
|
- (void)scrollColumnToVisible:(unsigned)columnIndex
|
||||||
|
{
|
||||||
|
[_contentView scrollRectToVisible:[[[self tableViewInColumn:columnIndex] enclosingScrollView] frame]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)scrollRowToVisible:(unsigned)rowIndex inColumn:(unsigned)columnIndex
|
||||||
|
{
|
||||||
|
[self scrollColumnToVisible:columnIndex];
|
||||||
|
[[self tableViewInColumn:columnIndex] scrollRowToVisible:rowIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)autohidesScroller
|
||||||
|
{
|
||||||
|
return [_horizontalScrollView autohidesScrollers];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setAutohidesScroller:(BOOL)shouldHide
|
||||||
|
{
|
||||||
|
[_horizontalScrollView setAutohidesScrollers:shouldHide];
|
||||||
|
}
|
||||||
|
|
||||||
|
// SELECTION
|
||||||
|
|
||||||
|
- (unsigned)selectedRowInColumn:(unsigned)columnIndex
|
||||||
|
{
|
||||||
|
if (columnIndex > [self lastColumn] || columnIndex < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return [_tableViews[columnIndex] selectedRow];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (unsigned)selectedColumn
|
||||||
|
{
|
||||||
|
var column = [self lastColumn],
|
||||||
|
row = [self selectedRowInColumn:column];
|
||||||
|
|
||||||
|
if (row >= 0)
|
||||||
|
return column;
|
||||||
|
else
|
||||||
|
return column - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)selectRow:(unsigned)row inColumn:(unsigned)column
|
||||||
|
{
|
||||||
|
var selectedIndexes = row === -1 ? [CPIndexSet indexSet] : [CPIndexSet indexSetWithIndex:row];
|
||||||
|
[self selectRowIndexes:selectedIndexes inColumn:column];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)allowsMultipleSelection
|
||||||
|
{
|
||||||
|
return _allowsMultipleSelection;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setAllowsMultipleSelection:(BOOL)shouldAllow
|
||||||
|
{
|
||||||
|
if (_allowsMultipleSelection === shouldAllow)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_allowsMultipleSelection = shouldAllow;
|
||||||
|
[_tableViews makeObjectsPerformSelector:@selector(setAllowsMultipleSelection:) withObject:shouldAllow];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)allowsEmptySelection
|
||||||
|
{
|
||||||
|
return _allowsEmptySelection;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setAllowsEmptySelection:(BOOL)shouldAllow
|
||||||
|
{
|
||||||
|
if (_allowsEmptySelection === shouldAllow)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_allowsEmptySelection = shouldAllow;
|
||||||
|
[_tableViews makeObjectsPerformSelector:@selector(setAllowsEmptySelection:) withObject:shouldAllow];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPIndexSet)selectedRowIndexesInColumn:(unsigned)column
|
||||||
|
{
|
||||||
|
if (column < 0 || column > [self lastColumn] +1)
|
||||||
|
return [CPIndexSet indexSet];
|
||||||
|
|
||||||
|
return [[self tableViewInColumn:column] selectedRowIndexes];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)selectRowIndexes:(CPIndexSet)indexSet inColumn:(unsigned)column
|
||||||
|
{
|
||||||
|
if (column < 0 || column > [self lastColumn] + 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:selectionIndexesForProposedSelection:inColumn:)])
|
||||||
|
indexSet = [_delegate browser:self selectionIndexesForProposedSelection:indexSet inColumn:column];
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:shouldSelectRowIndexes:inColumn:)] &&
|
||||||
|
![_delegate browser:self shouldSelectRowIndexes:indexSet inColumn:column])
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browserSelectionIsChanging:)])
|
||||||
|
[_delegate browserSelectionIsChanging:self];
|
||||||
|
|
||||||
|
if (column > [self lastColumn])
|
||||||
|
[self addColumn];
|
||||||
|
|
||||||
|
[self setLastColumn:column];
|
||||||
|
|
||||||
|
[[self tableViewInColumn:column] selectRowIndexes:indexSet byExtendingSelection:NO];
|
||||||
|
|
||||||
|
[self scrollColumnToVisible:column];
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(browserSelectionDidChange:)])
|
||||||
|
[_delegate browserSelectionDidChange:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setBackgroundColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
[super setBackgroundColor:aColor];
|
||||||
|
[_contentView setBackgroundColor:aColor];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)acceptsFirstResponder
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DRAG AND DROP
|
||||||
|
|
||||||
|
- (void)registerForDraggedTypes:(CPArray)types
|
||||||
|
{
|
||||||
|
[super registerForDraggedTypes:types];
|
||||||
|
[_tableViews makeObjectsPerformSelector:@selector(registerForDraggedTypes:) withObject:types];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(int)columnIndex withEvent:(CPEvent)dragEvent
|
||||||
|
{
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:canDragRowsWithIndexes:inColumn:withEvent:)])
|
||||||
|
return [_delegate browser:self canDragRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent];
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPImage)draggingImageForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(int)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
||||||
|
{
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:draggingImageForRowsWithIndexes:inColumn:withEvent:offset:)])
|
||||||
|
return [_delegate browser:self draggingImageForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPView)draggingViewForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(int)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
||||||
|
{
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:draggingViewForRowsWithIndexes:inColumn:withEvent:offset:)])
|
||||||
|
return [_delegate browser:self draggingViewForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var _CPBrowserResizeControlBackgroundImage = nil;
|
||||||
|
|
||||||
|
@implementation _CPBrowserResizeControl : CPView
|
||||||
|
{
|
||||||
|
CGPoint _mouseDownX;
|
||||||
|
CPBrowser _browser;
|
||||||
|
unsigned _index;
|
||||||
|
unsigned _width;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPImage)backgroundImage
|
||||||
|
{
|
||||||
|
if (!_CPBrowserResizeControlBackgroundImage)
|
||||||
|
{
|
||||||
|
var path = [[CPBundle bundleForClass:[self class]] pathForResource:"browser-resize-control.png"];
|
||||||
|
_CPBrowserResizeControlBackgroundImage = [[CPImage alloc] initWithContentsOfFile:path
|
||||||
|
size:CGSizeMake(15, 14)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return _CPBrowserResizeControlBackgroundImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
|
{
|
||||||
|
if (self = [super initWithFrame:aFrame])
|
||||||
|
[self setBackgroundColor:[CPColor colorWithPatternImage:[[self class] backgroundImage]]];
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseDown:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
_mouseDownX = [anEvent locationInWindow].x;
|
||||||
|
_browser = [[self superview] _browser];
|
||||||
|
_index = [_browser columnOfTableView:[[self superview] documentView]];
|
||||||
|
_width = [_browser widthOfColumn:_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseDragged:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
var deltaX = [anEvent locationInWindow].x - _mouseDownX;
|
||||||
|
[_browser setWidth:_width + deltaX ofColumn:_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseUp:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPBrowserScrollView : CPScrollView
|
||||||
|
{
|
||||||
|
_CPBrowserResizeControl _resizeControl;
|
||||||
|
CPBrowser _browser @accessors;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)initWithFrame:(CGRect)aFrame
|
||||||
|
{
|
||||||
|
if (self = [super initWithFrame:aFrame])
|
||||||
|
{
|
||||||
|
_resizeControl = [[_CPBrowserResizeControl alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
[self addSubview:_resizeControl];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reflectScrolledClipView:(CPClipView)aClipView
|
||||||
|
{
|
||||||
|
[super reflectScrolledClipView:aClipView];
|
||||||
|
|
||||||
|
var frame = [_verticalScroller frame];
|
||||||
|
frame.size.height = CGRectGetHeight([self bounds]) - 14.0 - frame.origin.y;
|
||||||
|
[_verticalScroller setFrameSize:frame.size];
|
||||||
|
|
||||||
|
var resizeFrame = CGRectMake(CGRectGetMinX(frame), CGRectGetMaxY(frame), [CPScroller scrollerWidth], 14.0);
|
||||||
|
[_resizeControl setFrame:resizeFrame];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPBrowserTableView : CPTableView
|
||||||
|
{
|
||||||
|
CPBrowser _browser;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithFrame:(CGRect)aFrame browser:(CPBrowser)aBrowser
|
||||||
|
{
|
||||||
|
if (self = [super initWithFrame:aFrame])
|
||||||
|
_browser = aBrowser;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)acceptsFirstResponder
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseDown:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
[super mouseDown:anEvent];
|
||||||
|
[[self window] makeFirstResponder:_browser];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPView)browserView
|
||||||
|
{
|
||||||
|
return _browser;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes atPoint:(CGPoint)mouseDownPoint
|
||||||
|
{
|
||||||
|
return [_browser canDragRowsWithIndexes:rowIndexes inColumn:[_browser columnOfTableView:self] withEvent:[CPApp currentEvent]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPImage)dragImageForRowsWithIndexes:(CPIndexSet)dragRows tableColumns:(CPArray)theTableColumns event:(CPEvent)dragEvent offset:(CPPointPointer)dragImageOffset
|
||||||
|
{
|
||||||
|
return [_browser draggingImageForRowsWithIndexes:dragRows inColumn:[_browser columnOfTableView:self] withEvent:dragEvent offset:dragImageOffset] ||
|
||||||
|
[super dragImageForRowsWithIndexes:dragRows tableColumns:theTableColumns event:dragEvent offset:dragImageOffset];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPView)dragViewForRowsWithIndexes:(CPIndexSet)dragRows tableColumns:(CPArray)theTableColumns event:(CPEvent)dragEvent offset:(CPPoint)dragViewOffset
|
||||||
|
{
|
||||||
|
var count = theTableColumns.length;
|
||||||
|
while (count--)
|
||||||
|
{
|
||||||
|
if ([theTableColumns[count] identifier] === "Leaf")
|
||||||
|
[theTableColumns removeObject:theTableColumns[count]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [_browser draggingViewForRowsWithIndexes:dragRows inColumn:[_browser columnOfTableView:self] withEvent:dragEvent offset:dragViewOffset] ||
|
||||||
|
[super dragViewForRowsWithIndexes:dragRows tableColumns:theTableColumns event:dragEvent offset:dragViewOffset];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveUp:(id)sender
|
||||||
|
{
|
||||||
|
[super moveUp:sender];
|
||||||
|
[_browser selectRow:[self selectedRow] inColumn:[_browser selectedColumn]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveDown:(id)sender
|
||||||
|
{
|
||||||
|
[super moveDown:sender];
|
||||||
|
[_browser selectRow:[self selectedRow] inColumn:[_browser selectedColumn]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveLeft:(id)sender
|
||||||
|
{
|
||||||
|
var previousColumn = [_browser selectedColumn] - 1,
|
||||||
|
selectedRow = [_browser selectedRowInColumn:previousColumn];
|
||||||
|
|
||||||
|
[_browser selectRow:selectedRow inColumn:previousColumn];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveRight:(id)sender
|
||||||
|
{
|
||||||
|
[_browser selectRow:0 inColumn:[_browser selectedColumn] + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
|
@implementation _CPBrowserTableDelegate : CPObject
|
||||||
|
{
|
||||||
|
CPBrowser _browser @accessors;
|
||||||
|
unsigned _index @accessors;
|
||||||
|
id _delegate @accessors;
|
||||||
|
id _item @accessors;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (unsigned)numberOfRowsInTableView:(CPTableView)aTableView
|
||||||
|
{
|
||||||
|
return [_delegate browser:_browser numberOfChildrenOfItem:_item];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tableView:(CPTableView)aTableView objectValueForTableColumn:(CPTableColumn)column row:(unsigned)row
|
||||||
|
{
|
||||||
|
if ([column identifier] === "Image")
|
||||||
|
return [_delegate browser:_browser imageValueForItem:[self childAtIndex:row]];
|
||||||
|
else if ([column identifier] === "Leaf")
|
||||||
|
return ![_browser isLeafItem:[self childAtIndex:row]];
|
||||||
|
else
|
||||||
|
return [_delegate browser:_browser objectValueForItem:[self childAtIndex:row]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_tableViewDoubleClicked:(CPTableView)aTableView
|
||||||
|
{
|
||||||
|
[_browser doDoubleClick:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_tableViewClicked:(CPTableView)aTableView
|
||||||
|
{
|
||||||
|
var selectedIndexes = [aTableView selectedRowIndexes];
|
||||||
|
[_browser _column:_index clickedRow:[selectedIndexes count] === 1 ? [selectedIndexes firstIndex] : -1];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)childAtIndex:(unsigned)index
|
||||||
|
{
|
||||||
|
return [_delegate browser:_browser child:index ofItem:_item];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id)info row:(int)row dropOperation:(CPTableViewDropOperation)operation
|
||||||
|
{
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:acceptDrop:atRow:column:dropOperation:)])
|
||||||
|
return [_delegate browser:_browser acceptDrop:info atRow:row column:_index dropOperation:operation];
|
||||||
|
else
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id)info proposedRow:(int)row proposedDropOperation:(CPTableViewDropOperation)operation
|
||||||
|
{
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:validateDrop:proposedRow:column:dropOperation:)])
|
||||||
|
return [_delegate browser:_browser validateDrop:info proposedRow:row column:_index dropOperation:operation];
|
||||||
|
else
|
||||||
|
return CPDragOperationNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)tableView:(CPTableView)aTableView writeRowsWithIndexes:(CPIndexSet)rowIndexes toPasteboard:(CPPasteboard)pboard
|
||||||
|
{
|
||||||
|
if ([_delegate respondsToSelector:@selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:)])
|
||||||
|
return [_delegate browser:_browser writeRowsWithIndexes:rowIndexes inColumn:_index toPasteboard:pboard];
|
||||||
|
else
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)respondsToSelector:(SEL)aSelector
|
||||||
|
{
|
||||||
|
if (aSelector === @selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:))
|
||||||
|
return [_delegate respondsToSelector:@selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:)];
|
||||||
|
else
|
||||||
|
return [super respondsToSelector:aSelector];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPBrowserLeafView : CPView
|
||||||
|
{
|
||||||
|
BOOL _isLeaf @accessors(readonly, property=isLeaf);
|
||||||
|
CPImage _branchImage @accessors(property=branchImage);
|
||||||
|
CPImage _highlightedBranchImage @accessors(property=highlightedBranchImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)objectValue
|
||||||
|
{
|
||||||
|
return _isLeaf;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setObjectValue:(id)aValue
|
||||||
|
{
|
||||||
|
_isLeaf = !!aValue;
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
||||||
|
{
|
||||||
|
if (aName === "image-view")
|
||||||
|
return CGRectInset([self bounds], 1, 1);
|
||||||
|
|
||||||
|
return [super rectForEphemeralSubviewNamed:aName];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||||
|
{
|
||||||
|
if (aName === "image-view")
|
||||||
|
return [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
|
return [super createEphemeralSubviewNamed:aName];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)layoutSubviews
|
||||||
|
{
|
||||||
|
var imageView = [self layoutEphemeralSubviewNamed:@"image-view"
|
||||||
|
positioned:CPWindowAbove
|
||||||
|
relativeToEphemeralSubviewNamed:nil],
|
||||||
|
isHighlighted = [self themeState] & CPThemeStateSelectedDataView;
|
||||||
|
|
||||||
|
[imageView setImage: _isLeaf ? (isHighlighted ? _highlightedBranchImage : _branchImage) : nil];
|
||||||
|
[imageView setImageScaling:CPScaleNone];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
[super encodeWithCoder:aCoder];
|
||||||
|
|
||||||
|
[aCoder encodeBool:_isLeaf forKey:"_CPBrowserLeafViewIsLeafKey"];
|
||||||
|
[aCoder encodeObject:_branchImage forKey:"_CPBrowserLeafViewBranchImageKey"];
|
||||||
|
[aCoder encodeObject:_highlightedBranchImage forKey:"_CPBrowserLeafViewHighlightedBranchImageKey"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)initWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
if (self = [super initWithCoder:aCoder])
|
||||||
|
{
|
||||||
|
_isLeaf = [aCoder decodeBoolForKey:"_CPBrowserLeafViewIsLeafKey"];
|
||||||
|
_branchImage = [aCoder decodeObjectForKey:"_CPBrowserLeafViewBranchImageKey"];
|
||||||
|
_highlightedBranchImage = [aCoder decodeObjectForKey:"_CPBrowserLeafViewHighlightedBranchImageKey"];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
+151
-70
@@ -24,31 +24,8 @@
|
|||||||
@import "CGGeometry.j"
|
@import "CGGeometry.j"
|
||||||
|
|
||||||
@import "CPControl.j"
|
@import "CPControl.j"
|
||||||
|
@import "CPStringDrawing.j"
|
||||||
|
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
|
|
||||||
CPScaleProportionally = 0;
|
|
||||||
CPScaleToFit = 1;
|
|
||||||
CPScaleNone = 2;
|
|
||||||
|
|
||||||
|
|
||||||
/* @group CPCellImagePosition */
|
|
||||||
|
|
||||||
CPNoImage = 0;
|
|
||||||
CPImageOnly = 1;
|
|
||||||
CPImageLeft = 2;
|
|
||||||
CPImageRight = 3;
|
|
||||||
CPImageBelow = 4;
|
|
||||||
CPImageAbove = 5;
|
|
||||||
CPImageOverlaps = 6;
|
|
||||||
|
|
||||||
|
|
||||||
/* @group CPButtonState */
|
|
||||||
|
|
||||||
CPOnState = 1;
|
|
||||||
CPOffState = 0;
|
|
||||||
CPMixedState = -1;
|
|
||||||
|
|
||||||
/* @group CPBezelStyle */
|
/* @group CPBezelStyle */
|
||||||
|
|
||||||
@@ -95,6 +72,9 @@ CPChangeBackgroundCellMask = CPBackgroundButtonMask;
|
|||||||
|
|
||||||
CPButtonStateMixed = CPThemeState("mixed");
|
CPButtonStateMixed = CPThemeState("mixed");
|
||||||
|
|
||||||
|
CPButtonDefaultHeight = 24.0;
|
||||||
|
CPButtonImageOffset = 3.0;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@class CPButton
|
@class CPButton
|
||||||
@@ -110,9 +90,6 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
CPString _title;
|
CPString _title;
|
||||||
CPString _alternateTitle;
|
CPString _alternateTitle;
|
||||||
|
|
||||||
CPImage _image;
|
|
||||||
CPImage _alternateImage;
|
|
||||||
|
|
||||||
CPInteger _showsStateBy;
|
CPInteger _showsStateBy;
|
||||||
CPInteger _highlightsBy;
|
CPInteger _highlightsBy;
|
||||||
BOOL _imageDimsWhenDisabled;
|
BOOL _imageDimsWhenDisabled;
|
||||||
@@ -120,6 +97,9 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
// NS-style Display Properties
|
// NS-style Display Properties
|
||||||
CPBezelStyle _bezelStyle;
|
CPBezelStyle _bezelStyle;
|
||||||
CPControlSize _controlSize;
|
CPControlSize _controlSize;
|
||||||
|
|
||||||
|
CPString _keyEquivalent;
|
||||||
|
unsigned _keyEquivalentModifierMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)buttonWithTitle:(CPString)aTitle
|
+ (id)buttonWithTitle:(CPString)aTitle
|
||||||
@@ -138,15 +118,15 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPString)themeClass
|
+ (CPString)defaultThemeClass
|
||||||
{
|
{
|
||||||
return @"button";
|
return @"button";
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)themeAttributes
|
+ (id)themeAttributes
|
||||||
{
|
{
|
||||||
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMakeZero(), nil]
|
return [CPDictionary dictionaryWithObjects:[[CPNull null], 0.0, _CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]]
|
||||||
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
|
forKeys:[@"image", @"image-offset", @"bezel-inset", @"content-inset", @"bezel-color"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
@@ -163,6 +143,9 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
|
|
||||||
_controlSize = CPRegularControlSize;
|
_controlSize = CPRegularControlSize;
|
||||||
|
|
||||||
|
_keyEquivalent = @"";
|
||||||
|
_keyEquivalentModifierMask = 0;
|
||||||
|
|
||||||
// [self setBezelStyle:CPRoundRectBezelStyle];
|
// [self setBezelStyle:CPRoundRectBezelStyle];
|
||||||
[self setBordered:YES];
|
[self setBordered:YES];
|
||||||
}
|
}
|
||||||
@@ -299,18 +282,12 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
|
|
||||||
- (void)setImage:(CPImage)anImage
|
- (void)setImage:(CPImage)anImage
|
||||||
{
|
{
|
||||||
if (_image === anImage)
|
[self setValue:anImage forThemeAttribute:@"image"];
|
||||||
return;
|
|
||||||
|
|
||||||
_image = anImage;
|
|
||||||
|
|
||||||
[self setNeedsLayout];
|
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPImage)image
|
- (CPImage)image
|
||||||
{
|
{
|
||||||
return _image;
|
return [self valueForThemeAttribute:@"image" inState:CPThemeStateNormal];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -319,13 +296,7 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
*/
|
*/
|
||||||
- (void)setAlternateImage:(CPImage)anImage
|
- (void)setAlternateImage:(CPImage)anImage
|
||||||
{
|
{
|
||||||
if (_alternateImage === anImage)
|
[self setValue:anImage forThemeAttribute:@"image" inState:CPThemeStateHighlighted];
|
||||||
return;
|
|
||||||
|
|
||||||
_alternateImage = anImage;
|
|
||||||
|
|
||||||
[self setNeedsLayout];
|
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -333,7 +304,17 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
*/
|
*/
|
||||||
- (CPImage)alternateImage
|
- (CPImage)alternateImage
|
||||||
{
|
{
|
||||||
return _alternateImage;
|
return [self valueForThemeAttribute:@"image" inState:CPThemeStateHighlighted];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setImageOffset:(float)theImageOffset
|
||||||
|
{
|
||||||
|
[self setValue:theImageOffset forThemeAttribute:@"image-offset"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (float)imageOffset
|
||||||
|
{
|
||||||
|
return [self valueForThemeAttribute:@"image-offset"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setShowsStateBy:(CPInteger)aMask
|
- (void)setShowsStateBy:(CPInteger)aMask
|
||||||
@@ -416,7 +397,7 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
|
|
||||||
_imageDimsWhenDisabled = imageShouldDimWhenDisabled;
|
_imageDimsWhenDisabled = imageShouldDimWhenDisabled;
|
||||||
|
|
||||||
if (_imageDimsWhenDisabled)
|
if ([self hasThemeState:CPThemeStateDisabled])
|
||||||
{
|
{
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
@@ -452,6 +433,7 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
if (_CGInsetIsEmpty(contentInset))
|
if (_CGInsetIsEmpty(contentInset))
|
||||||
return bounds;
|
return bounds;
|
||||||
|
|
||||||
|
bounds = _CGRectMakeCopy(bounds);
|
||||||
bounds.origin.x += contentInset.left;
|
bounds.origin.x += contentInset.left;
|
||||||
bounds.origin.y += contentInset.top;
|
bounds.origin.y += contentInset.top;
|
||||||
bounds.size.width -= contentInset.left + contentInset.right;
|
bounds.size.width -= contentInset.left + contentInset.right;
|
||||||
@@ -460,7 +442,7 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
return bounds;
|
return bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)bezelRectForBounds:(CFRect)bounds
|
- (CGRect)bezelRectForBounds:(CGRect)bounds
|
||||||
{
|
{
|
||||||
if (![self isBordered])
|
if (![self isBordered])
|
||||||
return _CGRectMakeZero();
|
return _CGRectMakeZero();
|
||||||
@@ -470,6 +452,7 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
if (_CGInsetIsEmpty(bezelInset))
|
if (_CGInsetIsEmpty(bezelInset))
|
||||||
return bounds;
|
return bounds;
|
||||||
|
|
||||||
|
bounds = _CGRectMakeCopy(bounds);
|
||||||
bounds.origin.x += bezelInset.left;
|
bounds.origin.x += bezelInset.left;
|
||||||
bounds.origin.y += bezelInset.top;
|
bounds.origin.y += bezelInset.top;
|
||||||
bounds.size.width -= bezelInset.left + bezelInset.right;
|
bounds.size.width -= bezelInset.left + bezelInset.right;
|
||||||
@@ -483,8 +466,20 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
*/
|
*/
|
||||||
- (void)sizeToFit
|
- (void)sizeToFit
|
||||||
{
|
{
|
||||||
var size = [([self title] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]],
|
[self layoutSubviews];
|
||||||
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
|
|
||||||
|
var size,
|
||||||
|
contentView = [self ephemeralSubviewNamed:@"content-view"];
|
||||||
|
|
||||||
|
if (contentView)
|
||||||
|
{
|
||||||
|
[contentView sizeToFit];
|
||||||
|
size = [contentView frameSize];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
size = [([self title] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]];
|
||||||
|
|
||||||
|
var contentInset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||||
minSize = [self currentValueForThemeAttribute:@"min-size"],
|
minSize = [self currentValueForThemeAttribute:@"min-size"],
|
||||||
maxSize = [self currentValueForThemeAttribute:@"max-size"];
|
maxSize = [self currentValueForThemeAttribute:@"max-size"];
|
||||||
|
|
||||||
@@ -523,8 +518,6 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
return [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
return [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
||||||
|
|
||||||
return [super createEphemeralSubviewNamed:aName];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)layoutSubviews
|
- (void)layoutSubviews
|
||||||
@@ -533,7 +526,6 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
positioned:CPWindowBelow
|
positioned:CPWindowBelow
|
||||||
relativeToEphemeralSubviewNamed:@"content-view"];
|
relativeToEphemeralSubviewNamed:@"content-view"];
|
||||||
|
|
||||||
if (bezelView)
|
|
||||||
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
|
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
|
||||||
|
|
||||||
var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
|
var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
|
||||||
@@ -543,7 +535,8 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
if (contentView)
|
if (contentView)
|
||||||
{
|
{
|
||||||
[contentView setText:([self hasThemeState:CPThemeStateHighlighted] && _alternateTitle) ? _alternateTitle : _title];
|
[contentView setText:([self hasThemeState:CPThemeStateHighlighted] && _alternateTitle) ? _alternateTitle : _title];
|
||||||
[contentView setImage:([self hasThemeState:CPThemeStateHighlighted] && _alternateImage) ? _alternateImage : _image];
|
[contentView setImage:[self currentValueForThemeAttribute:@"image"]];
|
||||||
|
[contentView setImageOffset:[self currentValueForThemeAttribute:@"image-offset"]];
|
||||||
|
|
||||||
[contentView setFont:[self currentValueForThemeAttribute:@"font"]];
|
[contentView setFont:[self currentValueForThemeAttribute:@"font"]];
|
||||||
[contentView setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
|
[contentView setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
|
||||||
@@ -554,17 +547,10 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
[contentView setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]];
|
[contentView setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]];
|
||||||
[contentView setImagePosition:[self currentValueForThemeAttribute:@"image-position"]];
|
[contentView setImagePosition:[self currentValueForThemeAttribute:@"image-position"]];
|
||||||
[contentView setImageScaling:[self currentValueForThemeAttribute:@"image-scaling"]];
|
[contentView setImageScaling:[self currentValueForThemeAttribute:@"image-scaling"]];
|
||||||
|
[contentView setDimsImage:[self hasThemeState:CPThemeStateDisabled] && _imageDimsWhenDisabled];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setDefaultButton:(BOOL)shouldBeDefaultButton
|
|
||||||
{
|
|
||||||
if (shouldBeDefaultButton)
|
|
||||||
[self setThemeState:CPThemeStateDefault];
|
|
||||||
else
|
|
||||||
[self unsetThemeState:CPThemeStateDefault];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setBordered:(BOOL)shouldBeBordered
|
- (void)setBordered:(BOOL)shouldBeBordered
|
||||||
{
|
{
|
||||||
if (shouldBeBordered)
|
if (shouldBeBordered)
|
||||||
@@ -578,6 +564,79 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
return [self hasThemeState:CPThemeStateBordered];
|
return [self hasThemeState:CPThemeStateBordered];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the keyboard shortcut for this button. For special keys see
|
||||||
|
CPEvent.j CP...FunctionKey and CPText.j CP...Character.
|
||||||
|
|
||||||
|
@param aString the keyboard shortcut as a string
|
||||||
|
*/
|
||||||
|
- (void)setKeyEquivalent:(CPString)aString
|
||||||
|
{
|
||||||
|
_keyEquivalent = aString || @"";
|
||||||
|
|
||||||
|
// Check if the key equivalent is the enter key
|
||||||
|
// Treat \r and \n as the same key equivalent. See issue #710.
|
||||||
|
if (aString === CPNewlineCharacter || aString === CPCarriageReturnCharacter)
|
||||||
|
[self setThemeState:CPThemeStateDefault];
|
||||||
|
else
|
||||||
|
[self unsetThemeState:CPThemeStateDefault];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewWillMoveToWindow:(CPWindow)aWindow
|
||||||
|
{
|
||||||
|
var selfWindow = [self window];
|
||||||
|
|
||||||
|
if (selfWindow === aWindow || aWindow === nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ([selfWindow defaultButton] === self)
|
||||||
|
[selfWindow setDefaultButton:nil];
|
||||||
|
|
||||||
|
if ([self keyEquivalent] === CPNewlineCharacter || [self keyEquivalent] === CPCarriageReturnCharacter)
|
||||||
|
[aWindow setDefaultButton:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the keyboard shortcut for this button.
|
||||||
|
*/
|
||||||
|
- (CPString)keyEquivalent
|
||||||
|
{
|
||||||
|
return _keyEquivalent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the mask used with this button's key equivalent.
|
||||||
|
*/
|
||||||
|
- (void)setKeyEquivalentModifierMask:(unsigned)aMask
|
||||||
|
{
|
||||||
|
_keyEquivalentModifierMask = aMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the mask to be used with this button's key equivalent.
|
||||||
|
*/
|
||||||
|
- (unsigned)keyEquivalentModifierMask
|
||||||
|
{
|
||||||
|
return _keyEquivalentModifierMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Checks the button's key equivalent against that in the event, and if they
|
||||||
|
match simulates a button click.
|
||||||
|
*/
|
||||||
|
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
// Don't handle the key equivalent for the default window because the window will handle it for us
|
||||||
|
if ([[self window] defaultButton] === self)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
if (![anEvent _triggersKeyEquivalent:[self keyEquivalent] withModifierMask:[self keyEquivalentModifierMask]])
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
[self performClick:nil];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation CPButton (NS)
|
@implementation CPButton (NS)
|
||||||
@@ -597,7 +656,12 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
|||||||
CPButtonAlternateImageKey = @"CPButtonAlternateImageKey",
|
CPButtonAlternateImageKey = @"CPButtonAlternateImageKey",
|
||||||
CPButtonTitleKey = @"CPButtonTitleKey",
|
CPButtonTitleKey = @"CPButtonTitleKey",
|
||||||
CPButtonAlternateTitleKey = @"CPButtonAlternateTitleKey",
|
CPButtonAlternateTitleKey = @"CPButtonAlternateTitleKey",
|
||||||
CPButtonIsBorderedKey = @"CPButtonIsBorderedKey";
|
CPButtonIsBorderedKey = @"CPButtonIsBorderedKey",
|
||||||
|
CPButtonAllowsMixedStateKey = @"CPButtonAllowsMixedStateKey",
|
||||||
|
CPButtonImageDimsWhenDisabledKey = @"CPButtonImageDimsWhenDisabledKey",
|
||||||
|
CPButtonImagePositionKey = @"CPButtonImagePositionKey",
|
||||||
|
CPButtonKeyEquivalentKey = @"CPButtonKeyEquivalentKey",
|
||||||
|
CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey";
|
||||||
|
|
||||||
@implementation CPButton (CPCoding)
|
@implementation CPButton (CPCoding)
|
||||||
|
|
||||||
@@ -613,11 +677,21 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
|||||||
{
|
{
|
||||||
_controlSize = CPRegularControlSize;
|
_controlSize = CPRegularControlSize;
|
||||||
|
|
||||||
[self setImage:[aCoder decodeObjectForKey:CPButtonImageKey]];
|
_title = [aCoder decodeObjectForKey:CPButtonTitleKey];
|
||||||
[self setAlternateImage:[aCoder decodeObjectForKey:CPButtonAlternateImageKey]];
|
_alternateTitle = [aCoder decodeObjectForKey:CPButtonAlternateTitleKey];
|
||||||
|
|
||||||
[self setTitle:[aCoder decodeObjectForKey:CPButtonTitleKey]];
|
if ([aCoder containsValueForKey:CPButtonAllowsMixedStateKey])
|
||||||
[self setAlternateTitle:[aCoder decodeObjectForKey:CPButtonAlternateTitleKey]];
|
_allowsMixedState = [aCoder decodeBoolForKey:CPButtonAllowsMixedStateKey];
|
||||||
|
|
||||||
|
[self setImageDimsWhenDisabled:[aCoder decodeObjectForKey:CPButtonImageDimsWhenDisabledKey]];
|
||||||
|
|
||||||
|
if ([aCoder containsValueForKey:CPButtonImagePositionKey])
|
||||||
|
[self setImagePosition:[aCoder decodeIntForKey:CPButtonImagePositionKey]];
|
||||||
|
|
||||||
|
if ([aCoder containsValueForKey:CPButtonKeyEquivalentKey])
|
||||||
|
[self setKeyEquivalent:CFData.decodeBase64ToUtf16String([aCoder decodeObjectForKey:CPButtonKeyEquivalentKey])];
|
||||||
|
|
||||||
|
_keyEquivalentModifierMask = [aCoder decodeIntForKey:CPButtonKeyEquivalentMaskKey];
|
||||||
|
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
@@ -634,11 +708,18 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
|||||||
{
|
{
|
||||||
[super encodeWithCoder:aCoder];
|
[super encodeWithCoder:aCoder];
|
||||||
|
|
||||||
[aCoder encodeObject:_image forKey:CPButtonImageKey];
|
|
||||||
[aCoder encodeObject:_alternateImage forKey:CPButtonAlternateImageKey];
|
|
||||||
|
|
||||||
[aCoder encodeObject:_title forKey:CPButtonTitleKey];
|
[aCoder encodeObject:_title forKey:CPButtonTitleKey];
|
||||||
[aCoder encodeObject:_alternateTitle forKey:CPButtonAlternateTitleKey];
|
[aCoder encodeObject:_alternateTitle forKey:CPButtonAlternateTitleKey];
|
||||||
|
|
||||||
|
[aCoder encodeBool:_allowsMixedState forKey:CPButtonAllowsMixedStateKey];
|
||||||
|
|
||||||
|
[aCoder encodeBool:[self imageDimsWhenDisabled] forKey:CPButtonImageDimsWhenDisabledKey];
|
||||||
|
[aCoder encodeInt:[self imagePosition] forKey:CPButtonImagePositionKey];
|
||||||
|
|
||||||
|
if (_keyEquivalent)
|
||||||
|
[aCoder encodeObject:CFData.encodeBase64Utf16String(_keyEquivalent) forKey:CPButtonKeyEquivalentKey];
|
||||||
|
|
||||||
|
[aCoder encodeInt:_keyEquivalentModifierMask forKey:CPButtonKeyEquivalentMaskKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+242
-26
@@ -1,61 +1,277 @@
|
|||||||
|
|
||||||
@import <AppKit/CPView.j>
|
@import "CPView.j"
|
||||||
|
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
|
|
||||||
@implementation CPButtonBar : CPControl
|
@implementation CPButtonBar : CPView
|
||||||
{
|
{
|
||||||
|
BOOL _hasResizeControl;
|
||||||
|
BOOL _resizeControlIsLeftAligned;
|
||||||
|
CPArray _buttons;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPString)themeClass
|
+ (id)plusButton
|
||||||
|
{
|
||||||
|
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
|
||||||
|
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"plus_button.png"] size:CGSizeMake(11, 12)];
|
||||||
|
|
||||||
|
[button setBordered:NO];
|
||||||
|
[button setImage:image];
|
||||||
|
[button setImagePosition:CPImageOnly];
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)minusButton
|
||||||
|
{
|
||||||
|
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
|
||||||
|
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"minus_button.png"] size:CGSizeMake(11, 4)];
|
||||||
|
|
||||||
|
[button setBordered:NO];
|
||||||
|
[button setImage:image];
|
||||||
|
[button setImagePosition:CPImageOnly];
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)actionPopupButton
|
||||||
|
{
|
||||||
|
var button = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
|
||||||
|
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"action_button.png"] size:CGSizeMake(22, 14)];
|
||||||
|
|
||||||
|
[button addItemWithTitle:nil];
|
||||||
|
[[button lastItem] setImage:image];
|
||||||
|
[button setImagePosition:CPImageOnly];
|
||||||
|
[button setValue:CGInsetMake(0, 0, 0, 0) forThemeAttribute:"content-inset"];
|
||||||
|
|
||||||
|
[button setPullsDown:YES];
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPString)defaultThemeClass
|
||||||
{
|
{
|
||||||
return @"button-bar";
|
return @"button-bar";
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)themeAttributes
|
+ (id)themeAttributes
|
||||||
{
|
{
|
||||||
return [CPDictionary dictionaryWithObjects:[nil]
|
return [CPDictionary dictionaryWithObjects:[CGInsetMake(0.0, 0.0, 0.0, 0.0), CGSizeMakeZero(), [CPNull null], [CPNull null], [CPNull null], [CPNull null]]
|
||||||
forKeys:[@"bezel-color"]];
|
forKeys:[@"resize-control-inset", @"resize-control-size", @"resize-control-color", @"bezel-color", @"button-bezel-color", @"button-text-color"]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
|
{
|
||||||
|
self = [super initWithFrame:aFrame];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_buttons = [];
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)awakeFromCib
|
||||||
|
{
|
||||||
|
var view = [self superview],
|
||||||
|
subview = self;
|
||||||
|
|
||||||
|
while (view)
|
||||||
|
{
|
||||||
|
if ([view isKindOfClass:[CPSplitView class]])
|
||||||
|
{
|
||||||
|
var viewIndex = [[view subviews] indexOfObject:subview];
|
||||||
|
[view setButtonBar:self forDividerAtIndex:viewIndex];
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
subview = view;
|
||||||
|
view = [view superview];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setButtons:(CPArray)buttons
|
||||||
|
{
|
||||||
|
_buttons = [CPArray arrayWithArray:buttons];
|
||||||
|
|
||||||
|
for (var i = 0, count = [_buttons count]; i < count; i++)
|
||||||
|
[_buttons[i] setBordered:YES];
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPArray)buttons
|
||||||
|
{
|
||||||
|
return [CPArray arrayWithArray:_buttons];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setHasResizeControl:(BOOL)shouldHaveResizeControl
|
||||||
|
{
|
||||||
|
if (_hasResizeControl === shouldHaveResizeControl)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_hasResizeControl = !!shouldHaveResizeControl;
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)hasResizeControl
|
||||||
|
{
|
||||||
|
return _hasResizeControl;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setResizeControlIsLeftAligned:(BOOL)shouldBeLeftAligned
|
||||||
|
{
|
||||||
|
if (_resizeControlIsLeftAligned === shouldBeLeftAligned)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_resizeControlIsLeftAligned = !!shouldBeLeftAligned;
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)resizeControlIsLeftAligned
|
||||||
|
{
|
||||||
|
return _resizeControlIsLeftAligned;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)resizeControlFrame
|
||||||
|
{
|
||||||
|
var inset = [self currentValueForThemeAttribute:@"resize-control-inset"],
|
||||||
|
size = [self currentValueForThemeAttribute:@"resize-control-size"],
|
||||||
|
currentSize = [self bounds],
|
||||||
|
leftOrigin = _resizeControlIsLeftAligned ? 0 : currentSize.size.width - size.width - inset.right - inset.left;
|
||||||
|
|
||||||
|
return CGRectMake(leftOrigin, 0, size.width + inset.left + inset.right, size.height + inset.top + inset.bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
||||||
{
|
{
|
||||||
if (aName === "bezel-view")
|
if (aName === "resize-control-view")
|
||||||
return [self bounds];
|
{
|
||||||
|
var inset = [self currentValueForThemeAttribute:@"resize-control-inset"],
|
||||||
|
size = [self currentValueForThemeAttribute:@"resize-control-size"],
|
||||||
|
currentSize = [self bounds];
|
||||||
|
|
||||||
|
if (_resizeControlIsLeftAligned)
|
||||||
|
return CGRectMake(inset.left, inset.top, size.width, size.height);
|
||||||
|
else
|
||||||
|
return CGRectMake(currentSize.size.width - size.width - inset.right, inset.top, size.width, size.height);
|
||||||
|
}
|
||||||
|
|
||||||
return [super rectForEphemeralSubviewNamed:aName];
|
return [super rectForEphemeralSubviewNamed:aName];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||||
{
|
{
|
||||||
if (aName === "bezel-view")
|
if (aName === "resize-control-view")
|
||||||
{
|
return [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
|
||||||
|
|
||||||
[view setHitTests:NO];
|
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [super createEphemeralSubviewNamed:aName];
|
return [super createEphemeralSubviewNamed:aName];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)layoutSubviews
|
- (void)layoutSubviews
|
||||||
{
|
{
|
||||||
var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
|
[self setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
|
||||||
positioned:CPWindowBelow
|
|
||||||
relativeToEphemeralSubviewNamed:@""];
|
|
||||||
|
|
||||||
if (bezelView)
|
var normalColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateNormal],
|
||||||
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
|
highlightedColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateHighlighted],
|
||||||
|
disabledColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateDisabled],
|
||||||
|
textColor = [self valueForThemeAttribute:@"button-text-color" inState:CPThemeStateNormal];
|
||||||
|
|
||||||
|
var buttonsNotHidden = [CPArray arrayWithArray:_buttons],
|
||||||
|
count = [buttonsNotHidden count];
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
if ([buttonsNotHidden[count] isHidden])
|
||||||
|
[buttonsNotHidden removeObject:buttonsNotHidden[count]];
|
||||||
|
|
||||||
|
var currentButtonOffset = _resizeControlIsLeftAligned ? CGRectGetMaxX([self bounds]) + 1 : -1,
|
||||||
|
bounds = [self bounds],
|
||||||
|
height = CGRectGetHeight(bounds) - 1,
|
||||||
|
frameWidth = CGRectGetWidth(bounds),
|
||||||
|
resizeRect = _hasResizeControl ? [self rectForEphemeralSubviewNamed:"resize-control-view"] : CGRectMakeZero(),
|
||||||
|
resizeWidth = CGRectGetWidth(resizeRect),
|
||||||
|
availableWidth = frameWidth - resizeWidth - 1;
|
||||||
|
|
||||||
|
for (var i = 0, count = [buttonsNotHidden count]; i < count; i++)
|
||||||
|
{
|
||||||
|
var button = buttonsNotHidden[i],
|
||||||
|
width = CGRectGetWidth([button frame]);
|
||||||
|
|
||||||
|
if (availableWidth > width)
|
||||||
|
availableWidth -= width;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (_resizeControlIsLeftAligned)
|
||||||
|
{
|
||||||
|
[button setFrame:CGRectMake(currentButtonOffset - width, 1, width, height)];
|
||||||
|
currentButtonOffset -= width - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[button setFrame:CGRectMake(currentButtonOffset, 1, width, height)];
|
||||||
|
currentButtonOffset += width - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addSubview:(CPView)aSubview
|
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal | CPThemeStateBordered];
|
||||||
{
|
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted | CPThemeStateBordered];
|
||||||
[super addSubview:aSubview];
|
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled | CPThemeStateBordered];
|
||||||
|
[button setValue:textColor forThemeAttribute:@"text-color" inState:CPThemeStateBordered];
|
||||||
|
|
||||||
[aSubview setAutoresizingMask:CPViewMinXMargin];
|
// FIXME shouldn't need this
|
||||||
|
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal | CPThemeStateBordered | CPPopUpButtonStatePullsDown];
|
||||||
|
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted | CPThemeStateBordered | CPPopUpButtonStatePullsDown];
|
||||||
|
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled | CPThemeStateBordered | CPPopUpButtonStatePullsDown];
|
||||||
|
|
||||||
|
[self addSubview:button];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_hasResizeControl)
|
||||||
|
{
|
||||||
|
var resizeControlView = [self layoutEphemeralSubviewNamed:@"resize-control-view"
|
||||||
|
positioned:CPWindowAbove
|
||||||
|
relativeToEphemeralSubviewNamed:nil];
|
||||||
|
|
||||||
|
[resizeControlView setAutoresizingMask: _resizeControlIsLeftAligned ? CPViewMaxXMargin : CPViewMinXMargin];
|
||||||
|
[resizeControlView setBackgroundColor:[self currentValueForThemeAttribute:@"resize-control-color"]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFrameSize:(CGSize)aSize
|
||||||
|
{
|
||||||
|
[super setFrameSize:aSize];
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var CPButtonBarHasResizeControlKey = @"CPButtonBarHasResizeControlKey",
|
||||||
|
CPButtonBarResizeControlIsLeftAlignedKey = @"CPButtonBarResizeControlIsLeftAlignedKey",
|
||||||
|
CPButtonBarButtonsKey = @"CPButtonBarButtonsKey";
|
||||||
|
|
||||||
|
@implementation CPButtonBar (CPCoding)
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
[super encodeWithCoder:aCoder];
|
||||||
|
|
||||||
|
[aCoder encodeBool:_hasResizeControl forKey:CPButtonBarHasResizeControlKey];
|
||||||
|
[aCoder encodeBool:_resizeControlIsLeftAligned forKey:CPButtonBarResizeControlIsLeftAlignedKey];
|
||||||
|
[aCoder encodeObject:_buttons forKey:CPButtonBarButtonsKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
if (self = [super initWithCoder:aCoder])
|
||||||
|
{
|
||||||
|
_buttons = [aCoder decodeObjectForKey:CPButtonBarButtonsKey] || [];
|
||||||
|
_hasResizeControl = [aCoder decodeBoolForKey:CPButtonBarHasResizeControlKey];
|
||||||
|
_resizeControlIsLeftAligned = [aCoder decodeBoolForKey:CPButtonBarResizeControlIsLeftAlignedKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+27
-2
@@ -23,6 +23,8 @@
|
|||||||
@import "CPButton.j"
|
@import "CPButton.j"
|
||||||
|
|
||||||
|
|
||||||
|
CPCheckBoxImageOffset = 4.0;
|
||||||
|
|
||||||
@implementation CPCheckBox : CPButton
|
@implementation CPCheckBox : CPButton
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -37,7 +39,7 @@
|
|||||||
return [self buttonWithTitle:aTitle];
|
return [self buttonWithTitle:aTitle];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPString)themeClass
|
+ (CPString)defaultThemeClass
|
||||||
{
|
{
|
||||||
return @"check-box";
|
return @"check-box";
|
||||||
}
|
}
|
||||||
@@ -55,10 +57,33 @@
|
|||||||
[self setImagePosition:CPImageLeft];
|
[self setImagePosition:CPImageLeft];
|
||||||
[self setAlignment:CPLeftTextAlignment];
|
[self setAlignment:CPLeftTextAlignment];
|
||||||
|
|
||||||
[self setBordered:YES];
|
[self setBordered:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)takeStateFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
|
||||||
|
{
|
||||||
|
var count = objects.length,
|
||||||
|
value = [objects[0] valueForKeyPath:aKeyPath] ? CPOnState : CPOffState;
|
||||||
|
|
||||||
|
[self setAllowsMixedState:NO];
|
||||||
|
[self setState:value];
|
||||||
|
|
||||||
|
while (count-- > 1)
|
||||||
|
{
|
||||||
|
if (value !== ([objects[count] valueForKeyPath:aKeyPath] ? CPOnState : CPOffState))
|
||||||
|
{
|
||||||
|
[self setAllowsMixedState:YES];
|
||||||
|
[self setState:CPMixedState];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)takeValueFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
|
||||||
|
{
|
||||||
|
[self takeStateFromKeyPath:aKeyPath ofObjects:objects];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+40
-12
@@ -22,8 +22,6 @@
|
|||||||
|
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -120,9 +118,13 @@
|
|||||||
|
|
||||||
[super setBoundsOrigin:aPoint];
|
[super setBoundsOrigin:aPoint];
|
||||||
|
|
||||||
var superview = [self superview];
|
var superview = [self superview],
|
||||||
|
|
||||||
if([superview isKindOfClass:[CPScrollView class]])
|
// This is hack to avoid having to import CPScrollView.
|
||||||
|
// FIXME: Should CPScrollView be finding out about this on its own somehow?
|
||||||
|
scrollViewClass = objj_getClass("CPScrollView");
|
||||||
|
|
||||||
|
if ([superview isKindOfClass:scrollViewClass])
|
||||||
[superview reflectScrolledClipView:self];
|
[superview reflectScrolledClipView:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,26 +175,52 @@
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// ... and we're in a scroll view of course.
|
// ... and we're in a scroll view of course.
|
||||||
var superview = [self superview];
|
var superview = [self superview],
|
||||||
|
|
||||||
if ([superview isKindOfClass:[CPScrollView class]])
|
// This is hack to avoid having to import CPScrollView.
|
||||||
|
// FIXME: Should CPScrollView be finding out about this on its own somehow?
|
||||||
|
scrollViewClass = objj_getClass("CPScrollView");
|
||||||
|
|
||||||
|
if ([superview isKindOfClass:scrollViewClass])
|
||||||
[superview reflectScrolledClipView:self];
|
[superview reflectScrolledClipView:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)autoscroll:(CPEvent)anEvent
|
- (BOOL)autoscroll:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
var bounds = [self bounds],
|
var bounds = [self bounds],
|
||||||
eventLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
eventLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||||
|
superview = [self superview],
|
||||||
|
deltaX = 0,
|
||||||
|
deltaY = 0;
|
||||||
|
|
||||||
if (CPRectContainsPoint(bounds, eventLocation))
|
if (CGRectContainsPoint(bounds, eventLocation))
|
||||||
return NO;
|
return NO;
|
||||||
|
|
||||||
var newRect = CGRectMakeZero();
|
if (![superview isKindOfClass:[CPScrollView class]] || [superview hasVerticalScroller])
|
||||||
|
{
|
||||||
|
if (eventLocation.y < CGRectGetMinY(bounds))
|
||||||
|
deltaY = CGRectGetMinY(bounds) - eventLocation.y;
|
||||||
|
else if (eventLocation.y > CGRectGetMaxY(bounds))
|
||||||
|
deltaY = CGRectGetMaxY(bounds) - eventLocation.y;
|
||||||
|
if (deltaY < -bounds.size.height)
|
||||||
|
deltaY = -bounds.size.height;
|
||||||
|
if (deltaY > bounds.size.height)
|
||||||
|
deltaY = bounds.size.height;
|
||||||
|
}
|
||||||
|
|
||||||
newRect.origin = eventLocation;
|
if (![superview isKindOfClass:[CPScrollView class]] || [superview hasHorizontalScroller])
|
||||||
newRect.size = CPSizeMake(10, 10);
|
{
|
||||||
|
if (eventLocation.x < CGRectGetMinX(bounds))
|
||||||
|
deltaX = CGRectGetMinX(bounds) - eventLocation.x;
|
||||||
|
else if (eventLocation.x > CGRectGetMaxX(bounds))
|
||||||
|
deltaX = CGRectGetMaxX(bounds) - eventLocation.x;
|
||||||
|
if (deltaX < -bounds.size.width)
|
||||||
|
deltaX = -bounds.size.width;
|
||||||
|
if (deltaX > bounds.size.width)
|
||||||
|
deltaX = bounds.size.width;
|
||||||
|
}
|
||||||
|
|
||||||
return [_documentView scrollRectToVisible:newRect];
|
return [self scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+231
-7
@@ -297,7 +297,7 @@
|
|||||||
*/
|
*/
|
||||||
- (void)setSelectionIndexes:(CPIndexSet)anIndexSet
|
- (void)setSelectionIndexes:(CPIndexSet)anIndexSet
|
||||||
{
|
{
|
||||||
if (_selectionIndexes == anIndexSet || !_isSelectable)
|
if ([_selectionIndexes isEqual:anIndexSet] || !_isSelectable)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var index = CPNotFound;
|
var index = CPNotFound;
|
||||||
@@ -312,8 +312,10 @@
|
|||||||
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
|
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
|
||||||
[_items[index] setSelected:YES];
|
[_items[index] setSelected:YES];
|
||||||
|
|
||||||
|
[[CPKeyValueBinding getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)])
|
if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)])
|
||||||
[_delegate collectionViewDidChangeSelection:self]
|
[_delegate collectionViewDidChangeSelection:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -321,7 +323,7 @@
|
|||||||
*/
|
*/
|
||||||
- (CPIndexSet)selectionIndexes
|
- (CPIndexSet)selectionIndexes
|
||||||
{
|
{
|
||||||
return _selectionIndexes;
|
return [_selectionIndexes copy];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
@@ -333,6 +335,8 @@
|
|||||||
while (count--)
|
while (count--)
|
||||||
{
|
{
|
||||||
[[_items[count] view] removeFromSuperview];
|
[[_items[count] view] removeFromSuperview];
|
||||||
|
[_items[count] setSelected:NO];
|
||||||
|
|
||||||
_cachedItems.push(_items[count]);
|
_cachedItems.push(_items[count]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,6 +356,10 @@
|
|||||||
[self addSubview:[_items[index] view]];
|
[self addSubview:[_items[index] view]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
index = CPNotFound;
|
||||||
|
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
|
||||||
|
[_items[index] setSelected:YES];
|
||||||
|
|
||||||
[self tile];
|
[self tile];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,8 +428,17 @@
|
|||||||
x += itemSize.width + _horizontalMargin;
|
x += itemSize.width + _horizontalMargin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var superview = [self superview],
|
||||||
|
proposedHeight = y + itemSize.height + _verticalMargin;
|
||||||
|
|
||||||
|
if ([superview isKindOfClass:[CPClipView class]])
|
||||||
|
{
|
||||||
|
var superviewSize = [superview bounds].size;
|
||||||
|
proposedHeight = MAX(superviewSize.height, proposedHeight);
|
||||||
|
}
|
||||||
|
|
||||||
_tileWidth = width;
|
_tileWidth = width;
|
||||||
[self setFrameSize:CGSizeMake(width, y + itemSize.height + _verticalMargin)];
|
[self setFrameSize:CGSizeMake(width, proposedHeight)];
|
||||||
_tileWidth = -1.0;
|
_tileWidth = -1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -576,14 +593,51 @@
|
|||||||
index = row * _numberOfColumns + column;
|
index = row * _numberOfColumns + column;
|
||||||
|
|
||||||
if (index >= 0 && index < _items.length)
|
if (index >= 0 && index < _items.length)
|
||||||
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
{
|
||||||
|
if (_allowsMultipleSelection && ([anEvent modifierFlags] & CPCommandKeyMask || [anEvent modifierFlags] & CPShiftKeyMask))
|
||||||
|
{
|
||||||
|
if ([anEvent modifierFlags] & CPCommandKeyMask)
|
||||||
|
{
|
||||||
|
var indexes = [_selectionIndexes copy];
|
||||||
|
|
||||||
|
if ([indexes containsIndex:index])
|
||||||
|
[indexes removeIndex:index];
|
||||||
|
else
|
||||||
|
[indexes addIndex:index];
|
||||||
|
}
|
||||||
|
else if ([anEvent modifierFlags] & CPShiftKeyMask)
|
||||||
|
{
|
||||||
|
var firstSelectedIndex = [[self selectionIndexes] firstIndex],
|
||||||
|
newSelectedRange = nil;
|
||||||
|
|
||||||
|
if (index < firstSelectedIndex)
|
||||||
|
newSelectedRange = CPMakeRange(index, (firstSelectedIndex - index) + 1);
|
||||||
|
else
|
||||||
|
newSelectedRange = CPMakeRange(firstSelectedIndex, (index - firstSelectedIndex) + 1);
|
||||||
|
|
||||||
|
indexes = [[self selectionIndexes] copy];
|
||||||
|
[indexes addIndexesInRange:newSelectedRange];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
indexes = [CPIndexSet indexSetWithIndex:index];
|
||||||
|
|
||||||
|
[self setSelectionIndexes:indexes];
|
||||||
|
}
|
||||||
else if (_allowsEmptySelection)
|
else if (_allowsEmptySelection)
|
||||||
[self setSelectionIndexes:[CPIndexSet indexSet]];
|
[self setSelectionIndexes:[CPIndexSet indexSet]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseDragged:(CPEvent)anEvent
|
- (void)mouseDragged:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
|
var locationInWindow = [anEvent locationInWindow],
|
||||||
|
mouseDownLocationInWindow = [_mouseDownEvent locationInWindow];
|
||||||
|
|
||||||
|
// FIXME: This is because Safari's drag hysteresis is 3px x 3px
|
||||||
|
if ((ABS(locationInWindow.x - mouseDownLocationInWindow.x) < 3) &&
|
||||||
|
(ABS(locationInWindow.y - mouseDownLocationInWindow.y) < 3))
|
||||||
|
return;
|
||||||
|
|
||||||
if (![_delegate respondsToSelector:@selector(collectionView:dragTypesForItemsAtIndexes:)])
|
if (![_delegate respondsToSelector:@selector(collectionView:dragTypesForItemsAtIndexes:)])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -591,13 +645,15 @@
|
|||||||
if (![_selectionIndexes count])
|
if (![_selectionIndexes count])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(collectionView:canDragItemsAtIndexes:withEvent:)] &&
|
||||||
|
![_delegate collectionView:self canDragItemsAtIndexes:_selectionIndexes withEvent:_mouseDownEvent])
|
||||||
|
return;
|
||||||
|
|
||||||
// Set up the pasteboard
|
// Set up the pasteboard
|
||||||
var dragTypes = [_delegate collectionView:self dragTypesForItemsAtIndexes:_selectionIndexes];
|
var dragTypes = [_delegate collectionView:self dragTypesForItemsAtIndexes:_selectionIndexes];
|
||||||
|
|
||||||
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:dragTypes owner:self];
|
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:dragTypes owner:self];
|
||||||
|
|
||||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
|
||||||
|
|
||||||
if (!_itemForDragging)
|
if (!_itemForDragging)
|
||||||
_itemForDragging = [self newItemForRepresentedObject:_content[[_selectionIndexes firstIndex]]];
|
_itemForDragging = [self newItemForRepresentedObject:_content[[_selectionIndexes firstIndex]]];
|
||||||
else
|
else
|
||||||
@@ -670,12 +726,172 @@
|
|||||||
return _delegate;
|
return _delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CPCollectionViewItem)itemAtIndex:(unsigned)anIndex
|
||||||
|
{
|
||||||
|
return [_items objectAtIndex:anIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)frameForItemAtIndex:(unsigned)anIndex
|
||||||
|
{
|
||||||
|
return [[[self itemAtIndex:anIndex] view] frame];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)frameForItemsAtIndexes:(CPIndexSet)anIndexSet
|
||||||
|
{
|
||||||
|
var indexArray = [],
|
||||||
|
frame = CGRectNull;
|
||||||
|
|
||||||
|
[anIndexSet getIndexes:indexArray maxCount:-1 inIndexRange:nil];
|
||||||
|
|
||||||
|
var index = 0,
|
||||||
|
count = [indexArray count];
|
||||||
|
|
||||||
|
for (; index < count; ++index)
|
||||||
|
frame = CGRectUnion(frame, [self frameForItemAtIndex:indexArray[index]]);
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation CPCollectionView (KeyboardInteraction)
|
||||||
|
|
||||||
|
- (void)_modifySelectionWithNewIndex:(int)anIndex direction:(int)aDirection expand:(BOOL)shouldExpand
|
||||||
|
{
|
||||||
|
anIndex = MIN(MAX(anIndex, 0), [[self items] count] - 1);
|
||||||
|
|
||||||
|
if (_allowsMultipleSelection && shouldExpand)
|
||||||
|
{
|
||||||
|
var indexes = [_selectionIndexes copy],
|
||||||
|
bottomAnchor = [indexes firstIndex],
|
||||||
|
topAnchor = [indexes lastIndex];
|
||||||
|
|
||||||
|
// if the direction is backward (-1) check with the bottom anchor
|
||||||
|
if (aDirection === -1)
|
||||||
|
[indexes addIndexesInRange:CPMakeRange(anIndex, bottomAnchor - anIndex + 1)];
|
||||||
|
else
|
||||||
|
[indexes addIndexesInRange:CPMakeRange(topAnchor, anIndex - topAnchor + 1)];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
indexes = [CPIndexSet indexSetWithIndex:anIndex];
|
||||||
|
|
||||||
|
[self setSelectionIndexes:indexes];
|
||||||
|
[self _scrollToSelection];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_scrollToSelection
|
||||||
|
{
|
||||||
|
var frame = [self frameForItemsAtIndexes:[self selectionIndexes]];
|
||||||
|
|
||||||
|
if (!CGRectIsNull(frame))
|
||||||
|
[self scrollRectToVisible:frame];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveLeft:(id)sender
|
||||||
|
{
|
||||||
|
var index = [[self selectionIndexes] firstIndex];
|
||||||
|
if (index === CPNotFound)
|
||||||
|
index = [[self items] count];
|
||||||
|
|
||||||
|
[self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveLeftAndModifySelection:(id)sender
|
||||||
|
{
|
||||||
|
var index = [[self selectionIndexes] firstIndex];
|
||||||
|
if (index === CPNotFound)
|
||||||
|
index = [[self items] count];
|
||||||
|
|
||||||
|
[self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveRight:(id)sender
|
||||||
|
{
|
||||||
|
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveRightAndModifySelection:(id)sender
|
||||||
|
{
|
||||||
|
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveDown:(id)sender
|
||||||
|
{
|
||||||
|
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveDownAndModifySelection:(id)sender
|
||||||
|
{
|
||||||
|
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveUp:(id)sender
|
||||||
|
{
|
||||||
|
var index = [[self selectionIndexes] firstIndex];
|
||||||
|
if (index == CPNotFound)
|
||||||
|
index = [[self items] count];
|
||||||
|
|
||||||
|
[self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveUpAndModifySelection:(id)sender
|
||||||
|
{
|
||||||
|
var index = [[self selectionIndexes] firstIndex];
|
||||||
|
if (index == CPNotFound)
|
||||||
|
index = [[self items] count];
|
||||||
|
|
||||||
|
[self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)deleteBackward:(id)sender
|
||||||
|
{
|
||||||
|
if ([[self delegate] respondsToSelector:@selector(collectionView:shouldDeleteItemsAtIndexes:)])
|
||||||
|
{
|
||||||
|
[[self delegate] collectionView:self shouldDeleteItemsAtIndexes:[self selectionIndexes]];
|
||||||
|
|
||||||
|
var index = [[self selectionIndexes] firstIndex];
|
||||||
|
if (index > [[self content] count] - 1)
|
||||||
|
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:[[self content] count] - 1]];
|
||||||
|
|
||||||
|
[self _scrollToSelection];
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)keyDown:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
[self interpretKeyEvents:[anEvent]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation CPCollectionView (Deprecated)
|
||||||
|
|
||||||
|
- (CGRect)rectForItemAtIndex:(int)anIndex
|
||||||
|
{
|
||||||
|
_CPReportLenientDeprecation([self class], _cmd, @selector(frameForItemAtIndex:));
|
||||||
|
|
||||||
|
// Don't re-compute anything just grab the current frame
|
||||||
|
// This allows subclasses to override tile without messing this up.
|
||||||
|
return [self frameForItemAtIndex:anIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)rectForItemsAtIndexes:(CPIndexSet)anIndexSet
|
||||||
|
{
|
||||||
|
_CPReportLenientDeprecation([self class], _cmd, @selector(frameForItemsAtIndexes:));
|
||||||
|
|
||||||
|
return [self frameForItemsAtIndexes:anIndexSet];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
||||||
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
|
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
|
||||||
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
|
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
|
||||||
|
CPCollectionViewMaxNumberOfRowsKey = @"CPCollectionViewMaxNumberOfRowsKey",
|
||||||
|
CPCollectionViewMaxNumberOfColumnsKey = @"CPCollectionViewMaxNumberOfColumnsKey",
|
||||||
CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey",
|
CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey",
|
||||||
|
CPCollectionViewAllowsMultipleSelectionKey = @"CPCollectionViewAllowsMultipleSelectionKey",
|
||||||
CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey";
|
CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey";
|
||||||
|
|
||||||
|
|
||||||
@@ -697,9 +913,13 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
|||||||
_minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey] || CGSizeMakeZero();
|
_minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey] || CGSizeMakeZero();
|
||||||
_maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey] || CGSizeMakeZero();
|
_maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey] || CGSizeMakeZero();
|
||||||
|
|
||||||
|
_maxNumberOfRows = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfRowsKey] || 0;
|
||||||
|
_maxNumberOfColumns = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfColumnsKey] || 0;
|
||||||
|
|
||||||
_verticalMargin = [aCoder decodeFloatForKey:CPCollectionViewVerticalMarginKey];
|
_verticalMargin = [aCoder decodeFloatForKey:CPCollectionViewVerticalMarginKey];
|
||||||
|
|
||||||
_isSelectable = [aCoder decodeBoolForKey:CPCollectionViewSelectableKey];
|
_isSelectable = [aCoder decodeBoolForKey:CPCollectionViewSelectableKey];
|
||||||
|
_allowsMultipleSelection = [aCoder decodeBoolForKey:CPCollectionViewAllowsMultipleSelectionKey];
|
||||||
|
|
||||||
[self setBackgroundColors:[aCoder decodeObjectForKey:CPCollectionViewBackgroundColorsKey]];
|
[self setBackgroundColors:[aCoder decodeObjectForKey:CPCollectionViewBackgroundColorsKey]];
|
||||||
|
|
||||||
@@ -723,7 +943,11 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
|||||||
if (!CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
|
if (!CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
|
||||||
[aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey];
|
[aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey];
|
||||||
|
|
||||||
|
[aCoder encodeInt:_maxNumberOfRows forKey:CPCollectionViewMaxNumberOfRowsKey];
|
||||||
|
[aCoder encodeInt:_maxNumberOfColumns forKey:CPCollectionViewMaxNumberOfColumnsKey];
|
||||||
|
|
||||||
[aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey];
|
[aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey];
|
||||||
|
[aCoder encodeBool:_allowsMultipleSelection forKey:CPCollectionViewAllowsMultipleSelectionKey];
|
||||||
|
|
||||||
[aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey];
|
[aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey];
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
@import "CPViewController.j"
|
@import "CPViewController.j"
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Represents an object inside a CPCollectionView.
|
Represents an object inside a CPCollectionView.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+31
-78
@@ -56,18 +56,12 @@ var cachedBlackColor,
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@code CPColor
|
|
||||||
|
|
||||||
\c CPColor can be used to represent color
|
\c CPColor can be used to represent color
|
||||||
in an RGB or HSB model with an optional transparency value.</p>
|
in an RGB or HSB model with an optional transparency value.</p>
|
||||||
|
|
||||||
<p>It also provides some class helper methods that
|
<p>It also provides some class helper methods that
|
||||||
returns instances of commonly used colors.</p>
|
returns instances of commonly used colors.</p>
|
||||||
|
|
||||||
<p>The class does not have a \c -set: method
|
|
||||||
like NextStep based frameworks to change the color of
|
|
||||||
the current context. To change the color of the current
|
|
||||||
context, use CGContextSetFillColor().
|
|
||||||
*/
|
*/
|
||||||
@implementation CPColor : CPObject
|
@implementation CPColor : CPObject
|
||||||
{
|
{
|
||||||
@@ -194,7 +188,8 @@ var cachedBlackColor,
|
|||||||
*/
|
*/
|
||||||
+ (CPColor)colorWithHexString:(string)hex
|
+ (CPColor)colorWithHexString:(string)hex
|
||||||
{
|
{
|
||||||
return [[CPColor alloc] _initWithRGBA: hexToRGB(hex)];
|
var rgba = hexToRGB(hex);
|
||||||
|
return rgba ? [[CPColor alloc] _initWithRGBA: rgba] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -414,15 +409,15 @@ var cachedBlackColor,
|
|||||||
|
|
||||||
self = [super init];
|
self = [super init];
|
||||||
|
|
||||||
var startingIndex = aString.indexOf("(");
|
var startingIndex = aString.indexOf("("),
|
||||||
var parts = aString.substring(startingIndex+1).split(',');
|
parts = aString.substring(startingIndex + 1).split(',');
|
||||||
|
|
||||||
_components = [
|
_components = [
|
||||||
parseInt(parts[0], 10) / 255.0,
|
parseInt(parts[0], 10) / 255.0,
|
||||||
parseInt(parts[1], 10) / 255.0,
|
parseInt(parts[1], 10) / 255.0,
|
||||||
parseInt(parts[2], 10) / 255.0,
|
parseInt(parts[2], 10) / 255.0,
|
||||||
parts[3] ? parseInt(parts[3], 10) / 255.0 : 1.0
|
parts[3] ? parseInt(parts[3], 10) / 255.0 : 1.0
|
||||||
]
|
];
|
||||||
|
|
||||||
_cssString = aString;
|
_cssString = aString;
|
||||||
|
|
||||||
@@ -438,41 +433,6 @@ var cachedBlackColor,
|
|||||||
{
|
{
|
||||||
_components = components;
|
_components = components;
|
||||||
|
|
||||||
if (!CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0 && window.Base64 && window.CRC32)
|
|
||||||
{
|
|
||||||
var bytes = [0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x8,0x3,0x0,0x0,0x0,0x28,0xcb,0x34,0xbb,0x0,0x0,0x3,0x0,0x50,0x4c,0x54,0x45,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x17,0x89,0x99,0x55,0x0,0x0,0x0,0x1,0x74,0x52,0x4e,0x53,0x0,0x40,0xe6,0xd8,0x66,0x0,0x0,0x0,0x10,0x49,0x44,0x41,0x54,0x78,0xda,0x62,0x60,0x0,0x0,0x0,0x0,0xff,0xff,0x3,0x0,0x0,0x2,0x0,0x1,0x24,0x7f,0x24,0xf1,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82,0xff];
|
|
||||||
var r_off = 41;
|
|
||||||
var g_off = 42;
|
|
||||||
var b_off = 43;
|
|
||||||
var a_off = 821;
|
|
||||||
var plte_crc_off = 809;
|
|
||||||
var trns_crc_off = 822;
|
|
||||||
var plte_type_off = 37;
|
|
||||||
var trns_type_off = 817;
|
|
||||||
|
|
||||||
bytes[r_off] = Math.round(_components[0]*255);
|
|
||||||
bytes[g_off] = Math.round(_components[1]*255);
|
|
||||||
bytes[b_off] = Math.round(_components[2]*255);
|
|
||||||
bytes[a_off] = Math.round(_components[3]*255);
|
|
||||||
|
|
||||||
// calculate new CRCs
|
|
||||||
var new_plte_crc = integerToBytes(CRC32.getCRC(bytes, plte_type_off, 4+768), 4);
|
|
||||||
var new_trns_crc = integerToBytes(CRC32.getCRC(bytes, trns_type_off, 4+1), 4);
|
|
||||||
|
|
||||||
// overwrite old CRCs with new ones
|
|
||||||
for (var i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
bytes[plte_crc_off+i] = new_plte_crc[i];
|
|
||||||
bytes[trns_crc_off+i] = new_trns_crc[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Base64 encode, strip whitespace and build data URL
|
|
||||||
var base64image = Base64.encode(bytes); //.replace(/[\s]/g, "");
|
|
||||||
|
|
||||||
_cssString = "url(\"data:image/png;base64," + base64image + "\")";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var hasAlpha = CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0;
|
var hasAlpha = CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0;
|
||||||
|
|
||||||
_cssString = (hasAlpha ? "rgba(" : "rgb(") +
|
_cssString = (hasAlpha ? "rgba(" : "rgb(") +
|
||||||
@@ -481,7 +441,7 @@ var cachedBlackColor,
|
|||||||
parseInt(_components[2] * 255.0) +
|
parseInt(_components[2] * 255.0) +
|
||||||
(hasAlpha ? (", " + _components[3]) : "") + ")";
|
(hasAlpha ? (", " + _components[3]) : "") + ")";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,6 +454,7 @@ var cachedBlackColor,
|
|||||||
{
|
{
|
||||||
_patternImage = anImage;
|
_patternImage = anImage;
|
||||||
_cssString = "url(\"" + [_patternImage filename] + "\")";
|
_cssString = "url(\"" + [_patternImage filename] + "\")";
|
||||||
|
_components = [0.0, 0.0, 0.0, 1.0];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -595,13 +556,16 @@ var cachedBlackColor,
|
|||||||
saturation = (max != 0) ? delta / max : 0;
|
saturation = (max != 0) ? delta / max : 0;
|
||||||
|
|
||||||
var hue;
|
var hue;
|
||||||
|
|
||||||
if (saturation == 0)
|
if (saturation == 0)
|
||||||
|
{
|
||||||
hue = 0;
|
hue = 0;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var rr = (max - red) / delta;
|
var rr = (max - red) / delta,
|
||||||
var gr = (max - green) / delta;
|
gr = (max - green) / delta,
|
||||||
var br = (max - blue) / delta;
|
br = (max - blue) / delta;
|
||||||
|
|
||||||
if (red == max)
|
if (red == max)
|
||||||
hue = br - gr;
|
hue = br - gr;
|
||||||
@@ -733,6 +697,7 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
var hexCharacters = "0123456789ABCDEF";
|
var hexCharacters = "0123456789ABCDEF";
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -741,10 +706,11 @@ var hexCharacters = "0123456789ABCDEF";
|
|||||||
@class CPColor
|
@class CPColor
|
||||||
@return an array of rgb components
|
@return an array of rgb components
|
||||||
*/
|
*/
|
||||||
function hexToRGB(hex)
|
var hexToRGB = function(hex)
|
||||||
{
|
{
|
||||||
if (hex.length == 3)
|
if (hex.length == 3)
|
||||||
hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2);
|
hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2);
|
||||||
|
|
||||||
if (hex.length != 6)
|
if (hex.length != 6)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -754,38 +720,25 @@ function hexToRGB(hex)
|
|||||||
if (hexCharacters.indexOf(hex.charAt(i)) == -1)
|
if (hexCharacters.indexOf(hex.charAt(i)) == -1)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var red = (hexCharacters.indexOf(hex.charAt(0)) * 16 + hexCharacters.indexOf(hex.charAt(1))) / 255.0;
|
var red = (hexCharacters.indexOf(hex.charAt(0)) * 16 + hexCharacters.indexOf(hex.charAt(1))) / 255.0,
|
||||||
var green = (hexCharacters.indexOf(hex.charAt(2)) * 16 + hexCharacters.indexOf(hex.charAt(3))) / 255.0;
|
green = (hexCharacters.indexOf(hex.charAt(2)) * 16 + hexCharacters.indexOf(hex.charAt(3))) / 255.0,
|
||||||
var blue = (hexCharacters.indexOf(hex.charAt(4)) * 16 + hexCharacters.indexOf(hex.charAt(5))) / 255.0;
|
blue = (hexCharacters.indexOf(hex.charAt(4)) * 16 + hexCharacters.indexOf(hex.charAt(5))) / 255.0;
|
||||||
|
|
||||||
return [red, green, blue, 1.0];
|
return [red, green, blue, 1.0];
|
||||||
}
|
};
|
||||||
|
|
||||||
function integerToBytes(integer, length) {
|
var rgbToHex = function(r,g,b)
|
||||||
if (!length)
|
{
|
||||||
length = (integer == 0) ? 1 : Math.round((Math.log(integer)/Math.log(2))/8+0.5);
|
|
||||||
|
|
||||||
var bytes = new Array(length);
|
|
||||||
for (var i = length-1; i >= 0; i--) {
|
|
||||||
bytes[i] = integer & 255;
|
|
||||||
integer = integer >> 8
|
|
||||||
}
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
function rgbToHex(r,g,b) {
|
|
||||||
return byteToHex(r) + byteToHex(g) + byteToHex(b);
|
return byteToHex(r) + byteToHex(g) + byteToHex(b);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
var byteToHex = function(n)
|
||||||
|
{
|
||||||
|
if (!n || isNaN(n))
|
||||||
|
return "00";
|
||||||
|
|
||||||
|
n = FLOOR(MIN(255, MAX(0, 256 * n)));
|
||||||
|
|
||||||
function byteToHex(n) {
|
|
||||||
if (!n || isNaN(n)) return "00";
|
|
||||||
n = ROUND(MIN(255,MAX(0,256*n)));
|
|
||||||
return hexCharacters.charAt((n - n % 16) / 16) +
|
return hexCharacters.charAt((n - n % 16) / 16) +
|
||||||
hexCharacters.charAt(n % 16);
|
hexCharacters.charAt(n % 16);
|
||||||
}
|
};
|
||||||
|
|
||||||
// Toll-Free bridge CPColor to CGColor.
|
|
||||||
//CGColor.prototype.isa = CPColor;
|
|
||||||
//[CPColor initialize];
|
|
||||||
|
|
||||||
//http://dev.mootools.net/browser/trunk/Source/Utilities/Color.js?rev=1184
|
|
||||||
|
|||||||
+15
-11
@@ -20,11 +20,13 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@import "CPApplication.j"
|
||||||
@import "CPButton.j"
|
@import "CPButton.j"
|
||||||
@import "CPCookie.j"
|
@import "CPCookie.j"
|
||||||
@import "CPPanel.j"
|
@import "CPPanel.j"
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
|
||||||
|
|
||||||
CPColorPanelColorDidChangeNotification = @"CPColorPanelColorDidChangeNotification";
|
CPColorPanelColorDidChangeNotification = @"CPColorPanelColorDidChangeNotification";
|
||||||
|
|
||||||
var PREVIEW_HEIGHT = 20.0,
|
var PREVIEW_HEIGHT = 20.0,
|
||||||
@@ -457,6 +459,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
|||||||
- (CPArray)startingColorList
|
- (CPArray)startingColorList
|
||||||
{
|
{
|
||||||
var cookieValue = [_swatchCookie value];
|
var cookieValue = [_swatchCookie value];
|
||||||
|
|
||||||
if (cookieValue == "")
|
if (cookieValue == "")
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
@@ -472,8 +475,8 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
var cookieValue = eval(cookieValue);
|
var cookieValue = eval(cookieValue),
|
||||||
var result = [];
|
result = [];
|
||||||
|
|
||||||
for (var i = 0; i < cookieValue.length; i++)
|
for (var i = 0; i < cookieValue.length; i++)
|
||||||
result.push([CPColor colorWithHexString: cookieValue[i]]);
|
result.push([CPColor colorWithHexString: cookieValue[i]]);
|
||||||
@@ -518,9 +521,10 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
|||||||
|
|
||||||
- (void)mouseUp:(CPEvent)anEvent
|
- (void)mouseUp:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||||
|
bounds = [self bounds];
|
||||||
|
|
||||||
if(point.x > [self bounds].size.width - 1 || point.x < 1)
|
if (!CGRectContainsPoint(bounds, point) || point.x > [self bounds].size.width - 1 || point.x < 1)
|
||||||
return NO;
|
return NO;
|
||||||
|
|
||||||
[_colorPanel setColor: [self colorAtIndex:FLOOR(point.x / 13)] updatePicker: YES];
|
[_colorPanel setColor: [self colorAtIndex:FLOOR(point.x / 13)] updatePicker: YES];
|
||||||
@@ -543,7 +547,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
|||||||
var bounds = CPRectCreateCopy([swatch bounds]);
|
var bounds = CPRectCreateCopy([swatch bounds]);
|
||||||
|
|
||||||
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
||||||
var dragView = [[CPView alloc] initWithFrame: bounds];
|
var dragView = [[CPView alloc] initWithFrame: bounds],
|
||||||
dragFillView = [[CPView alloc] initWithFrame:CGRectInset(bounds, 1.0, 1.0)];
|
dragFillView = [[CPView alloc] initWithFrame:CGRectInset(bounds, 1.0, 1.0)];
|
||||||
|
|
||||||
[dragView setBackgroundColor:[CPColor blackColor]];
|
[dragView setBackgroundColor:[CPColor blackColor]];
|
||||||
@@ -563,7 +567,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
|||||||
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
|
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
|
||||||
{
|
{
|
||||||
if (aType == CPColorDragType)
|
if (aType == CPColorDragType)
|
||||||
[aPasteboard setData:_dragColor forType:aType];
|
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:_dragColor] forType:aType];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)performDragOperation:(id <CPDraggingInfo>)aSender
|
- (void)performDragOperation:(id <CPDraggingInfo>)aSender
|
||||||
@@ -575,7 +579,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
|||||||
if (![pasteboard availableTypeFromArray:[CPColorDragType]] || location.x > [self bounds].size.width - 1 || location.x < 1)
|
if (![pasteboard availableTypeFromArray:[CPColorDragType]] || location.x > [self bounds].size.width - 1 || location.x < 1)
|
||||||
return NO;
|
return NO;
|
||||||
|
|
||||||
[self setColor:[pasteboard dataForType:CPColorDragType] atIndex: FLOOR(location.x / 13)];
|
[self setColor:[CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]] atIndex: FLOOR(location.x / 13)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -612,7 +616,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
|||||||
if (![pasteboard availableTypeFromArray:[CPColorDragType]])
|
if (![pasteboard availableTypeFromArray:[CPColorDragType]])
|
||||||
return NO;
|
return NO;
|
||||||
|
|
||||||
var color = [pasteboard dataForType:CPColorDragType];
|
var color = [CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]];
|
||||||
[_colorPanel setColor:color updatePicker:YES];
|
[_colorPanel setColor:color updatePicker:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -625,12 +629,12 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
|||||||
{
|
{
|
||||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||||
|
|
||||||
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPArray arrayWithObject:CPColorDragType] owner:self];
|
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPColorDragType] owner:self];
|
||||||
|
|
||||||
var bounds = CPRectMake(0, 0, 15, 15);
|
var bounds = CPRectMake(0, 0, 15, 15);
|
||||||
|
|
||||||
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
||||||
var dragView = [[CPView alloc] initWithFrame: bounds];
|
var dragView = [[CPView alloc] initWithFrame: bounds],
|
||||||
dragFillView = [[CPView alloc] initWithFrame:CGRectInset(bounds, 1.0, 1.0)];
|
dragFillView = [[CPView alloc] initWithFrame:CGRectInset(bounds, 1.0, 1.0)];
|
||||||
|
|
||||||
[dragView setBackgroundColor:[CPColor blackColor]];
|
[dragView setBackgroundColor:[CPColor blackColor]];
|
||||||
@@ -650,7 +654,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
|||||||
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
|
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
|
||||||
{
|
{
|
||||||
if (aType == CPColorDragType)
|
if (aType == CPColorDragType)
|
||||||
[aPasteboard setData:[self backgroundColor] forType:aType];
|
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:[self backgroundColor]] forType:aType];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+15
-14
@@ -21,7 +21,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
@import "CPColorPanel.j"
|
|
||||||
|
@import "CPView.j"
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -239,8 +241,10 @@
|
|||||||
_blackWheelImage.style.filter = "alpha(opacity=0)"
|
_blackWheelImage.style.filter = "alpha(opacity=0)"
|
||||||
_blackWheelImage.style.position = "absolute";
|
_blackWheelImage.style.position = "absolute";
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
_DOMElement.appendChild(_wheelImage);
|
_DOMElement.appendChild(_wheelImage);
|
||||||
_DOMElement.appendChild(_blackWheelImage);
|
_DOMElement.appendChild(_blackWheelImage);
|
||||||
|
#endif
|
||||||
|
|
||||||
[self setWheelSize:aFrame.size];
|
[self setWheelSize:aFrame.size];
|
||||||
|
|
||||||
@@ -325,13 +329,11 @@
|
|||||||
- (void)reposition:(CPEvent)anEvent
|
- (void)reposition:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
var bounds = [self bounds],
|
var bounds = [self bounds],
|
||||||
location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||||
|
midX = CGRectGetMidX(bounds),
|
||||||
var midX = CGRectGetMidX(bounds);
|
midY = CGRectGetMidY(bounds),
|
||||||
var midY = CGRectGetMidY(bounds);
|
distance = MIN(SQRT((location.x - midX) * (location.x - midX) + (location.y - midY) * (location.y - midY)), _radius),
|
||||||
|
angle = ATAN2(location.y - midY, location.x - midX);
|
||||||
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];
|
[self setAngle:angle distance:distance];
|
||||||
|
|
||||||
@@ -340,9 +342,9 @@
|
|||||||
|
|
||||||
- (void)setAngle:(int)angle distance:(float)distance
|
- (void)setAngle:(int)angle distance:(float)distance
|
||||||
{
|
{
|
||||||
var bounds = [self bounds];
|
var bounds = [self bounds],
|
||||||
var midX = CGRectGetMidX(bounds);
|
midX = CGRectGetMidX(bounds),
|
||||||
var midY = CGRectGetMidY(bounds);
|
midY = CGRectGetMidY(bounds);
|
||||||
|
|
||||||
_angle = [self radiansToDegrees:angle];
|
_angle = [self radiansToDegrees:angle];
|
||||||
_distance = (distance / _radius) * 100.0;
|
_distance = (distance / _radius) * 100.0;
|
||||||
@@ -353,9 +355,8 @@
|
|||||||
- (void)setPositionToColor:(CPColor)aColor
|
- (void)setPositionToColor:(CPColor)aColor
|
||||||
{
|
{
|
||||||
var hsb = [aColor hsbComponents],
|
var hsb = [aColor hsbComponents],
|
||||||
bounds = [self bounds];
|
bounds = [self bounds],
|
||||||
|
angle = [self degreesToRadians:hsb[0]],
|
||||||
var angle = [self degreesToRadians:hsb[0]],
|
|
||||||
distance = (hsb[1] / 100.0) * _radius;
|
distance = (hsb[1] / 100.0) * _radius;
|
||||||
|
|
||||||
[self setAngle:angle distance:distance];
|
[self setAngle:angle distance:distance];
|
||||||
|
|||||||
@@ -231,11 +231,17 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
|||||||
|
|
||||||
- (void)mouseDown:(CPEvent)anEvent
|
- (void)mouseDown:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
|
if (![self isEnabled])
|
||||||
|
return;
|
||||||
|
|
||||||
[self drawBezelWithHighlight:YES];
|
[self drawBezelWithHighlight:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseDragged:(CPEvent)anEvent
|
- (void)mouseDragged:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
|
if (![self isEnabled])
|
||||||
|
return;
|
||||||
|
|
||||||
[self drawBezelWithHighlight:CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil])];
|
[self drawBezelWithHighlight:CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil])];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,7 +249,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
|||||||
{
|
{
|
||||||
[self drawBezelWithHighlight:NO];
|
[self drawBezelWithHighlight:NO];
|
||||||
|
|
||||||
if (!CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil]))
|
if (!CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil]) || ![self isEnabled])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[self activate:YES];
|
[self activate:YES];
|
||||||
@@ -272,7 +278,7 @@ var CPColorWellColorKey = "CPColorWellColorKey",
|
|||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_active = NO;
|
_active = NO;
|
||||||
_bordered = [aCoder decodeObjectForKey:CPColorWellBorderedKey];
|
_bordered = [aCoder decodeBoolForKey:CPColorWellBorderedKey];
|
||||||
_color = [aCoder decodeObjectForKey:CPColorWellColorKey];
|
_color = [aCoder decodeObjectForKey:CPColorWellColorKey];
|
||||||
|
|
||||||
[self drawBezelWithHighlight:NO];
|
[self drawBezelWithHighlight:NO];
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
@import "CPEvent.j"
|
@import "CPEvent.j"
|
||||||
@import "CPPlatform.j"
|
@import "CPPlatform.j"
|
||||||
|
|
||||||
|
|
||||||
// Browser Engines
|
// Browser Engines
|
||||||
CPUnknownBrowserEngine = 0;
|
CPUnknownBrowserEngine = 0;
|
||||||
CPGeckoBrowserEngine = 1;
|
CPGeckoBrowserEngine = 1;
|
||||||
@@ -65,8 +66,6 @@ CPInputTypeCanBeChangedFeature = 1 << 25;
|
|||||||
CPHTML5DragAndDropSourceYOffBy1 = 1 << 26;
|
CPHTML5DragAndDropSourceYOffBy1 = 1 << 26;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var USER_AGENT = "",
|
var USER_AGENT = "",
|
||||||
PLATFORM_ENGINE = CPUnknownBrowserEngine,
|
PLATFORM_ENGINE = CPUnknownBrowserEngine,
|
||||||
PLATFORM_FEATURES = 0;
|
PLATFORM_FEATURES = 0;
|
||||||
@@ -75,11 +74,11 @@ var USER_AGENT = "",
|
|||||||
|
|
||||||
PLATFORM_FEATURES |= CPInputTypeCanBeChangedFeature;
|
PLATFORM_FEATURES |= CPInputTypeCanBeChangedFeature;
|
||||||
|
|
||||||
if (typeof window != "undfined" && typeof window.navigator != "undefined")
|
if (typeof window !== "undefined" && typeof window.navigator !== "undefined")
|
||||||
USER_AGENT = window.navigator.userAgent;
|
USER_AGENT = window.navigator.userAgent;
|
||||||
|
|
||||||
// Opera
|
// Opera
|
||||||
if (window.opera)
|
if (typeof window !== "undefined" && window.opera)
|
||||||
{
|
{
|
||||||
PLATFORM_ENGINE = CPOperaBrowserEngine;
|
PLATFORM_ENGINE = CPOperaBrowserEngine;
|
||||||
|
|
||||||
@@ -87,7 +86,7 @@ if (window.opera)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Internet Explorer
|
// Internet Explorer
|
||||||
else if (window.attachEvent) // Must follow Opera check.
|
else if (typeof window !== "undefined" && window.attachEvent) // Must follow Opera check.
|
||||||
{
|
{
|
||||||
PLATFORM_ENGINE = CPInternetExplorerBrowserEngine;
|
PLATFORM_ENGINE = CPInternetExplorerBrowserEngine;
|
||||||
|
|
||||||
@@ -109,7 +108,10 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
|
|||||||
// Features we can only be sure of with WebKit (no known independent tests)
|
// Features we can only be sure of with WebKit (no known independent tests)
|
||||||
PLATFORM_FEATURES |= CPCSSRGBAFeature;
|
PLATFORM_FEATURES |= CPCSSRGBAFeature;
|
||||||
PLATFORM_FEATURES |= CPHTMLContentEditableFeature;
|
PLATFORM_FEATURES |= CPHTMLContentEditableFeature;
|
||||||
|
|
||||||
|
if (USER_AGENT.indexOf("Chrome") === -1)
|
||||||
PLATFORM_FEATURES |= CPHTMLDragAndDropFeature;
|
PLATFORM_FEATURES |= CPHTMLDragAndDropFeature;
|
||||||
|
|
||||||
PLATFORM_FEATURES |= CPJavascriptClipboardEventsFeature;
|
PLATFORM_FEATURES |= CPJavascriptClipboardEventsFeature;
|
||||||
PLATFORM_FEATURES |= CPJavascriptClipboardAccessFeature;
|
PLATFORM_FEATURES |= CPJavascriptClipboardAccessFeature;
|
||||||
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
|
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
|
||||||
@@ -204,11 +206,11 @@ if (USER_AGENT.indexOf("Mac") !== -1)
|
|||||||
|
|
||||||
CPPlatformActionKeyMask = CPCommandKeyMask;
|
CPPlatformActionKeyMask = CPCommandKeyMask;
|
||||||
|
|
||||||
CPUndoKeyEquivalent = @"Z";
|
CPUndoKeyEquivalent = @"z";
|
||||||
CPRedoKeyEquivalent = @"Z";
|
CPRedoKeyEquivalent = @"Z";
|
||||||
|
|
||||||
CPUndoKeyEquivalentModifierMask = CPCommandKeyMask;
|
CPUndoKeyEquivalentModifierMask = CPCommandKeyMask;
|
||||||
CPRedoKeyEquivalentModifierMask = CPCommandKeyMask | CPShiftKeyMask;
|
CPRedoKeyEquivalentModifierMask = CPCommandKeyMask;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -217,8 +219,8 @@ else
|
|||||||
|
|
||||||
CPPlatformActionKeyMask = CPControlKeyMask;
|
CPPlatformActionKeyMask = CPControlKeyMask;
|
||||||
|
|
||||||
CPUndoKeyEquivalent = @"Z";
|
CPUndoKeyEquivalent = @"z";
|
||||||
CPRedoKeyEquivalent = @"Y";
|
CPRedoKeyEquivalent = @"y";
|
||||||
|
|
||||||
CPUndoKeyEquivalentModifierMask = CPControlKeyMask;
|
CPUndoKeyEquivalentModifierMask = CPControlKeyMask;
|
||||||
CPRedoKeyEquivalentModifierMask = CPControlKeyMask;
|
CPRedoKeyEquivalentModifierMask = CPControlKeyMask;
|
||||||
|
|||||||
+178
-59
@@ -23,52 +23,46 @@
|
|||||||
@import "CPFont.j"
|
@import "CPFont.j"
|
||||||
@import "CPShadow.j"
|
@import "CPShadow.j"
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
@import "CPKeyValueBinding.j"
|
||||||
|
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
|
||||||
#include "Platform/Platform.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPTextAlignment
|
|
||||||
*/
|
|
||||||
CPLeftTextAlignment = 0;
|
CPLeftTextAlignment = 0;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPTextAlignment
|
|
||||||
*/
|
|
||||||
CPRightTextAlignment = 1;
|
CPRightTextAlignment = 1;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPTextAlignment
|
|
||||||
*/
|
|
||||||
CPCenterTextAlignment = 2;
|
CPCenterTextAlignment = 2;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPTextAlignment
|
|
||||||
*/
|
|
||||||
CPJustifiedTextAlignment = 3;
|
CPJustifiedTextAlignment = 3;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPTextAlignment
|
|
||||||
*/
|
|
||||||
CPNaturalTextAlignment = 4;
|
CPNaturalTextAlignment = 4;
|
||||||
|
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPControlSize
|
|
||||||
*/
|
|
||||||
CPRegularControlSize = 0;
|
CPRegularControlSize = 0;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPControlSize
|
|
||||||
*/
|
|
||||||
CPSmallControlSize = 1;
|
CPSmallControlSize = 1;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPControlSize
|
|
||||||
*/
|
|
||||||
CPMiniControlSize = 2;
|
CPMiniControlSize = 2;
|
||||||
|
|
||||||
|
CPLineBreakByWordWrapping = 0;
|
||||||
|
CPLineBreakByCharWrapping = 1;
|
||||||
|
CPLineBreakByClipping = 2;
|
||||||
|
CPLineBreakByTruncatingHead = 3;
|
||||||
|
CPLineBreakByTruncatingTail = 4;
|
||||||
|
CPLineBreakByTruncatingMiddle = 5;
|
||||||
|
|
||||||
|
CPTopVerticalTextAlignment = 1,
|
||||||
|
CPCenterVerticalTextAlignment = 2,
|
||||||
|
CPBottomVerticalTextAlignment = 3;
|
||||||
|
|
||||||
|
CPScaleProportionally = 0;
|
||||||
|
CPScaleToFit = 1;
|
||||||
|
CPScaleNone = 2;
|
||||||
|
|
||||||
|
CPNoImage = 0;
|
||||||
|
CPImageOnly = 1;
|
||||||
|
CPImageLeft = 2;
|
||||||
|
CPImageRight = 3;
|
||||||
|
CPImageBelow = 4;
|
||||||
|
CPImageAbove = 5;
|
||||||
|
CPImageOverlaps = 6;
|
||||||
|
|
||||||
|
CPOnState = 1;
|
||||||
|
CPOffState = 0;
|
||||||
|
CPMixedState = -1;
|
||||||
|
|
||||||
CPControlNormalBackgroundColor = "CPControlNormalBackgroundColor";
|
CPControlNormalBackgroundColor = "CPControlNormalBackgroundColor";
|
||||||
CPControlSelectedBackgroundColor = "CPControlSelectedBackgroundColor";
|
CPControlSelectedBackgroundColor = "CPControlSelectedBackgroundColor";
|
||||||
CPControlHighlightedBackgroundColor = "CPControlHighlightedBackgroundColor";
|
CPControlHighlightedBackgroundColor = "CPControlHighlightedBackgroundColor";
|
||||||
@@ -112,7 +106,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
CPLineBreakByClipping,
|
CPLineBreakByClipping,
|
||||||
[CPColor blackColor],
|
[CPColor blackColor],
|
||||||
[CPFont systemFontOfSize:12.0],
|
[CPFont systemFontOfSize:12.0],
|
||||||
nil,
|
[CPNull null],
|
||||||
_CGSizeMakeZero(),
|
_CGSizeMakeZero(),
|
||||||
CPImageLeft,
|
CPImageLeft,
|
||||||
CPScaleToFit,
|
CPScaleToFit,
|
||||||
@@ -131,6 +125,36 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
@"max-size"]];
|
@"max-size"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
if (self === [CPControl class])
|
||||||
|
{
|
||||||
|
[self exposeBinding:@"value"];
|
||||||
|
[self exposeBinding:@"objectValue"];
|
||||||
|
[self exposeBinding:@"stringValue"];
|
||||||
|
[self exposeBinding:@"integerValue"];
|
||||||
|
[self exposeBinding:@"intValue"];
|
||||||
|
[self exposeBinding:@"doubleValue"];
|
||||||
|
[self exposeBinding:@"floatValue"];
|
||||||
|
|
||||||
|
[self exposeBinding:@"enabled"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_reverseSetBinding
|
||||||
|
{
|
||||||
|
var theBinding = [CPKeyValueBinding getBinding:CPValueBinding forObject:self];
|
||||||
|
[theBinding reverseSetValueFor:@"objectValue"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_replacementKeyPathForBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
if (aBinding === @"value")
|
||||||
|
return @"objectValue";
|
||||||
|
|
||||||
|
return [super _replacementKeyPathForBinding:aBinding];
|
||||||
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
{
|
{
|
||||||
self = [super initWithFrame:aFrame];
|
self = [super initWithFrame:aFrame];
|
||||||
@@ -185,6 +209,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
*/
|
*/
|
||||||
- (void)sendAction:(SEL)anAction to:(id)anObject
|
- (void)sendAction:(SEL)anAction to:(id)anObject
|
||||||
{
|
{
|
||||||
|
[self _reverseSetBinding];
|
||||||
[CPApp sendAction:anAction to:anObject from:self];
|
[CPApp sendAction:anAction to:anObject from:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,7 +278,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
- (void)trackMouse:(CPEvent)anEvent
|
- (void)trackMouse:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
var type = [anEvent type],
|
var type = [anEvent type],
|
||||||
currentLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
currentLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||||
isWithinFrame = [self tracksMouseOutsideOfFrame] || CGRectContainsPoint([self bounds], currentLocation);
|
isWithinFrame = [self tracksMouseOutsideOfFrame] || CGRectContainsPoint([self bounds], currentLocation);
|
||||||
|
|
||||||
if (type === CPLeftMouseUp)
|
if (type === CPLeftMouseUp)
|
||||||
@@ -262,7 +287,6 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
|
|
||||||
_trackingMouseDownFlags = 0;
|
_trackingMouseDownFlags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (type === CPLeftMouseDown)
|
if (type === CPLeftMouseDown)
|
||||||
@@ -305,9 +329,28 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
|
|
||||||
- (void)performClick:(id)sender
|
- (void)performClick:(id)sender
|
||||||
{
|
{
|
||||||
|
if (![self isEnabled])
|
||||||
|
return;
|
||||||
|
|
||||||
[self highlight:YES];
|
[self highlight:YES];
|
||||||
[self setState:[self nextState]];
|
[self setState:[self nextState]];
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
[self sendAction:[self action] to:[self target]];
|
[self sendAction:[self action] to:[self target]];
|
||||||
|
}
|
||||||
|
catch (e)
|
||||||
|
{
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
[CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)unhighlightButtonTimerDidFinish:(id)sender
|
||||||
|
{
|
||||||
[self highlight:NO];
|
[self highlight:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,7 +472,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the receiver's int value
|
Returns the receiver's string value
|
||||||
*/
|
*/
|
||||||
- (CPString)stringValue
|
- (CPString)stringValue
|
||||||
{
|
{
|
||||||
@@ -437,7 +480,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Set's the receiver's int value
|
Set's the receiver's string value
|
||||||
*/
|
*/
|
||||||
- (void)setStringValue:(CPString)anObject
|
- (void)setStringValue:(CPString)anObject
|
||||||
{
|
{
|
||||||
@@ -508,30 +551,100 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
if ([note object] != self)
|
if ([note object] != self)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
[self _reverseSetBinding];
|
||||||
|
|
||||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidEndEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidEndEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BRIDGE(UPPERCASE, LOWERCASE, ATTRIBUTENAME) \
|
- (void)setAlignment:(CPTextAlignment)alignment
|
||||||
/*! Sets the value for ATTRIBUTENAME */\
|
{
|
||||||
- (void)set##UPPERCASE:(id)aValue\
|
[self setValue:alignment forThemeAttribute:@"alignment"];
|
||||||
{\
|
|
||||||
[self setValue:aValue forThemeAttribute:ATTRIBUTENAME];\
|
|
||||||
}\
|
|
||||||
/*! Returns the current value for ATTRIBUTENAME */\
|
|
||||||
- (id)LOWERCASE\
|
|
||||||
{\
|
|
||||||
return [self valueForThemeAttribute:ATTRIBUTENAME];\
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BRIDGE(Alignment, alignment, "alignment")
|
- (CPTextAlignment)alignment
|
||||||
BRIDGE(VerticalAlignment, verticalAlignment, "vertical-alignment")
|
{
|
||||||
BRIDGE(LineBreakMode, lineBreakMode, "line-break-mode")
|
return [self valueForThemeAttribute:@"alignment"];
|
||||||
BRIDGE(TextColor, textColor, "text-color")
|
}
|
||||||
BRIDGE(Font, font, "font")
|
|
||||||
BRIDGE(TextShadowColor, textShadowColor, "text-shadow-color")
|
- (void)setVerticalAlignment:(CPTextVerticalAlignment)alignment
|
||||||
BRIDGE(TextShadowOffset, textShadowOffset, "text-shadow-offset")
|
{
|
||||||
BRIDGE(ImagePosition, imagePosition, "image-position")
|
[self setValue:alignment forThemeAttribute:@"vertical-alignment"];
|
||||||
BRIDGE(ImageScaling, imageScaling, "image-scaling")
|
}
|
||||||
|
|
||||||
|
- (CPTextVerticalAlignment)verticalAlignment
|
||||||
|
{
|
||||||
|
return [self valueForThemeAttribute:@"vertical-alignment"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setLineBreakMode:(CPLineBreakMode)mode
|
||||||
|
{
|
||||||
|
[self setValue:mode forThemeAttribute:@"line-break-mode"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPLineBreakMode)lineBreakMode
|
||||||
|
{
|
||||||
|
return [self valueForThemeAttribute:@"line-break-mode"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTextColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
[self setValue:aColor forThemeAttribute:@"text-color"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPColor)textColor
|
||||||
|
{
|
||||||
|
return [self valueForThemeAttribute:@"text-color"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTextShadowColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
[self setValue:aColor forThemeAttribute:@"text-shadow-color"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPColor)textShadowColor
|
||||||
|
{
|
||||||
|
return [self valueForThemeAttribute:@"text-shadow-color"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTextShadowOffset:(float)offset
|
||||||
|
{
|
||||||
|
[self setValue:offset forThemeAttribute:@"text-shadow-offset"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (float)textShadowOffset
|
||||||
|
{
|
||||||
|
return [self valueForThemeAttribute:@"text-shadow-offset"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFont:(CPFont)aFont
|
||||||
|
{
|
||||||
|
[self setValue:aFont forThemeAttribute:@"font"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPFont)font
|
||||||
|
{
|
||||||
|
return [self valueForThemeAttribute:@"font"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setImagePosition:(CPCellImagePosition)position
|
||||||
|
{
|
||||||
|
[self setValue:position forThemeAttribute:@"image-position"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPCellImagePosition)imagePosition
|
||||||
|
{
|
||||||
|
return [self valueForThemeAttribute:@"image-position"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setImageScaling:(CPImageScaling)scaling
|
||||||
|
{
|
||||||
|
[self setValue:scaling forThemeAttribute:@"image-scaling"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPImageScaling)imageScaling
|
||||||
|
{
|
||||||
|
return [self valueForThemeAttribute:@"image-scaling"];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setEnabled:(BOOL)isEnabled
|
- (void)setEnabled:(BOOL)isEnabled
|
||||||
{
|
{
|
||||||
@@ -572,7 +685,9 @@ var CPControlValueKey = "CPControlValueKey",
|
|||||||
|
|
||||||
CPControlTargetKey = "CPControlTargetKey",
|
CPControlTargetKey = "CPControlTargetKey",
|
||||||
CPControlActionKey = "CPControlActionKey",
|
CPControlActionKey = "CPControlActionKey",
|
||||||
CPControlSendActionOnKey = "CPControlSendActionOnKey";
|
CPControlSendActionOnKey = "CPControlSendActionOnKey",
|
||||||
|
|
||||||
|
CPControlSendsActionOnEndEditingKey = "CPControlSendsActionOnEndEditingKey";
|
||||||
|
|
||||||
var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
|
var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
|
||||||
|
|
||||||
@@ -595,6 +710,7 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
|
|||||||
[self setAction:[aCoder decodeObjectForKey:CPControlActionKey]];
|
[self setAction:[aCoder decodeObjectForKey:CPControlActionKey]];
|
||||||
|
|
||||||
[self sendActionOn:[aCoder decodeIntForKey:CPControlSendActionOnKey]];
|
[self sendActionOn:[aCoder decodeIntForKey:CPControlSendActionOnKey]];
|
||||||
|
[self setSendsActionOnEndEditing:[aCoder decodeBoolForKey:CPControlSendsActionOnEndEditingKey]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -608,6 +724,9 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
|
|||||||
{
|
{
|
||||||
[super encodeWithCoder:aCoder];
|
[super encodeWithCoder:aCoder];
|
||||||
|
|
||||||
|
if (_sendsActionOnEndEditing)
|
||||||
|
[aCoder encodeBool:_sendsActionOnEndEditing forKey:CPControlSendsActionOnEndEditingKey];
|
||||||
|
|
||||||
if (_value !== nil)
|
if (_value !== nil)
|
||||||
[aCoder encodeObject:_value forKey:CPControlValueKey];
|
[aCoder encodeObject:_value forKey:CPControlValueKey];
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
//
|
||||||
|
// CPController.j
|
||||||
|
// AppKit
|
||||||
|
//
|
||||||
|
// Created by Ross Boucher 1/15/09
|
||||||
|
// Copyright 280 North
|
||||||
|
//
|
||||||
|
// Adapted from GNUStep
|
||||||
|
// Copyright (C) 2007 Free Software Foundation, Inc
|
||||||
|
// Released under the LGPL.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
|
var CPControllerDeclaredKeysKey = @"CPControllerDeclaredKeysKey";
|
||||||
|
|
||||||
|
@implementation CPController : CPObject
|
||||||
|
{
|
||||||
|
CPArray _editors;
|
||||||
|
CPArray _declaredKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_editors = [];
|
||||||
|
_declaredKeys = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
if ([_declaredKeys count] > 0)
|
||||||
|
[aCoder encodeObject:_declaredKeys forKey:CPControllerDeclaredKeysKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)aDecoder
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_editors = [];
|
||||||
|
_declaredKeys = [aDecoder decodeObjectForKey:CPControllerDeclaredKeysKey] || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEditing
|
||||||
|
{
|
||||||
|
return [_editors count] > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)commitEditing
|
||||||
|
{
|
||||||
|
var index = 0,
|
||||||
|
count = _editors.length;
|
||||||
|
|
||||||
|
for (; index < count; ++index)
|
||||||
|
if (![[_editors objectAtIndex:i] commitEditing])
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)discardEditing
|
||||||
|
{
|
||||||
|
[_editors makeObjectsPerformSelector:@selector(discardEditing)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)objectDidBeginEditing:(id)anEditor
|
||||||
|
{
|
||||||
|
[_editors addObject:anEditor];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)objectDidEndEditing:(id)anEditor
|
||||||
|
{
|
||||||
|
[_editors removeObject:anEditor];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
+12
-3
@@ -93,19 +93,28 @@
|
|||||||
else
|
else
|
||||||
domain = "";
|
domain = "";
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
document.cookie = _cookieName+"="+value+expires+"; path=/"+domain;
|
document.cookie = _cookieName+"="+value+expires+"; path=/"+domain;
|
||||||
|
#else
|
||||||
|
_cookieValue = value;
|
||||||
|
_expires = expires;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
- (CPString)_readCookieValue
|
- (CPString)_readCookieValue
|
||||||
{
|
{
|
||||||
var nameEQ = _cookieName + "=";
|
#if PLATFORM(DOM)
|
||||||
var ca = document.cookie.split(';');
|
var nameEQ = _cookieName + "=",
|
||||||
for(var i=0;i < ca.length;i++) {
|
ca = document.cookie.split(';');
|
||||||
|
|
||||||
|
for (var i = 0; i < ca.length; i++)
|
||||||
|
{
|
||||||
var c = ca[i];
|
var c = ca[i];
|
||||||
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
|
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
|
||||||
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
|
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+22
-9
@@ -12,6 +12,8 @@ Implemented class methods:
|
|||||||
Opera : All except resizeLeftRightCursor resizeUpDownCursor operationNotAllowedCursor dragCopyCursor dragLinkCursor contextualMenuCursor openHandCursor closedHandCursor disappearingItemCursor // Opera does not support url cursors so these won't work with images
|
Opera : All except resizeLeftRightCursor resizeUpDownCursor operationNotAllowedCursor dragCopyCursor dragLinkCursor contextualMenuCursor openHandCursor closedHandCursor disappearingItemCursor // Opera does not support url cursors so these won't work with images
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
var currentCursor = nil,
|
var currentCursor = nil,
|
||||||
cursorStack = [],
|
cursorStack = [],
|
||||||
cursors = {},
|
cursors = {},
|
||||||
@@ -165,7 +167,9 @@ var currentCursor = nil,
|
|||||||
{
|
{
|
||||||
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
|
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
|
||||||
return [CPCursor cursorWithCSSString:@"-webkit-grab"];
|
return [CPCursor cursorWithCSSString:@"-webkit-grab"];
|
||||||
else if (CPBrowserIsEngine(CPGeckoBrowserEngine) || CPBrowserIsEngine(CPOperaBrowserEngine))
|
else if (CPBrowserIsEngine(CPGeckoBrowserEngine))
|
||||||
|
return [CPCursor cursorWithCSSString:@"-moz-grab"];
|
||||||
|
else if (CPBrowserIsEngine(CPOperaBrowserEngine))
|
||||||
return [CPCursor cursorWithCSSString:@"move"];
|
return [CPCursor cursorWithCSSString:@"move"];
|
||||||
|
|
||||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit only. move in FFMac|Opera
|
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit only. move in FFMac|Opera
|
||||||
@@ -175,8 +179,10 @@ var currentCursor = nil,
|
|||||||
{
|
{
|
||||||
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
|
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
|
||||||
return [CPCursor cursorWithCSSString:@"-webkit-grabbing"];
|
return [CPCursor cursorWithCSSString:@"-webkit-grabbing"];
|
||||||
|
else if (CPBrowserIsEngine(CPGeckoBrowserEngine))
|
||||||
|
return [CPCursor cursorWithCSSString:@"-moz-grabbing"];
|
||||||
|
|
||||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit only
|
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit || FF
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPCursor)disappearingItemCursor
|
+ (CPCursor)disappearingItemCursor
|
||||||
@@ -186,12 +192,12 @@ var currentCursor = nil,
|
|||||||
|
|
||||||
+ (void)hide
|
+ (void)hide
|
||||||
{
|
{
|
||||||
document.body.style.cursor = 'none'; // Not supported in IE
|
[self _setCursorCSS:"none"]; // Not supported in IE
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)unhide
|
+ (void)unhide
|
||||||
{
|
{
|
||||||
document.body.style.cursor = [currentCursor _cssString];
|
[self _setCursorCSS:[currentCursor _cssString]];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)setHiddenUntilMouseMoves:(BOOL)flag
|
+ (void)setHiddenUntilMouseMoves:(BOOL)flag
|
||||||
@@ -204,9 +210,10 @@ var currentCursor = nil,
|
|||||||
|
|
||||||
- (id)initWithImage:(CPImage)image hotSpot:(CPPoint)hotSpot
|
- (id)initWithImage:(CPImage)image hotSpot:(CPPoint)hotSpot
|
||||||
{
|
{
|
||||||
return [self initWithCSSString:"url(" + [image filename] + ")"];
|
return [self initWithCSSString:"url(" + [image filename] + "), auto"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)mouseEntered:(CPEvent)event
|
- (void)mouseEntered:(CPEvent)event
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -217,17 +224,23 @@ var currentCursor = nil,
|
|||||||
|
|
||||||
- (void)set
|
- (void)set
|
||||||
{
|
{
|
||||||
document.body.style.cursor = _cssString;
|
|
||||||
currentCursor = self;
|
currentCursor = self;
|
||||||
|
|
||||||
#if PLATFORM(DOM)
|
#if PLATFORM(DOM)
|
||||||
var platformWindows = [[CPPlatformWindow visiblePlatformWindows] allObjects];
|
[[self class] _setCursorCSS:_cssString];
|
||||||
for (var i = 0, count = [platformWindows count]; i < count; i++)
|
|
||||||
platformWindows[i]._DOMWindow.document.body.style.cursor = _cssString;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (void)_setCursorCSS:(CPString)aString
|
||||||
|
{
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
var platformWindows = [[CPPlatformWindow visiblePlatformWindows] allObjects];
|
||||||
|
for (var i = 0, count = [platformWindows count]; i < count; i++)
|
||||||
|
platformWindows[i]._DOMBodyElement.style.cursor = aString;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
- (void)push
|
- (void)push
|
||||||
{
|
{
|
||||||
currentCursor = cursorStack.push(self);
|
currentCursor = cursorStack.push(self);
|
||||||
|
|||||||
+6
-6
@@ -23,6 +23,7 @@
|
|||||||
@import <Foundation/CPString.j>
|
@import <Foundation/CPString.j>
|
||||||
@import <Foundation/CPArray.j>
|
@import <Foundation/CPArray.j>
|
||||||
|
|
||||||
|
@import "CPApplication.j"
|
||||||
@import "CPResponder.j"
|
@import "CPResponder.j"
|
||||||
@import "CPSavePanel.j"
|
@import "CPSavePanel.j"
|
||||||
@import "CPViewController.j"
|
@import "CPViewController.j"
|
||||||
@@ -484,14 +485,14 @@ var CPDocumentUntitledCount = 0;
|
|||||||
else
|
else
|
||||||
[_writeRequest setHTTPMethod:@"PUT"];
|
[_writeRequest setHTTPMethod:@"PUT"];
|
||||||
|
|
||||||
[_writeRequest setHTTPBody:[data string]];
|
[_writeRequest setHTTPBody:[data rawString]];
|
||||||
|
|
||||||
[_writeRequest setValue:@"close" forHTTPHeaderField:@"Connection"];
|
[_writeRequest setValue:@"close" forHTTPHeaderField:@"Connection"];
|
||||||
|
|
||||||
if (aSaveOperation == CPSaveOperation)
|
if (aSaveOperation === CPSaveOperation)
|
||||||
[_writeRequest setValue:@"true" forHTTPHeaderField:@"x-cappuccino-overwrite"];
|
[_writeRequest setValue:@"true" forHTTPHeaderField:@"x-cappuccino-overwrite"];
|
||||||
|
|
||||||
if (aSaveOperation != CPSaveToOperation)
|
if (aSaveOperation !== CPSaveToOperation)
|
||||||
[self updateChangeCount:CPChangeCleared];
|
[self updateChangeCount:CPChangeCleared];
|
||||||
|
|
||||||
// FIXME: Oh man is this every looking for trouble, we need to handle login at the Cappuccino level, with HTTP Errors.
|
// FIXME: Oh man is this every looking for trouble, we need to handle login at the Cappuccino level, with HTTP Errors.
|
||||||
@@ -567,7 +568,7 @@ var CPDocumentUntitledCount = 0;
|
|||||||
// READ
|
// READ
|
||||||
if (aConnection == _readConnection)
|
if (aConnection == _readConnection)
|
||||||
{
|
{
|
||||||
[self readFromData:[CPData dataWithString:aData] ofType:session.fileType error:nil];
|
[self readFromData:[CPData dataWithRawString:aData] ofType:session.fileType error:nil];
|
||||||
|
|
||||||
objj_msgSend(session.delegate, session.didReadSelector, self, YES, session.contextInfo);
|
objj_msgSend(session.delegate, session.didReadSelector, self, YES, session.contextInfo);
|
||||||
}
|
}
|
||||||
@@ -888,8 +889,7 @@ var CPDocumentUntitledCount = 0;
|
|||||||
[_canCloseAlert setDelegate:self];
|
[_canCloseAlert setDelegate:self];
|
||||||
[_canCloseAlert setAlertStyle:CPWarningAlertStyle];
|
[_canCloseAlert setAlertStyle:CPWarningAlertStyle];
|
||||||
[_canCloseAlert setTitle:@"Unsaved Document"];
|
[_canCloseAlert setTitle:@"Unsaved Document"];
|
||||||
[_canCloseAlert setMessageText:sprintf(@"Do you want to save the changes you've made to the document \"%@\"?",
|
[_canCloseAlert setMessageText:@"Do you want to save the changes you've made to the document \"" + ([self displayName] || [self fileName]) + "\"?"];
|
||||||
[self displayName] || [self fileName])];
|
|
||||||
|
|
||||||
[_canCloseAlert addButtonWithTitle:@"Save"];
|
[_canCloseAlert addButtonWithTitle:@"Save"];
|
||||||
[_canCloseAlert addButtonWithTitle:@"Cancel"];
|
[_canCloseAlert addButtonWithTitle:@"Cancel"];
|
||||||
|
|||||||
+116
-41
@@ -20,13 +20,12 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@import <AppKit/CPView.j>
|
@import "CPApplication.j"
|
||||||
@import <AppKit/CPEvent.j>
|
@import "CPEvent.j"
|
||||||
@import <AppKit/CPPasteboard.j>
|
@import "CPImageView.j"
|
||||||
@import <AppKit/CPImageView.j>
|
@import "CPPasteboard.j"
|
||||||
|
@import "CPView.j"
|
||||||
#import "CoreGraphics/CGGeometry.h"
|
@import "CPWindow.j"
|
||||||
#import "Platform/Platform.h"
|
|
||||||
|
|
||||||
|
|
||||||
CPDragOperationNone = 0,
|
CPDragOperationNone = 0,
|
||||||
@@ -41,26 +40,7 @@ CPDragOperationEvery = -1;
|
|||||||
#define DRAGGING_WINDOW(anObject) ([anObject isKindOfClass:[CPWindow class]] ? anObject : [anObject window])
|
#define DRAGGING_WINDOW(anObject) ([anObject isKindOfClass:[CPWindow class]] ? anObject : [anObject window])
|
||||||
|
|
||||||
var CPDragServerPreviousEvent = nil,
|
var CPDragServerPreviousEvent = nil,
|
||||||
CPDragServerAutoscrollInterval = nil;
|
CPDragServerPeriodicUpdateInterval = 0.05;
|
||||||
/*
|
|
||||||
var CPDragServerAutoscroll = function()
|
|
||||||
{
|
|
||||||
[CPDragServerSource autoscroll:CPDragServerPreviousEvent];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CPDragServerAutoscrollInterval === nil)
|
|
||||||
{
|
|
||||||
if ([CPDragServerSource respondsToSelector:@selector(autoscroll:)])
|
|
||||||
CPDragServerAutoscrollInterval = setInterval(CPDragServerAutoscroll, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
CPDragServerPreviousEvent = anEvent;
|
|
||||||
|
|
||||||
if (CPDragServerAutoscrollInterval !== nil)
|
|
||||||
clearInterval(CPDragServerAutoscrollInterval);
|
|
||||||
|
|
||||||
CPDragServerAutoscrollInterval = nil;
|
|
||||||
*/
|
|
||||||
|
|
||||||
var CPSharedDragServer = nil;
|
var CPSharedDragServer = nil;
|
||||||
|
|
||||||
@@ -127,7 +107,7 @@ var CPDragServerDraggingInfo = nil;
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||||
CPDraggingSource_draggedImage_endAt_operation_ = 1 << 1,
|
CPDraggingSource_draggedImage_endedAt_operation_ = 1 << 1,
|
||||||
CPDraggingSource_draggedView_movedTo_ = 1 << 2,
|
CPDraggingSource_draggedView_movedTo_ = 1 << 2,
|
||||||
CPDraggingSource_draggedView_endedAt_operation_ = 1 << 3;
|
CPDraggingSource_draggedView_endedAt_operation_ = 1 << 3;
|
||||||
|
|
||||||
@@ -150,6 +130,13 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
|||||||
|
|
||||||
CGPoint _draggingLocation;
|
CGPoint _draggingLocation;
|
||||||
id _draggingDestination;
|
id _draggingDestination;
|
||||||
|
BOOL _draggingDestinationWantsPeriodicUpdates;
|
||||||
|
|
||||||
|
CGPoint _startDragLocation;
|
||||||
|
BOOL _shouldSlideBack;
|
||||||
|
unsigned _dragOperation;
|
||||||
|
|
||||||
|
CPTimer _draggingUpdateTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -189,6 +176,11 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (id)draggingDestination
|
||||||
|
{
|
||||||
|
return _draggingDestination;
|
||||||
|
}
|
||||||
|
|
||||||
- (CGPoint)draggingLocation
|
- (CGPoint)draggingLocation
|
||||||
{
|
{
|
||||||
return _draggingLocation
|
return _draggingLocation
|
||||||
@@ -225,6 +217,9 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
|||||||
|
|
||||||
- (CPDragOperation)draggingUpdatedInPlatformWindow:(CPPlatformWindow)aPlatformWindow location:(CGPoint)aLocation
|
- (CPDragOperation)draggingUpdatedInPlatformWindow:(CPPlatformWindow)aPlatformWindow location:(CGPoint)aLocation
|
||||||
{
|
{
|
||||||
|
[_draggingUpdateTimer invalidate];
|
||||||
|
_draggingUpdateTimer = nil;
|
||||||
|
|
||||||
var dragOperation = CPDragOperationCopy;
|
var dragOperation = CPDragOperationCopy;
|
||||||
// We have to convert base to bridge since the drag event comes from the source window, not the drag window.
|
// We have to convert base to bridge since the drag event comes from the source window, not the drag window.
|
||||||
var draggingDestination = [aPlatformWindow _dragHitTest:aLocation pasteboard:[CPDragServerDraggingInfo draggingPasteboard]];
|
var draggingDestination = [aPlatformWindow _dragHitTest:aLocation pasteboard:[CPDragServerDraggingInfo draggingPasteboard]];
|
||||||
@@ -234,33 +229,96 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
|||||||
|
|
||||||
if(draggingDestination !== _draggingDestination)
|
if(draggingDestination !== _draggingDestination)
|
||||||
{
|
{
|
||||||
if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingExited:)])
|
if ([_draggingDestination respondsToSelector:@selector(draggingExited:)])
|
||||||
[_draggingDestination draggingExited:CPDragServerDraggingInfo];
|
[_draggingDestination draggingExited:CPDragServerDraggingInfo];
|
||||||
|
|
||||||
_draggingDestination = draggingDestination;
|
_draggingDestination = draggingDestination;
|
||||||
|
|
||||||
if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingEntered:)])
|
if ([_draggingDestination respondsToSelector:@selector(wantsPeriodicDraggingUpdates)])
|
||||||
|
_draggingDestinationWantsPeriodicUpdates = [_draggingDestination wantsPeriodicDraggingUpdates];
|
||||||
|
else
|
||||||
|
_draggingDestinationWantsPeriodicUpdates = YES;
|
||||||
|
|
||||||
|
if ([_draggingDestination respondsToSelector:@selector(draggingEntered:)])
|
||||||
dragOperation = [_draggingDestination draggingEntered:CPDragServerDraggingInfo];
|
dragOperation = [_draggingDestination draggingEntered:CPDragServerDraggingInfo];
|
||||||
}
|
}
|
||||||
else if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingUpdated:)])
|
else if ([_draggingDestination respondsToSelector:@selector(draggingUpdated:)])
|
||||||
dragOperation = [_draggingDestination draggingUpdated:CPDragServerDraggingInfo];
|
dragOperation = [_draggingDestination draggingUpdated:CPDragServerDraggingInfo];
|
||||||
|
|
||||||
if (!_draggingDestination)
|
if (!_draggingDestination)
|
||||||
dragOperation = CPDragOperationNone;
|
dragOperation = CPDragOperationNone;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_draggingDestinationWantsPeriodicUpdates)
|
||||||
|
_draggingUpdateTimer = [CPTimer scheduledTimerWithTimeInterval:CPDragServerPeriodicUpdateInterval
|
||||||
|
target:self
|
||||||
|
selector:@selector(_sendPeriodicDraggingUpdate:)
|
||||||
|
userInfo:[CPDictionary dictionaryWithJSObject:{platformWindow:aPlatformWindow, location:aLocation}]
|
||||||
|
repeats:NO];
|
||||||
|
|
||||||
|
var scrollView = [_draggingDestination isKindOfClass:[CPView class]] ? [_draggingDestination enclosingScrollView] : nil;
|
||||||
|
if (scrollView)
|
||||||
|
{
|
||||||
|
var contentView = [scrollView contentView],
|
||||||
|
bounds = [contentView bounds],
|
||||||
|
insetBounds = CGRectInset(bounds, 10, 10),
|
||||||
|
eventLocation = [contentView convertPoint:_draggingLocation fromView:nil],
|
||||||
|
deltaX = 0,
|
||||||
|
deltaY = 0;
|
||||||
|
|
||||||
|
if (!CGRectContainsPoint(insetBounds, eventLocation))
|
||||||
|
{
|
||||||
|
if ([scrollView hasVerticalScroller])
|
||||||
|
{
|
||||||
|
if (eventLocation.y < CGRectGetMinY(insetBounds))
|
||||||
|
deltaY = CGRectGetMinY(insetBounds) - eventLocation.y;
|
||||||
|
else if (eventLocation.y > CGRectGetMaxY(insetBounds))
|
||||||
|
deltaY = CGRectGetMaxY(insetBounds) - eventLocation.y;
|
||||||
|
if (deltaY < -insetBounds.size.height)
|
||||||
|
deltaY = -insetBounds.size.height;
|
||||||
|
if (deltaY > insetBounds.size.height)
|
||||||
|
deltaY = insetBounds.size.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([scrollView hasHorizontalScroller])
|
||||||
|
{
|
||||||
|
if (eventLocation.x < CGRectGetMinX(insetBounds))
|
||||||
|
deltaX = CGRectGetMinX(insetBounds) - eventLocation.x;
|
||||||
|
else if (eventLocation.x > CGRectGetMaxX(insetBounds))
|
||||||
|
deltaX = CGRectGetMaxX(insetBounds) - eventLocation.x;
|
||||||
|
if (deltaX < -insetBounds.size.width)
|
||||||
|
deltaX = -insetBounds.size.width;
|
||||||
|
if (deltaX > insetBounds.size.width)
|
||||||
|
deltaX = insetBounds.size.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
[contentView scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return dragOperation;
|
return dragOperation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)_sendPeriodicDraggingUpdate:(CPTimer)aTimer
|
||||||
|
{
|
||||||
|
var userInfo = [aTimer userInfo];
|
||||||
|
_dragOperation = [self draggingUpdatedInPlatformWindow:[userInfo objectForKey:@"platformWindow"]
|
||||||
|
location:[userInfo objectForKey:@"location"]];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)draggingEndedInPlatformWindow:(CPPlatformWindow)aPlatformWindow globalLocation:(CGPoint)aLocation operation:(CPDragOperation)anOperation
|
- (void)draggingEndedInPlatformWindow:(CPPlatformWindow)aPlatformWindow globalLocation:(CGPoint)aLocation operation:(CPDragOperation)anOperation
|
||||||
{
|
{
|
||||||
|
[_draggingUpdateTimer invalidate];
|
||||||
|
_draggingUpdateTimer = nil;
|
||||||
|
|
||||||
[_draggedView removeFromSuperview];
|
[_draggedView removeFromSuperview];
|
||||||
|
|
||||||
if (![CPPlatform supportsDragAndDrop])
|
if (![CPPlatform supportsDragAndDrop])
|
||||||
[_draggedWindow orderOut:self];
|
[_draggedWindow orderOut:self];
|
||||||
|
|
||||||
if (_implementedDraggingSourceMethods & CPDraggingSource_draggedImage_endAt_operation_)
|
if (_implementedDraggingSourceMethods & CPDraggingSource_draggedImage_endedAt_operation_)
|
||||||
[_draggingSource draggedImage:[_draggedView image] endedAt:aLocation operation:anOperation];
|
[_draggingSource draggedImage:[_draggedView image] endedAt:aLocation operation:anOperation];
|
||||||
|
|
||||||
else if (_implementedDraggingSourceMethods & CPDraggingSource_draggedView_endedAt_operation_)
|
else if (_implementedDraggingSourceMethods & CPDraggingSource_draggedView_endedAt_operation_)
|
||||||
[_draggingSource draggedView:_draggedView endedAt:aLocation operation:anOperation];
|
[_draggingSource draggedView:_draggedView endedAt:aLocation operation:anOperation];
|
||||||
|
|
||||||
@@ -296,6 +354,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
|||||||
_draggingPasteboard = aPasteboard || [CPPasteboard pasteboardWithName:CPDragPboard];
|
_draggingPasteboard = aPasteboard || [CPPasteboard pasteboardWithName:CPDragPboard];
|
||||||
_draggingSource = aSourceObject;
|
_draggingSource = aSourceObject;
|
||||||
_draggingDestination = nil;
|
_draggingDestination = nil;
|
||||||
|
_shouldSlideBack = slideBack;
|
||||||
|
|
||||||
// The offset is based on the distance from where we want the view to be initially from where the mouse is initially
|
// The offset is based on the distance from where we want the view to be initially from where the mouse is initially
|
||||||
// Hence the use of mouseDownEvent's location and view's location in global coordinates.
|
// Hence the use of mouseDownEvent's location and view's location in global coordinates.
|
||||||
@@ -310,7 +369,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
|||||||
_draggingOffset = _CGSizeMake(mouseDownEventLocation.x - viewLocation.x, mouseDownEventLocation.y - viewLocation.y);
|
_draggingOffset = _CGSizeMake(mouseDownEventLocation.x - viewLocation.x, mouseDownEventLocation.y - viewLocation.y);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
_draggingOffset = _CGSizeMakerZero();
|
_draggingOffset = _CGSizeMakeZero();
|
||||||
|
|
||||||
if ([CPPlatform isBrowser])
|
if ([CPPlatform isBrowser])
|
||||||
[_draggedWindow setPlatformWindow:[aWindow platformWindow]];
|
[_draggedWindow setPlatformWindow:[aWindow platformWindow]];
|
||||||
@@ -320,7 +379,8 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
|||||||
var mouseLocation = [CPEvent mouseLocation];
|
var mouseLocation = [CPEvent mouseLocation];
|
||||||
|
|
||||||
// Place it where the mouse pointer is.
|
// Place it where the mouse pointer is.
|
||||||
[_draggedWindow setFrameOrigin:_CGPointMake(mouseLocation.x - _draggingOffset.width, mouseLocation.y - _draggingOffset.height)];
|
_startDragLocation = _CGPointMake(mouseLocation.x - _draggingOffset.width, mouseLocation.y - _draggingOffset.height);
|
||||||
|
[_draggedWindow setFrameOrigin:_startDragLocation];
|
||||||
[_draggedWindow setFrameSize:[aView frame].size];
|
[_draggedWindow setFrameSize:[aView frame].size];
|
||||||
|
|
||||||
[[_draggedWindow contentView] addSubview:aView];
|
[[_draggedWindow contentView] addSubview:aView];
|
||||||
@@ -332,8 +392,8 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
|||||||
if ([_draggingSource respondsToSelector:@selector(draggedImage:movedTo:)])
|
if ([_draggingSource respondsToSelector:@selector(draggedImage:movedTo:)])
|
||||||
_implementedDraggingSourceMethods |= CPDraggingSource_draggedImage_movedTo_;
|
_implementedDraggingSourceMethods |= CPDraggingSource_draggedImage_movedTo_;
|
||||||
|
|
||||||
if ([_draggingSource respondsToSelector:@selector(draggedImage:endAt:operation:)])
|
if ([_draggingSource respondsToSelector:@selector(draggedImage:endedAt:operation:)])
|
||||||
_implementedDraggingSourceMethods |= CPDraggingSource_draggedImage_endAt_operation_;
|
_implementedDraggingSourceMethods |= CPDraggingSource_draggedImage_endedAt_operation_;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -385,19 +445,34 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
|||||||
|
|
||||||
if (type === CPLeftMouseUp)
|
if (type === CPLeftMouseUp)
|
||||||
{
|
{
|
||||||
|
// Make sure we do not finalize (cancel) the drag if the last drag update was disallowed
|
||||||
|
if (_dragOperation !== CPDragOperationNone)
|
||||||
[self performDragOperationInPlatformWindow:platformWindow];
|
[self performDragOperationInPlatformWindow:platformWindow];
|
||||||
[self draggingEndedInPlatformWindow:platformWindow globalLocation:platformWindowLocation operation:CPDragOperationNone];
|
|
||||||
|
[self draggingEndedInPlatformWindow:platformWindow globalLocation:platformWindowLocation operation:_dragOperation];
|
||||||
|
|
||||||
// Stop tracking events.
|
// Stop tracking events.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (type === CPKeyDown)
|
||||||
|
{
|
||||||
|
var keyCode = [anEvent keyCode];
|
||||||
|
if (keyCode === CPEscapeKeyCode)
|
||||||
|
{
|
||||||
|
_dragOperation = CPDragOperationNone;
|
||||||
|
[self draggingEndedInPlatformWindow:platformWindow globalLocation:CGPointMakeZero() operation:_dragOperation];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
[self draggingSourceUpdatedWithGlobalLocation:platformWindowLocation];
|
[self draggingSourceUpdatedWithGlobalLocation:platformWindowLocation];
|
||||||
[self draggingUpdatedInPlatformWindow:platformWindow location:platformWindowLocation];
|
_dragOperation = [self draggingUpdatedInPlatformWindow:platformWindow location:platformWindowLocation];
|
||||||
|
}
|
||||||
|
|
||||||
// If we're not a mouse up, then we're going to want to grab the next event.
|
// If we're not a mouse up, then we're going to want to grab the next event.
|
||||||
[CPApp setTarget:self selector:@selector(trackDragging:)
|
[CPApp setTarget:self selector:@selector(trackDragging:)
|
||||||
forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask
|
forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPKeyDownMask
|
||||||
untilDate:nil inMode:0 dequeue:NO];
|
untilDate:nil inMode:0 dequeue:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+138
-8
@@ -21,8 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
@import "CPText.j"
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
|
|
||||||
CPLeftMouseDown = 1;
|
CPLeftMouseDown = 1;
|
||||||
@@ -53,7 +52,6 @@ CPTouchMove = 29;
|
|||||||
CPTouchEnd = 30;
|
CPTouchEnd = 30;
|
||||||
CPTouchCancel = 31;
|
CPTouchCancel = 31;
|
||||||
|
|
||||||
|
|
||||||
CPAlphaShiftKeyMask = 1 << 16;
|
CPAlphaShiftKeyMask = 1 << 16;
|
||||||
CPShiftKeyMask = 1 << 17;
|
CPShiftKeyMask = 1 << 17;
|
||||||
CPControlKeyMask = 1 << 18;
|
CPControlKeyMask = 1 << 18;
|
||||||
@@ -87,6 +85,81 @@ CPPeriodicMask = 1 << CPPeriodic;
|
|||||||
CPScrollWheelMask = 1 << CPScrollWheel;
|
CPScrollWheelMask = 1 << CPScrollWheel;
|
||||||
CPAnyEventMask = 0xffffffff;
|
CPAnyEventMask = 0xffffffff;
|
||||||
|
|
||||||
|
CPUpArrowFunctionKey = "\uF700";
|
||||||
|
CPDownArrowFunctionKey = "\uF701";
|
||||||
|
CPLeftArrowFunctionKey = "\uF702";
|
||||||
|
CPRightArrowFunctionKey = "\uF703";
|
||||||
|
CPF1FunctionKey = "\uF704";
|
||||||
|
CPF2FunctionKey = "\uF705";
|
||||||
|
CPF3FunctionKey = "\uF706";
|
||||||
|
CPF4FunctionKey = "\uF707";
|
||||||
|
CPF5FunctionKey = "\uF708";
|
||||||
|
CPF6FunctionKey = "\uF709";
|
||||||
|
CPF7FunctionKey = "\uF70A";
|
||||||
|
CPF8FunctionKey = "\uF70B";
|
||||||
|
CPF9FunctionKey = "\uF70C";
|
||||||
|
CPF10FunctionKey = "\uF70D";
|
||||||
|
CPF11FunctionKey = "\uF70E";
|
||||||
|
CPF12FunctionKey = "\uF70F";
|
||||||
|
CPF13FunctionKey = "\uF710";
|
||||||
|
CPF14FunctionKey = "\uF711";
|
||||||
|
CPF15FunctionKey = "\uF712";
|
||||||
|
CPF16FunctionKey = "\uF713";
|
||||||
|
CPF17FunctionKey = "\uF714";
|
||||||
|
CPF18FunctionKey = "\uF715";
|
||||||
|
CPF19FunctionKey = "\uF716";
|
||||||
|
CPF20FunctionKey = "\uF717";
|
||||||
|
CPF21FunctionKey = "\uF718";
|
||||||
|
CPF22FunctionKey = "\uF719";
|
||||||
|
CPF23FunctionKey = "\uF71A";
|
||||||
|
CPF24FunctionKey = "\uF71B";
|
||||||
|
CPF25FunctionKey = "\uF71C";
|
||||||
|
CPF26FunctionKey = "\uF71D";
|
||||||
|
CPF27FunctionKey = "\uF71E";
|
||||||
|
CPF28FunctionKey = "\uF71F";
|
||||||
|
CPF29FunctionKey = "\uF720";
|
||||||
|
CPF30FunctionKey = "\uF721";
|
||||||
|
CPF31FunctionKey = "\uF722";
|
||||||
|
CPF32FunctionKey = "\uF723";
|
||||||
|
CPF33FunctionKey = "\uF724";
|
||||||
|
CPF34FunctionKey = "\uF725";
|
||||||
|
CPF35FunctionKey = "\uF726";
|
||||||
|
CPInsertFunctionKey = "\uF727";
|
||||||
|
CPDeleteFunctionKey = "\uF728";
|
||||||
|
CPHomeFunctionKey = "\uF729";
|
||||||
|
CPBeginFunctionKey = "\uF72A";
|
||||||
|
CPEndFunctionKey = "\uF72B";
|
||||||
|
CPPageUpFunctionKey = "\uF72C";
|
||||||
|
CPPageDownFunctionKey = "\uF72D";
|
||||||
|
CPPrintScreenFunctionKey = "\uF72E";
|
||||||
|
CPScrollLockFunctionKey = "\uF72F";
|
||||||
|
CPPauseFunctionKey = "\uF730";
|
||||||
|
CPSysReqFunctionKey = "\uF731";
|
||||||
|
CPBreakFunctionKey = "\uF732";
|
||||||
|
CPResetFunctionKey = "\uF733";
|
||||||
|
CPStopFunctionKey = "\uF734";
|
||||||
|
CPMenuFunctionKey = "\uF735";
|
||||||
|
CPUserFunctionKey = "\uF736";
|
||||||
|
CPSystemFunctionKey = "\uF737";
|
||||||
|
CPPrintFunctionKey = "\uF738";
|
||||||
|
CPClearLineFunctionKey = "\uF739";
|
||||||
|
CPClearDisplayFunctionKey = "\uF73A";
|
||||||
|
CPInsertLineFunctionKey = "\uF73B";
|
||||||
|
CPDeleteLineFunctionKey = "\uF73C";
|
||||||
|
CPInsertCharFunctionKey = "\uF73D";
|
||||||
|
CPDeleteCharFunctionKey = "\uF73E";
|
||||||
|
CPPrevFunctionKey = "\uF73F";
|
||||||
|
CPNextFunctionKey = "\uF740";
|
||||||
|
CPSelectFunctionKey = "\uF741";
|
||||||
|
CPExecuteFunctionKey = "\uF742";
|
||||||
|
CPUndoFunctionKey = "\uF743";
|
||||||
|
CPRedoFunctionKey = "\uF744";
|
||||||
|
CPFindFunctionKey = "\uF745";
|
||||||
|
CPHelpFunctionKey = "\uF746";
|
||||||
|
CPModeSwitchFunctionKey = "\uF747";
|
||||||
|
CPEscapeFunctionKey = "\u001B";
|
||||||
|
|
||||||
|
|
||||||
CPDOMEventDoubleClick = "dblclick",
|
CPDOMEventDoubleClick = "dblclick",
|
||||||
CPDOMEventMouseDown = "mousedown",
|
CPDOMEventMouseDown = "mousedown",
|
||||||
CPDOMEventMouseUp = "mouseup",
|
CPDOMEventMouseUp = "mouseup",
|
||||||
@@ -104,7 +177,8 @@ CPDOMEventTouchEnd = "touchend";
|
|||||||
CPDOMEventTouchCancel = "touchcancel";
|
CPDOMEventTouchCancel = "touchcancel";
|
||||||
|
|
||||||
var _CPEventPeriodicEventPeriod = 0,
|
var _CPEventPeriodicEventPeriod = 0,
|
||||||
_CPEventPeriodicEventTimer = nil;
|
_CPEventPeriodicEventTimer = nil,
|
||||||
|
_CPEventUpperCaseRegex = new RegExp("[A-Z]");
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -345,7 +419,10 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
*/
|
*/
|
||||||
- (int)buttonNumber
|
- (int)buttonNumber
|
||||||
{
|
{
|
||||||
return _buttonNumber;
|
if (_type === CPRightMouseDown || _type === CPRightMouseUp || _type === CPRightMouseDragged)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -442,12 +519,65 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
return _deltaZ;
|
return _deltaZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)_triggersKeyEquivalent:(CPString)aKeyEquivalent withModifierMask:aKeyEquivalentModifierMask
|
||||||
|
{
|
||||||
|
if (!aKeyEquivalent)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
if (_CPEventUpperCaseRegex.test(aKeyEquivalent))
|
||||||
|
aKeyEquivalentModifierMask |= CPShiftKeyMask;
|
||||||
|
|
||||||
|
if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (aKeyEquivalentModifierMask & CPCommandKeyMask))
|
||||||
|
{
|
||||||
|
aKeyEquivalentModifierMask |= CPControlKeyMask;
|
||||||
|
aKeyEquivalentModifierMask &= ~CPCommandKeyMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((_modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== aKeyEquivalentModifierMask)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
// Treat \r and \n as the same key equivalent. See issue #710.
|
||||||
|
if (_characters === CPNewlineCharacter || _characters === CPCarriageReturnCharacter)
|
||||||
|
return CPNewlineCharacter === aKeyEquivalent || CPCarriageReturnCharacter === aKeyEquivalent;
|
||||||
|
|
||||||
|
return [_characters caseInsensitiveCompare:aKeyEquivalent] === CPOrderedSame;
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)_couldBeKeyEquivalent
|
- (BOOL)_couldBeKeyEquivalent
|
||||||
{
|
{
|
||||||
|
if (_type !== CPKeyDown)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
var characterCount = _characters.length;
|
||||||
|
|
||||||
|
if (!characterCount)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
if (_modifierFlags & (CPCommandKeyMask | CPControlKeyMask))
|
||||||
|
return YES;
|
||||||
|
|
||||||
|
for(var i=0; i<characterCount; i++)
|
||||||
|
{
|
||||||
|
switch(_characters.charAt(i))
|
||||||
|
{
|
||||||
|
case CPBackspaceCharacter:
|
||||||
|
case CPDeleteCharacter:
|
||||||
|
case CPDeleteFunctionKey:
|
||||||
|
case CPTabCharacter:
|
||||||
|
case CPCarriageReturnCharacter:
|
||||||
|
case CPNewlineCharacter:
|
||||||
|
case CPEscapeFunctionKey:
|
||||||
|
case CPPageUpFunctionKey:
|
||||||
|
case CPPageDownFunctionKey:
|
||||||
|
case CPLeftArrowFunctionKey:
|
||||||
|
case CPUpArrowFunctionKey:
|
||||||
|
case CPRightArrowFunctionKey:
|
||||||
|
case CPDownArrowFunctionKey:
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
// FIXME: More cases? Space?
|
// FIXME: More cases? Space?
|
||||||
return _type === CPKeyDown &&
|
return NO;
|
||||||
_modifierFlags & (CPCommandKeyMask | CPControlKeyMask) &&
|
|
||||||
[_characters length] > 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
+29
-5
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@class CPFlashMovie
|
@class CPFlashMovie
|
||||||
@@ -30,7 +31,7 @@
|
|||||||
*/
|
*/
|
||||||
@implementation CPFlashMovie : CPObject
|
@implementation CPFlashMovie : CPObject
|
||||||
{
|
{
|
||||||
CPString _fileName;
|
CPString _filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -38,9 +39,9 @@
|
|||||||
@param aFilename the swf to load
|
@param aFilename the swf to load
|
||||||
@return the initialized CPFlashMovie
|
@return the initialized CPFlashMovie
|
||||||
*/
|
*/
|
||||||
+ (id)flashMovieWithFile:(CPString)aFileName
|
+ (id)flashMovieWithFile:(CPString)aFilename
|
||||||
{
|
{
|
||||||
return [[self alloc] initWithFile:aFileName];
|
return [[self alloc] initWithFile:aFilename];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -48,14 +49,37 @@
|
|||||||
@param aFilename the swf to load
|
@param aFilename the swf to load
|
||||||
@return the initialized CPFlashMovie
|
@return the initialized CPFlashMovie
|
||||||
*/
|
*/
|
||||||
- (id)initWithFile:(CPString)aFileName
|
- (id)initWithFile:(CPString)aFilename
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
_fileName = aFileName;
|
_filename = aFilename;
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CPString)filename
|
||||||
|
{
|
||||||
|
return _filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var CPFlashMovieFilenameKey = "CPFlashMovieFilenameKey";
|
||||||
|
|
||||||
|
@implementation CPFlashMovie (CPCoding)
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
_filename = [aCoder decodeObjectForKey:CPFlashMovieFilenameKey];
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
[aCoder encodeObject:_filename forKey:CPFlashMovieFilenameKey];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
+122
-31
@@ -24,6 +24,8 @@
|
|||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
|
||||||
|
|
||||||
|
var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
*/
|
*/
|
||||||
@@ -31,9 +33,13 @@
|
|||||||
{
|
{
|
||||||
CPFlashMovie _flashMovie;
|
CPFlashMovie _flashMovie;
|
||||||
|
|
||||||
DOMElement _DOMEmbedElement;
|
CPDictionary _params;
|
||||||
DOMElement _DOMMParamElement;
|
CPDictionary _paramElements;
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
DOMElement _DOMParamElement;
|
||||||
DOMElement _DOMObjectElement;
|
DOMElement _DOMObjectElement;
|
||||||
|
DOMElement _DOMInnerObjectElement;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
@@ -42,36 +48,33 @@
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_DOMObjectElement = document.createElement("object");
|
#if PLATFORM(DOM)
|
||||||
_DOMObjectElement.width = "100%";
|
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||||
_DOMObjectElement.height = "100%";
|
{
|
||||||
_DOMObjectElement.style.top = "0px";
|
_DOMObjectElement = document.createElement(@"object");
|
||||||
_DOMObjectElement.style.left = "0px";
|
_DOMObjectElement.width = @"100%";
|
||||||
|
_DOMObjectElement.height = @"100%";
|
||||||
|
_DOMObjectElement.style.top = @"0px";
|
||||||
|
_DOMObjectElement.style.left = @"0px";
|
||||||
|
_DOMObjectElement.type = @"application/x-shockwave-flash";
|
||||||
|
_DOMObjectElement.setAttribute(@"classid", IEFlashCLSID);
|
||||||
|
|
||||||
_DOMParamElement = document.createElement("param");
|
_DOMParamElement = document.createElement(@"param");
|
||||||
_DOMParamElement.name = "movie";
|
_DOMParamElement.name = @"movie";
|
||||||
|
|
||||||
|
_DOMInnerObjectElement = document.createElement(@"object");
|
||||||
|
_DOMInnerObjectElement.width = @"100%";
|
||||||
|
_DOMInnerObjectElement.height = @"100%";
|
||||||
|
|
||||||
_DOMObjectElement.appendChild(_DOMParamElement);
|
_DOMObjectElement.appendChild(_DOMParamElement);
|
||||||
|
_DOMObjectElement.appendChild(_DOMInnerObjectElement);
|
||||||
var param = document.createElement("param");
|
|
||||||
|
|
||||||
param.name = "wmode";
|
|
||||||
param.value = "transparent";
|
|
||||||
|
|
||||||
_DOMObjectElement.appendChild(param);
|
|
||||||
|
|
||||||
_DOMEmbedElement = document.createElement("embed");
|
|
||||||
|
|
||||||
_DOMEmbedElement.type = "application/x-shockwave-flash";
|
|
||||||
_DOMEmbedElement.setAttribute("wmode", "transparent");
|
|
||||||
_DOMEmbedElement.width = "100%";
|
|
||||||
_DOMEmbedElement.height = "100%";
|
|
||||||
|
|
||||||
// IE requires this thing to be in the _DOMElement and not the _DOMObjectElement.
|
|
||||||
_DOMElement.appendChild(_DOMEmbedElement);
|
|
||||||
|
|
||||||
_DOMElement.appendChild(_DOMObjectElement);
|
_DOMElement.appendChild(_DOMObjectElement);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
[self _rebuildIEObjects];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -82,11 +85,15 @@
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_flashMovie = aFlashMovie;
|
_flashMovie = aFlashMovie;
|
||||||
|
#if PLATFORM(DOM)
|
||||||
_DOMParamElement.value = aFlashMovie._fileName;
|
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||||
|
{
|
||||||
if (_DOMEmbedElement)
|
_DOMParamElement.value = [aFlashMovie filename];
|
||||||
_DOMEmbedElement.src = aFlashMovie._fileName;
|
_DOMInnerObjectElement.data = [aFlashMovie filename];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[self _rebuildIEObjects];
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPFlashMovie)flashMovie
|
- (CPFlashMovie)flashMovie
|
||||||
@@ -94,6 +101,90 @@
|
|||||||
return _flashMovie;
|
return _flashMovie;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setFlashVars:(CPDictionary)aDictionary
|
||||||
|
{
|
||||||
|
var varString = @"",
|
||||||
|
enumerator = [aDictionary keyEnumerator];
|
||||||
|
|
||||||
|
var key;
|
||||||
|
while (key = [enumerator nextObject])
|
||||||
|
varString = [varString stringByAppendingFormat:@"&%@=%@", key, [aDictionary objectForKey:key]];
|
||||||
|
|
||||||
|
if (!_params)
|
||||||
|
_params = [CPDictionary dictionary];
|
||||||
|
|
||||||
|
[_params setObject:varString forKey:@"flashvars"];
|
||||||
|
[self setParameters:_params];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPDictionary)flashVars
|
||||||
|
{
|
||||||
|
return [_params objectForKey:@"flashvars"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setParameters:(CPDictionary)aDictionary
|
||||||
|
{
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
if (_paramElements && !CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||||
|
{
|
||||||
|
var elements = [_paramElements allValues],
|
||||||
|
count = [elements count];
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
_DOMObjectElement.removeChild([elements objectAtIndex:i]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
_params = aDictionary;
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||||
|
{
|
||||||
|
_paramElements = [CPDictionary dictionary];
|
||||||
|
|
||||||
|
var enumerator = [_params keyEnumerator],
|
||||||
|
key;
|
||||||
|
|
||||||
|
while (key = [enumerator nextObject] && _DOMObjectElement)
|
||||||
|
{
|
||||||
|
var param = document.createElement(@"param");
|
||||||
|
param.name = key;
|
||||||
|
param.value = [_params objectForKey:key];
|
||||||
|
|
||||||
|
_DOMObjectElement.appendChild(param);
|
||||||
|
|
||||||
|
[_paramElements setObject:param forKey:key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[self _rebuildIEObjects];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPDictionary)parameters
|
||||||
|
{
|
||||||
|
return _params;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
- (void)_rebuildIEObjects
|
||||||
|
{
|
||||||
|
_DOMElement.innerHTML = @"";
|
||||||
|
if (![_flashMovie filename])
|
||||||
|
return;
|
||||||
|
|
||||||
|
var paramString = [CPString stringWithFormat:@"<param name='movie' value='%@' />", [_flashMovie filename]],
|
||||||
|
paramEnumerator = [_params keyEnumerator],
|
||||||
|
key;
|
||||||
|
|
||||||
|
while (key = [paramEnumerator nextObject])
|
||||||
|
paramString = [paramString stringByAppendingFormat:@"<param name='%@' value='%@' />", key, [_params objectForKey:key]];
|
||||||
|
|
||||||
|
_DOMObjectElement = document.createElement(@"object");
|
||||||
|
_DOMElement.appendChild(_DOMObjectElement);
|
||||||
|
|
||||||
|
_DOMObjectElement.outerHTML = [CPString stringWithFormat:@"<object classid=%@ width=%@ height=%@>%@</object>", IEFlashCLSID, CGRectGetWidth([self bounds]), CGRectGetHeight([self bounds]), paramString];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
- (void)mouseDragged:(CPEvent)anEvent
|
- (void)mouseDragged:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||||
|
|||||||
+83
-5
@@ -20,10 +20,19 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var _CPFonts = {};
|
@import <Foundation/CPObject.j>
|
||||||
_CPFontSystemFontFace = @"Arial";
|
@import <Foundation/CPBundle.j>
|
||||||
|
|
||||||
#define _CPCachedFont(aName, aSize, isBold) _CPFonts[(isBold ? @"bold " : @"") + ROUND(aSize) + @"px '" + aName + @"'"]
|
@import "CPView.j"
|
||||||
|
|
||||||
|
|
||||||
|
var _CPFonts = {},
|
||||||
|
_CPFontSystemFontFace = @"Arial, sans-serif",
|
||||||
|
_CPWrapRegExp = new RegExp("\\s*,\\s*", "g");
|
||||||
|
|
||||||
|
|
||||||
|
#define _CPCreateCSSString(aName, aSize, isBold) (isBold ? @"bold " : @"") + ROUND(aSize) + @"px " + ((aName === _CPFontSystemFontFace) ? aName : (@"\"" + aName.replace(_CPWrapRegExp, '", "') + @"\", " + _CPFontSystemFontFace))
|
||||||
|
#define _CPCachedFont(aName, aSize, isBold) _CPFonts[_CPCreateCSSString(aName, aSize, isBold)]
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -35,11 +44,22 @@ var _CPFonts = {};
|
|||||||
{
|
{
|
||||||
CPString _name;
|
CPString _name;
|
||||||
float _size;
|
float _size;
|
||||||
|
float _ascender;
|
||||||
|
float _descender;
|
||||||
|
float _lineHeight;
|
||||||
BOOL _isBold;
|
BOOL _isBold;
|
||||||
|
|
||||||
CPString _cssString;
|
CPString _cssString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
var systemFont = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:"CPSystemFontFace"];
|
||||||
|
|
||||||
|
if (systemFont)
|
||||||
|
_CPFontSystemFontFace = systemFont;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns a font with the specified name and size.
|
Returns a font with the specified name and size.
|
||||||
@param aName the name of the font
|
@param aName the name of the font
|
||||||
@@ -93,9 +113,12 @@ var _CPFonts = {};
|
|||||||
{
|
{
|
||||||
_name = aName;
|
_name = aName;
|
||||||
_size = aSize;
|
_size = aSize;
|
||||||
|
_ascender = 0;
|
||||||
|
_descender = 0;
|
||||||
|
_lineHeight = 0;
|
||||||
_isBold = isBold;
|
_isBold = isBold;
|
||||||
|
|
||||||
_cssString = (_isBold ? @"bold " : @"") + ROUND(aSize) + @"px '" + aName + @"'";
|
_cssString = _CPCreateCSSString(_name, _size, _isBold);
|
||||||
|
|
||||||
_CPFonts[_cssString] = self;
|
_CPFonts[_cssString] = self;
|
||||||
}
|
}
|
||||||
@@ -104,7 +127,43 @@ var _CPFonts = {};
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the font size (in points)
|
Returns the distance of the longest ascender's top y-coordinate from the baseline (in CSS px)
|
||||||
|
*/
|
||||||
|
- (float)ascender
|
||||||
|
{
|
||||||
|
if (!_ascender)
|
||||||
|
[self _getMetrics];
|
||||||
|
|
||||||
|
return _ascender;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the bottom y coordinate (in CSS px), offset from the baseline, of the receiver's longest descender.
|
||||||
|
Thus, if the longest descender extends 2 points below the baseline, descender will return –2.
|
||||||
|
*/
|
||||||
|
- (float)descender
|
||||||
|
{
|
||||||
|
if (!_descender)
|
||||||
|
[self _getMetrics];
|
||||||
|
|
||||||
|
return _descender;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the default line height.
|
||||||
|
|
||||||
|
NOTE: This was moved from NSFont to NSLayoutManager in Cocoa, but since there is no CPLayoutManager, it has been kept here.
|
||||||
|
*/
|
||||||
|
- (float)defaultLineHeightForFont
|
||||||
|
{
|
||||||
|
if (!_lineHeight)
|
||||||
|
[self _getMetrics];
|
||||||
|
|
||||||
|
return _lineHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the font size (in CSS px)
|
||||||
*/
|
*/
|
||||||
- (float)size
|
- (float)size
|
||||||
{
|
{
|
||||||
@@ -127,6 +186,25 @@ var _CPFonts = {};
|
|||||||
return _name;
|
return _name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEqual:(id)anObject
|
||||||
|
{
|
||||||
|
return [anObject isKindOfClass:[CPFont class]] && [anObject cssString] === [self cssString];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)description
|
||||||
|
{
|
||||||
|
return [CPString stringWithFormat:@"%@ %@ %f pt.", [super description], [self familyName], [self size]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_getMetrics
|
||||||
|
{
|
||||||
|
var metrics = [CPString metricsOfFont:self];
|
||||||
|
|
||||||
|
_ascender = [metrics objectForKey:@"ascender"];
|
||||||
|
_descender = [metrics objectForKey:@"descender"];
|
||||||
|
_lineHeight = [metrics objectForKey:@"lineHeight"];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPFontNameKey = @"CPFontNameKey",
|
var CPFontNameKey = @"CPFontNameKey",
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
@import <AppKit/CPFont.j>
|
@import "CPFont.j"
|
||||||
|
|
||||||
|
|
||||||
var CPSharedFontManager = nil,
|
var CPSharedFontManager = nil,
|
||||||
@@ -51,7 +51,7 @@ var CPSharedFontManager = nil,
|
|||||||
|
|
||||||
// Changing the Default Font Conversion Classes
|
// Changing the Default Font Conversion Classes
|
||||||
/*!
|
/*!
|
||||||
Sets the class that will be used to create the applcation's
|
Sets the class that will be used to create the application's
|
||||||
font manager.
|
font manager.
|
||||||
*/
|
*/
|
||||||
+ (void)setFontManagerFactory:(Class)aClass
|
+ (void)setFontManagerFactory:(Class)aClass
|
||||||
|
|||||||
@@ -380,6 +380,20 @@ function CPRectIsNull(aRect)
|
|||||||
return aRect.size.width <= 0.0 || aRect.size.height <= 0.0;
|
return aRect.size.width <= 0.0 || aRect.size.height <= 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Creates two rectangles -- slice and rem -- from inRect, by dividing inRect
|
||||||
|
with a line that's parallel to the side of inRect specified by edge.
|
||||||
|
The size of slice is determined by amount, which specifies the distance from edge.
|
||||||
|
|
||||||
|
slice and rem must not be NULL.
|
||||||
|
|
||||||
|
@group CGRect
|
||||||
|
*/
|
||||||
|
function CPDivideRect(inRect, slice, rem, amount, edge)
|
||||||
|
{
|
||||||
|
CGRectDivide(inRect, slice, rem, amount, edge);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns \c YES if the two CGSizes are identical.
|
Returns \c YES if the two CGSizes are identical.
|
||||||
@group CGSize
|
@group CGSize
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* CPGraphics.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Francisco Tolmasky.
|
||||||
|
* Copyright 2010, 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 "CPColor.j"
|
||||||
|
@import "CPGraphicsContext.j"
|
||||||
|
|
||||||
|
|
||||||
|
function CPDrawTiledRects(
|
||||||
|
/* CGRect */ boundsRect,
|
||||||
|
/* CGRect */ clipRect,
|
||||||
|
/* CPRectEdge[] */ sides,
|
||||||
|
/* float[] */ grays)
|
||||||
|
{
|
||||||
|
if (sides.length != grays.length)
|
||||||
|
[CPException raise:CPInvalidArgumentException reason:@"sides (length: " + sides.length + ") and grays (length: " + grays.length + ") must have the same length."];
|
||||||
|
|
||||||
|
var colors = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < grays.length; ++i)
|
||||||
|
colors.push([CPColor colorWithCalibratedWhite:grays[i] alpha:1.0]);
|
||||||
|
|
||||||
|
return CPDrawColorTiledRects(boundsRect, clipRect, sides, colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
function CPDrawColorTiledRects(
|
||||||
|
/* CGRect */ boundsRect,
|
||||||
|
/* CGRect */ clipRect,
|
||||||
|
/* CPRectEdge[] */ sides,
|
||||||
|
/* CPColor[] */ colors)
|
||||||
|
{
|
||||||
|
if (sides.length != colors.length)
|
||||||
|
[CPException raise:CPInvalidArgumentException reason:@"sides (length: " + sides.length + ") and colors (length: " + colors.length + ") must have the same length."];
|
||||||
|
|
||||||
|
var resultRect = _CGRectMakeCopy(boundsRect),
|
||||||
|
slice = _CGRectMakeZero(),
|
||||||
|
remainder = _CGRectMakeZero(),
|
||||||
|
context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||||
|
|
||||||
|
CGContextSaveGState(context);
|
||||||
|
CGContextSetLineWidth(context, 1.0);
|
||||||
|
|
||||||
|
for (var sideIndex = 0; sideIndex < sides.length; ++sideIndex)
|
||||||
|
{
|
||||||
|
var side = sides[sideIndex];
|
||||||
|
|
||||||
|
CGRectDivide(resultRect, slice, remainder, 1.0, side);
|
||||||
|
resultRect = remainder;
|
||||||
|
slice = CGRectIntersection(slice, clipRect);
|
||||||
|
|
||||||
|
// Cocoa docs say that only slices that are within the clipRect are actually drawn
|
||||||
|
if (_CGRectIsEmpty(slice))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var minX, maxX, minY, maxY;
|
||||||
|
|
||||||
|
if (side == CPMinXEdge || side == CPMaxXEdge)
|
||||||
|
{
|
||||||
|
// Make sure we have at least 1 pixel to draw a line
|
||||||
|
if (_CGRectGetWidth(slice) < 1.0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
minX = _CGRectGetMinX(slice) + 0.5;
|
||||||
|
maxX = minX;
|
||||||
|
minY = _CGRectGetMinY(slice);
|
||||||
|
maxY = _CGRectGetMaxY(slice);
|
||||||
|
}
|
||||||
|
else // CPMinYEdge || CPMaxYEdge
|
||||||
|
{
|
||||||
|
// Make sure we have at least 1 pixel to draw a line
|
||||||
|
if (_CGRectGetHeight(slice) < 1.0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
minX = _CGRectGetMinX(slice);
|
||||||
|
maxX = _CGRectGetMaxX(slice);
|
||||||
|
minY = _CGRectGetMinY(slice) + 0.5;
|
||||||
|
maxY = minY;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
CGContextMoveToPoint(context, minX, minY);
|
||||||
|
CGContextAddLineToPoint(context, maxX, maxY);
|
||||||
|
CGContextSetStrokeColor(context, colors[sideIndex]);
|
||||||
|
CGContextStrokePath(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
CGContextRestoreGState(context);
|
||||||
|
|
||||||
|
return resultRect;
|
||||||
|
}
|
||||||
@@ -20,6 +20,11 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
|
@import "CGContext.j"
|
||||||
|
|
||||||
|
|
||||||
var CPGraphicsContextCurrent = nil;
|
var CPGraphicsContextCurrent = nil;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
+66
-1
@@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
@import "CPGeometry.j"
|
@import "CPGeometry.j"
|
||||||
|
|
||||||
|
|
||||||
CPImageLoadStatusInitialized = 0;
|
CPImageLoadStatusInitialized = 0;
|
||||||
CPImageLoadStatusLoading = 1;
|
CPImageLoadStatusLoading = 1;
|
||||||
CPImageLoadStatusCompleted = 2;
|
CPImageLoadStatusCompleted = 2;
|
||||||
@@ -38,6 +39,16 @@ CPImageLoadStatusReadError = 6;
|
|||||||
|
|
||||||
CPImageDidLoadNotification = @"CPImageDidLoadNotification";
|
CPImageDidLoadNotification = @"CPImageDidLoadNotification";
|
||||||
|
|
||||||
|
// Image Names
|
||||||
|
CPImageNameColorPanel = @"CPImageNameColorPanel";
|
||||||
|
CPImageNameColorPanelHighlighted = @"CPImageNameColorPanelHighlighted";
|
||||||
|
|
||||||
|
var imagesForNames = { },
|
||||||
|
AppKitImageForNames = { };
|
||||||
|
|
||||||
|
AppKitImageForNames[CPImageNameColorPanel] = CGSizeMake(26.0, 29.0);
|
||||||
|
AppKitImageForNames[CPImageNameColorPanelHighlighted] = CGSizeMake(26.0, 29.0);
|
||||||
|
|
||||||
function CPImageInBundle(aFilename, aSize, aBundle)
|
function CPImageInBundle(aFilename, aSize, aBundle)
|
||||||
{
|
{
|
||||||
if (!aBundle)
|
if (!aBundle)
|
||||||
@@ -49,6 +60,11 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
|||||||
return [[CPImage alloc] initWithContentsOfFile:[aBundle pathForResource:aFilename]];
|
return [[CPImage alloc] initWithContentsOfFile:[aBundle pathForResource:aFilename]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function CPAppKitImage(aFilename, aSize)
|
||||||
|
{
|
||||||
|
return CPImageInBundle(aFilename, aSize, [CPBundle bundleForClass:[CPView class]]);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@class CPImage
|
@class CPImage
|
||||||
@@ -74,6 +90,7 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
|||||||
{
|
{
|
||||||
CGSize _size;
|
CGSize _size;
|
||||||
CPString _filename;
|
CPString _filename;
|
||||||
|
CPString _name;
|
||||||
|
|
||||||
id _delegate;
|
id _delegate;
|
||||||
unsigned _loadStatus;
|
unsigned _loadStatus;
|
||||||
@@ -165,6 +182,50 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
|||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (id)imageNamed:(CPString)aName
|
||||||
|
{
|
||||||
|
var image = imagesForNames[aName];
|
||||||
|
|
||||||
|
if (image)
|
||||||
|
return image;
|
||||||
|
|
||||||
|
var imageOrSize = AppKitImageForNames[aName];
|
||||||
|
|
||||||
|
if (!imageOrSize)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
if (!imageOrSize.isa)
|
||||||
|
{
|
||||||
|
imageOrSize = CPAppKitImage("CPImage/" + aName + ".png", imageOrSize);
|
||||||
|
|
||||||
|
[imageOrSize setName:aName];
|
||||||
|
|
||||||
|
AppKitImageForNames[aName] = imageOrSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return imageOrSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)setName:(CPString)aName
|
||||||
|
{
|
||||||
|
if (_name === aName)
|
||||||
|
return YES;
|
||||||
|
|
||||||
|
if (imagesForNames[aName])
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
_name = aName;
|
||||||
|
|
||||||
|
imagesForNames[aName] = self;
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)name
|
||||||
|
{
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the receiver's delegate.
|
Sets the receiver's delegate.
|
||||||
@param the delegate
|
@param the delegate
|
||||||
@@ -203,6 +264,7 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
|||||||
|
|
||||||
_loadStatus = CPImageLoadStatusLoading;
|
_loadStatus = CPImageLoadStatusLoading;
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
_image = new Image();
|
_image = new Image();
|
||||||
|
|
||||||
var isSynchronous = YES;
|
var isSynchronous = YES;
|
||||||
@@ -246,7 +308,10 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
|||||||
|
|
||||||
_image.src = _filename;
|
_image.src = _filename;
|
||||||
|
|
||||||
isSynchronous = NO;
|
// onload and friends may fire after this point but BEFORE the end of the run loop,
|
||||||
|
// crazy, I know. So don't set isSynchronous here, rather wait a bit longer.
|
||||||
|
window.setTimeout(function() { isSynchronous = NO; }, 0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isThreePartImage
|
- (BOOL)isThreePartImage
|
||||||
|
|||||||
+96
-21
@@ -26,30 +26,23 @@
|
|||||||
@import "CPImage.j"
|
@import "CPImage.j"
|
||||||
@import "CPShadowView.j"
|
@import "CPShadowView.j"
|
||||||
|
|
||||||
#include "Platform/Platform.h"
|
|
||||||
#include "Platform/DOM/CPDOMDisplayServer.h"
|
|
||||||
|
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPImageScaling
|
|
||||||
*/
|
|
||||||
CPScaleProportionally = 0;
|
CPScaleProportionally = 0;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPImageScaling
|
|
||||||
*/
|
|
||||||
CPScaleToFit = 1;
|
CPScaleToFit = 1;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPImageScaling
|
|
||||||
*/
|
|
||||||
CPScaleNone = 2;
|
CPScaleNone = 2;
|
||||||
|
|
||||||
|
CPImageAlignCenter = 0;
|
||||||
|
CPImageAlignTop = 1;
|
||||||
|
CPImageAlignTopLeft = 2;
|
||||||
|
CPImageAlignTopRight = 3;
|
||||||
|
CPImageAlignLeft = 4;
|
||||||
|
CPImageAlignBottom = 5;
|
||||||
|
CPImageAlignBottomLeft = 6;
|
||||||
|
CPImageAlignBottomRight = 7;
|
||||||
|
CPImageAlignRight = 8;
|
||||||
|
|
||||||
var CPImageViewShadowBackgroundColor = nil;
|
var CPImageViewShadowBackgroundColor = nil,
|
||||||
|
CPImageViewEmptyPlaceholderImage = nil;
|
||||||
|
|
||||||
var LEFT_SHADOW_INSET = 3.0,
|
var LEFT_SHADOW_INSET = 3.0,
|
||||||
RIGHT_SHADOW_INSET = 3.0,
|
RIGHT_SHADOW_INSET = 3.0,
|
||||||
@@ -74,6 +67,14 @@ var LEFT_SHADOW_INSET = 3.0,
|
|||||||
BOOL _isEditable;
|
BOOL _isEditable;
|
||||||
|
|
||||||
CGRect _imageRect;
|
CGRect _imageRect;
|
||||||
|
CPImageAlignment _imageAlignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
var bundle = [CPBundle bundleForClass:[CPView class]];
|
||||||
|
|
||||||
|
CPImageViewEmptyPlaceholderImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"empty.png"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
@@ -134,7 +135,7 @@ var LEFT_SHADOW_INSET = 3.0,
|
|||||||
var newImage = [self objectValue];
|
var newImage = [self objectValue];
|
||||||
|
|
||||||
#if PLATFORM(DOM)
|
#if PLATFORM(DOM)
|
||||||
_DOMImageElement.src = newImage ? [newImage filename] : "";
|
_DOMImageElement.src = newImage ? [newImage filename] : [CPImageViewEmptyPlaceholderImage filename];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
var size = [newImage size];
|
var size = [newImage size];
|
||||||
@@ -205,6 +206,30 @@ var LEFT_SHADOW_INSET = 3.0,
|
|||||||
[self hideOrDisplayContents];
|
[self hideOrDisplayContents];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the type of image alignment that should be used to
|
||||||
|
render the image.
|
||||||
|
@param anImageAlignment the type of scaling to use
|
||||||
|
*/
|
||||||
|
- (void)setImageAlignment:(CPImageAlignment)anImageAlignment
|
||||||
|
{
|
||||||
|
if (_imageAlignment == anImageAlignment)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_imageAlignment = anImageAlignment;
|
||||||
|
|
||||||
|
if (![self image])
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (unsigned)imageAlignment
|
||||||
|
{
|
||||||
|
return _imageAlignment;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the type of image scaling that should be used to
|
Sets the type of image scaling that should be used to
|
||||||
render the image.
|
render the image.
|
||||||
@@ -225,6 +250,11 @@ var LEFT_SHADOW_INSET = 3.0,
|
|||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (unsigned)imageScaling
|
||||||
|
{
|
||||||
|
return [self currentValueForThemeAttribute:@"image-scaling"];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Toggles the display of the image view.
|
Toggles the display of the image view.
|
||||||
*/
|
*/
|
||||||
@@ -327,8 +357,45 @@ var LEFT_SHADOW_INSET = 3.0,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
var x = (boundsWidth - width) / 2.0,
|
var x, y;
|
||||||
|
|
||||||
|
switch (_imageAlignment)
|
||||||
|
{
|
||||||
|
case CPImageAlignLeft:
|
||||||
|
case CPImageAlignTopLeft:
|
||||||
|
case CPImageAlignBottomLeft:
|
||||||
|
x = 0.0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPImageAlignRight:
|
||||||
|
case CPImageAlignTopRight:
|
||||||
|
case CPImageAlignBottomRight:
|
||||||
|
x = boundsWidth - width;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
x = (boundsWidth - width) / 2.0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (_imageAlignment)
|
||||||
|
{
|
||||||
|
case CPImageAlignTop:
|
||||||
|
case CPImageAlignTopLeft:
|
||||||
|
case CPImageAlignTopRight:
|
||||||
|
y = 0.0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPImageAlignBottom:
|
||||||
|
case CPImageAlignBottomLeft:
|
||||||
|
case CPImageAlignBottomRight:
|
||||||
|
y = boundsHeight - height;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
y = (boundsHeight - height) / 2.0;
|
y = (boundsHeight - height) / 2.0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
#if PLATFORM(DOM)
|
#if PLATFORM(DOM)
|
||||||
CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, x, y);
|
CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, x, y);
|
||||||
@@ -374,18 +441,24 @@ var LEFT_SHADOW_INSET = 3.0,
|
|||||||
return _isEditable;
|
return _isEditable;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)performDragOperation:(CPDraggingInfo)aSender
|
- (BOOL)performDragOperation:(CPDraggingInfo)aSender
|
||||||
{
|
{
|
||||||
var images = [CPKeyedUnarchiver unarchiveObjectWithData:[[aSender draggingPasteboard] dataForType:CPImagesPboardType]];
|
var images = [CPKeyedUnarchiver unarchiveObjectWithData:[[aSender draggingPasteboard] dataForType:CPImagesPboardType]];
|
||||||
|
|
||||||
if ([images count])
|
if ([images count])
|
||||||
|
{
|
||||||
[self setImage:images[0]];
|
[self setImage:images[0]];
|
||||||
|
[self sendAction:[self action] to:[self target]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPImageViewImageKey = @"CPImageViewImageKey",
|
var CPImageViewImageKey = @"CPImageViewImageKey",
|
||||||
CPImageViewImageScalingKey = @"CPImageViewImageScalingKey",
|
CPImageViewImageScalingKey = @"CPImageViewImageScalingKey",
|
||||||
|
CPImageViewImageAlignmentKey = @"CPImageViewImageAlignmentKey",
|
||||||
CPImageViewHasShadowKey = @"CPImageViewHasShadowKey",
|
CPImageViewHasShadowKey = @"CPImageViewHasShadowKey",
|
||||||
CPImageViewIsEditableKey = @"CPImageViewIsEditableKey";
|
CPImageViewIsEditableKey = @"CPImageViewIsEditableKey";
|
||||||
|
|
||||||
@@ -420,6 +493,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
[self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]];
|
[self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]];
|
||||||
|
[self setImageAlignment:[aCoder decodeIntForKey:CPImageViewImageAlignmentKey]];
|
||||||
|
|
||||||
if ([aCoder decodeBoolForKey:CPImageViewIsEditableKey] || NO)
|
if ([aCoder decodeBoolForKey:CPImageViewIsEditableKey] || NO)
|
||||||
[self setEditable:YES];
|
[self setEditable:YES];
|
||||||
@@ -454,6 +528,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
|
|||||||
_subviews = actualSubviews;
|
_subviews = actualSubviews;
|
||||||
|
|
||||||
[aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey];
|
[aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey];
|
||||||
|
[aCoder encodeInt:_imageAlignment forKey:CPImageViewImageAlignmentKey];
|
||||||
|
|
||||||
if (_isEditable)
|
if (_isEditable)
|
||||||
[aCoder encodeBool:_isEditable forKey:CPImageViewIsEditableKey];
|
[aCoder encodeBool:_isEditable forKey:CPImageViewIsEditableKey];
|
||||||
|
|||||||
@@ -0,0 +1,263 @@
|
|||||||
|
/*
|
||||||
|
* CPKeyBinding.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Nicholas Small.
|
||||||
|
* Copyright 2010, 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 "CPEvent.j"
|
||||||
|
|
||||||
|
|
||||||
|
CPStandardKeyBindings = {
|
||||||
|
@"@.": @"cancelOperation:",
|
||||||
|
|
||||||
|
@"^a": @"moveToBeginningOfParagraph:",
|
||||||
|
@"^$a": @"moveToBeginningOfParagraphAndModifySelection:",
|
||||||
|
@"^b": @"moveBackward:",
|
||||||
|
@"^$b": @"moveBackwardAndModifySelection:",
|
||||||
|
@"^~b": @"moveWordBackward:",
|
||||||
|
@"^~$b": @"moveWordBackwardAndModifySelection:",
|
||||||
|
@"^d": @"deleteForward:",
|
||||||
|
@"^e": @"moveToEndOfParagraph:",
|
||||||
|
@"^$e": @"moveToEndOfParagraphAndModifySelection:",
|
||||||
|
@"^f": @"moveForward:",
|
||||||
|
@"^$f": @"moveForwardAndModifySelection:",
|
||||||
|
@"^~f": @"moveWordForward:",
|
||||||
|
@"^~$f": @"moveWordForwardAndModifySelection:",
|
||||||
|
@"^h": @"deleteBackward:",
|
||||||
|
@"^k": @"deleteToEndOfParagraph:",
|
||||||
|
@"^l": @"centerSelectionInVisibleArea:",
|
||||||
|
@"^n": @"moveDown:",
|
||||||
|
@"^$n": @"moveDownAndModifySelection:",
|
||||||
|
@"^o": [@"insertNewlineIgnoringFieldEditor:", @"moveBackward:"],
|
||||||
|
@"^p": @"moveUp:",
|
||||||
|
@"^$p": @"moveUpAndModifySelection:",
|
||||||
|
@"^t": @"transpose:",
|
||||||
|
@"^v": @"pageDown:",
|
||||||
|
@"^$v": @"pageDownAndModifySelection:",
|
||||||
|
@"^y": @"yank:"
|
||||||
|
};
|
||||||
|
|
||||||
|
CPStandardKeyBindings[CPNewlineCharacter] = @"insertNewline:";
|
||||||
|
CPStandardKeyBindings[CPCarriageReturnCharacter] = @"insertNewline:";
|
||||||
|
CPStandardKeyBindings[CPEnterCharacter] = @"insertNewline:";
|
||||||
|
CPStandardKeyBindings[@"~" + CPNewlineCharacter] = @"insertNewlineIgnoringFieldEditor:";
|
||||||
|
CPStandardKeyBindings[@"~" + CPCarriageReturnCharacter] = @"insertNewlineIgnoringFieldEditor:";
|
||||||
|
CPStandardKeyBindings[@"~" + CPEnterCharacter] = @"insertNewlineIgnoringFieldEditor:";
|
||||||
|
CPStandardKeyBindings[@"^" + CPNewlineCharacter] = @"insertLineBreak:";
|
||||||
|
CPStandardKeyBindings[@"^" + CPCarriageReturnCharacter] = @"insertLineBreak:";
|
||||||
|
CPStandardKeyBindings[@"^" + CPEnterCharacter] = @"insertLineBreak:";
|
||||||
|
|
||||||
|
CPStandardKeyBindings[CPBackspaceCharacter] = @"deleteBackward:";
|
||||||
|
CPStandardKeyBindings[@"~" + CPBackspaceCharacter] = @"deleteWordBackward:";
|
||||||
|
CPStandardKeyBindings[CPDeleteCharacter] = @"deleteBackward:";
|
||||||
|
CPStandardKeyBindings[@"@" + CPDeleteCharacter] = @"deleteToBeginningOfLine:";
|
||||||
|
CPStandardKeyBindings[@"~" + CPDeleteCharacter] = @"deleteWordBackward:";
|
||||||
|
CPStandardKeyBindings[@"^" + CPDeleteCharacter] = @"deleteBackwardByDecomposingPreviousCharacter:";
|
||||||
|
CPStandardKeyBindings[@"^~" + CPDeleteCharacter] = @"deleteWordBackward:";
|
||||||
|
|
||||||
|
CPStandardKeyBindings[CPDeleteFunctionKey] = @"deleteForward:";
|
||||||
|
CPStandardKeyBindings[@"~" + CPDeleteFunctionKey] = @"deleteWordForward:";
|
||||||
|
|
||||||
|
CPStandardKeyBindings[CPTabCharacter] = @"insertTab:";
|
||||||
|
CPStandardKeyBindings[@"~" + CPTabCharacter] = @"insertTabIgnoringFieldEditor:";
|
||||||
|
CPStandardKeyBindings[@"^" + CPTabCharacter] = @"selectNextKeyView:";
|
||||||
|
CPStandardKeyBindings[CPBackTabCharacter] = @"insertBacktab:";
|
||||||
|
CPStandardKeyBindings[@"^" + CPBackTabCharacter] = @"selectPreviousKeyView:";
|
||||||
|
|
||||||
|
CPStandardKeyBindings[CPEscapeFunctionKey] = @"cancelOperation:";
|
||||||
|
CPStandardKeyBindings[@"~" + CPEscapeFunctionKey] = @"complete:";
|
||||||
|
CPStandardKeyBindings[CPF5FunctionKey] = @"complete:";
|
||||||
|
|
||||||
|
CPStandardKeyBindings[CPLeftArrowFunctionKey] = @"moveLeft:";
|
||||||
|
CPStandardKeyBindings[@"~" + CPLeftArrowFunctionKey] = @"moveWordLeft:";
|
||||||
|
CPStandardKeyBindings[@"^" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLine:";
|
||||||
|
CPStandardKeyBindings[@"@" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLine:";
|
||||||
|
CPStandardKeyBindings[@"$" + CPLeftArrowFunctionKey] = @"moveLeftAndModifySelection:";
|
||||||
|
CPStandardKeyBindings[@"$~" + CPLeftArrowFunctionKey] = @"moveWordLeftAndModifySelection:";
|
||||||
|
CPStandardKeyBindings[@"$^" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLineAndModifySelection:";
|
||||||
|
CPStandardKeyBindings[@"$@" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLineAndModifySelection:";
|
||||||
|
CPStandardKeyBindings[@"@^" + CPLeftArrowFunctionKey] = @"makeBaseWritingDirectionRightToLeft:";
|
||||||
|
CPStandardKeyBindings[@"@^~" + CPLeftArrowFunctionKey] = @"makeTextWritingDirectionRightToLeft:";
|
||||||
|
|
||||||
|
CPStandardKeyBindings[CPRightArrowFunctionKey] = @"moveRight:";
|
||||||
|
CPStandardKeyBindings[@"~" + CPRightArrowFunctionKey] = @"moveWordRight:";
|
||||||
|
CPStandardKeyBindings[@"^" + CPRightArrowFunctionKey] = @"moveToRightEndOfLine:";
|
||||||
|
CPStandardKeyBindings[@"@" + CPRightArrowFunctionKey] = @"moveToRightEndOfLine:";
|
||||||
|
CPStandardKeyBindings[@"$" + CPRightArrowFunctionKey] = @"moveRightAndModifySelection:";
|
||||||
|
CPStandardKeyBindings[@"$~" + CPRightArrowFunctionKey] = @"moveWordRightAndModifySelection:";
|
||||||
|
CPStandardKeyBindings[@"$^" + CPRightArrowFunctionKey] = @"moveToRightEndOfLineAndModifySelection:";
|
||||||
|
CPStandardKeyBindings[@"$@" + CPRightArrowFunctionKey] = @"moveToRightEndOfLineAndModifySelection:";
|
||||||
|
CPStandardKeyBindings[@"@^" + CPRightArrowFunctionKey] = @"makeBaseWritingDirectionLeftToRight:";
|
||||||
|
CPStandardKeyBindings[@"@^~" + CPRightArrowFunctionKey] = @"makeTextWritingDirectionLeftToRight:";
|
||||||
|
|
||||||
|
CPStandardKeyBindings[CPUpArrowFunctionKey] = @"moveUp:";
|
||||||
|
CPStandardKeyBindings[@"~" + CPUpArrowFunctionKey] = [@"moveBackward:", @"moveToBeginningOfParagraph:"];
|
||||||
|
CPStandardKeyBindings[@"^" + CPUpArrowFunctionKey] = @"scrollPageUp:";
|
||||||
|
CPStandardKeyBindings[@"@" + CPUpArrowFunctionKey] = @"moveToBeginningOfDocument:";
|
||||||
|
CPStandardKeyBindings[@"$" + CPUpArrowFunctionKey] = @"moveUpAndModifySelection:";
|
||||||
|
CPStandardKeyBindings[@"$~" + CPUpArrowFunctionKey] = @"moveParagraphBackwardAndModifySelection:";
|
||||||
|
CPStandardKeyBindings[@"$@" + CPUpArrowFunctionKey] = @"moveToBeginningOfDocumentAndModifySelection:";
|
||||||
|
|
||||||
|
CPStandardKeyBindings[CPDownArrowFunctionKey] = @"moveDown:";
|
||||||
|
CPStandardKeyBindings[@"~" + CPDownArrowFunctionKey] = [@"moveForward:", @"moveToEndOfParagraph:"];
|
||||||
|
CPStandardKeyBindings[@"^" + CPDownArrowFunctionKey] = @"scrollPageDown:";
|
||||||
|
CPStandardKeyBindings[@"@" + CPDownArrowFunctionKey] = @"moveToEndOfDocument:";
|
||||||
|
CPStandardKeyBindings[@"$" + CPDownArrowFunctionKey] = @"moveDownAndModifySelection:";
|
||||||
|
CPStandardKeyBindings[@"$~" + CPDownArrowFunctionKey] = @"moveParagraphForwardAndModifySelection:";
|
||||||
|
CPStandardKeyBindings[@"$@" + CPDownArrowFunctionKey] = @"moveToEndOfDocumentAndModifySelection:";
|
||||||
|
CPStandardKeyBindings[@"@^" + CPDownArrowFunctionKey] = @"makeBaseWritingDirectionNatural:";
|
||||||
|
CPStandardKeyBindings[@"@^~" + CPDownArrowFunctionKey] = @"makeTextWritingDirectionNatural:";
|
||||||
|
|
||||||
|
CPStandardKeyBindings[CPHomeFunctionKey] = @"scrollToBeginningOfDocument:";
|
||||||
|
CPStandardKeyBindings[@"$" + CPHomeFunctionKey] = @"moveToBeginningOfDocumentAndModifySelection:";
|
||||||
|
CPStandardKeyBindings[CPEndFunctionKey] = @"scrollToEndOfDocument:";
|
||||||
|
CPStandardKeyBindings[@"$" + CPEndFunctionKey] = @"moveToEndOfDocumentAndModifySelection:";
|
||||||
|
|
||||||
|
CPStandardKeyBindings[CPPageUpFunctionKey] = @"scrollPageUp:";
|
||||||
|
CPStandardKeyBindings[@"~" + CPPageUpFunctionKey] = @"pageUp:";
|
||||||
|
CPStandardKeyBindings[@"$" + CPPageUpFunctionKey] = @"pageUpAndModifySelection:";
|
||||||
|
CPStandardKeyBindings[CPPageDownFunctionKey] = @"scrollPageDown:";
|
||||||
|
CPStandardKeyBindings[@"~" + CPPageDownFunctionKey] = @"pageDown:";
|
||||||
|
CPStandardKeyBindings[@"$" + CPPageDownFunctionKey] = @"pageDownAndModifySelection:";
|
||||||
|
|
||||||
|
var CPKeyBindingCache = {};
|
||||||
|
|
||||||
|
@implementation CPKeyBinding : CPObject
|
||||||
|
{
|
||||||
|
CPString _key;
|
||||||
|
unsigned _modifierFlags;
|
||||||
|
|
||||||
|
CPArray _selectors;
|
||||||
|
|
||||||
|
CPString _cacheName;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
if ([self class] !== CPKeyBinding)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self createKeyBindingsFromJSObject:CPStandardKeyBindings];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)createKeyBindingsFromJSObject:(JSObject)anObject
|
||||||
|
{
|
||||||
|
var binding;
|
||||||
|
for (binding in anObject)
|
||||||
|
[self cacheKeyBinding:[[CPKeyBinding alloc] initWithPhysicalKeyString:binding selectors:anObject[binding]]];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)cacheKeyBinding:(CPKeyBinding)aBinding
|
||||||
|
{
|
||||||
|
if (!aBinding)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CPKeyBindingCache[[aBinding _cacheName]] = aBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPKeyBinding)keyBindingForKey:(CPString)aKey modifierFlags:(unsigned)aFlag
|
||||||
|
{
|
||||||
|
var tempBinding = [[self alloc] initWithKey:aKey modifierFlags:aFlag selectors:nil];
|
||||||
|
return CPKeyBindingCache[[tempBinding _cacheName]];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPArray)selectorsForKey:(CPString)aKey modifierFlags:(unsigned)aFlag
|
||||||
|
{
|
||||||
|
return [[self keyBindingForKey:aKey modifierFlags:aFlag] selectors];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithPhysicalKeyString:(CPString)binding selectors:(CPArray)selectors
|
||||||
|
{
|
||||||
|
var components = binding.split(@""),
|
||||||
|
modifierFlags = ([components containsObject:@"$"] ? CPShiftKeyMask : 0) |
|
||||||
|
([components containsObject:@"^"] ? CPControlKeyMask : 0) |
|
||||||
|
([components containsObject:@"~"] ? CPAlternateKeyMask : 0) |
|
||||||
|
([components containsObject:@"@"] ? CPCommandKeyMask : 0);
|
||||||
|
|
||||||
|
if (![selectors isKindOfClass:CPArray])
|
||||||
|
selectors = [selectors];
|
||||||
|
|
||||||
|
return [self initWithKey:[components lastObject] modifierFlags:modifierFlags selectors:selectors];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithKey:(CPString)aKey modifierFlags:(unsigned)aFlag selectors:(CPArray)selectors
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_key = aKey;
|
||||||
|
_modifierFlags = aFlag;
|
||||||
|
|
||||||
|
_selectors = selectors;
|
||||||
|
|
||||||
|
// We normalize our key binding string in order to properly cache it.
|
||||||
|
// We want to ensure the modifiers are always in the same order.
|
||||||
|
var cacheName = [];
|
||||||
|
|
||||||
|
if (_modifierFlags & CPCommandKeyMask)
|
||||||
|
cacheName.push(@"@");
|
||||||
|
if (_modifierFlags & CPControlKeyMask)
|
||||||
|
cacheName.push(@"^");
|
||||||
|
if (_modifierFlags & CPAlternateKeyMask)
|
||||||
|
cacheName.push(@"~");
|
||||||
|
if (_modifierFlags & CPShiftKeyMask)
|
||||||
|
cacheName.push(@"$");
|
||||||
|
|
||||||
|
cacheName.push(_key);
|
||||||
|
|
||||||
|
_cacheName = cacheName.join(@"");
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)key
|
||||||
|
{
|
||||||
|
return _key;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (unsigned)modifierFlags
|
||||||
|
{
|
||||||
|
return _modifierFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPArray)selectors
|
||||||
|
{
|
||||||
|
return _selectors;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)_cacheName
|
||||||
|
{
|
||||||
|
return _cacheName;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEqual:(CPKeyBinding)rhs
|
||||||
|
{
|
||||||
|
return _key === [rhs key] && _modifierFlags === [rhs modifierFlags];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)description
|
||||||
|
{
|
||||||
|
return [CPString stringWithFormat:@"<KeyBinding string: '%@' modifierFlags: 0x%lx selectors: %@>", _key, _modifierFlags, _selectors];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,472 @@
|
|||||||
|
/*
|
||||||
|
* CPKeyValueBinding.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Ross Boucher 1/13/09
|
||||||
|
* Copyright 280 North, Inc.
|
||||||
|
*
|
||||||
|
* Adapted from GNUStep
|
||||||
|
* Released under the LGPL.
|
||||||
|
*
|
||||||
|
* 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/CPArray.j>
|
||||||
|
@import <Foundation/CPDictionary.j>
|
||||||
|
@import <Foundation/CPValueTransformer.j>
|
||||||
|
|
||||||
|
|
||||||
|
var exposedBindingsMap = [CPDictionary new],
|
||||||
|
bindingsMap = [CPDictionary new];
|
||||||
|
|
||||||
|
var CPBindingOperationAnd = 0,
|
||||||
|
CPBindingOperationOr = 1;
|
||||||
|
|
||||||
|
@implementation CPKeyValueBinding : CPObject
|
||||||
|
{
|
||||||
|
CPDictionary _info;
|
||||||
|
id _source;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)exposeBinding:(CPString)aBinding forClass:(Class)aClass
|
||||||
|
{
|
||||||
|
var bindings = [exposedBindingsMap objectForKey:[aClass hash]];
|
||||||
|
|
||||||
|
if (!bindings)
|
||||||
|
{
|
||||||
|
bindings = [];
|
||||||
|
[exposedBindingsMap setObject:bindings forKey:[aClass hash]];
|
||||||
|
}
|
||||||
|
|
||||||
|
bindings.push(aBinding);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPArray)exposedBindingsForClass:(Class)aClass
|
||||||
|
{
|
||||||
|
return [[exposedBindingsMap objectForKey:[aClass hash]] copy];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPKeyValueBinding)getBinding:(CPString)aBinding forObject:(id)anObject
|
||||||
|
{
|
||||||
|
return [[bindingsMap objectForKey:[anObject hash]] objectForKey:aBinding];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPDictionary)infoForBinding:(CPString)aBinding forObject:(id)anObject
|
||||||
|
{
|
||||||
|
var theBinding = [self getBinding:aBinding forObject:anObject];
|
||||||
|
|
||||||
|
if (theBinding)
|
||||||
|
return theBinding._info;
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPDictionary)allBindingsForObject:(id)anObject
|
||||||
|
{
|
||||||
|
return [bindingsMap objectForKey:[anObject hash]];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)unbind:(CPString)aBinding forObject:(id)anObject
|
||||||
|
{
|
||||||
|
var bindings = [bindingsMap objectForKey:[anObject hash]];
|
||||||
|
|
||||||
|
if (!bindings)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var theBinding = [bindings objectForKey:aBinding];
|
||||||
|
|
||||||
|
if (!theBinding)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var infoDictionary = theBinding._info,
|
||||||
|
observedObject = [infoDictionary objectForKey:CPObservedObjectKey],
|
||||||
|
keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey];
|
||||||
|
|
||||||
|
[observedObject removeObserver:theBinding forKeyPath:keyPath];
|
||||||
|
[bindings removeObjectForKey:aBinding];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)unbindAllForObject:(id)anObject
|
||||||
|
{
|
||||||
|
var bindings = [bindingsMap objectForKey:[anObject hash]];
|
||||||
|
if (!bindings)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var allKeys = [bindings allKeys],
|
||||||
|
count = allKeys.length;
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
[anObject unbind:[bindings objectForKey:allKeys[count]]];
|
||||||
|
|
||||||
|
[bindingsMap removeObjectForKey:[anObject hash]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithBinding:(CPString)aBinding name:(CPString)aName to:(id)aDestination keyPath:(CPString)aKeyPath options:(CPDictionary)options from:(id)aSource
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_source = aSource;
|
||||||
|
_info = [CPDictionary dictionaryWithObjects:[aDestination, aKeyPath] forKeys:[CPObservedObjectKey, CPObservedKeyPathKey]];
|
||||||
|
|
||||||
|
if (options)
|
||||||
|
[_info setObject:options forKey:CPOptionsKey];
|
||||||
|
|
||||||
|
[aDestination addObserver:self forKeyPath:aKeyPath options:CPKeyValueObservingOptionNew context:aBinding];
|
||||||
|
|
||||||
|
var bindings = [bindingsMap objectForKey:[_source hash]];
|
||||||
|
if (!bindings)
|
||||||
|
{
|
||||||
|
bindings = [CPDictionary new];
|
||||||
|
[bindingsMap setObject:bindings forKey:[_source hash]];
|
||||||
|
}
|
||||||
|
|
||||||
|
[bindings setObject:self forKey:aName];
|
||||||
|
[self setValueFor:aBinding];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setValueFor:(CPString)aBinding
|
||||||
|
{
|
||||||
|
var destination = [_info objectForKey:CPObservedObjectKey],
|
||||||
|
keyPath = [_info objectForKey:CPObservedKeyPathKey],
|
||||||
|
options = [_info objectForKey:CPOptionsKey],
|
||||||
|
newValue = [destination valueForKeyPath:keyPath],
|
||||||
|
isPlaceholder = CPIsControllerMarker(newValue);
|
||||||
|
|
||||||
|
if (isPlaceholder)
|
||||||
|
{
|
||||||
|
switch (newValue)
|
||||||
|
{
|
||||||
|
case CPMultipleValuesMarker:
|
||||||
|
newValue = [options objectForKey:CPMultipleValuesPlaceholderBindingOption] || @"Multiple Values";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPNoSelectionMarker:
|
||||||
|
newValue = [options objectForKey:CPNoSelectionPlaceholderBindingOption] || @"No Selection";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPNotApplicableMarker:
|
||||||
|
if ([options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
||||||
|
[CPException raise:CPGenericException reason:@"can't transform non applicable key on: "+_source+" value: "+newValue];
|
||||||
|
|
||||||
|
newValue = [options objectForKey:CPNotApplicablePlaceholderBindingOption] || @"Not Applicable";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Only transform the value if the current value is not a placeholder
|
||||||
|
newValue = [self transformValue:newValue withOptions:options];
|
||||||
|
}
|
||||||
|
|
||||||
|
[_source setValue:newValue forKey:aBinding];
|
||||||
|
|
||||||
|
if ([_source respondsToSelector:@selector(_setCurrentValueIsPlaceholder:)])
|
||||||
|
[_source _setCurrentValueIsPlaceholder:isPlaceholder];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)reverseSetValueFor:(CPString)aBinding
|
||||||
|
{
|
||||||
|
var destination = [_info objectForKey:CPObservedObjectKey],
|
||||||
|
keyPath = [_info objectForKey:CPObservedKeyPathKey],
|
||||||
|
options = [_info objectForKey:CPOptionsKey],
|
||||||
|
newValue = [_source valueForKeyPath:aBinding];
|
||||||
|
|
||||||
|
newValue = [self reverseTransformValue:newValue withOptions:options];
|
||||||
|
[destination setValue:newValue forKeyPath:keyPath];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)context
|
||||||
|
{
|
||||||
|
if (!changes)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self setValueFor:context];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)transformValue:(id)aValue withOptions:(CPDictionary)options
|
||||||
|
{
|
||||||
|
var valueTransformerName,
|
||||||
|
valueTransformer,
|
||||||
|
placeholder;
|
||||||
|
|
||||||
|
var valueTransformerName = [options objectForKey:CPValueTransformerNameBindingOption],
|
||||||
|
valueTransformer;
|
||||||
|
|
||||||
|
if (valueTransformerName)
|
||||||
|
{
|
||||||
|
valueTransformer = [CPValueTransformer valueTransformerForName:valueTransformerName];
|
||||||
|
|
||||||
|
if (!valueTransformer)
|
||||||
|
{
|
||||||
|
var valueTransformerClass = CPClassFromString(valueTransformerName);
|
||||||
|
if (valueTransformerClass)
|
||||||
|
{
|
||||||
|
valueTransformer = [[valueTransformerClass alloc] init];
|
||||||
|
[valueTransformerClass setValueTransformer:valueTransformer forName:valueTransformerName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
valueTransformer = [options objectForKey:CPValueTransformerBindingOption];
|
||||||
|
|
||||||
|
if (valueTransformer)
|
||||||
|
aValue = [valueTransformer transformedValue:aValue];
|
||||||
|
|
||||||
|
|
||||||
|
if (aValue === undefined || aValue === nil)
|
||||||
|
aValue = [options objectForKey:CPNullPlaceholderBindingOption] || nil;
|
||||||
|
|
||||||
|
return aValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)reverseTransformValue:(id)aValue withOptions: (CPDictionary)options
|
||||||
|
{
|
||||||
|
var valueTransformerName = [options objectForKey:CPValueTransformerNameBindingOption],
|
||||||
|
valueTransformer;
|
||||||
|
|
||||||
|
if (valueTransformerName)
|
||||||
|
valueTransformer = [CPValueTransformer valueTransformerForName:valueTransformerName];
|
||||||
|
else
|
||||||
|
valueTransformer = [options objectForKey:CPValueTransformerBindingOption];
|
||||||
|
|
||||||
|
if (valueTransformer && [[valueTransformer class] allowsReverseTransformation])
|
||||||
|
aValue = [valueTransformer reverseTransformedValue:aValue];
|
||||||
|
|
||||||
|
return aValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation CPObject (KeyValueBindingCreation)
|
||||||
|
|
||||||
|
+ (void)exposeBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
[CPKeyValueBinding exposeBinding:aBinding forClass:[self class]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPArray)exposedBindings
|
||||||
|
{
|
||||||
|
var exposedBindings = [],
|
||||||
|
theClass = [self class];
|
||||||
|
|
||||||
|
while (theClass)
|
||||||
|
{
|
||||||
|
var temp = [CPKeyValueBinding exposedBindingsForClass:theClass];
|
||||||
|
|
||||||
|
if (temp)
|
||||||
|
[exposedBindings addObjectsFromArray:temp];
|
||||||
|
|
||||||
|
theClass = [theClass superclass];
|
||||||
|
}
|
||||||
|
|
||||||
|
return exposedBindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (Class)valueClassForBinding:(CPString)binding
|
||||||
|
{
|
||||||
|
return [CPString class];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options
|
||||||
|
{
|
||||||
|
if (!anObject || !aKeyPath)
|
||||||
|
return CPLog.error("Invalid object or path on "+self+" for "+aBinding);
|
||||||
|
|
||||||
|
//if (![[self exposedBindings] containsObject:aBinding])
|
||||||
|
// CPLog.warn("No binding exposed on "+self+" for "+aBinding);
|
||||||
|
|
||||||
|
[self unbind:aBinding];
|
||||||
|
[[CPKeyValueBinding alloc] initWithBinding:[self _replacementKeyPathForBinding:aBinding] name:aBinding to:anObject keyPath:aKeyPath options:options from:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPDictionary)infoForBinding:(CPString)aBinding
|
||||||
|
{
|
||||||
|
return [CPKeyValueBinding infoForBinding:aBinding forObject:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)unbind:(CPString)aBinding
|
||||||
|
{
|
||||||
|
[CPKeyValueBinding unbind:aBinding forObject:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)_replacementKeyPathForBinding:(CPString)binding
|
||||||
|
{
|
||||||
|
return binding;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPKeyValueOrBinding : CPKeyValueBinding
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setValueFor:(CPString)aBinding
|
||||||
|
{
|
||||||
|
var bindings = [bindingsMap valueForKey:[_source hash]];
|
||||||
|
|
||||||
|
if (!bindings)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_source setValue:resolveMultipleValues(aBinding, bindings, CPBindingOperationOr) forKey:aBinding];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)context
|
||||||
|
{
|
||||||
|
[self setValueFor:context];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPKeyValueAndBinding : CPKeyValueBinding
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setValueFor:(CPString)aBinding
|
||||||
|
{
|
||||||
|
var bindings = [bindingsMap objectForKey:[_source hash]];
|
||||||
|
|
||||||
|
if (!bindings)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_source setValue:resolveMultipleValues(aBinding, bindings, CPBindingOperationAnd) forKey:aBinding];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObejct change:(CPDictionary)changes context:(id)context
|
||||||
|
{
|
||||||
|
[self setValueFor:context];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var resolveMultipleValues = function resolveMultipleValues(/*CPString*/key, /*CPDictionary*/bindings, /*GSBindingOperationKind*/operation)
|
||||||
|
{
|
||||||
|
var bindingName = key,
|
||||||
|
theBinding,
|
||||||
|
count = 1;
|
||||||
|
|
||||||
|
while (theBinding = [bindings objectForKey:bindingName])
|
||||||
|
{
|
||||||
|
var infoDictionary = theBinding._info,
|
||||||
|
object = [infoDictionary objectForKey:CPObservedObjectKey],
|
||||||
|
keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey],
|
||||||
|
options = [infoDictionary objectForKey:CPOptionsKey];
|
||||||
|
|
||||||
|
var value = [theBinding transformValue:[object valueForKeyPath:keyPath] withOptions:options];
|
||||||
|
|
||||||
|
if (value == operation)
|
||||||
|
return operation;
|
||||||
|
|
||||||
|
bindingName = [CPString stringWithFormat:@"%@%i", key, ++count];
|
||||||
|
}
|
||||||
|
|
||||||
|
return !operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
var invokeAction = function invokeAction(/*CPString*/targetKey, /*CPString*/argumentKey, /*CPDictionary*/bindings)
|
||||||
|
{
|
||||||
|
var theBinding = [bindings objectForKey:targetKey],
|
||||||
|
infoDictionary = theBinding._info,
|
||||||
|
|
||||||
|
object = [infoDictionary objectForKey:CPObservedObjectKey],
|
||||||
|
keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey],
|
||||||
|
options = [infoDictionary objectForKey:CPOptionsKey],
|
||||||
|
|
||||||
|
target = [object valueForKeyPath:keyPath],
|
||||||
|
selector = [options objectForKey:CPSelectorNameBindingOption];
|
||||||
|
|
||||||
|
if (!target || !selector)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var invocation = [CPInvocation invocationWithMethodSignature:[target methodSignatureForSelector:selector]];
|
||||||
|
[invocation setSelector:selector];
|
||||||
|
|
||||||
|
var bindingName = argumentKey,
|
||||||
|
count = 1;
|
||||||
|
|
||||||
|
while (theBinding = [bindings objectForKey:bindingName])
|
||||||
|
{
|
||||||
|
infoDictionary = theBinding._info;
|
||||||
|
|
||||||
|
keyPath = [infoDictionary objectForKey:CPObserverKeyPathKey];
|
||||||
|
object = [[infoDictionary objectForKey:CPObservedObjectKey] valueForKeyPath:keyPath];
|
||||||
|
|
||||||
|
if (object)
|
||||||
|
[invocation setArgument:object atIndex:++count];
|
||||||
|
|
||||||
|
bindingName = [CPString stringWithFormat:@"%@%i", argumentKey, count];
|
||||||
|
}
|
||||||
|
|
||||||
|
[invocation invoke];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keys in options dictionary
|
||||||
|
|
||||||
|
// Keys in dictionary returned by infoForBinding
|
||||||
|
CPObservedObjectKey = @"CPObservedObjectKey";
|
||||||
|
CPObservedKeyPathKey = @"CPObservedKeyPathKey";
|
||||||
|
CPOptionsKey = @"CPOptionsKey";
|
||||||
|
|
||||||
|
// special markers
|
||||||
|
CPMultipleValuesMarker = @"CPMultipleValuesMarker";
|
||||||
|
CPNoSelectionMarker = @"CPNoSelectionMarker";
|
||||||
|
CPNotApplicableMarker = @"CPNotApplicableMarker";
|
||||||
|
|
||||||
|
// Binding name constants
|
||||||
|
CPAlignmentBinding = @"CPAlignmentBinding";
|
||||||
|
CPEditableBinding = @"CPEditableBinding";
|
||||||
|
CPEnabledBinding = @"CPEnabledBinding";
|
||||||
|
CPFontBinding = @"CPFontBinding";
|
||||||
|
CPHiddenBinding = @"CPHiddenBinding";
|
||||||
|
CPSelectedIndexBinding = @"CPSelectedIndexBinding";
|
||||||
|
CPTextColorBinding = @"CPTextColorBinding";
|
||||||
|
CPToolTipBinding = @"CPToolTipBinding";
|
||||||
|
CPValueBinding = @"value";
|
||||||
|
|
||||||
|
//Binding options constants
|
||||||
|
CPAllowsEditingMultipleValuesSelectionBindingOption = @"CPAllowsEditingMultipleValuesSelectionBindingOption";
|
||||||
|
CPAllowsNullArgumentBindingOption = @"CPAllowsNullArgumentBindingOption";
|
||||||
|
CPConditionallySetsEditableBindingOption = @"CPConditionallySetsEditableBindingOption";
|
||||||
|
CPConditionallySetsEnabledBindingOption = @"CPConditionallySetsEnabledBindingOption";
|
||||||
|
CPConditionallySetsHiddenBindingOption = @"CPConditionallySetsHiddenBindingOption";
|
||||||
|
CPContinuouslyUpdatesValueBindingOption = @"CPContinuouslyUpdatesValueBindingOption";
|
||||||
|
CPCreatesSortDescriptorBindingOption = @"CPCreatesSortDescriptorBindingOption";
|
||||||
|
CPDeletesObjectsOnRemoveBindingsOption = @"CPDeletesObjectsOnRemoveBindingsOption";
|
||||||
|
CPDisplayNameBindingOption = @"CPDisplayNameBindingOption";
|
||||||
|
CPDisplayPatternBindingOption = @"CPDisplayPatternBindingOption";
|
||||||
|
CPHandlesContentAsCompoundValueBindingOption = @"CPHandlesContentAsCompoundValueBindingOption";
|
||||||
|
CPInsertsNullPlaceholderBindingOption = @"CPInsertsNullPlaceholderBindingOption";
|
||||||
|
CPInvokesSeparatelyWithArrayObjectsBindingOption = @"CPInvokesSeparatelyWithArrayObjectsBindingOption";
|
||||||
|
CPMultipleValuesPlaceholderBindingOption = @"CPMultipleValuesPlaceholderBindingOption";
|
||||||
|
CPNoSelectionPlaceholderBindingOption = @"CPNoSelectionPlaceholderBindingOption";
|
||||||
|
CPNotApplicablePlaceholderBindingOption = @"CPNotApplicablePlaceholderBindingOption";
|
||||||
|
CPNullPlaceholderBindingOption = @"CPNullPlaceholderBindingOption";
|
||||||
|
CPPredicateFormatBindingOption = @"CPPredicateFormatBindingOption";
|
||||||
|
CPRaisesForNotApplicableKeysBindingOption = @"CPRaisesForNotApplicableKeysBindingOption";
|
||||||
|
CPSelectorNameBindingOption = @"CPSelectorNameBindingOption";
|
||||||
|
CPSelectsAllWhenSettingContentBindingOption = @"CPSelectsAllWhenSettingContentBindingOption";
|
||||||
|
CPValidatesImmediatelyBindingOption = @"CPValidatesImmediatelyBindingOption";
|
||||||
|
CPValueTransformerNameBindingOption = @"CPValueTransformerNameBindingOption";
|
||||||
|
CPValueTransformerBindingOption = @"CPValueTransformerBindingOption";
|
||||||
|
|
||||||
|
CPIsControllerMarker = function(/*id*/anObject)
|
||||||
|
{
|
||||||
|
return anObject === CPMultipleValuesMarker || anObject === CPNoSelectionMarker || anObject === CPNotApplicableMarker;
|
||||||
|
}
|
||||||
+26
-13
@@ -31,9 +31,6 @@
|
|||||||
@import "CPMenuItem.j"
|
@import "CPMenuItem.j"
|
||||||
@import "CPPanel.j"
|
@import "CPPanel.j"
|
||||||
|
|
||||||
#include "../CoreGraphics/CGGeometry.h"
|
|
||||||
#include "../Platform/Platform.h"
|
|
||||||
|
|
||||||
|
|
||||||
CPMenuDidAddItemNotification = @"CPMenuDidAddItemNotification";
|
CPMenuDidAddItemNotification = @"CPMenuDidAddItemNotification";
|
||||||
CPMenuDidChangeItemNotification = @"CPMenuDidChangeItemNotification";
|
CPMenuDidChangeItemNotification = @"CPMenuDidChangeItemNotification";
|
||||||
@@ -75,7 +72,7 @@ var _CPMenuBarVisible = NO,
|
|||||||
|
|
||||||
id _delegate;
|
id _delegate;
|
||||||
|
|
||||||
CPMenuItem _highlightedIndex;
|
int _highlightedIndex;
|
||||||
_CPMenuWindow _menuWindow;
|
_CPMenuWindow _menuWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +90,7 @@ var _CPMenuBarVisible = NO,
|
|||||||
|
|
||||||
+ (void)setMenuBarVisible:(BOOL)menuBarShouldBeVisible
|
+ (void)setMenuBarVisible:(BOOL)menuBarShouldBeVisible
|
||||||
{
|
{
|
||||||
if (_CPMenuBarVisible == menuBarShouldBeVisible)
|
if (_CPMenuBarVisible === menuBarShouldBeVisible)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_CPMenuBarVisible = menuBarShouldBeVisible;
|
_CPMenuBarVisible = menuBarShouldBeVisible;
|
||||||
@@ -648,7 +645,10 @@ var _CPMenuBarVisible = NO,
|
|||||||
while ([highlightedItem submenu] && [highlightedItem action] === @selector(submenuAction:))
|
while ([highlightedItem submenu] && [highlightedItem action] === @selector(submenuAction:))
|
||||||
highlightedItem = [[highlightedItem submenu] highlightedItem];
|
highlightedItem = [[highlightedItem submenu] highlightedItem];
|
||||||
|
|
||||||
if (highlightedItem)
|
// FIXME: It is theoretically not necessarily to check isEnabled here since
|
||||||
|
// highlightedItem is always enabled. Do there exist edge cases: disabling on closing a menu,
|
||||||
|
// etc.? Requires further investigation and tests.
|
||||||
|
if (highlightedItem && [highlightedItem isEnabled])
|
||||||
[CPApp sendAction:[highlightedItem action] to:[highlightedItem target] from:highlightedItem];
|
[CPApp sendAction:[highlightedItem action] to:[highlightedItem target] from:highlightedItem];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -744,6 +744,9 @@ var _CPMenuBarVisible = NO,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Show it.
|
// Show it.
|
||||||
|
if ([CPPlatform isBrowser])
|
||||||
|
[menuWindow setPlatformWindow:[[aView window] platformWindow]];
|
||||||
|
|
||||||
[menuWindow orderFront:self];
|
[menuWindow orderFront:self];
|
||||||
|
|
||||||
// Track it.
|
// Track it.
|
||||||
@@ -813,6 +816,9 @@ var _CPMenuBarVisible = NO,
|
|||||||
[menuWindow setFrameOrigin:CGRectIntersection(unconstrainedFrame, constraintRect).origin];
|
[menuWindow setFrameOrigin:CGRectIntersection(unconstrainedFrame, constraintRect).origin];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ([CPPlatform isBrowser])
|
||||||
|
[menuWindow setPlatformWindow:[[aView window] platformWindow]];
|
||||||
|
|
||||||
[menuWindow orderFront:self];
|
[menuWindow orderFront:self];
|
||||||
|
|
||||||
[[_CPMenuManager sharedMenuManager]
|
[[_CPMenuManager sharedMenuManager]
|
||||||
@@ -883,6 +889,13 @@ var _CPMenuBarVisible = NO,
|
|||||||
subtype:0
|
subtype:0
|
||||||
data1:0
|
data1:0
|
||||||
data2:0]];
|
data2:0]];
|
||||||
|
|
||||||
|
// FIXME: We need to do this because this happens in a limitDateForMode:, thus
|
||||||
|
// the second limitDateForMode: won't take effect and the perform selector that
|
||||||
|
// actually draws also won't go into effect. In Safari this works because it sends
|
||||||
|
// an additional mouse move after all this, but not in other browsers.
|
||||||
|
// This will be fixed correctly with the coming run loop changes.
|
||||||
|
[_CPDisplayServer run];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
@@ -920,10 +933,9 @@ var _CPMenuBarVisible = NO,
|
|||||||
for(; index < count; ++index)
|
for(; index < count; ++index)
|
||||||
{
|
{
|
||||||
var item = _items[index],
|
var item = _items[index],
|
||||||
modifierMask = [item keyEquivalentModifierMask] | ([item keyEquivalent] === [[item keyEquivalent] uppercaseString] ? CPShiftKeyMask : 0);
|
modifierMask = [item keyEquivalentModifierMask];
|
||||||
|
|
||||||
if ((modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) == modifierMask &&
|
if ([anEvent _triggersKeyEquivalent:[item keyEquivalent] withModifierMask:[item keyEquivalentModifierMask]])
|
||||||
[characters caseInsensitiveCompare:[item keyEquivalent]] == CPOrderedSame)
|
|
||||||
{
|
{
|
||||||
if ([item isEnabled])
|
if ([item isEnabled])
|
||||||
[self performActionForItemAtIndex:index];
|
[self performActionForItemAtIndex:index];
|
||||||
@@ -968,13 +980,14 @@ var _CPMenuBarVisible = NO,
|
|||||||
*/
|
*/
|
||||||
- (void)_highlightItemAtIndex:(int)anIndex
|
- (void)_highlightItemAtIndex:(int)anIndex
|
||||||
{
|
{
|
||||||
var previousHighlightedIndex = _highlightedIndex;
|
if (_highlightedIndex === anIndex)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_highlightedIndex !== CPNotFound)
|
||||||
|
[[_items[_highlightedIndex] _menuItemView] highlight:NO];
|
||||||
|
|
||||||
_highlightedIndex = anIndex;
|
_highlightedIndex = anIndex;
|
||||||
|
|
||||||
if (previousHighlightedIndex !== CPNotFound)
|
|
||||||
[[_items[previousHighlightedIndex] _menuItemView] highlight:NO];
|
|
||||||
|
|
||||||
if (_highlightedIndex !== CPNotFound)
|
if (_highlightedIndex !== CPNotFound)
|
||||||
[[_items[_highlightedIndex] _menuItemView] highlight:YES];
|
[[_items[_highlightedIndex] _menuItemView] highlight:YES];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
|
@import "CPPanel.j"
|
||||||
#include "../CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
@import "_CPMenuWindow.j"
|
@import "_CPMenuWindow.j"
|
||||||
|
|
||||||
|
|
||||||
@@ -60,8 +58,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/39-dont-allow-windows-to-go-above-menubar
|
[self setLevel:CPMainMenuWindowLevel];
|
||||||
[self setLevel:-1];//CPTornOffMenuWindowLevel];
|
|
||||||
[self setAutoresizingMask:CPWindowWidthSizable];
|
[self setAutoresizingMask:CPWindowWidthSizable];
|
||||||
|
|
||||||
var contentView = [self contentView];
|
var contentView = [self contentView];
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
|
|
||||||
#include "../CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
|
|
||||||
@@ -57,14 +54,34 @@ var SharedMenuManager = nil;
|
|||||||
constraintRect:(CGRect)aRect
|
constraintRect:(CGRect)aRect
|
||||||
callback:(Function)aCallback
|
callback:(Function)aCallback
|
||||||
{
|
{
|
||||||
CPApp._activeMenu = [aMenuContainer menu];
|
var menu = [aMenuContainer menu];
|
||||||
|
|
||||||
|
CPApp._activeMenu = menu;
|
||||||
|
|
||||||
_startTime = [anEvent timestamp];//new Date();
|
_startTime = [anEvent timestamp];//new Date();
|
||||||
_scrollingState = _CPMenuManagerScrollingStateNone;
|
_scrollingState = _CPMenuManagerScrollingStateNone;
|
||||||
|
|
||||||
_constraintRect = aRect;
|
_constraintRect = aRect;
|
||||||
_trackingCallback = aCallback;
|
|
||||||
_menuContainerStack = [aMenuContainer];
|
_menuContainerStack = [aMenuContainer];
|
||||||
|
_trackingCallback = aCallback;
|
||||||
|
|
||||||
|
if (menu === [CPApp mainMenu])
|
||||||
|
{
|
||||||
|
var globalLocation = [anEvent globalLocation];
|
||||||
|
|
||||||
|
// Find which menu window the mouse is currently on top of
|
||||||
|
var menuLocation = [aMenuContainer convertGlobalToBase:globalLocation];
|
||||||
|
|
||||||
|
// Find out the item the mouse is currently on top of
|
||||||
|
var activeItemIndex = [aMenuContainer itemIndexAtPoint:menuLocation],
|
||||||
|
activeItem = activeItemIndex !== CPNotFound ? [menu itemAtIndex:activeItemIndex] : nil;
|
||||||
|
|
||||||
|
_menuBarButtonItemIndex = activeItemIndex;
|
||||||
|
_menuBarButtonMenuContainer = aMenuContainer;
|
||||||
|
|
||||||
|
if ([activeItem _isMenuBarButton])
|
||||||
|
return [self trackMenuBarButtonEvent:anEvent];
|
||||||
|
}
|
||||||
|
|
||||||
[self trackEvent:anEvent];
|
[self trackEvent:anEvent];
|
||||||
}
|
}
|
||||||
@@ -76,32 +93,7 @@ var SharedMenuManager = nil;
|
|||||||
|
|
||||||
// Close Menu Event.
|
// Close Menu Event.
|
||||||
if (type === CPAppKitDefined)
|
if (type === CPAppKitDefined)
|
||||||
{
|
return [self completeTracking];
|
||||||
// Stop all periodic events at this point.
|
|
||||||
[CPEvent stopPeriodicEvents];
|
|
||||||
|
|
||||||
// Get the highlighted item from the original menu.
|
|
||||||
var highlightedItem = [trackingMenu highlightedItem];
|
|
||||||
|
|
||||||
// Hide all submenus.
|
|
||||||
[self showMenu:nil fromMenu:trackingMenu atPoint:nil];
|
|
||||||
|
|
||||||
var delegate = [trackingMenu delegate];
|
|
||||||
|
|
||||||
if ([delegate respondsToSelector:@selector(menuDidClose:)])
|
|
||||||
[delegate menuDidClose:trackingMenu];
|
|
||||||
|
|
||||||
if (_trackingCallback)
|
|
||||||
_trackingCallback([self trackingMenuContainer], trackingMenu);
|
|
||||||
|
|
||||||
[[CPNotificationCenter defaultCenter]
|
|
||||||
postNotificationName:CPMenuDidEndTrackingNotification
|
|
||||||
object:trackingMenu];
|
|
||||||
|
|
||||||
CPApp._activeMenu = nil;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask untilDate:nil inMode:nil dequeue:YES];
|
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask untilDate:nil inMode:nil dequeue:YES];
|
||||||
|
|
||||||
@@ -113,11 +105,21 @@ var SharedMenuManager = nil;
|
|||||||
|
|
||||||
// Find which menu window the mouse is currently on top of
|
// Find which menu window the mouse is currently on top of
|
||||||
var activeMenuContainer = [self menuContainerForPoint:globalLocation],
|
var activeMenuContainer = [self menuContainerForPoint:globalLocation],
|
||||||
menuLocation = [activeMenuContainer convertGlobalToBase:globalLocation],
|
activeMenu = [activeMenuContainer menu],
|
||||||
activeItemIndex = activeMenuContainer ? [activeMenuContainer itemIndexAtPoint:menuLocation] : CPNotFound,
|
menuLocation = [activeMenuContainer convertGlobalToBase:globalLocation];
|
||||||
activeMenu = activeMenuContainer ? [activeMenuContainer menu] : nil,
|
|
||||||
activeItem = activeItemIndex !== CPNotFound ? [activeMenu itemAtIndex:activeItemIndex] : nil,
|
// Find out the item the mouse is currently on top of
|
||||||
mouseOverMenuView = activeMenuContainer ? [activeItem view] : nil;
|
var activeItemIndex = activeMenuContainer ? [activeMenuContainer itemIndexAtPoint:menuLocation] : CPNotFound,
|
||||||
|
activeItem = activeItemIndex !== CPNotFound ? [activeMenu itemAtIndex:activeItemIndex] : nil;
|
||||||
|
|
||||||
|
// If the item isn't enabled its as if we clicked on nothing.
|
||||||
|
if (![activeItem isEnabled] || [activeItem _isMenuBarButton])
|
||||||
|
{
|
||||||
|
activeItemIndex = CPNotFound;
|
||||||
|
activeItem = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mouseOverMenuView = [activeItem view];
|
||||||
|
|
||||||
if (type === CPPeriodic)
|
if (type === CPPeriodic)
|
||||||
{
|
{
|
||||||
@@ -207,6 +209,59 @@ var SharedMenuManager = nil;
|
|||||||
[self showMenu:nil fromMenu:activeMenu atPoint:CGPointMakeZero()];
|
[self showMenu:nil fromMenu:activeMenu atPoint:CGPointMakeZero()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)trackMenuBarButtonEvent:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
var type = [anEvent type];
|
||||||
|
|
||||||
|
if (type === CPAppKitDefined)
|
||||||
|
return [self completeTracking];
|
||||||
|
|
||||||
|
var globalLocation = [anEvent globalLocation];
|
||||||
|
|
||||||
|
// Find which menu window the mouse is currently on top of
|
||||||
|
var menu = [self trackingMenu],
|
||||||
|
trackingMenuContainer = [self trackingMenuContainer],
|
||||||
|
menuLocation = [trackingMenuContainer convertGlobalToBase:globalLocation];
|
||||||
|
|
||||||
|
if ([trackingMenuContainer itemIndexAtPoint:menuLocation] === _menuBarButtonItemIndex)
|
||||||
|
[menu _highlightItemAtIndex:_menuBarButtonItemIndex];
|
||||||
|
|
||||||
|
else
|
||||||
|
[menu _highlightItemAtIndex:CPNotFound];
|
||||||
|
|
||||||
|
[CPApp setTarget:self selector:@selector(trackMenuBarButtonEvent:) forNextEventMatchingMask:CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask untilDate:nil inMode:nil dequeue:YES];
|
||||||
|
|
||||||
|
if (type === CPLeftMouseUp)
|
||||||
|
[menu cancelTracking];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)completeTracking
|
||||||
|
{
|
||||||
|
var trackingMenu = [self trackingMenu];
|
||||||
|
|
||||||
|
// Stop all periodic events at this point.
|
||||||
|
[CPEvent stopPeriodicEvents];
|
||||||
|
|
||||||
|
// Get the highlighted item from the original menu.
|
||||||
|
var highlightedItem = [trackingMenu highlightedItem];
|
||||||
|
|
||||||
|
// Hide all submenus.
|
||||||
|
[self showMenu:nil fromMenu:trackingMenu atPoint:nil];
|
||||||
|
|
||||||
|
var delegate = [trackingMenu delegate];
|
||||||
|
|
||||||
|
if ([delegate respondsToSelector:@selector(menuDidClose:)])
|
||||||
|
[delegate menuDidClose:trackingMenu];
|
||||||
|
|
||||||
|
if (_trackingCallback)
|
||||||
|
_trackingCallback([self trackingMenuContainer], trackingMenu);
|
||||||
|
|
||||||
|
[[CPNotificationCenter defaultCenter]
|
||||||
|
postNotificationName:CPMenuDidEndTrackingNotification
|
||||||
|
object:trackingMenu];
|
||||||
|
|
||||||
|
CPApp._activeMenu = nil;
|
||||||
|
}
|
||||||
|
|
||||||
- (id)menuContainerForPoint:(float)aGlobalLocation
|
- (id)menuContainerForPoint:(float)aGlobalLocation
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
|
@import "CPWindow.j"
|
||||||
#include "../CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
|
|
||||||
var _CPMenuWindowPool = [],
|
var _CPMenuWindowPool = [],
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
@import "_CPMenuItemView.j"
|
@import "_CPMenuItemView.j"
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@class CPMenuItem
|
@class CPMenuItem
|
||||||
@@ -590,16 +591,35 @@ CPControlKeyMask
|
|||||||
if (![_keyEquivalent length])
|
if (![_keyEquivalent length])
|
||||||
return @"";
|
return @"";
|
||||||
|
|
||||||
var string = _keyEquivalent.toUpperCase();
|
var string = _keyEquivalent.toUpperCase(),
|
||||||
|
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask ||
|
||||||
|
(string === _keyEquivalent && _keyEquivalent.toLowerCase() !== _keyEquivalent.toUpperCase());
|
||||||
|
|
||||||
|
if (CPBrowserIsOperatingSystem(CPMacOperatingSystem))
|
||||||
|
{
|
||||||
if (_keyEquivalentModifierMask & CPCommandKeyMask)
|
if (_keyEquivalentModifierMask & CPCommandKeyMask)
|
||||||
string = "⌘" + string;
|
string = "⌘" + string;
|
||||||
|
|
||||||
if (_keyEquivalentModifierMask & CPShiftKeyMask)
|
if (needsShift)
|
||||||
string = "⇧" + string;
|
string = "⇧" + string;
|
||||||
|
|
||||||
|
if (_keyEquivalentModifierMask & CPAlternateKeyMask)
|
||||||
|
string = "⌥" + string;
|
||||||
|
|
||||||
if (_keyEquivalentModifierMask & CPControlKeyMask)
|
if (_keyEquivalentModifierMask & CPControlKeyMask)
|
||||||
string = "^" + string;
|
string = "^" + string;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (needsShift)
|
||||||
|
string = "Shift-" + string;
|
||||||
|
|
||||||
|
if (_keyEquivalentModifierMask & CPAlternateKeyMask)
|
||||||
|
string = "Alt-" + string;
|
||||||
|
|
||||||
|
if (_keyEquivalentModifierMask & CPControlKeyMask || _keyEquivalentModifierMask & CPCommandKeyMask)
|
||||||
|
string = "Ctrl-" + string;
|
||||||
|
}
|
||||||
|
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
@@ -763,7 +783,48 @@ CPControlKeyMask
|
|||||||
return [[self menu] highlightedItem] == self;
|
return [[self menu] highlightedItem] == self;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
#pragma mark CPObject Overrides
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns a copy of the item. The copy does not belong If the item has a submenu, it is NOT copied.
|
||||||
|
*/
|
||||||
|
- (id)copy
|
||||||
|
{
|
||||||
|
var item = [[CPMenuItem alloc] init];
|
||||||
|
|
||||||
|
// No point in going through accessors and doing lots of unnecessary state checking/updating
|
||||||
|
item._isSeparator = _isSeparator;
|
||||||
|
|
||||||
|
[item setTitle:_title];
|
||||||
|
[item setFont:_font];
|
||||||
|
[item setTarget:_target];
|
||||||
|
[item setAction:_action];
|
||||||
|
[item setEnabled:_isEnabled];
|
||||||
|
[item setHidden:_isHidden]
|
||||||
|
[item setTag:_tag];
|
||||||
|
[item setState:_state];
|
||||||
|
[item setImage:_image];
|
||||||
|
[item setAlternateImage:_alternateImage];
|
||||||
|
[item setOnStateImage:_onStateImage];
|
||||||
|
[item setOffStateImage:_offStateImage];
|
||||||
|
[item setMixedStateImage:_mixedStateImage];
|
||||||
|
[item setKeyEquivalent:_keyEquivalent];
|
||||||
|
[item setKeyEquivalentModifierMask:_keyEquivalentModifierMask];
|
||||||
|
[item setMnemonicLocation:_mnemonicLocation];
|
||||||
|
[item setAlternate:_isAlternate];
|
||||||
|
[item setIndentationLevel:_indentationLevel];
|
||||||
|
[item setToolTip:_toolTip];
|
||||||
|
[item setRepresentedObject:_representedObject];
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)mutableCopy
|
||||||
|
{
|
||||||
|
return [self copy];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark Internal
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ignore
|
@ignore
|
||||||
@@ -781,6 +842,11 @@ CPControlKeyMask
|
|||||||
return ![self submenu] || [self action] !== @selector(submenuAction:) || [self target] !== [self menu];
|
return ![self submenu] || [self action] !== @selector(submenuAction:) || [self target] !== [self menu];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)_isMenuBarButton
|
||||||
|
{
|
||||||
|
return ![self submenu] && [self menu] === [CPApp mainMenu];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
||||||
@@ -837,7 +903,6 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
|||||||
_isHidden = DEFAULT_VALUE(CPMenuItemIsHiddenKey, NO);
|
_isHidden = DEFAULT_VALUE(CPMenuItemIsHiddenKey, NO);
|
||||||
_tag = DEFAULT_VALUE(CPMenuItemTagKey, 0);
|
_tag = DEFAULT_VALUE(CPMenuItemTagKey, 0);
|
||||||
_state = DEFAULT_VALUE(CPMenuItemStateKey, CPOffState);
|
_state = DEFAULT_VALUE(CPMenuItemStateKey, CPOffState);
|
||||||
// int _state;
|
|
||||||
|
|
||||||
_image = DEFAULT_VALUE(CPMenuItemImageKey, nil);
|
_image = DEFAULT_VALUE(CPMenuItemImageKey, nil);
|
||||||
_alternateImage = DEFAULT_VALUE(CPMenuItemAlternateImageKey, nil);
|
_alternateImage = DEFAULT_VALUE(CPMenuItemAlternateImageKey, nil);
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
@import "CPView.j"
|
||||||
|
|
||||||
|
|
||||||
var HORIZONTAL_MARGIN = 8.0,
|
var HORIZONTAL_MARGIN = 8.0,
|
||||||
SUBMENU_INDICATOR_MARGIN = 3.0,
|
SUBMENU_INDICATOR_MARGIN = 3.0,
|
||||||
VERTICAL_MARGIN = 4.0;
|
VERTICAL_MARGIN = 4.0;
|
||||||
@@ -62,6 +65,7 @@ var SelectionColor = nil,
|
|||||||
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(HORIZONTAL_MARGIN, 0.0, 0.0, 0.0)];
|
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(HORIZONTAL_MARGIN, 0.0, 0.0, 0.0)];
|
||||||
|
|
||||||
[_imageAndTextView setImagePosition:CPImageLeft];
|
[_imageAndTextView setImagePosition:CPImageLeft];
|
||||||
|
[_imageAndTextView setImageOffset:3.0];
|
||||||
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||||
[_imageAndTextView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
|
[_imageAndTextView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
|
||||||
|
|
||||||
@@ -155,12 +159,14 @@ var SelectionColor = nil,
|
|||||||
{
|
{
|
||||||
// FIXME: This should probably be even throw.
|
// FIXME: This should probably be even throw.
|
||||||
if (![_menuItem isEnabled])
|
if (![_menuItem isEnabled])
|
||||||
return;
|
shouldHighlight = NO;
|
||||||
|
|
||||||
if (shouldHighlight)
|
if (shouldHighlight)
|
||||||
{
|
{
|
||||||
|
if (![_menuItem _isMenuBarButton])
|
||||||
[self setBackgroundColor:SelectionColor];
|
[self setBackgroundColor:SelectionColor];
|
||||||
|
|
||||||
|
[_imageAndTextView setImage:[_menuItem alternateImage] || [_menuItem image]];
|
||||||
[_imageAndTextView setTextColor:[CPColor whiteColor]];
|
[_imageAndTextView setTextColor:[CPColor whiteColor]];
|
||||||
[_imageAndTextView setTextShadowColor:_CPMenuItemTextShadowColor];
|
[_imageAndTextView setTextShadowColor:_CPMenuItemTextShadowColor];
|
||||||
|
|
||||||
@@ -171,6 +177,7 @@ var SelectionColor = nil,
|
|||||||
{
|
{
|
||||||
[self setBackgroundColor:nil];
|
[self setBackgroundColor:nil];
|
||||||
|
|
||||||
|
[_imageAndTextView setImage:[_menuItem image]];
|
||||||
[_imageAndTextView setTextColor:[self textColor]];
|
[_imageAndTextView setTextColor:[self textColor]];
|
||||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||||
|
|
||||||
@@ -224,8 +231,8 @@ var SelectionColor = nil,
|
|||||||
|
|
||||||
CGContextClosePath(context);
|
CGContextClosePath(context);
|
||||||
|
|
||||||
CGContextSetShadowWithColor(context, CGSizeMake(0.0, 1.0), 1.1, _shadowColor);
|
CGContextSetShadowWithColor(context, CGSizeMake(0.0, 1.0), 1.1, _shadowColor || [CPColor whiteColor]);
|
||||||
CGContextSetFillColor(context, _color);
|
CGContextSetFillColor(context, _color || [CPColor blackColor]);
|
||||||
CGContextFillPath(context);
|
CGContextFillPath(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
@import <AppKit/CPView.j>
|
@import "CPView.j"
|
||||||
|
|
||||||
|
|
||||||
@implementation _CPMenuItemSeparatorView : CPView
|
@implementation _CPMenuItemSeparatorView : CPView
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
@import "CPControl.j"
|
||||||
|
|
||||||
|
|
||||||
var LEFT_MARGIN = 3.0,
|
var LEFT_MARGIN = 3.0,
|
||||||
RIGHT_MARGIN = 14.0 + 3.0,
|
RIGHT_MARGIN = 14.0 + 3.0,
|
||||||
STATE_COLUMN_WIDTH = 14.0,
|
STATE_COLUMN_WIDTH = 14.0,
|
||||||
@@ -39,7 +42,7 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
|||||||
SUBMENU_INDICATOR_COLOR = [CPColor grayColor];
|
SUBMENU_INDICATOR_COLOR = [CPColor grayColor];
|
||||||
|
|
||||||
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
|
_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]
|
_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];
|
var bundle = [CPBundle bundleForClass:self];
|
||||||
|
|
||||||
@@ -236,6 +239,7 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
|||||||
{
|
{
|
||||||
[self setBackgroundColor:_CPMenuItemSelectionColor];
|
[self setBackgroundColor:_CPMenuItemSelectionColor];
|
||||||
|
|
||||||
|
[_imageAndTextView setImage:[_menuItem alternateImage] || [_menuItem image]];
|
||||||
[_imageAndTextView setTextColor:[CPColor whiteColor]];
|
[_imageAndTextView setTextColor:[CPColor whiteColor]];
|
||||||
[_keyEquivalentView setTextColor:[CPColor whiteColor]];
|
[_keyEquivalentView setTextColor:[CPColor whiteColor]];
|
||||||
[_submenuIndicatorView setColor:[CPColor whiteColor]];
|
[_submenuIndicatorView setColor:[CPColor whiteColor]];
|
||||||
@@ -247,6 +251,7 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
|||||||
{
|
{
|
||||||
[self setBackgroundColor:nil];
|
[self setBackgroundColor:nil];
|
||||||
|
|
||||||
|
[_imageAndTextView setImage:[_menuItem image]];
|
||||||
[_imageAndTextView setTextColor:[self textColor]];
|
[_imageAndTextView setTextColor:[self textColor]];
|
||||||
[_keyEquivalentView setTextColor:[self textColor]];
|
[_keyEquivalentView setTextColor:[self textColor]];
|
||||||
[_submenuIndicatorView setColor:SUBMENU_INDICATOR_COLOR];
|
[_submenuIndicatorView setColor:SUBMENU_INDICATOR_COLOR];
|
||||||
@@ -255,11 +260,14 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
|||||||
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
|
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ([[_menuItem menu] showsStateColumn])
|
||||||
|
{
|
||||||
if (shouldHighlight)
|
if (shouldHighlight)
|
||||||
[_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil];
|
[_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil];
|
||||||
else
|
else
|
||||||
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
|
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
|
@import <AppKit/CPControl.j>
|
||||||
|
|
||||||
@import "_CPMenuItemSeparatorView.j"
|
@import "_CPMenuItemSeparatorView.j"
|
||||||
@import "_CPMenuItemStandardView.j"
|
@import "_CPMenuItemStandardView.j"
|
||||||
@import "_CPMenuItemMenuBarView.j"
|
@import "_CPMenuItemMenuBarView.j"
|
||||||
@@ -43,7 +45,7 @@ var _CPMenuItemSelectionColor = nil,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.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]
|
_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];
|
var bundle = [CPBundle bundleForClass:self];
|
||||||
|
|
||||||
@@ -155,24 +157,6 @@ var _CPMenuItemSelectionColor = nil,
|
|||||||
[_view highlight:shouldHighlight];
|
[_view highlight:shouldHighlight];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)activate:(BOOL)shouldActivate
|
|
||||||
{
|
|
||||||
[_imageAndTextView setImage:[_menuItem image]];
|
|
||||||
|
|
||||||
if (shouldActivate)
|
|
||||||
{
|
|
||||||
[_imageAndTextView setTextColor:[self activateColor] || [CPColor whiteColor]];
|
|
||||||
[_imageAndTextView setTextShadowColor:[self activateShadowColor] || [CPColor blackColor]];
|
|
||||||
[_submenuView setColor:[self activateColor] || [CPColor whiteColor]];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
[_imageAndTextView setTextColor:[self textColor]];
|
|
||||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
|
||||||
[_submenuView setColor:[self textColor]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)eventOnSubmenu:(CPEvent)anEvent
|
- (BOOL)eventOnSubmenu:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
if (![_menuItem hasSubmenu])
|
if (![_menuItem hasSubmenu])
|
||||||
|
|||||||
@@ -0,0 +1,625 @@
|
|||||||
|
|
||||||
|
@import <Foundation/CPDictionary.j>
|
||||||
|
@import <Foundation/CPCountedSet.j>
|
||||||
|
|
||||||
|
@import "CPController.j"
|
||||||
|
|
||||||
|
|
||||||
|
@implementation CPObjectController : CPController
|
||||||
|
{
|
||||||
|
id _contentObject;
|
||||||
|
id _selection;
|
||||||
|
|
||||||
|
Class _objectClass;
|
||||||
|
|
||||||
|
BOOL _isEditable;
|
||||||
|
BOOL _automaticallyPreparesContent;
|
||||||
|
|
||||||
|
CPCountedSet _observedKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)initialize
|
||||||
|
{
|
||||||
|
[self exposeBinding:@"editable"];
|
||||||
|
[self exposeBinding:@"contentObject"];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPSet)keyPathsForValuesAffectingContentObject
|
||||||
|
{
|
||||||
|
return [CPSet setWithObjects:"content"];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)automaticallyNotifiesObserversForKey:(CPString)aKey
|
||||||
|
{
|
||||||
|
if (aKey === @"contentObject")
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPSet)keyPathsForValuesAffectingCanAdd
|
||||||
|
{
|
||||||
|
return [CPSet setWithObject:"editable"];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPSet)keyPathsForValuesAffectingCanInsert
|
||||||
|
{
|
||||||
|
return [CPSet setWithObject:"editable"];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPSet)keyPathsForValuesAffectingCanRemove
|
||||||
|
{
|
||||||
|
return [CPSet setWithObjects:"editable", "selection"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
return [self initWithContent:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithContent:(id)aContent
|
||||||
|
{
|
||||||
|
if (self = [super init])
|
||||||
|
{
|
||||||
|
[self setContent:aContent];
|
||||||
|
[self setEditable:YES];
|
||||||
|
[self setObjectClass:[CPMutableDictionary class]];
|
||||||
|
|
||||||
|
_observedKeys = [[CPCountedSet alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)content
|
||||||
|
{
|
||||||
|
return _contentObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setContent:(id)aContent
|
||||||
|
{
|
||||||
|
[self willChangeValueForKey:@"contentObject"];
|
||||||
|
[self _selectionWillChange];
|
||||||
|
|
||||||
|
_contentObject = aContent;
|
||||||
|
|
||||||
|
[self didChangeValueForKey:@"contentObject"];
|
||||||
|
[self _selectionDidChange];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_setContentObject:(id)aContent
|
||||||
|
{
|
||||||
|
[self setContent:aContent];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)_contentObject
|
||||||
|
{
|
||||||
|
return [self content];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setAutomaticallyPreparesContent:(BOOL)shouldAutomaticallyPrepareContent
|
||||||
|
{
|
||||||
|
_automaticallyPreparesContent = shouldAutomaticallyPrepareContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)automaticallyPreparesContent
|
||||||
|
{
|
||||||
|
return _automaticallyPreparesContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)prepareContent
|
||||||
|
{
|
||||||
|
[self setContent:[self newObject]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setObjectClass:(Class)aClass
|
||||||
|
{
|
||||||
|
_objectClass = aClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (Class)objectClass
|
||||||
|
{
|
||||||
|
return _objectClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)newObject
|
||||||
|
{
|
||||||
|
return [[[self objectClass] alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)addObject:(id)anObject
|
||||||
|
{
|
||||||
|
[self setContent:anObject];
|
||||||
|
|
||||||
|
[[CPKeyValueBinding getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeObject:(id)anObject
|
||||||
|
{
|
||||||
|
if ([self content] === anObject)
|
||||||
|
[self setContent:nil];
|
||||||
|
|
||||||
|
[[CPKeyValueBinding getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)add:(id)aSender
|
||||||
|
{
|
||||||
|
// FIXME: This should happen on the next run loop?
|
||||||
|
[self addObject:[self newObject]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)canAdd
|
||||||
|
{
|
||||||
|
return [self isEditable];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)remove:(id)aSender
|
||||||
|
{
|
||||||
|
// FIXME: This should happen on the next run loop?
|
||||||
|
[self removeObject:[self content]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)canRemove
|
||||||
|
{
|
||||||
|
return [self isEditable] && [[self selectedObjects] count];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setEditable:(BOOL)shouldBeEditable
|
||||||
|
{
|
||||||
|
_isEditable = shouldBeEditable;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEditable
|
||||||
|
{
|
||||||
|
return _isEditable;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPArray)selectedObjects
|
||||||
|
{
|
||||||
|
return [[_CPObservableArray alloc] initWithObjects:[_contentObject] count:1];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)selection
|
||||||
|
{
|
||||||
|
return _selection;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_selectionWillChange
|
||||||
|
{
|
||||||
|
[_selection controllerWillChange];
|
||||||
|
[self willChangeValueForKey:@"selection"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_selectionDidChange
|
||||||
|
{
|
||||||
|
if (_selection === undefined || _selection === nil)
|
||||||
|
_selection = [[CPControllerSelectionProxy alloc] initWithController:self];
|
||||||
|
|
||||||
|
[_selection controllerDidChange];
|
||||||
|
[self didChangeValueForKey:@"selection"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)observedKeys
|
||||||
|
{
|
||||||
|
return _observedKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)addObserver:(id)anObserver forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context
|
||||||
|
{
|
||||||
|
[_observedKeys addObject:aKeyPath];
|
||||||
|
[super addObserver:anObserver forKeyPath:aKeyPath options:options context:context];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeObserver:(id)anObserver forKeyPath:(CPString)aKeyPath
|
||||||
|
{
|
||||||
|
[_observedKeys removeObject:aKeyPath];
|
||||||
|
[super removeObserver:anObserver forKeyPath:aKeyPath];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var CPObjectControllerObjectClassNameKey = @"CPObjectControllerObjectClassNameKey",
|
||||||
|
CPObjectControllerIsEditableKey = @"CPObjectControllerIsEditableKey",
|
||||||
|
CPObjectControllerAutomaticallyPreparesContentKey = @"CPObjectControllerAutomaticallyPreparesContentKey";
|
||||||
|
|
||||||
|
@implementation CPObjectController (CPCoding)
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
var objectClassName = [aCoder decodeObjectForKey:CPObjectControllerObjectClassNameKey],
|
||||||
|
objectClass = CPClassFromString(objectClassName);
|
||||||
|
|
||||||
|
// FIXME: Error if objectClass === nil
|
||||||
|
|
||||||
|
[self setObjectClass:objectClass];
|
||||||
|
[self setEditable:[aCoder decodeBoolForKey:CPObjectControllerIsEditableKey]];
|
||||||
|
[self setAutomaticallyPreparesContent:[aCoder decodeBoolForKey:CPObjectControllerAutomaticallyPreparesContentKey] || NO];
|
||||||
|
|
||||||
|
_observedKeys = [[CPCountedSet alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
[aCoder encodeObject:CPStringFromClass(objectClass) forKey:CPObjectControllerObjectClassNameKey];
|
||||||
|
[aCoder encodeObject:[self isEditable] forKey:CPObjectControllerIsEditableKey];
|
||||||
|
|
||||||
|
if (![self automaticallyPreparesContent])
|
||||||
|
[aCoder encodeBOOL:YES forKey:CPObjectControllerAutomaticallyPreparesContentKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPObservationProxy : CPObject
|
||||||
|
{
|
||||||
|
id _keyPath;
|
||||||
|
id _observer;
|
||||||
|
id _object;
|
||||||
|
|
||||||
|
BOOL _notifyObject;
|
||||||
|
|
||||||
|
id _context;
|
||||||
|
int _options;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithKeyPath:(id)aKeyPath observer:(id)anObserver object:(id)anObject
|
||||||
|
{
|
||||||
|
if (self=[super init])
|
||||||
|
{
|
||||||
|
_keyPath = aKeyPath;
|
||||||
|
_observer = anObserver;
|
||||||
|
_object = anObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)observer
|
||||||
|
{
|
||||||
|
return _observer;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)keyPath
|
||||||
|
{
|
||||||
|
return _keyPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)context
|
||||||
|
{
|
||||||
|
return _context;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int)options
|
||||||
|
{
|
||||||
|
return _options;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setNotifyObject:(BOOL)notify
|
||||||
|
{
|
||||||
|
_notifyObject = notify;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEqual:(id)anObject
|
||||||
|
{
|
||||||
|
if ([anObject class] === [self class])
|
||||||
|
{
|
||||||
|
if (anObject._observer === _observer && [anObject._keyPath isEqual:_keyPath] && [anObject._object isEqual:_object])
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)change context:(id)context
|
||||||
|
{
|
||||||
|
if (_notifyObject)
|
||||||
|
[_object observeValueForKeyPath:_keyPath ofObject:_object change:change context:context];
|
||||||
|
|
||||||
|
[_observer observeValueForKeyPath:_keyPath ofObject:_object change:change context:context];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)description
|
||||||
|
{
|
||||||
|
return [super description] + [CPString stringWithFormat:@"observation proxy for %@ on key path %@", _observer, _keyPath];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPObservableArray : CPMutableArray
|
||||||
|
{
|
||||||
|
CPArray _observationProxies;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)alloc
|
||||||
|
{
|
||||||
|
var a = [];
|
||||||
|
a.isa = self;
|
||||||
|
|
||||||
|
var ivars = class_copyIvarList(self),
|
||||||
|
count = ivars.length;
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
a[ivar_getName(ivars[count])] = nil;
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)description
|
||||||
|
{
|
||||||
|
return "<_CPObservableArray: "+[super description]+" >";
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithArray:(CPArray)anArray
|
||||||
|
{
|
||||||
|
if (self = [super initWithArray:anArray])
|
||||||
|
{
|
||||||
|
_observationProxies = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithObjects:(CPArray)objects count:(unsigned)count
|
||||||
|
{
|
||||||
|
if (self = [super initWithObjects:objects count:count])
|
||||||
|
{
|
||||||
|
_observationProxies = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)addObserver:(id)anObserver forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context
|
||||||
|
{
|
||||||
|
if (aKeyPath.indexOf("@") === 0)
|
||||||
|
{
|
||||||
|
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObserver object:self];
|
||||||
|
|
||||||
|
proxy._options = options;
|
||||||
|
proxy._context = context;
|
||||||
|
|
||||||
|
[_observationProxies addObject:proxy];
|
||||||
|
|
||||||
|
var dotIndex = aKeyPath.indexOf("."),
|
||||||
|
remaining = aKeyPath.substring(dotIndex+1),
|
||||||
|
indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
|
||||||
|
|
||||||
|
[self addObserver:proxy toObjectsAtIndexes:indexes forKeyPath:remaining options:options context:context];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
|
||||||
|
[self addObserver:anObserver toObjectsAtIndexes:indexes forKeyPath:aKeyPath options:options context:context];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeObserver:(id)anObserver forKeyPath:(CPString)aKeyPath
|
||||||
|
{
|
||||||
|
if (aKeyPath.indexOf("@") === 0)
|
||||||
|
{
|
||||||
|
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObserver object:self],
|
||||||
|
index = [_observationProxies indexOfObject:proxy];
|
||||||
|
|
||||||
|
proxy = [_observationProxies objectAtIndex:index];
|
||||||
|
|
||||||
|
var dotIndex = aKeyPath.indexOf("."),
|
||||||
|
remaining = aKeyPath.substring(dotIndex+1),
|
||||||
|
indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
|
||||||
|
|
||||||
|
[self removeObserver:proxy fromObjectsAtIndexes:indexes forKeyPath:remaining];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
|
||||||
|
[self removeObserver:anObserver fromObjectsAtIndexes:indexes forKeyPath:aKeyPath];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)insertObject:(id)anObject atIndex:(unsigned)anIndex
|
||||||
|
{
|
||||||
|
for (var i=0, count=[_observationProxies count]; i<count; i++)
|
||||||
|
{
|
||||||
|
var proxy = [_observationProxies objectAtIndex:i],
|
||||||
|
keyPath = [proxy keyPath],
|
||||||
|
operator = keyPath.indexOf(".") === 0;
|
||||||
|
|
||||||
|
if (operator)
|
||||||
|
[self willChangeValueForKey:keyPath];
|
||||||
|
|
||||||
|
[anObject addObserver:proxy forKeyPath:keyPath options:[proxy options] context:[proxy context]];
|
||||||
|
|
||||||
|
if (operator)
|
||||||
|
[self didChangeValueForKey:keyPath];
|
||||||
|
}
|
||||||
|
|
||||||
|
[super insertObject:anObject atIndex:anIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeObjectAtIndex:(unsigned)anIndex
|
||||||
|
{
|
||||||
|
for (var i=0, count=[_observationProxies count]; i<count; i++)
|
||||||
|
{
|
||||||
|
var proxy = [_observationProxies objectAtIndex:i],
|
||||||
|
keyPath = [proxy keyPath],
|
||||||
|
operator = keyPath.indexOf(".") === 0;
|
||||||
|
|
||||||
|
if (operator)
|
||||||
|
[self willChangeValueForKey:keyPath];
|
||||||
|
|
||||||
|
[anObject removeObserver:proxy forKeyPath:keyPath];
|
||||||
|
|
||||||
|
if (operator)
|
||||||
|
[self didChangeValueForKey:keyPath];
|
||||||
|
}
|
||||||
|
|
||||||
|
[super removeObjectAtIndex:anIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (_CPObservableArray)objectsAtIndexes:(CPIndexSet)theIndexes
|
||||||
|
{
|
||||||
|
return [_CPObservableArray arrayWithArray:[super objectsAtIndexes:theIndexes]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)addObject:(id)anObject
|
||||||
|
{
|
||||||
|
[self insertObject:anObject atIndex:[self count]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeLastObject
|
||||||
|
{
|
||||||
|
[self removeObjectAtIndex:[self count]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)replaceObjectAtIndex:(unsigned)anIndex withObject:(id)anObject
|
||||||
|
{
|
||||||
|
var currentObject = [self objectAtIndex:anIndex];
|
||||||
|
|
||||||
|
for (var i=0, count=[_observationProxies count]; i<count; i++)
|
||||||
|
{
|
||||||
|
var proxy = [_observationProxies objectAtIndex:i],
|
||||||
|
keyPath = [proxy keyPath],
|
||||||
|
operator = keyPath.indexOf(".") === 0;
|
||||||
|
|
||||||
|
if (operator)
|
||||||
|
[self willChangeValueForKey:keyPath];
|
||||||
|
|
||||||
|
[currentObject removeObserver:proxy forKeyPath:keyPath];
|
||||||
|
[anObject addObserver:proxy forKeyPath:keyPath options:[proxy options] context:[proxy context]];
|
||||||
|
|
||||||
|
if (operator)
|
||||||
|
[self didChangeValueForKey:keyPath];
|
||||||
|
}
|
||||||
|
|
||||||
|
[super replaceObjectAtIndex:anIndex withObject:anObject];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation CPControllerSelectionProxy : CPObject
|
||||||
|
{
|
||||||
|
id _controller;
|
||||||
|
id _keys;
|
||||||
|
|
||||||
|
CPDictionary _cachedValues;
|
||||||
|
CPArray _observationProxies;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithController:(id)aController
|
||||||
|
{
|
||||||
|
if (self = [super init])
|
||||||
|
{
|
||||||
|
_cachedValues = [CPDictionary dictionary];
|
||||||
|
_observationProxies = [CPArray array];
|
||||||
|
_controller = aController;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)valueForKey:(CPString)aKey
|
||||||
|
{
|
||||||
|
var value = [_cachedValues objectForKey:aKey];
|
||||||
|
|
||||||
|
if (value !== undefined && value !== nil)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
var allValues = [[_controller selectedObjects] valueForKeyPath:aKey],
|
||||||
|
count = [allValues count];
|
||||||
|
|
||||||
|
if (!count)
|
||||||
|
value = CPNoSelectionMarker;
|
||||||
|
else if (count === 1)
|
||||||
|
value = [allValues objectAtIndex:0];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ([_controller alwaysUsesMultipleValuesMarker])
|
||||||
|
value = CPMultipleValuesMarker;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value = [allValues objectAtIndex:0];
|
||||||
|
|
||||||
|
for (var i=0, count=[allValues count]; i<count && value!=CPMultipleValuesMarker; i++)
|
||||||
|
{
|
||||||
|
if (![value isEqual:[allValues objectAtIndex:i]])
|
||||||
|
value = CPMultipleValuesMarker;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[_cachedValues setValue:value forKey:aKey];
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (unsigned)count
|
||||||
|
{
|
||||||
|
return [_cachedValues count];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)keyEnumerator
|
||||||
|
{
|
||||||
|
return [_cachedValues keyEnumerator];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setValue:(id)aValue forKey:(CPString)aKey
|
||||||
|
{
|
||||||
|
[[_controller selectedObjects] setValue:aValue forKey:aKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)controllerWillChange
|
||||||
|
{
|
||||||
|
_keys = [_cachedValues allKeys];
|
||||||
|
|
||||||
|
if (!_keys)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (var i=0, count=_keys.length; i<count; i++)
|
||||||
|
[self willChangeValueForKey:_keys[i]];
|
||||||
|
|
||||||
|
[_cachedValues removeAllObjects];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)controllerDidChange
|
||||||
|
{
|
||||||
|
[_cachedValues removeAllObjects];
|
||||||
|
|
||||||
|
if (!_keys)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (var i=0, count=_keys.length; i<count; i++)
|
||||||
|
[self didChangeValueForKey:_keys[i]];
|
||||||
|
|
||||||
|
_keys = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)change context:(id)context
|
||||||
|
{
|
||||||
|
[_cachedValues removeObjectForKey:aKeyPath];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)addObserver:(id)anObject forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context
|
||||||
|
{
|
||||||
|
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObject object:self];
|
||||||
|
|
||||||
|
[proxy setNotifyObject:YES];
|
||||||
|
[_observationProxies addObject:proxy];
|
||||||
|
|
||||||
|
[[_controller selectedObjects] addObserver:proxy forKeyPath:aKeyPath options:options context:context];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeObserver:(id)anObject forKeyPath:(CPString)aKeyPath
|
||||||
|
{
|
||||||
|
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObject object:self],
|
||||||
|
index = [_observationProxies indexOfObject:proxy];
|
||||||
|
|
||||||
|
[[_controller selectedObjects] removeObserver:[_observationProxies objectAtIndex:index] forKeyPath:aKeyPath];
|
||||||
|
[_observationProxies removeObjectAtIndex:index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
@import <AppKit/CPPanel.j>
|
@import "CPPanel.j"
|
||||||
|
|
||||||
|
|
||||||
@implementation CPOpenPanel : CPPanel
|
@implementation CPOpenPanel : CPPanel
|
||||||
|
|||||||
+557
-76
@@ -23,8 +23,6 @@
|
|||||||
@import "CPTableColumn.j"
|
@import "CPTableColumn.j"
|
||||||
@import "CPTableView.j"
|
@import "CPTableView.j"
|
||||||
|
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
|
|
||||||
CPOutlineViewColumnDidMoveNotification = @"CPOutlineViewColumnDidMoveNotification";
|
CPOutlineViewColumnDidMoveNotification = @"CPOutlineViewColumnDidMoveNotification";
|
||||||
CPOutlineViewColumnDidResizeNotification = @"CPOutlineViewColumnDidResizeNotification";
|
CPOutlineViewColumnDidResizeNotification = @"CPOutlineViewColumnDidResizeNotification";
|
||||||
@@ -50,6 +48,33 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
|||||||
|
|
||||||
CPOutlineViewDataSource_outlineView_sortDescriptorsDidChange_ = 1 << 10;
|
CPOutlineViewDataSource_outlineView_sortDescriptorsDidChange_ = 1 << 10;
|
||||||
|
|
||||||
|
var CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_ = 1 << 1,
|
||||||
|
CPOutlineViewDelegate_outlineView_didClickTableColumn_ = 1 << 2,
|
||||||
|
CPOutlineViewDelegate_outlineView_didDragTableColumn_ = 1 << 3,
|
||||||
|
CPOutlineViewDelegate_outlineView_heightOfRowByItem_ = 1 << 4,
|
||||||
|
CPOutlineViewDelegate_outlineView_isGroupItem_ = 1 << 5,
|
||||||
|
CPOutlineViewDelegate_outlineView_mouseDownInHeaderOfTableColumn_ = 1 << 6,
|
||||||
|
CPOutlineViewDelegate_outlineView_nextTypeSelectMatchFromItem_toItem_forString_ = 1 << 7,
|
||||||
|
CPOutlineViewDelegate_outlineView_selectionIndexesForProposedSelection_ = 1 << 8,
|
||||||
|
CPOutlineViewDelegate_outlineView_shouldCollapseItem_ = 1 << 9,
|
||||||
|
CPOutlineViewDelegate_outlineView_shouldEditTableColumn_item_ = 1 << 10,
|
||||||
|
CPOutlineViewDelegate_outlineView_shouldExpandItem_ = 1 << 11,
|
||||||
|
CPOutlineViewDelegate_outlineView_shouldReorderColumn_toColumn_ = 1 << 12,
|
||||||
|
CPOutlineViewDelegate_outlineView_shouldSelectItem_ = 1 << 13,
|
||||||
|
CPOutlineViewDelegate_outlineView_shouldSelectTableColumn_ = 1 << 14,
|
||||||
|
CPOutlineViewDelegate_outlineView_shouldShowOutlineViewForItem_ = 1 << 15,
|
||||||
|
CPOutlineViewDelegate_outlineView_shouldShowViewExpansionForTableColumn_item_ = 1 << 16,
|
||||||
|
CPOutlineViewDelegate_outlineView_shouldTrackView_forTableColumn_item_ = 1 << 17,
|
||||||
|
CPOutlineViewDelegate_outlineView_shouldTypeSelectForEvent_withCurrentSearchString_ = 1 << 18,
|
||||||
|
CPOutlineViewDelegate_outlineView_sizeToFitWidthOfColumn_ = 1 << 19,
|
||||||
|
CPOutlineViewDelegate_outlineView_toolTipForView_rect_tableColumn_item_mouseLocation_ = 1 << 20,
|
||||||
|
CPOutlineViewDelegate_outlineView_typeSelectStringForTableColumn_item_ = 1 << 21,
|
||||||
|
CPOutlineViewDelegate_outlineView_willDisplayOutlineView_forTableColumn_item_ = 1 << 22,
|
||||||
|
CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ = 1 << 23,
|
||||||
|
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ = 1 << 24;
|
||||||
|
|
||||||
|
CPOutlineViewDropOnItemIndex = -1;
|
||||||
|
|
||||||
@implementation CPOutlineView : CPTableView
|
@implementation CPOutlineView : CPTableView
|
||||||
{
|
{
|
||||||
id _outlineViewDataSource;
|
id _outlineViewDataSource;
|
||||||
@@ -60,6 +85,7 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
|||||||
BOOL _indentationMarkerFollowsDataView;
|
BOOL _indentationMarkerFollowsDataView;
|
||||||
|
|
||||||
CPInteger _implementedOutlineViewDataSourceMethods;
|
CPInteger _implementedOutlineViewDataSourceMethods;
|
||||||
|
CPInteger _implementedOutlineViewDelegateMethods;
|
||||||
|
|
||||||
Object _rootItemInfo;
|
Object _rootItemInfo;
|
||||||
CPMutableArray _itemsForRows;
|
CPMutableArray _itemsForRows;
|
||||||
@@ -69,6 +95,14 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
|||||||
CPArray _disclosureControlsForRows;
|
CPArray _disclosureControlsForRows;
|
||||||
CPData _disclosureControlData;
|
CPData _disclosureControlData;
|
||||||
CPArray _disclosureControlQueue;
|
CPArray _disclosureControlQueue;
|
||||||
|
|
||||||
|
BOOL _shouldRetargetItem;
|
||||||
|
id _retargetedItem;
|
||||||
|
|
||||||
|
BOOL _shouldRetargetChildIndex;
|
||||||
|
CPInteger _retargedChildIndex;
|
||||||
|
CPTimer _dragHoverTimer;
|
||||||
|
id _dropItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
@@ -77,6 +111,9 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
_selectionHighlightStyle = CPTableViewSelectionHighlightStyleSourceList;
|
||||||
|
|
||||||
// The root item has weight "0", thus represents the weight solely of its descendants.
|
// The root item has weight "0", thus represents the weight solely of its descendants.
|
||||||
_rootItemInfo = { isExpanded:YES, isExpandable:NO, level:-1, row:-1, children:[], weight:0 };
|
_rootItemInfo = { isExpanded:YES, isExpandable:NO, level:-1, row:-1, children:[], weight:0 };
|
||||||
|
|
||||||
@@ -84,10 +121,18 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
|||||||
_itemInfosForItems = { };
|
_itemInfosForItems = { };
|
||||||
_disclosureControlsForRows = [];
|
_disclosureControlsForRows = [];
|
||||||
|
|
||||||
|
_retargetedItem = nil;
|
||||||
|
_shouldRetargetItem = NO;
|
||||||
|
|
||||||
|
_retargedChildIndex = nil;
|
||||||
|
_shouldRetargetChildIndex = NO;
|
||||||
|
_startHoverTime = nil;
|
||||||
|
|
||||||
[self setIndentationPerLevel:16.0];
|
[self setIndentationPerLevel:16.0];
|
||||||
[self setIndentationMarkerFollowsDataView:YES];
|
[self setIndentationMarkerFollowsDataView:YES];
|
||||||
|
|
||||||
[super setDataSource:[[_CPOutlineViewTableViewDataSource alloc] initWithOutlineView:self]];
|
[super setDataSource:[[_CPOutlineViewTableViewDataSource alloc] initWithOutlineView:self]];
|
||||||
|
[super setDelegate:[[_CPOutlineViewTableViewDelegate alloc] initWithOutlineView:self]];
|
||||||
|
|
||||||
[self setDisclosureControlPrototype:[[CPDisclosureButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 10.0)]];
|
[self setDisclosureControlPrototype:[[CPDisclosureButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 10.0)]];
|
||||||
}
|
}
|
||||||
@@ -181,22 +226,40 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
|||||||
|
|
||||||
- (void)expandItem:(id)anItem
|
- (void)expandItem:(id)anItem
|
||||||
{
|
{
|
||||||
if (!anItem)
|
[self expandItem:anItem expandChildren:NO];
|
||||||
return;
|
}
|
||||||
|
|
||||||
var itemInfo = _itemInfosForItems[[anItem UID]];
|
- (void)expandItem:(id)anItem expandChildren:(BOOL)shouldExpandChildren
|
||||||
|
{
|
||||||
|
var itemInfo = null;
|
||||||
|
|
||||||
|
if (!anItem)
|
||||||
|
itemInfo = _rootItemInfo;
|
||||||
|
else
|
||||||
|
itemInfo = _itemInfosForItems[[anItem UID]];
|
||||||
|
|
||||||
if (!itemInfo)
|
if (!itemInfo)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (itemInfo.isExpanded)
|
// to prevent items which are already expanded from firing notifications
|
||||||
return;
|
if (!itemInfo.isExpanded)
|
||||||
|
{
|
||||||
|
[self _noteItemWillExpand:anItem];
|
||||||
itemInfo.isExpanded = YES;
|
itemInfo.isExpanded = YES;
|
||||||
|
[self _noteItemDidExpand:anItem];
|
||||||
[self reloadItem:anItem reloadChildren:YES];
|
[self reloadItem:anItem reloadChildren:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shouldExpandChildren)
|
||||||
|
{
|
||||||
|
var children = itemInfo.children,
|
||||||
|
childIndex = children.length;
|
||||||
|
|
||||||
|
while (childIndex--)
|
||||||
|
[self expandItem:children[childIndex] expandChildren:YES];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)collapseItem:(id)anItem
|
- (void)collapseItem:(id)anItem
|
||||||
{
|
{
|
||||||
if (!anItem)
|
if (!anItem)
|
||||||
@@ -210,7 +273,9 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
|||||||
if (!itemInfo.isExpanded)
|
if (!itemInfo.isExpanded)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
[self _noteItemWillCollapse:anItem];
|
||||||
itemInfo.isExpanded = NO;
|
itemInfo.isExpanded = NO;
|
||||||
|
[self _noteItemDidCollapse:anItem];
|
||||||
|
|
||||||
[self reloadItem:anItem reloadChildren:YES];
|
[self reloadItem:anItem reloadChildren:YES];
|
||||||
}
|
}
|
||||||
@@ -324,7 +389,13 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
|||||||
if (!itemInfo)
|
if (!itemInfo)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
return itemInfo.parent;
|
var parent = itemInfo.parent;
|
||||||
|
|
||||||
|
// Check if the parent is the root item because we never return the actual root item
|
||||||
|
if (itemInfo[[parent UID]] === _rootItemInfo)
|
||||||
|
parent = nil;
|
||||||
|
|
||||||
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)frameOfOutlineDataViewAtColumn:(CPInteger)aColumn row:(CPInteger)aRow
|
- (CGRect)frameOfOutlineDataViewAtColumn:(CPInteger)aColumn row:(CPInteger)aRow
|
||||||
@@ -338,6 +409,16 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
|||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)_performSelection:(BOOL)select forRow:(CPInteger)rowIndex context:(id)context
|
||||||
|
{
|
||||||
|
[super _performSelection:select forRow:rowIndex context:context];
|
||||||
|
|
||||||
|
var control = _disclosureControlsForRows[rowIndex],
|
||||||
|
selector = select ? @"setThemeState:" : @"unsetThemeState:";
|
||||||
|
|
||||||
|
[control performSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelected];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setDelegate:(id)aDelegate
|
- (void)setDelegate:(id)aDelegate
|
||||||
{
|
{
|
||||||
if (_outlineViewDelegate === aDelegate)
|
if (_outlineViewDelegate === aDelegate)
|
||||||
@@ -370,65 +451,77 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
|||||||
removeObserver:_outlineViewDelegate
|
removeObserver:_outlineViewDelegate
|
||||||
name:CPOutlineViewSelectionIsChangingNotification
|
name:CPOutlineViewSelectionIsChangingNotification
|
||||||
object:self];
|
object:self];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemWillExpand:)])
|
||||||
|
[defaultCenter
|
||||||
|
removeObserver:_outlineViewDelegate
|
||||||
|
name:CPOutlineViewItemWillExpandNotification
|
||||||
|
object:self];
|
||||||
|
|
||||||
|
|
||||||
|
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemDidExpand:)])
|
||||||
|
[defaultCenter
|
||||||
|
removeObserver:_outlineViewDelegate
|
||||||
|
name:CPOutlineViewItemDidExpandNotification
|
||||||
|
object:self];
|
||||||
|
|
||||||
|
|
||||||
|
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemWillCollapse:)])
|
||||||
|
[defaultCenter
|
||||||
|
removeObserver:_outlineViewDelegate
|
||||||
|
name:CPOutlineViewItemWillCollapseNotification
|
||||||
|
object:self];
|
||||||
|
|
||||||
|
|
||||||
|
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemDidCollapse:)])
|
||||||
|
[defaultCenter
|
||||||
|
removeObserver:_outlineViewDelegate
|
||||||
|
name:CPOutlineViewItemDidCollapseNotification
|
||||||
|
object:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
_outlineViewDelegate = aDelegate;/*
|
_outlineViewDelegate = aDelegate;
|
||||||
_implementedDelegateMethods = 0;
|
_implementedOutlineViewDelegateMethods = 0;
|
||||||
|
|
||||||
if ([_outlineViewDelegate respondsToSelector:@selector(selectionShouldChangeInTableView:)])
|
var delegateMethods = [
|
||||||
_implementedDelegateMethods |= CPTableViewDelegate_selectionShouldChangeInTableView_;
|
CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_ , @selector(outlineView:dataViewForTableColumn:item:),
|
||||||
|
CPOutlineViewDelegate_outlineView_didClickTableColumn_ , @selector(outlineView:didClickTableColumn:),
|
||||||
|
CPOutlineViewDelegate_outlineView_didDragTableColumn_ , @selector(outlineView:didDragTableColumn:),
|
||||||
|
CPOutlineViewDelegate_outlineView_heightOfRowByItem_ , @selector(outlineView:heightOfRowByItem:),
|
||||||
|
CPOutlineViewDelegate_outlineView_isGroupItem_ , @selector(outlineView:isGroupItem:),
|
||||||
|
CPOutlineViewDelegate_outlineView_mouseDownInHeaderOfTableColumn_ , @selector(outlineView:mouseDownInHeaderOfTableColumn:),
|
||||||
|
CPOutlineViewDelegate_outlineView_nextTypeSelectMatchFromItem_toItem_forString_ , @selector(outlineView:nextTypeSelectMatchFromItem:toItem:forString:),
|
||||||
|
CPOutlineViewDelegate_outlineView_selectionIndexesForProposedSelection_ , @selector(outlineView:selectionIndexesForProposedSelection:),
|
||||||
|
CPOutlineViewDelegate_outlineView_shouldCollapseItem_ , @selector(outlineView:shouldCollapseItem:),
|
||||||
|
CPOutlineViewDelegate_outlineView_shouldEditTableColumn_item_ , @selector(outlineView:shouldEditTableColumn:item:),
|
||||||
|
CPOutlineViewDelegate_outlineView_shouldExpandItem_ , @selector(outlineView:shouldExpandItem:),
|
||||||
|
CPOutlineViewDelegate_outlineView_shouldReorderColumn_toColumn_ , @selector(outlineView:shouldReorderColumn:toColumn:),
|
||||||
|
CPOutlineViewDelegate_outlineView_shouldSelectItem_ , @selector(outlineView:shouldSelectItem:),
|
||||||
|
CPOutlineViewDelegate_outlineView_shouldSelectTableColumn_ , @selector(outlineView:shouldSelectTableColumn:),
|
||||||
|
CPOutlineViewDelegate_outlineView_shouldShowOutlineViewForItem_ , @selector(outlineView:shouldShowOutlineViewForItem:),
|
||||||
|
CPOutlineViewDelegate_outlineView_shouldShowViewExpansionForTableColumn_item_ , @selector(outlineView:shouldShowViewExpansionForTableColumn:item:),
|
||||||
|
CPOutlineViewDelegate_outlineView_shouldTrackView_forTableColumn_item_ , @selector(outlineView:shouldTrackView:forTableColumn:item:),
|
||||||
|
CPOutlineViewDelegate_outlineView_shouldTypeSelectForEvent_withCurrentSearchString_ , @selector(outlineView:shouldTypeSelectForEvent:withCurrentSearchString:),
|
||||||
|
CPOutlineViewDelegate_outlineView_sizeToFitWidthOfColumn_ , @selector(outlineView:sizeToFitWidthOfColumn:),
|
||||||
|
CPOutlineViewDelegate_outlineView_toolTipForView_rect_tableColumn_item_mouseLocation_, @selector(outlineView:toolTipForView:rect:tableColumn:item:mouseLocation:),
|
||||||
|
CPOutlineViewDelegate_outlineView_typeSelectStringForTableColumn_item_ , @selector(outlineView:typeSelectStringForTableColumn:item:),
|
||||||
|
CPOutlineViewDelegate_outlineView_willDisplayOutlineView_forTableColumn_item_ , @selector(outlineView:willDisplayOutlineView:forTableColumn:item:),
|
||||||
|
CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ , @selector(outlineView:willDisplayView:forTableColumn:item:),
|
||||||
|
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ , @selector(selectionShouldChangeInOutlineView:)
|
||||||
|
],
|
||||||
|
delegateCount = [delegateMethods count];
|
||||||
|
|
||||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:dataViewForTableColumn:row:)])
|
for (var i=0; i < delegateCount; i += 2)
|
||||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_dataViewForTableColumn_row_;
|
{
|
||||||
|
var bitMask = delegateMethods[i],
|
||||||
|
selector = delegateMethods[i+1];
|
||||||
|
|
||||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:didClickTableColumn:)])
|
if ([_outlineViewDelegate respondsToSelector:selector])
|
||||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_didClickTableColumn_;
|
_implementedOutlineViewDelegateMethods |= bitMask;
|
||||||
|
}
|
||||||
|
|
||||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:didDragTableColumn:)])
|
|
||||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_didDragTableColumn_;
|
|
||||||
|
|
||||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:heightOfRow:)])
|
|
||||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_heightOfRow_;
|
|
||||||
|
|
||||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:isGroupRow:)])
|
|
||||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_isGroupRow_;
|
|
||||||
|
|
||||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:mouseDownInHeaderOfTableColumn:)])
|
|
||||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_mouseDownInHeaderOfTableColumn_;
|
|
||||||
|
|
||||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:nextTypeSelectMatchFromRow:toRow:forString:)])
|
|
||||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_nextTypeSelectMatchFromRow_toRow_forString_;
|
|
||||||
|
|
||||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:selectionIndexesForProposedSelection:)])
|
|
||||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_selectionIndexesForProposedSelection_;
|
|
||||||
|
|
||||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldEditTableColumn:row:)])
|
|
||||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldEditTableColumn_row_;
|
|
||||||
|
|
||||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldSelectRow:)])
|
|
||||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldSelectRow_;
|
|
||||||
|
|
||||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldSelectTableColumn:)])
|
|
||||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldSelectTableColumn_;
|
|
||||||
|
|
||||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldShowViewExpansionForTableColumn:row:)])
|
|
||||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldShowViewExpansionForTableColumn_row_;
|
|
||||||
|
|
||||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldTrackView:forTableColumn:row:)])
|
|
||||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldTrackView_forTableColumn_row_;
|
|
||||||
|
|
||||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:shouldTypeSelectForEvent:withCurrentSearchString:)])
|
|
||||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_shouldTypeSelectForEvent_withCurrentSearchString_;
|
|
||||||
|
|
||||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:toolTipForView:rect:tableColumn:row:mouseLocation:)])
|
|
||||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_toolTipForView_rect_tableColumn_row_mouseLocation_;
|
|
||||||
|
|
||||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:typeSelectStringForTableColumn:row:)])
|
|
||||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_typeSelectStringForTableColumn_row_;
|
|
||||||
|
|
||||||
if ([_outlineViewDelegate respondsToSelector:@selector(tableView:willDisplayView:forTableColumn:row:)])
|
|
||||||
_implementedDelegateMethods |= CPTableViewDelegate_tableView_willDisplayView_forTableColumn_row_;
|
|
||||||
*/
|
|
||||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewColumnDidMove:)])
|
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewColumnDidMove:)])
|
||||||
[defaultCenter
|
[defaultCenter
|
||||||
addObserver:_outlineViewDelegate
|
addObserver:_outlineViewDelegate
|
||||||
@@ -456,6 +549,36 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
|||||||
selector:@selector(outlineViewSelectionIsChanging:)
|
selector:@selector(outlineViewSelectionIsChanging:)
|
||||||
name:CPOutlineViewSelectionIsChangingNotification
|
name:CPOutlineViewSelectionIsChangingNotification
|
||||||
object:self];
|
object:self];
|
||||||
|
|
||||||
|
|
||||||
|
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemWillExpand:)])
|
||||||
|
[defaultCenter
|
||||||
|
addObserver:_outlineViewDelegate
|
||||||
|
selector:@selector(outlineViewItemWillExpand:)
|
||||||
|
name:CPOutlineViewItemWillExpandNotification
|
||||||
|
object:self];
|
||||||
|
|
||||||
|
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemDidExpand:)])
|
||||||
|
[defaultCenter
|
||||||
|
addObserver:_outlineViewDelegate
|
||||||
|
selector:@selector(outlineViewItemDidExpand:)
|
||||||
|
name:CPOutlineViewItemDidExpandNotification
|
||||||
|
object:self];
|
||||||
|
|
||||||
|
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemWillCollapse:)])
|
||||||
|
[defaultCenter
|
||||||
|
addObserver:_outlineViewDelegate
|
||||||
|
selector:@selector(outlineViewItemWillCollapse:)
|
||||||
|
name:CPOutlineViewItemWillCollapseNotification
|
||||||
|
object:self];
|
||||||
|
|
||||||
|
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemDidCollapse:)])
|
||||||
|
[defaultCenter
|
||||||
|
addObserver:_outlineViewDelegate
|
||||||
|
selector:@selector(outlineViewItemDidCollapse:)
|
||||||
|
name:CPOutlineViewItemDidCollapseNotification
|
||||||
|
object:self];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)delegate
|
- (id)delegate
|
||||||
@@ -488,6 +611,100 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
|||||||
return [super frameOfDataViewAtColumn:aColumn row:aRow];
|
return [super frameOfDataViewAtColumn:aColumn row:aRow];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setDropItem:(id)theItem dropChildIndex:(int)theIndex
|
||||||
|
{
|
||||||
|
if (_dropItem !== theItem && theIndex < 0 && [self isExpandable:theItem] && ![self isItemExpanded:theItem])
|
||||||
|
{
|
||||||
|
if (_dragHoverTimer)
|
||||||
|
[_dragHoverTimer invalidate];
|
||||||
|
|
||||||
|
var autoExpandCallBack = function(){
|
||||||
|
if (_dropItem)
|
||||||
|
{
|
||||||
|
[_dropOperationFeedbackView blink];
|
||||||
|
[CPTimer scheduledTimerWithTimeInterval:.3 callback:objj_msgSend(self, "expandItem:", _dropItem) repeats:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_dragHoverTimer = [CPTimer scheduledTimerWithTimeInterval:.8 callback:autoExpandCallBack repeats:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (theIndex >= 0)
|
||||||
|
{
|
||||||
|
[_dragHoverTimer invalidate];
|
||||||
|
_dragHoverTimer = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dropItem = theItem;
|
||||||
|
_retargetedItem = theItem;
|
||||||
|
_shouldRetargetItem = YES;
|
||||||
|
|
||||||
|
_retargedChildIndex = theIndex;
|
||||||
|
_shouldRetargetChildIndex = YES;
|
||||||
|
|
||||||
|
// set CPTableView's _retargetedDropRow based on retargetedItem and retargetedChildIndex
|
||||||
|
var retargetedItemInfo = (_retargetedItem !== nil) ? _itemInfosForItems[[_retargetedItem UID]] : _rootItemInfo;
|
||||||
|
|
||||||
|
if (_retargedChildIndex === [retargetedItemInfo.children count])
|
||||||
|
{
|
||||||
|
var retargetedChildItem = [retargetedItemInfo.children lastObject];
|
||||||
|
_retargetedDropRow = [self rowForItem:retargetedChildItem] + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var retargetedChildItem = (_retargedChildIndex !== CPOutlineViewDropOnItemIndex) ? retargetedItemInfo.children[_retargedChildIndex] : _retargetedItem;
|
||||||
|
_retargetedDropRow = [self rowForItem:retargetedChildItem];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_draggingEnded
|
||||||
|
{
|
||||||
|
[super _draggingEnded];
|
||||||
|
_dropItem = nil;
|
||||||
|
[_dragHoverTimer invalidate];
|
||||||
|
_dragHoverTimer = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)_parentItemForUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex atMouseOffset:(CPPoint)theOffset
|
||||||
|
{
|
||||||
|
if (_shouldRetargetItem)
|
||||||
|
return _retargetedItem;
|
||||||
|
|
||||||
|
var lowerLevel = [self levelForRow:theLowerRowIndex]
|
||||||
|
upperItem = [self itemAtRow:theUpperRowIndex];
|
||||||
|
upperLevel = [self levelForItem:upperItem];
|
||||||
|
|
||||||
|
// If the row above us has a higher level the item can be added to multiple parent items
|
||||||
|
// Determine which one by looping through all possible parents and return the first
|
||||||
|
// of which the indentation level is larger than the current x offset
|
||||||
|
while (upperLevel > lowerLevel)
|
||||||
|
{
|
||||||
|
upperLevel = [self levelForItem:upperItem];
|
||||||
|
|
||||||
|
// See if this item's indentation level matches the mouse offset
|
||||||
|
if (theOffset.x > (upperLevel + 1) * [self indentationPerLevel])
|
||||||
|
return [self parentForItem:upperItem];
|
||||||
|
|
||||||
|
// Check the next parent
|
||||||
|
upperItem = [self parentForItem:upperItem];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [self parentForItem:[self itemAtRow:theLowerRowIndex]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPRect)_rectForDropHighlightViewBetweenUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex offset:(CPPoint)theOffset
|
||||||
|
{
|
||||||
|
// Call super and the update x to reflect the current indentation level
|
||||||
|
var rect = [super _rectForDropHighlightViewBetweenUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex offset:theOffset],
|
||||||
|
parentItem = [self _parentItemForUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex atMouseOffset:theOffset],
|
||||||
|
level = [self levelForItem:parentItem];
|
||||||
|
|
||||||
|
rect.origin.x = (level + 1) * [self indentationPerLevel];
|
||||||
|
rect.size.width -= rect.origin.x; // This assumes that the x returned by super is zero
|
||||||
|
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)_loadDataViewsInRows:(CPIndexSet)rows columns:(CPIndexSet)columns
|
- (void)_loadDataViewsInRows:(CPIndexSet)rows columns:(CPIndexSet)columns
|
||||||
{
|
{
|
||||||
[super _loadDataViewsInRows:rows columns:columns];
|
[super _loadDataViewsInRows:rows columns:columns];
|
||||||
@@ -526,6 +743,8 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
|||||||
_disclosureControlsForRows[row] = control;
|
_disclosureControlsForRows[row] = control;
|
||||||
|
|
||||||
[control setState:[self isItemExpanded:item] ? CPOnState : CPOffState];
|
[control setState:[self isItemExpanded:item] ? CPOnState : CPOffState];
|
||||||
|
var selector = [self isRowSelected:row] ? @"setThemeState:" : @"unsetThemeState:";
|
||||||
|
[control performSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelected];
|
||||||
[control setFrame:frame];
|
[control setFrame:frame];
|
||||||
|
|
||||||
[self addSubview:control];
|
[self addSubview:control];
|
||||||
@@ -616,16 +835,51 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
|||||||
userInfo:nil];
|
userInfo:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)_noteItemWillExpand:(id)item
|
||||||
|
{
|
||||||
|
[[CPNotificationCenter defaultCenter]
|
||||||
|
postNotificationName:CPOutlineViewItemWillExpandNotification
|
||||||
|
object:self
|
||||||
|
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_noteItemDidExpand:(id)item
|
||||||
|
{
|
||||||
|
[[CPNotificationCenter defaultCenter]
|
||||||
|
postNotificationName:CPOutlineViewItemDidExpandNotification
|
||||||
|
object:self
|
||||||
|
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_noteItemWillCollapse:(id)item
|
||||||
|
{
|
||||||
|
[[CPNotificationCenter defaultCenter]
|
||||||
|
postNotificationName:CPOutlineViewItemWillCollapseNotification
|
||||||
|
object:self
|
||||||
|
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_noteItemDidCollapse:(id)item
|
||||||
|
{
|
||||||
|
[[CPNotificationCenter defaultCenter]
|
||||||
|
postNotificationName:CPOutlineViewItemDidCollapseNotification
|
||||||
|
object:self
|
||||||
|
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
// FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever...
|
||||||
var _reloadItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem)
|
var _reloadItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem)
|
||||||
{
|
{
|
||||||
if (!anItem)
|
if (!anItem)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
with(anOutlineView)
|
||||||
|
{
|
||||||
// Get the existing info if it exists.
|
// Get the existing info if it exists.
|
||||||
var itemInfosForItems = anOutlineView._itemInfosForItems,
|
var itemInfosForItems = _itemInfosForItems,
|
||||||
dataSource = anOutlineView._outlineViewDataSource,
|
dataSource = _outlineViewDataSource,
|
||||||
itemUID = [anItem UID],
|
itemUID = [anItem UID],
|
||||||
itemInfo = itemInfosForItems[itemUID];
|
itemInfo = itemInfosForItems[itemUID];
|
||||||
|
|
||||||
@@ -635,7 +889,7 @@ var _reloadItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem)
|
|||||||
|
|
||||||
// See if the item itself can be swapped out.
|
// See if the item itself can be swapped out.
|
||||||
var parent = itemInfo.parent,
|
var parent = itemInfo.parent,
|
||||||
parentItemInfo = parent ? itemInfosForItems[[parent UID]] : anOutlineView._rootItemInfo,
|
parentItemInfo = parent ? itemInfosForItems[[parent UID]] : _rootItemInfo,
|
||||||
parentChildren = parentItemInfo.children,
|
parentChildren = parentItemInfo.children,
|
||||||
index = [parentChildren indexOfObjectIdenticalTo:anItem],
|
index = [parentChildren indexOfObjectIdenticalTo:anItem],
|
||||||
newItem = [dataSource outlineView:anOutlineView child:index ofItem:parent];
|
newItem = [dataSource outlineView:anOutlineView child:index ofItem:parent];
|
||||||
@@ -646,20 +900,24 @@ var _reloadItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem)
|
|||||||
itemInfosForItems[[newItem UID]] = itemInfo;
|
itemInfosForItems[[newItem UID]] = itemInfo;
|
||||||
|
|
||||||
parentChildren[index] = newItem;
|
parentChildren[index] = newItem;
|
||||||
anOutlineView._itemsForRows[itemInfo.row] = newItem;
|
_itemsForRows[itemInfo.row] = newItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:newItem];
|
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:newItem];
|
||||||
itemInfo.isExpanded = itemInfo.isExpandable && itemInfo.isExpanded;
|
itemInfo.isExpanded = itemInfo.isExpandable && itemInfo.isExpanded;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever...
|
||||||
var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem, /*BOOL*/ isIntermediate)
|
var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem, /*BOOL*/ isIntermediate)
|
||||||
{
|
{
|
||||||
var itemInfosForItems = anOutlineView._itemInfosForItems,
|
with(anOutlineView)
|
||||||
dataSource = anOutlineView._outlineViewDataSource;
|
{
|
||||||
|
var itemInfosForItems = _itemInfosForItems,
|
||||||
|
dataSource = _outlineViewDataSource;
|
||||||
|
|
||||||
if (!anItem)
|
if (!anItem)
|
||||||
var itemInfo = anOutlineView._rootItemInfo;
|
var itemInfo = _rootItemInfo;
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -686,7 +944,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
|||||||
var weight = itemInfo.weight,
|
var weight = itemInfo.weight,
|
||||||
descendants = anItem ? [anItem] : [];
|
descendants = anItem ? [anItem] : [];
|
||||||
|
|
||||||
if (itemInfo.isExpanded && (!(anOutlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_shouldDeferDisplayingChildrenOfItem_) ||
|
if (itemInfo.isExpanded && (!(_implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_shouldDeferDisplayingChildrenOfItem_) ||
|
||||||
![dataSource outlineView:anOutlineView shouldDeferDisplayingChildrenOfItem:anItem]))
|
![dataSource outlineView:anOutlineView shouldDeferDisplayingChildrenOfItem:anItem]))
|
||||||
{
|
{
|
||||||
var index = 0,
|
var index = 0,
|
||||||
@@ -722,7 +980,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
|||||||
{
|
{
|
||||||
// row = -1 is the root item, so just go to row 0 since it is ignored.
|
// row = -1 is the root item, so just go to row 0 since it is ignored.
|
||||||
var index = MAX(itemInfo.row, 0),
|
var index = MAX(itemInfo.row, 0),
|
||||||
itemsForRows = anOutlineView._itemsForRows;
|
itemsForRows = _itemsForRows;
|
||||||
|
|
||||||
descendants.unshift(index, weight);
|
descendants.unshift(index, weight);
|
||||||
|
|
||||||
@@ -748,10 +1006,10 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (anItem)
|
if (anItem)
|
||||||
anOutlineView._rootItemInfo.weight += deltaWeight;
|
_rootItemInfo.weight += deltaWeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}//end of with
|
||||||
return descendants;
|
return descendants;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -780,6 +1038,100 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
|||||||
return [_outlineView._outlineViewDataSource outlineView:_outlineView objectValueForTableColumn:aTableColumn byItem:_outlineView._itemsForRows[aRow]];
|
return [_outlineView._outlineViewDataSource outlineView:_outlineView objectValueForTableColumn:aTableColumn byItem:_outlineView._itemsForRows[aRow]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)tableView:(CPTableView)aTableView setObjectValue:(id)aValue forTableColumn:(CPTableColumn)aColumn row:(CPInteger)aRow
|
||||||
|
{
|
||||||
|
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_))
|
||||||
|
return;
|
||||||
|
[_outlineView._outlineViewDataSource outlineView:_outlineView setObjectValue:aValue forTableColumn:aColumn byItem:_outlineView._itemsForRows[aRow]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)tableView:(CPTableView)aTableColumn writeRowsWithIndexes:(CPIndexSet)theIndexes toPasteboard:(CPPasteboard)thePasteboard
|
||||||
|
{
|
||||||
|
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_writeItems_toPasteboard_))
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
var rowIndexes = [];
|
||||||
|
[theIndexes getIndexes:rowIndexes maxCount:[theIndexes count] inIndexRange:nil];
|
||||||
|
|
||||||
|
var rowIndex = [rowIndexes count],
|
||||||
|
items = [];
|
||||||
|
|
||||||
|
while (rowIndex--)
|
||||||
|
[items addObject:[_outlineView itemAtRow:[rowIndexes objectAtIndex:rowIndex]]];
|
||||||
|
|
||||||
|
return [_outlineView._outlineViewDataSource outlineView:_outlineView writeItems:items toPasteboard:thePasteboard];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int)_childIndexForDropOperation:(CPTableViewDropOperation)theDropOperation row:(int)theRow offset:(CPPoint)theOffset
|
||||||
|
{
|
||||||
|
if (_outlineView._shouldRetargetChildIndex)
|
||||||
|
return _outlineView._retargedChildIndex;
|
||||||
|
|
||||||
|
var childIndex = CPNotFound;
|
||||||
|
|
||||||
|
if (theDropOperation === CPTableViewDropAbove)
|
||||||
|
{
|
||||||
|
var parentItem = [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset],
|
||||||
|
itemInfo = (parentItem !== nil) ? _outlineView._itemInfosForItems[[parentItem UID]] : _outlineView._rootItemInfo,
|
||||||
|
children = itemInfo.children;
|
||||||
|
|
||||||
|
childIndex = [children indexOfObject:[_outlineView itemAtRow:theRow]];
|
||||||
|
|
||||||
|
if (childIndex === CPNotFound)
|
||||||
|
childIndex = children.length;
|
||||||
|
}
|
||||||
|
else if (theDropOperation === CPTableViewDropOn)
|
||||||
|
childIndex = -1;
|
||||||
|
|
||||||
|
return childIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_parentItemForDropOperation:(CPTableViewDropOperation)theDropOperation row:(int)theRow offset:(CPPoint)theOffset
|
||||||
|
{
|
||||||
|
if (theDropOperation === CPTableViewDropAbove)
|
||||||
|
return [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset]
|
||||||
|
|
||||||
|
return [_outlineView itemAtRow:theRow];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id < CPDraggingInfo >)theInfo
|
||||||
|
proposedRow:(int)theRow proposedDropOperation:(CPTableViewDropOperation)theOperation
|
||||||
|
{
|
||||||
|
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_validateDrop_proposedItem_proposedChildIndex_))
|
||||||
|
return CPDragOperationNone;
|
||||||
|
|
||||||
|
// Make sure the retargeted item and index are reset
|
||||||
|
_outlineView._retargetedItem = nil;
|
||||||
|
_outlineView._shouldRetargetItem = NO;
|
||||||
|
|
||||||
|
_outlineView._retargedChildIndex = nil;
|
||||||
|
_outlineView._shouldRetargetChildIndex = NO;
|
||||||
|
|
||||||
|
var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil],
|
||||||
|
parentItem = [self _parentItemForDropOperation:theOperation row:theRow offset:location],
|
||||||
|
childIndex = [self _childIndexForDropOperation:theOperation row:theRow offset:location];
|
||||||
|
|
||||||
|
return [_outlineView._outlineViewDataSource outlineView:_outlineView validateDrop:theInfo proposedItem:parentItem proposedChildIndex:childIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id <CPDraggingInfo>)theInfo row:(int)theRow dropOperation:(CPTableViewDropOperation)theOperation
|
||||||
|
{
|
||||||
|
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_acceptDrop_item_childIndex_))
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil],
|
||||||
|
parentItem = [self _parentItemForDropOperation:theOperation row:theRow offset:location];
|
||||||
|
childIndex = [self _childIndexForDropOperation:theOperation row:theRow offset:location];
|
||||||
|
|
||||||
|
_outlineView._retargetedItem = nil;
|
||||||
|
_outlineView._shouldRetargetItem = NO;
|
||||||
|
|
||||||
|
_outlineView._retargedChildIndex = nil;
|
||||||
|
_outlineView._shouldRetargetChildIndex = NO;
|
||||||
|
|
||||||
|
return [_outlineView._outlineViewDataSource outlineView:_outlineView acceptDrop:theInfo item:parentItem childIndex:childIndex];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation _CPOutlineViewTableViewDelegate : CPObject
|
@implementation _CPOutlineViewTableViewDelegate : CPObject
|
||||||
@@ -797,6 +1149,62 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CPView)tableView:(CPTableView)theTableView dataViewForTableColumn:(CPTableColumn)theTableColumn row:(int)theRow
|
||||||
|
{
|
||||||
|
var dataView = nil;
|
||||||
|
|
||||||
|
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_))
|
||||||
|
dataView = [_outlineView._outlineViewDelegate outlineView:_outlineView
|
||||||
|
dataViewForTableColumn:theTableColumn
|
||||||
|
item:[_outlineView itemAtRow:theRow]];
|
||||||
|
|
||||||
|
if (!dataView)
|
||||||
|
dataView = [theTableColumn dataViewForRow:theRow];
|
||||||
|
|
||||||
|
return dataView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)tableView:(CPTableView)theTableView shouldSelectRow:(int)theRow
|
||||||
|
{
|
||||||
|
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldSelectItem_))
|
||||||
|
return [_outlineView._outlineViewDelegate outlineView:_outlineView shouldSelectItem:[_outlineView itemAtRow:theRow]];
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)tableView:(CPTableView)aTableView shouldEditTableColumn:(CPTableColumn)aColumn row:(int)aRow
|
||||||
|
{
|
||||||
|
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldEditTableColumn_item_))
|
||||||
|
return [_outlineView._outlineViewDelegate outlineView:_outlineView shouldEditTableColumn:aColumn item:[_outlineView itemAtRow:aRow]];
|
||||||
|
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (float)tableView:(CPTableView)theTableView heightOfRow:(int)theRow
|
||||||
|
{
|
||||||
|
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_heightOfRowByItem_))
|
||||||
|
return [_outlineView._outlineViewDelegate outlineView:_outlineView heightOfRowByItem:[_outlineView itemAtRow:theRow]];
|
||||||
|
|
||||||
|
return [theTableView rowHeight];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tableView:(CPTableView)aTableView willDisplayView:(id)aView forTableColumn:(CPTableColumn)aTableColumn row:(int)aRowIndex
|
||||||
|
{
|
||||||
|
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_))
|
||||||
|
{
|
||||||
|
var item = [_outlineView itemAtRow:aRowIndex];
|
||||||
|
[_outlineView._outlineViewDelegate outlineView:_outlineView willDisplayView:aView forTableColumn:aTableColumn item:item];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)tableView:(CPTableView)aTableView isGroupRow:(int)aRow
|
||||||
|
{
|
||||||
|
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_isGroupItem_))
|
||||||
|
return [_outlineView._outlineViewDelegate outlineView:_outlineView isGroupItem:[_outlineView itemAtRow:aRow]];
|
||||||
|
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation CPDisclosureButton : CPButton
|
@implementation CPDisclosureButton : CPButton
|
||||||
@@ -845,9 +1253,82 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
|||||||
CGContextAddLineToPoint(context, 0.0, 0.0);
|
CGContextAddLineToPoint(context, 0.0, 0.0);
|
||||||
|
|
||||||
CGContextClosePath(context);
|
CGContextClosePath(context);
|
||||||
|
CGContextSetFillColor(context,
|
||||||
CGContextSetFillColor(context, ([self themeState] & CPThemeState("highlighted")) ? [CPColor blackColor] : [CPColor grayColor]);
|
colorForDisclosureTriangle([self hasThemeState:CPThemeStateSelected],
|
||||||
|
[self hasThemeState:CPThemeStateHighlighted]));
|
||||||
CGContextFillPath(context);
|
CGContextFillPath(context);
|
||||||
|
|
||||||
|
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
CGContextMoveToPoint(context, 0.0, 0.0);
|
||||||
|
if(_angle === 0.0) {
|
||||||
|
CGContextAddLineToPoint(context, 4.5, 8.0);
|
||||||
|
CGContextAddLineToPoint(context, 9.0, 0.0);
|
||||||
|
} else {
|
||||||
|
CGContextAddLineToPoint(context, 4.5, 8.0);
|
||||||
|
}
|
||||||
|
CGContextSetStrokeColor(context, [CPColor colorWithCalibratedWhite:1.0 alpha: 0.8]);
|
||||||
|
CGContextStrokePath(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
var CPOutlineViewIndentationPerLevelKey = @"CPOutlineViewIndentationPerLevelKey",
|
||||||
|
CPOutlineViewOutlineTableColumnKey = @"CPOutlineViewOutlineTableColumnKey",
|
||||||
|
CPOutlineViewDataSourceKey = @"CPOutlineViewDataSourceKey",
|
||||||
|
CPOutlineViewDelegateKey = @"CPOutlineViewDelegateKey";
|
||||||
|
|
||||||
|
@implementation CPOutlineView (CPCoding)
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
self = [super initWithCoder:aCoder];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
// The root item has weight "0", thus represents the weight solely of its descendants.
|
||||||
|
_rootItemInfo = { isExpanded:YES, isExpandable:NO, level:-1, row:-1, children:[], weight:0 };
|
||||||
|
|
||||||
|
_itemsForRows = [];
|
||||||
|
_itemInfosForItems = { };
|
||||||
|
_disclosureControlsForRows = [];
|
||||||
|
|
||||||
|
[self setIndentationMarkerFollowsDataView:YES];
|
||||||
|
[self setDisclosureControlPrototype:[[CPDisclosureButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 10.0)]];
|
||||||
|
|
||||||
|
_outlineTableColumn = [aCoder decodeObjectForKey:CPOutlineViewOutlineTableColumnKey];
|
||||||
|
_indentationPerLevel = [aCoder decodeFloatForKey:CPOutlineViewIndentationPerLevelKey];
|
||||||
|
|
||||||
|
_outlineViewDataSource = [aCoder decodeObjectForKey:CPOutlineViewDataSourceKey];
|
||||||
|
_outlineViewDelegate = [aCoder decodeObjectForKey:CPOutlineViewDelegateKey];
|
||||||
|
|
||||||
|
[super setDataSource:[[_CPOutlineViewTableViewDataSource alloc] initWithOutlineView:self]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
[super encodeWithCoder:aCoder];
|
||||||
|
|
||||||
|
[aCoder encodeObject:_outlineTableColumn forKey:CPOutlineViewOutlineTableColumnKey];
|
||||||
|
[aCoder encodeFloat:_indentationPerLevel forKey:CPOutlineViewIndentationPerLevelKey];
|
||||||
|
|
||||||
|
[aCoder encodeObject:_outlineViewDataSource forKey:CPOutlineViewDataSourceKey];
|
||||||
|
[aCoder encodeObject:_outlineViewDelegate forKey:CPOutlineViewDelegateKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
var colorForDisclosureTriangle = function(isSelected, isHighlighted) {
|
||||||
|
return isSelected
|
||||||
|
? (isHighlighted
|
||||||
|
? [CPColor colorWithCalibratedWhite:0.9 alpha: 1.0]
|
||||||
|
: [CPColor colorWithCalibratedWhite:1.0 alpha: 1.0])
|
||||||
|
: (isHighlighted
|
||||||
|
? [CPColor colorWithCalibratedWhite:0.4 alpha: 1.0]
|
||||||
|
: [CPColor colorWithCalibratedWhite:0.5 alpha: 1.0]);
|
||||||
|
}
|
||||||
|
|||||||
+83
-13
@@ -25,8 +25,6 @@
|
|||||||
@import <Foundation/CPDictionary.j>
|
@import <Foundation/CPDictionary.j>
|
||||||
@import <Foundation/CPPropertyListSerialization.j>
|
@import <Foundation/CPPropertyListSerialization.j>
|
||||||
|
|
||||||
#include "Platform/Platform.h"
|
|
||||||
|
|
||||||
|
|
||||||
CPGeneralPboard = @"CPGeneralPboard";
|
CPGeneralPboard = @"CPGeneralPboard";
|
||||||
CPFontPboard = @"CPFontPboard";
|
CPFontPboard = @"CPFontPboard";
|
||||||
@@ -43,11 +41,14 @@ CPURLPboardType = @"CPURLPboardType";
|
|||||||
CPImagesPboardType = @"CPImagesPboardType";
|
CPImagesPboardType = @"CPImagesPboardType";
|
||||||
CPVideosPboardType = @"CPVideosPboardType";
|
CPVideosPboardType = @"CPVideosPboardType";
|
||||||
|
|
||||||
|
UTF8PboardType = @"public.utf8-plain-text";
|
||||||
|
|
||||||
// Deprecated
|
// Deprecated
|
||||||
CPImagePboardType = @"CPImagePboardType";
|
CPImagePboardType = @"CPImagePboardType";
|
||||||
|
|
||||||
|
|
||||||
var CPPasteboards = nil;
|
var CPPasteboards = nil,
|
||||||
|
supportsNativePasteboard = NO;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -63,6 +64,8 @@ var CPPasteboards = nil;
|
|||||||
|
|
||||||
unsigned _changeCount;
|
unsigned _changeCount;
|
||||||
CPString _stateUID;
|
CPString _stateUID;
|
||||||
|
|
||||||
|
WebScriptObject _nativePasteboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -76,6 +79,9 @@ var CPPasteboards = nil;
|
|||||||
[self setVersion:1.0];
|
[self setVersion:1.0];
|
||||||
|
|
||||||
CPPasteboards = [CPDictionary dictionary];
|
CPPasteboards = [CPDictionary dictionary];
|
||||||
|
|
||||||
|
if (typeof window.cpPasteboardWithName !== "undefined")
|
||||||
|
supportsNativePasteboard = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -118,6 +124,12 @@ var CPPasteboards = nil;
|
|||||||
_provided = [CPDictionary dictionary];
|
_provided = [CPDictionary dictionary];
|
||||||
|
|
||||||
_changeCount = 0;
|
_changeCount = 0;
|
||||||
|
|
||||||
|
if (supportsNativePasteboard)
|
||||||
|
{
|
||||||
|
_nativePasteboard = window.cpPasteboardWithName(aName);
|
||||||
|
[self _synchronizePasteboard];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -147,6 +159,15 @@ var CPPasteboards = nil;
|
|||||||
[_owners setObject:anOwner forKey:type];
|
[_owners setObject:anOwner forKey:type];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_nativePasteboard)
|
||||||
|
{
|
||||||
|
var nativeTypes = [types copy];
|
||||||
|
if ([types containsObject:CPStringPboardType])
|
||||||
|
nativeTypes.push(UTF8PboardType);
|
||||||
|
|
||||||
|
_nativePasteboard.addTypes_(nativeTypes);
|
||||||
|
}
|
||||||
|
|
||||||
return ++_changeCount;
|
return ++_changeCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,6 +178,12 @@ var CPPasteboards = nil;
|
|||||||
@return the pasteboard's change count
|
@return the pasteboard's change count
|
||||||
*/
|
*/
|
||||||
- (unsigned)declareTypes:(CPArray)types owner:(id)anOwner
|
- (unsigned)declareTypes:(CPArray)types owner:(id)anOwner
|
||||||
|
{
|
||||||
|
[self _declareTypes:types owner:anOwner updateNativePasteboard:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ignore */
|
||||||
|
- (unsigned)_declareTypes:(CPArray)types owner:(id)anOwner updateNativePasteboard:(BOOL)shouldUpdate
|
||||||
{
|
{
|
||||||
[_types setArray:types];
|
[_types setArray:types];
|
||||||
|
|
||||||
@@ -168,6 +195,15 @@ var CPPasteboards = nil;
|
|||||||
while (count--)
|
while (count--)
|
||||||
[_owners setObject:anOwner forKey:_types[count]];
|
[_owners setObject:anOwner forKey:_types[count]];
|
||||||
|
|
||||||
|
if (_nativePasteboard && shouldUpdate)
|
||||||
|
{
|
||||||
|
var nativeTypes = [types copy];
|
||||||
|
if ([types containsObject:CPStringPboardType])
|
||||||
|
nativeTypes.push(UTF8PboardType);
|
||||||
|
|
||||||
|
_nativePasteboard.declareTypes_(nativeTypes);
|
||||||
|
_changeCount = _nativePasteboard.changeCount();
|
||||||
|
}
|
||||||
return ++_changeCount;
|
return ++_changeCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,6 +217,9 @@ var CPPasteboards = nil;
|
|||||||
{
|
{
|
||||||
[_provided setObject:aData forKey:aType];
|
[_provided setObject:aData forKey:aType];
|
||||||
|
|
||||||
|
if (aType === CPStringPboardType)
|
||||||
|
[self setData:aData forType:UTF8PboardType];
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +231,7 @@ var CPPasteboards = nil;
|
|||||||
*/
|
*/
|
||||||
- (BOOL)setPropertyList:(id)aPropertyList forType:(CPString)aType
|
- (BOOL)setPropertyList:(id)aPropertyList forType:(CPString)aType
|
||||||
{
|
{
|
||||||
return [self setData:[CPPropertyListSerialization dataFromPropertyList:aPropertyList format:CPPropertyListXMLFormat_v1_0 errorDescription:nil] forType:aType];
|
return [self setData:[CPPropertyListSerialization dataFromPropertyList:aPropertyList format:CPPropertyList280NorthFormat_v1_0] forType:aType];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -203,7 +242,7 @@ var CPPasteboards = nil;
|
|||||||
*/
|
*/
|
||||||
- (void)setString:(CPString)aString forType:(CPString)aType
|
- (void)setString:(CPString)aString forType:(CPString)aType
|
||||||
{
|
{
|
||||||
return [self setPropertyList:aString forType:aType];
|
[self setPropertyList:aString forType:aType];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determining Types
|
// Determining Types
|
||||||
@@ -223,6 +262,7 @@ var CPPasteboards = nil;
|
|||||||
*/
|
*/
|
||||||
- (CPArray)types
|
- (CPArray)types
|
||||||
{
|
{
|
||||||
|
[self _synchronizePasteboard];
|
||||||
return _types;
|
return _types;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,15 +292,45 @@ var CPPasteboards = nil;
|
|||||||
if (owner)
|
if (owner)
|
||||||
{
|
{
|
||||||
[owner pasteboard:self provideDataForType:aType];
|
[owner pasteboard:self provideDataForType:aType];
|
||||||
|
|
||||||
++_changeCount;
|
|
||||||
|
|
||||||
return [_provided objectForKey:aType];
|
return [_provided objectForKey:aType];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (aType === CPStringPboardType)
|
||||||
|
return [self dataForType:UTF8PboardType];
|
||||||
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)_synchronizePasteboard
|
||||||
|
{
|
||||||
|
if (_nativePasteboard && _nativePasteboard.changeCount() > _changeCount)
|
||||||
|
{
|
||||||
|
var nativeTypes = [_nativePasteboard.types() copy];
|
||||||
|
if ([nativeTypes containsObject:UTF8PboardType])
|
||||||
|
nativeTypes.push(CPStringPboardType);
|
||||||
|
|
||||||
|
[self _declareTypes:nativeTypes owner:self updateNativePasteboard:NO];
|
||||||
|
|
||||||
|
_changeCount = _nativePasteboard.changeCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @ignore
|
||||||
|
method provided for integration with native pasteboard
|
||||||
|
*/
|
||||||
|
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
|
||||||
|
{
|
||||||
|
if (aType === CPStringPboardType)
|
||||||
|
{
|
||||||
|
var string = _nativePasteboard.stringForType_(UTF8PboardType);
|
||||||
|
|
||||||
|
[self setString:string forType:CPStringPboardType];
|
||||||
|
[self setString:string forType:UTF8PboardType];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[self setString:_nativePasteboard.stringForType_(aType) forType:aType];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the property list for the specified data type
|
Returns the property list for the specified data type
|
||||||
@param aType the requested data type
|
@param aType the requested data type
|
||||||
@@ -271,7 +341,7 @@ var CPPasteboards = nil;
|
|||||||
var data = [self dataForType:aType];
|
var data = [self dataForType:aType];
|
||||||
|
|
||||||
if (data)
|
if (data)
|
||||||
return [CPPropertyListSerialization propertyListFromData:data format:CPPropertyListXMLFormat_v1_0 errorDescription:nil];
|
return [CPPropertyListSerialization propertyListFromData:data format:CPPropertyList280NorthFormat_v1_0];
|
||||||
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
@@ -343,7 +413,7 @@ var DOMDataTransferPasteboard = nil;
|
|||||||
if (type === CPStringPboardType)
|
if (type === CPStringPboardType)
|
||||||
_dataTransfer.setData(type, [aPasteboard stringForType:type]);
|
_dataTransfer.setData(type, [aPasteboard stringForType:type]);
|
||||||
else
|
else
|
||||||
_dataTransfer.setData(type, [[aPasteboard dataForType:type] string]);
|
_dataTransfer.setData(type, [[aPasteboard dataForType:type] rawString]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,9 +427,9 @@ var DOMDataTransferPasteboard = nil;
|
|||||||
var dataString = _dataTransfer.getData(aType);
|
var dataString = _dataTransfer.getData(aType);
|
||||||
|
|
||||||
if (aType === CPStringPboardType)
|
if (aType === CPStringPboardType)
|
||||||
return [CPData dataFromPropertyList:dataString format:kCFPropertyList280NorthFormat_v1_0 errorDescription:0];
|
return [CPData dataFromPropertyList:dataString format:kCFPropertyList280NorthFormat_v1_0];
|
||||||
|
|
||||||
return [CPData dataWithString:dataString];
|
return [CPData dataWithRawString:dataString];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)propertyListForType:(CPString)aType
|
- (id)propertyListForType:(CPString)aType
|
||||||
@@ -367,7 +437,7 @@ var DOMDataTransferPasteboard = nil;
|
|||||||
if (aType === CPStringPboardType)
|
if (aType === CPStringPboardType)
|
||||||
return _dataTransfer.getData(aType);
|
return _dataTransfer.getData(aType);
|
||||||
|
|
||||||
return [CPPropertyListSerialization propertyListFromData:[self dataForType:aType] format:CPPropertyListUnknownFormat errorDescription:nil];
|
return [CPPropertyListSerialization propertyListFromData:[self dataForType:aType] format:CPPropertyListUnknownFormat];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+29
-5
@@ -25,8 +25,6 @@
|
|||||||
@import "CPMenu.j"
|
@import "CPMenu.j"
|
||||||
@import "CPMenuItem.j"
|
@import "CPMenuItem.j"
|
||||||
|
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
|
|
||||||
var VISIBLE_MARGIN = 7.0;
|
var VISIBLE_MARGIN = 7.0;
|
||||||
|
|
||||||
@@ -46,7 +44,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
CPMenu _menu;
|
CPMenu _menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPString)themeClass
|
+ (CPString)defaultThemeClass
|
||||||
{
|
{
|
||||||
return "popup-button";
|
return "popup-button";
|
||||||
}
|
}
|
||||||
@@ -396,12 +394,13 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
{
|
{
|
||||||
var titles = [],
|
var titles = [],
|
||||||
items = [self itemArray],
|
items = [self itemArray],
|
||||||
|
|
||||||
index = 0,
|
index = 0,
|
||||||
count = [items count];
|
count = [items count];
|
||||||
|
|
||||||
for (; index < count; ++index)
|
for (; index < count; ++index)
|
||||||
items.push([items[index] title]);
|
titles.push([items[index] title]);
|
||||||
|
|
||||||
|
return titles;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -661,6 +660,9 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
location = CGPointMake(CGRectGetMinX(contentRect) - standardLeftMargin, 0.0);
|
location = CGPointMake(CGRectGetMinX(contentRect) - standardLeftMargin, 0.0);
|
||||||
|
|
||||||
minimumWidth += standardLeftMargin;
|
minimumWidth += standardLeftMargin;
|
||||||
|
|
||||||
|
// To ensure the selected item is highlighted correctly, unset the highlighted item
|
||||||
|
[menu _highlightItemAtIndex:CPNotFound];
|
||||||
}
|
}
|
||||||
|
|
||||||
[menu setMinimumWidth:minimumWidth];
|
[menu setMinimumWidth:minimumWidth];
|
||||||
@@ -698,11 +700,33 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)rightMouseDown:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
// Disable standard CPView behaviour which incorrectly displays the menu as a 'context menu'.
|
||||||
|
}
|
||||||
|
|
||||||
- (void)_popUpItemAction:(id)aSender
|
- (void)_popUpItemAction:(id)aSender
|
||||||
{
|
{
|
||||||
[self sendAction:[self action] to:[self target]];
|
[self sendAction:[self action] to:[self target]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)takeValueFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
|
||||||
|
{
|
||||||
|
var count = objects.length,
|
||||||
|
value = [objects[0] valueForKeyPath:aKeyPath];
|
||||||
|
|
||||||
|
[self selectItemWithTag:value];
|
||||||
|
[self setEnabled:YES];
|
||||||
|
|
||||||
|
while (count-- > 1)
|
||||||
|
{
|
||||||
|
if (value !== [objects[count] valueForKeyPath:aKeyPath])
|
||||||
|
{
|
||||||
|
[[self selectedItem] setState:CPOffState];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
|
var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
|
||||||
|
|||||||
@@ -20,11 +20,9 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@import <AppKit/CGGeometry.j>
|
@import "CGGeometry.j"
|
||||||
@import <AppKit/CPImageView.j>
|
@import "CPImageView.j"
|
||||||
@import <AppKit/CPView.j>
|
@import "CPView.j"
|
||||||
|
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -104,15 +102,12 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
for (; start <= end; ++start)
|
for (; start <= end; ++start)
|
||||||
{
|
{
|
||||||
CPProgressIndicatorBezelBorderViewPool[start] = [];
|
CPProgressIndicatorBezelBorderViewPool[start] = [];
|
||||||
|
|
||||||
CPProgressIndicatorBezelBorderViewPool[start][CPMiniControlSize] = [];
|
CPProgressIndicatorBezelBorderViewPool[start][CPMiniControlSize] = [];
|
||||||
CPProgressIndicatorBezelBorderViewPool[start][CPSmallControlSize] = [];
|
CPProgressIndicatorBezelBorderViewPool[start][CPSmallControlSize] = [];
|
||||||
CPProgressIndicatorBezelBorderViewPool[start][CPRegularControlSize] = [];
|
CPProgressIndicatorBezelBorderViewPool[start][CPRegularControlSize] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
CPProgressIndicatorClassName = [self className];
|
CPProgressIndicatorClassName = [self className];
|
||||||
|
|
||||||
|
|
||||||
CPProgressIndicatorStyleIdentifiers = [];
|
CPProgressIndicatorStyleIdentifiers = [];
|
||||||
|
|
||||||
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle] = @"Bar";
|
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle] = @"Bar";
|
||||||
@@ -126,30 +121,20 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
CPProgressIndicatorStyleSizes = [];
|
CPProgressIndicatorStyleSizes = [];
|
||||||
|
|
||||||
// Bar Sttyle
|
// Bar Sttyle
|
||||||
var prefix = CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle];
|
var prefixes = [
|
||||||
|
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle],
|
||||||
|
CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle],
|
||||||
|
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle],
|
||||||
|
CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle]
|
||||||
|
];
|
||||||
|
|
||||||
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
|
for (var i = 0, count = prefixes.length; i<count; i++)
|
||||||
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
|
{
|
||||||
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
|
var prefix = prefixes[i];
|
||||||
|
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = [_CGSizeMake(3.0, 16.0), _CGSizeMake(1.0, 16.0), _CGSizeMake(3.0, 16.0)];
|
||||||
prefix = CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle];
|
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = [_CGSizeMake(3.0, 16.0), _CGSizeMake(1.0, 16.0), _CGSizeMake(3.0, 16.0)];
|
||||||
|
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = [_CGSizeMake(3.0, 16.0), _CGSizeMake(1.0, 16.0), _CGSizeMake(3.0, 16.0)];
|
||||||
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = _CGSizeMake(1.0, 9.0);
|
}
|
||||||
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = _CGSizeMake(1.0, 9.0);
|
|
||||||
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = _CGSizeMake(1.0, 9.0);
|
|
||||||
|
|
||||||
// HUD Bar Style
|
|
||||||
prefix = CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle];
|
|
||||||
|
|
||||||
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
|
|
||||||
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
|
|
||||||
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
|
|
||||||
|
|
||||||
prefix = CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle];
|
|
||||||
|
|
||||||
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = _CGSizeMake(1.0, 9.0);
|
|
||||||
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = _CGSizeMake(1.0, 9.0);
|
|
||||||
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = _CGSizeMake(1.0, 9.0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
@@ -428,21 +413,25 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
|
|
||||||
if (!_barView)
|
if (!_barView)
|
||||||
{
|
{
|
||||||
_barView = [[CPView alloc] initWithFrame:CGRectMake(2.0, 2.0, 0.0, 9.0)];
|
_barView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 16.0)];
|
||||||
|
|
||||||
[_barView setBackgroundColor:[CPColor redColor]];
|
|
||||||
|
|
||||||
[self addSubview:_barView];
|
[self addSubview:_barView];
|
||||||
}
|
}
|
||||||
|
|
||||||
[_barView setBackgroundColor:_CPControlColorWithPatternImage(
|
[_barView setBackgroundColor:_CPControlThreePartImagePattern(
|
||||||
|
NO,
|
||||||
CPProgressIndicatorStyleSizes,
|
CPProgressIndicatorStyleSizes,
|
||||||
CPProgressIndicatorClassName,
|
CPProgressIndicatorClassName,
|
||||||
@"Bar",
|
@"Bar",
|
||||||
CPProgressIndicatorStyleIdentifiers[_style],
|
CPProgressIndicatorStyleIdentifiers[_style],
|
||||||
_CPControlIdentifierForControlSize(_controlSize))];
|
_CPControlIdentifierForControlSize(_controlSize))];
|
||||||
|
|
||||||
[_barView setFrameSize:CGSizeMake(CGRectGetWidth([self bounds]) * (_doubleValue - _minValue) / (_maxValue - _minValue) - 4.0, 9.0)];
|
var width = CGRectGetWidth([self bounds]),
|
||||||
|
barWidth = width * ((_doubleValue - _minValue) / (_maxValue - _minValue));
|
||||||
|
|
||||||
|
if (barWidth > 0.0 && barWidth < 4.0)
|
||||||
|
barWidth = 4.0;
|
||||||
|
|
||||||
|
[_barView setFrameSize:CGSizeMake(barWidth, 16.0)];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
|
|||||||
+5
-1
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
@import "CPButton.j"
|
@import "CPButton.j"
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
|
|
||||||
@@ -62,6 +63,9 @@
|
|||||||
option.
|
option.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
CPRadioImageOffset = 4.0;
|
||||||
|
|
||||||
@implementation CPRadio : CPButton
|
@implementation CPRadio : CPButton
|
||||||
{
|
{
|
||||||
CPRadioGroup _radioGroup;
|
CPRadioGroup _radioGroup;
|
||||||
@@ -86,7 +90,7 @@
|
|||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPString)themeClass
|
+ (CPString)defaultThemeClass
|
||||||
{
|
{
|
||||||
return @"radio";
|
return @"radio";
|
||||||
}
|
}
|
||||||
|
|||||||
+52
-33
@@ -27,10 +27,14 @@ CPDeleteKeyCode = 8;
|
|||||||
CPTabKeyCode = 9;
|
CPTabKeyCode = 9;
|
||||||
CPReturnKeyCode = 13;
|
CPReturnKeyCode = 13;
|
||||||
CPEscapeKeyCode = 27;
|
CPEscapeKeyCode = 27;
|
||||||
|
CPSpaceKeyCode = 32;
|
||||||
|
CPPageUpKeyCode = 33;
|
||||||
|
CPPageDownKeyCode = 34;
|
||||||
CPLeftArrowKeyCode = 37;
|
CPLeftArrowKeyCode = 37;
|
||||||
CPUpArrowKeyCode = 38;
|
CPUpArrowKeyCode = 38;
|
||||||
CPRightArrowKeyCode = 39;
|
CPRightArrowKeyCode = 39;
|
||||||
CPDownArrowKeyCode = 40;
|
CPDownArrowKeyCode = 40;
|
||||||
|
CPDeleteForwardKeyCode = 46;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -101,39 +105,25 @@ CPDownArrowKeyCode = 40;
|
|||||||
|
|
||||||
for (; index < count; ++index)
|
for (; index < count; ++index)
|
||||||
{
|
{
|
||||||
var event = events[index];
|
var event = events[index],
|
||||||
|
modifierFlags = [event modifierFlags],
|
||||||
|
character = [event charactersIgnoringModifiers],
|
||||||
|
selectorNames = [CPKeyBinding selectorsForKey:character modifierFlags:modifierFlags];
|
||||||
|
|
||||||
switch([event keyCode])
|
if (selectorNames)
|
||||||
{
|
{
|
||||||
case CPLeftArrowKeyCode: [self doCommandBySelector:@selector(moveLeft:)];
|
for (var s = 0, scount = selectorNames.length; s < scount; s++)
|
||||||
break;
|
{
|
||||||
case CPRightArrowKeyCode: [self doCommandBySelector:@selector(moveRight:)];
|
var selector = selectorNames[s];
|
||||||
break;
|
if (!selector)
|
||||||
case CPUpArrowKeyCode: [self doCommandBySelector:@selector(moveUp:)];
|
continue;
|
||||||
break;
|
|
||||||
case CPDownArrowKeyCode: [self doCommandBySelector:@selector(moveDown:)];
|
|
||||||
break;
|
|
||||||
case CPDeleteKeyCode: [self doCommandBySelector:@selector(deleteBackward:)];
|
|
||||||
break;
|
|
||||||
case CPReturnKeyCode:
|
|
||||||
case 3: [self doCommandBySelector:@selector(insertLineBreak:)];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CPEscapeKeyCode: [self doCommandBySelector:@selector(cancel:)];
|
[self doCommandBySelector:CPSelectorFromString(selector)];
|
||||||
break;
|
|
||||||
|
|
||||||
case CPTabKeyCode: var shift = [event modifierFlags] & CPShiftKeyMask;
|
|
||||||
|
|
||||||
if (!shift)
|
|
||||||
[self doCommandBySelector:@selector(insertTab:)];
|
|
||||||
else
|
|
||||||
[self doCommandBySelector:@selector(insertBackTab:)];
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: [self insertText:[event characters]];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (!(modifierFlags & (CPCommandKeyMask | CPControlKeyMask)) && [self respondsToSelector:@selector(insertText:)])
|
||||||
|
[self insertText:[event characters]];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -145,6 +135,15 @@ CPDownArrowKeyCode = 40;
|
|||||||
[_nextResponder performSelector:_cmd withObject:anEvent];
|
[_nextResponder performSelector:_cmd withObject:anEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Notifies the receiver that the user has clicked the right mouse down in its area.
|
||||||
|
@param anEvent contains information about the right click
|
||||||
|
*/
|
||||||
|
- (void)rightMouseDown:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
[_nextResponder performSelector:_cmd withObject:anEvent];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Notifies the receiver that the user has initiated a drag
|
Notifies the receiver that the user has initiated a drag
|
||||||
over it. A drag is a mouse movement while the left button is down.
|
over it. A drag is a mouse movement while the left button is down.
|
||||||
@@ -164,6 +163,15 @@ CPDownArrowKeyCode = 40;
|
|||||||
[_nextResponder performSelector:_cmd withObject:anEvent];
|
[_nextResponder performSelector:_cmd withObject:anEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Notifies the receiver that the user has released the right mouse button.
|
||||||
|
@param anEvent contains information about the release
|
||||||
|
*/
|
||||||
|
- (void)rightMouseUp:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
[_nextResponder performSelector:_cmd withObject:anEvent];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Notifies the receiver that the user has moved the mouse (with no buttons down).
|
Notifies the receiver that the user has moved the mouse (with no buttons down).
|
||||||
@param anEvent contains information about the movement
|
@param anEvent contains information about the movement
|
||||||
@@ -214,6 +222,15 @@ CPDownArrowKeyCode = 40;
|
|||||||
[_nextResponder performSelector:_cmd withObject:anEvent];
|
[_nextResponder performSelector:_cmd withObject:anEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Notifies the receiver that the user has pressed or released a modifier key (Shift, Control, and so on).
|
||||||
|
@param anEvent information about the key press
|
||||||
|
*/
|
||||||
|
- (void)flagsChanged:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
[_nextResponder performSelector:_cmd withObject:anEvent];
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
FIXME This description is bad.
|
FIXME This description is bad.
|
||||||
Based on \c anEvent, the receiver should simulate the event.
|
Based on \c anEvent, the receiver should simulate the event.
|
||||||
@@ -244,10 +261,6 @@ CPDownArrowKeyCode = 40;
|
|||||||
[[self nextResponder] insertNewline:aSender];
|
[[self nextResponder] insertNewline:aSender];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)cancel:(id)sender
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)insertTab:(id)sender
|
- (void)insertTab:(id)sender
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -329,7 +342,8 @@ CPDownArrowKeyCode = 40;
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPResponderNextResponderKey = @"CPResponderNextResponderKey";
|
var CPResponderNextResponderKey = @"CPResponderNextResponderKey",
|
||||||
|
CPResponderMenuKey = @"CPResponderMenuKey";
|
||||||
|
|
||||||
@implementation CPResponder (CPCoding)
|
@implementation CPResponder (CPCoding)
|
||||||
|
|
||||||
@@ -343,7 +357,10 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey";
|
|||||||
self = [super init];
|
self = [super init];
|
||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
|
{
|
||||||
_nextResponder = [aCoder decodeObjectForKey:CPResponderNextResponderKey];
|
_nextResponder = [aCoder decodeObjectForKey:CPResponderNextResponderKey];
|
||||||
|
_menu = [aCoder decodeObjectForKey:CPResponderMenuKey];
|
||||||
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -357,6 +374,8 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey";
|
|||||||
// This will come out nil on the other side with decodeObjectForKey:
|
// This will come out nil on the other side with decodeObjectForKey:
|
||||||
if (_nextResponder !== nil)
|
if (_nextResponder !== nil)
|
||||||
[aCoder encodeConditionalObject:_nextResponder forKey:CPResponderNextResponderKey];
|
[aCoder encodeConditionalObject:_nextResponder forKey:CPResponderNextResponderKey];
|
||||||
|
|
||||||
|
[aCoder encodeObject:_menu forKey:CPResponderMenuKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
@import <AppKit/CPPanel.j>
|
@import "CPPanel.j"
|
||||||
|
|
||||||
|
|
||||||
@implementation CPSavePanel : CPPanel
|
@implementation CPSavePanel : CPPanel
|
||||||
|
|||||||
+4
-2
@@ -2,15 +2,17 @@
|
|||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
|
|
||||||
#import "CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
@implementation CPScreen : CPObject
|
@implementation CPScreen : CPObject
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)visibleFrame
|
- (CGRect)visibleFrame
|
||||||
{
|
{
|
||||||
|
#if PLATFORM(DOM)
|
||||||
return _CGRectMake(window.screen.availLeft, window.screen.availTop, window.screen.availWidth, window.screen.availHeight);
|
return _CGRectMake(window.screen.availLeft, window.screen.availTop, window.screen.availWidth, window.screen.availHeight);
|
||||||
|
#else
|
||||||
|
return _CGRectMakeZero();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
+389
-75
@@ -20,11 +20,10 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@import "CPView.j"
|
@import "CPBox.j"
|
||||||
@import "CPClipView.j"
|
@import "CPClipView.j"
|
||||||
@import "CPScroller.j"
|
@import "CPScroller.j"
|
||||||
|
@import "CPView.j"
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -40,6 +39,7 @@
|
|||||||
CPClipView _contentView;
|
CPClipView _contentView;
|
||||||
CPClipView _headerClipView;
|
CPClipView _headerClipView;
|
||||||
CPView _cornerView;
|
CPView _cornerView;
|
||||||
|
CPView _bottomCornerView;
|
||||||
|
|
||||||
BOOL _hasVerticalScroller;
|
BOOL _hasVerticalScroller;
|
||||||
BOOL _hasHorizontalScroller;
|
BOOL _hasHorizontalScroller;
|
||||||
@@ -54,6 +54,21 @@
|
|||||||
float _verticalPageScroll;
|
float _verticalPageScroll;
|
||||||
float _horizontalLineScroll;
|
float _horizontalLineScroll;
|
||||||
float _horizontalPageScroll;
|
float _horizontalPageScroll;
|
||||||
|
|
||||||
|
CPBorderType _borderType;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPString)defaultThemeClass
|
||||||
|
{
|
||||||
|
return @"scrollview"
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPDictionary)themeAttributes
|
||||||
|
{
|
||||||
|
return [CPDictionary dictionaryWithJSObject:{
|
||||||
|
@"bottom-corner-color": [CPColor whiteColor],
|
||||||
|
@"border-color": [CPColor blackColor]
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
@@ -68,14 +83,18 @@
|
|||||||
_horizontalLineScroll = 10.0;
|
_horizontalLineScroll = 10.0;
|
||||||
_horizontalPageScroll = 10.0;
|
_horizontalPageScroll = 10.0;
|
||||||
|
|
||||||
_contentView = [[CPClipView alloc] initWithFrame:[self bounds]];
|
_borderType = CPNoBorder;
|
||||||
|
|
||||||
|
_contentView = [[CPClipView alloc] initWithFrame:[self _insetBounds]];
|
||||||
|
|
||||||
[self addSubview:_contentView];
|
[self addSubview:_contentView];
|
||||||
|
|
||||||
_headerClipView = [[CPClipView alloc] init];
|
_headerClipView = [[CPClipView alloc] init];
|
||||||
|
|
||||||
[self addSubview:_headerClipView];
|
[self addSubview:_headerClipView];
|
||||||
|
|
||||||
|
_bottomCornerView = [[CPView alloc] init];
|
||||||
|
[self addSubview:_bottomCornerView];
|
||||||
|
|
||||||
[self setHasVerticalScroller:YES];
|
[self setHasVerticalScroller:YES];
|
||||||
[self setHasHorizontalScroller:YES];
|
[self setHasHorizontalScroller:YES];
|
||||||
}
|
}
|
||||||
@@ -83,11 +102,70 @@
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculating Layout
|
||||||
|
|
||||||
|
+ (CGSize)contentSizeForFrameSize:(CGSize)frameSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType
|
||||||
|
{
|
||||||
|
var bounds = [self _insetBounds:_CGRectMake(0.0, 0.0, frameSize.width, frameSize.height) borderType:borderType],
|
||||||
|
scrollerWidth = [CPScroller scrollerWidth];
|
||||||
|
|
||||||
|
if (hFlag)
|
||||||
|
bounds.size.height -= scrollerWidth;
|
||||||
|
|
||||||
|
if (vFlag)
|
||||||
|
bounds.size.width -= scrollerWidth;
|
||||||
|
|
||||||
|
return bounds.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CGSize)frameSizeForContentSize:(CGSize)contentSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType
|
||||||
|
{
|
||||||
|
var bounds = [self _insetBounds:_CGRectMake(0.0, 0.0, contentSize.width, contentSize.height) borderType:borderType],
|
||||||
|
widthInset = contentSize.width - bounds.size.width,
|
||||||
|
heightInset = contentSize.height - bounds.size.height,
|
||||||
|
frameSize = _CGSizeMake(contentSize.width + widthInset, contentSize.height + heightInset),
|
||||||
|
scrollerWidth = [CPScroller scrollerWidth];
|
||||||
|
|
||||||
|
if (hFlag)
|
||||||
|
frameSize.height -= scrollerWidth;
|
||||||
|
|
||||||
|
if (vFlag)
|
||||||
|
frameSize.width -= scrollerWidth;
|
||||||
|
|
||||||
|
return frameSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CGRect)_insetBounds:(CGRect)bounds borderType:(CPBorderType)borderType
|
||||||
|
{
|
||||||
|
switch (borderType)
|
||||||
|
{
|
||||||
|
case CPLineBorder:
|
||||||
|
case CPBezelBorder:
|
||||||
|
return _CGRectInset(bounds, 1.0, 1.0);
|
||||||
|
|
||||||
|
case CPGrooveBorder:
|
||||||
|
bounds = _CGRectInset(bounds, 2.0, 2.0);
|
||||||
|
++bounds.origin.y;
|
||||||
|
--bounds.size.height;
|
||||||
|
|
||||||
|
return bounds;
|
||||||
|
|
||||||
|
case CPNoBorder:
|
||||||
|
default:
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)_insetBounds
|
||||||
|
{
|
||||||
|
return [[self class] _insetBounds:[self bounds] borderType:_borderType];
|
||||||
|
}
|
||||||
|
|
||||||
// Determining component sizes
|
// Determining component sizes
|
||||||
/*!
|
/*!
|
||||||
Returns the size of the scroll view's content view.
|
Returns the size of the scroll view's content view.
|
||||||
*/
|
*/
|
||||||
- (CGRect)contentSize
|
- (CGSize)contentSize
|
||||||
{
|
{
|
||||||
return [_contentView frame].size;
|
return [_contentView frame].size;
|
||||||
}
|
}
|
||||||
@@ -106,7 +184,7 @@
|
|||||||
*/
|
*/
|
||||||
- (void)setContentView:(CPClipView)aContentView
|
- (void)setContentView:(CPClipView)aContentView
|
||||||
{
|
{
|
||||||
if (_contentView !== aContentView || !aContentView)
|
if (_contentView === aContentView || !aContentView)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var documentView = [aContentView documentView];
|
var documentView = [aContentView documentView];
|
||||||
@@ -176,7 +254,7 @@
|
|||||||
// [_horizontalScroller setEnabled:NO];
|
// [_horizontalScroller setEnabled:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
[_contentView setFrame:[self bounds]];
|
[_contentView setFrame:[self _insetBounds]];
|
||||||
[_headerClipView setFrame:_CGRectMakeZero()];
|
[_headerClipView setFrame:_CGRectMakeZero()];
|
||||||
|
|
||||||
--_recursionCount;
|
--_recursionCount;
|
||||||
@@ -185,7 +263,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
var documentFrame = [documentView frame], // the size of the whole document
|
var documentFrame = [documentView frame], // the size of the whole document
|
||||||
contentFrame = [self bounds], // assume it takes up the entire size of the scrollview (no scrollers)
|
contentFrame = [self _insetBounds], // assume it takes up the entire size of the scrollview (no scrollers)
|
||||||
headerClipViewFrame = [self _headerClipViewFrame],
|
headerClipViewFrame = [self _headerClipViewFrame],
|
||||||
headerClipViewHeight = _CGRectGetHeight(headerClipViewFrame);
|
headerClipViewHeight = _CGRectGetHeight(headerClipViewFrame);
|
||||||
|
|
||||||
@@ -235,11 +313,10 @@
|
|||||||
|
|
||||||
if (shouldShowVerticalScroller)
|
if (shouldShowVerticalScroller)
|
||||||
{
|
{
|
||||||
var verticalScrollerY = MAX(_CGRectGetHeight([self _cornerViewFrame]), headerClipViewHeight),
|
var verticalScrollerY =
|
||||||
verticalScrollerHeight = _CGRectGetHeight([self bounds]) - verticalScrollerY;
|
MAX(_CGRectGetMinY(contentFrame), MAX(_CGRectGetMaxY([self _cornerViewFrame]), _CGRectGetMaxY(headerClipViewFrame)));
|
||||||
|
|
||||||
if (shouldShowHorizontalScroller)
|
var verticalScrollerHeight = _CGRectGetMaxY(contentFrame) - verticalScrollerY;
|
||||||
verticalScrollerHeight -= horizontalScrollerHeight;
|
|
||||||
|
|
||||||
[_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height];
|
[_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height];
|
||||||
[_verticalScroller setKnobProportion:_CGRectGetHeight(contentFrame) / _CGRectGetHeight(documentFrame)];
|
[_verticalScroller setKnobProportion:_CGRectGetHeight(contentFrame) / _CGRectGetHeight(documentFrame)];
|
||||||
@@ -255,7 +332,7 @@
|
|||||||
{
|
{
|
||||||
[_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width];
|
[_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width];
|
||||||
[_horizontalScroller setKnobProportion:_CGRectGetWidth(contentFrame) / _CGRectGetWidth(documentFrame)];
|
[_horizontalScroller setKnobProportion:_CGRectGetWidth(contentFrame) / _CGRectGetWidth(documentFrame)];
|
||||||
[_horizontalScroller setFrame:_CGRectMake(0.0, _CGRectGetMaxY(contentFrame), _CGRectGetWidth(contentFrame), horizontalScrollerHeight)];
|
[_horizontalScroller setFrame:_CGRectMake(_CGRectGetMinX(contentFrame), _CGRectGetMaxY(contentFrame), _CGRectGetWidth(contentFrame), horizontalScrollerHeight)];
|
||||||
}
|
}
|
||||||
else if (wasShowingHorizontalScroller)
|
else if (wasShowingHorizontalScroller)
|
||||||
{
|
{
|
||||||
@@ -267,9 +344,36 @@
|
|||||||
[_headerClipView setFrame:headerClipViewFrame];
|
[_headerClipView setFrame:headerClipViewFrame];
|
||||||
[_cornerView setFrame:[self _cornerViewFrame]];
|
[_cornerView setFrame:[self _cornerViewFrame]];
|
||||||
|
|
||||||
|
[[self bottomCornerView] setFrame:[self _bottomCornerViewFrame]];
|
||||||
|
[[self bottomCornerView] setBackgroundColor:[self currentValueForThemeAttribute:@"bottom-corner-color"]];
|
||||||
|
|
||||||
--_recursionCount;
|
--_recursionCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Managing Graphics Attributes
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the type of border to be drawn around the view.
|
||||||
|
*/
|
||||||
|
- (void)setBorderType:(CPBorderType)borderType
|
||||||
|
{
|
||||||
|
if (_borderType == borderType)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_borderType = borderType;
|
||||||
|
|
||||||
|
[self reflectScrolledClipView:_contentView];
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the border type drawn around the view.
|
||||||
|
*/
|
||||||
|
- (CPBorderType)borderType
|
||||||
|
{
|
||||||
|
return _borderType;
|
||||||
|
}
|
||||||
|
|
||||||
// Managing Scrollers
|
// Managing Scrollers
|
||||||
/*!
|
/*!
|
||||||
Sets the scroll view's horizontal scroller.
|
Sets the scroll view's horizontal scroller.
|
||||||
@@ -315,7 +419,12 @@
|
|||||||
_hasHorizontalScroller = shouldHaveHorizontalScroller;
|
_hasHorizontalScroller = shouldHaveHorizontalScroller;
|
||||||
|
|
||||||
if (_hasHorizontalScroller && !_horizontalScroller)
|
if (_hasHorizontalScroller && !_horizontalScroller)
|
||||||
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, _CGRectGetWidth([self bounds]), [CPScroller scrollerWidth])]];
|
{
|
||||||
|
var bounds = [self _insetBounds];
|
||||||
|
|
||||||
|
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(_CGRectGetWidth(bounds), [CPScroller scrollerWidth] + 1), [CPScroller scrollerWidth])]];
|
||||||
|
[[self horizontalScroller] setFrameSize:CGSizeMake(_CGRectGetWidth(bounds), [CPScroller scrollerWidth])];
|
||||||
|
}
|
||||||
|
|
||||||
[self reflectScrolledClipView:_contentView];
|
[self reflectScrolledClipView:_contentView];
|
||||||
}
|
}
|
||||||
@@ -373,7 +482,12 @@
|
|||||||
_hasVerticalScroller = shouldHaveVerticalScroller;
|
_hasVerticalScroller = shouldHaveVerticalScroller;
|
||||||
|
|
||||||
if (_hasVerticalScroller && !_verticalScroller)
|
if (_hasVerticalScroller && !_verticalScroller)
|
||||||
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], _CGRectGetHeight([self bounds]))]];
|
{
|
||||||
|
var bounds = [self _insetBounds];
|
||||||
|
|
||||||
|
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], MAX(_CGRectGetHeight(bounds), [CPScroller scrollerWidth] + 1))]];
|
||||||
|
[[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidth], _CGRectGetHeight(bounds))];
|
||||||
|
}
|
||||||
|
|
||||||
[self reflectScrolledClipView:_contentView];
|
[self reflectScrolledClipView:_contentView];
|
||||||
}
|
}
|
||||||
@@ -439,9 +553,7 @@
|
|||||||
|
|
||||||
- (CPView)_headerView
|
- (CPView)_headerView
|
||||||
{
|
{
|
||||||
var headerClipViewSubviews = [_headerClipView subviews];
|
return [_headerClipView documentView];
|
||||||
|
|
||||||
return [headerClipViewSubviews count] ? headerClipViewSubviews[0] : nil;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)_cornerViewFrame
|
- (CGRect)_cornerViewFrame
|
||||||
@@ -449,11 +561,11 @@
|
|||||||
if (!_cornerView)
|
if (!_cornerView)
|
||||||
return _CGRectMakeZero();
|
return _CGRectMakeZero();
|
||||||
|
|
||||||
var bounds = [self bounds],
|
var bounds = [self _insetBounds],
|
||||||
frame = [_cornerView frame];
|
frame = [_cornerView frame];
|
||||||
|
|
||||||
frame.origin.x = _CGRectGetMaxX(bounds) - _CGRectGetWidth(frame);
|
frame.origin.x = _CGRectGetMaxX(bounds) - _CGRectGetWidth(frame);
|
||||||
frame.origin.y = 0;
|
frame.origin.y = _CGRectGetMinY(bounds);
|
||||||
|
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
@@ -465,7 +577,7 @@
|
|||||||
if (!headerView)
|
if (!headerView)
|
||||||
return _CGRectMakeZero();
|
return _CGRectMakeZero();
|
||||||
|
|
||||||
var frame = [self bounds];
|
var frame = [self _insetBounds];
|
||||||
|
|
||||||
frame.size.height = _CGRectGetHeight([headerView frame]);
|
frame.size.height = _CGRectGetHeight([headerView frame]);
|
||||||
frame.size.width -= _CGRectGetWidth([self _cornerViewFrame]);
|
frame.size.width -= _CGRectGetWidth([self _cornerViewFrame]);
|
||||||
@@ -473,11 +585,47 @@
|
|||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CGRect)_bottomCornerViewFrame
|
||||||
|
{
|
||||||
|
if ([[self horizontalScroller] isHidden] || [[self verticalScroller] isHidden])
|
||||||
|
return CGRectMakeZero();
|
||||||
|
|
||||||
|
var verticalFrame = [[self verticalScroller] frame],
|
||||||
|
bottomCornerFrame = CGRectMakeZero();
|
||||||
|
|
||||||
|
bottomCornerFrame.origin.x = CGRectGetMinX(verticalFrame);
|
||||||
|
bottomCornerFrame.origin.y = CGRectGetMaxY(verticalFrame);
|
||||||
|
bottomCornerFrame.size.width = [CPScroller scrollerWidth];
|
||||||
|
bottomCornerFrame.size.height = [CPScroller scrollerWidth];
|
||||||
|
|
||||||
|
return bottomCornerFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setBottomCornerView:(CPView)aBottomCornerView
|
||||||
|
{
|
||||||
|
if (_bottomCornerView === aBottomCornerView)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_bottomCornerView removeFromSuperview];
|
||||||
|
|
||||||
|
[aBottomCornerView setFrame:[self _bottomCornerViewFrame]];
|
||||||
|
[self addSubview:aBottomCornerView];
|
||||||
|
|
||||||
|
_bottomCornerView = aBottomCornerView;
|
||||||
|
|
||||||
|
[self _updateCornerAndHeaderView];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPView)bottomCornerView
|
||||||
|
{
|
||||||
|
return _bottomCornerView;
|
||||||
|
}
|
||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
- (void)_verticalScrollerDidScroll:(CPScroller)aScroller
|
- (void)_verticalScrollerDidScroll:(CPScroller)aScroller
|
||||||
{
|
{
|
||||||
var value = [aScroller floatValue],
|
var value = [aScroller floatValue],
|
||||||
documentFrame = [[_contentView documentView] frame];
|
documentFrame = [[_contentView documentView] frame],
|
||||||
contentBounds = [_contentView bounds];
|
contentBounds = [_contentView bounds];
|
||||||
|
|
||||||
switch ([_verticalScroller hitPart])
|
switch ([_verticalScroller hitPart])
|
||||||
@@ -658,57 +806,201 @@
|
|||||||
return _verticalPageScroll;
|
return _verticalPageScroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CPView Overrides
|
||||||
|
|
||||||
|
- (void)drawRect:(CPRect)aRect
|
||||||
|
{
|
||||||
|
[super drawRect:aRect];
|
||||||
|
|
||||||
|
if (_borderType == CPNoBorder)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var strokeRect = [self bounds],
|
||||||
|
context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||||
|
|
||||||
|
CGContextSetLineWidth(context, 1);
|
||||||
|
|
||||||
|
switch (_borderType)
|
||||||
|
{
|
||||||
|
case CPLineBorder:
|
||||||
|
CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:@"border-color"]);
|
||||||
|
CGContextStrokeRect(context, _CGRectInset(strokeRect, 0.5, 0.5));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPBezelBorder:
|
||||||
|
[self _drawGrayBezelInContext:context bounds:strokeRect];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPGrooveBorder:
|
||||||
|
[self _drawGrooveInContext:context bounds:strokeRect];
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_drawGrayBezelInContext:(CGContext)context bounds:(CGRect)aRect
|
||||||
|
{
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
CGContextSetStrokeColor(context, [CPColor colorWithWhite:142.0 / 255.0 alpha:1.0]);
|
||||||
|
|
||||||
|
var y = _CGRectGetMinY(aRect) + 0.5;
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, _CGRectGetMinX(aRect), y);
|
||||||
|
CGContextAddLineToPoint(context, _CGRectGetMinX(aRect) + 1.0, y);
|
||||||
|
CGContextStrokePath(context);
|
||||||
|
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
CGContextSetStrokeColor(context, [CPColor colorWithWhite:192.0 / 255.0 alpha:1.0]);
|
||||||
|
CGContextMoveToPoint(context, _CGRectGetMinX(aRect) + 1.0, y);
|
||||||
|
CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y);
|
||||||
|
CGContextStrokePath(context);
|
||||||
|
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
CGContextSetStrokeColor(context, [CPColor colorWithWhite:142.0 / 255.0 alpha:1.0]);
|
||||||
|
CGContextMoveToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y);
|
||||||
|
CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect), y);
|
||||||
|
CGContextStrokePath(context);
|
||||||
|
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
CGContextSetStrokeColor(context, [CPColor colorWithWhite:190.0 / 255.0 alpha:1.0]);
|
||||||
|
|
||||||
|
var x = _CGRectGetMaxX(aRect) - 0.5;
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, x, _CGRectGetMinY(aRect) + 1.0);
|
||||||
|
CGContextAddLineToPoint(context, x, _CGRectGetMaxY(aRect));
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, x - 0.5, _CGRectGetMaxY(aRect) - 0.5);
|
||||||
|
CGContextAddLineToPoint(context, _CGRectGetMinX(aRect), _CGRectGetMaxY(aRect) - 0.5);
|
||||||
|
|
||||||
|
x = _CGRectGetMinX(aRect) + 0.5;
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, x, _CGRectGetMaxY(aRect));
|
||||||
|
CGContextAddLineToPoint(context, x, _CGRectGetMinY(aRect) + 1.0);
|
||||||
|
|
||||||
|
CGContextStrokePath(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_drawGrooveInContext:(CGContext)context bounds:(CGRect)aRect
|
||||||
|
{
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
CGContextSetStrokeColor(context, [CPColor colorWithWhite:159.0 / 255.0 alpha:1.0]);
|
||||||
|
|
||||||
|
var y = _CGRectGetMinY(aRect) + 0.5;
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, _CGRectGetMinX(aRect), y);
|
||||||
|
CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect), y);
|
||||||
|
|
||||||
|
var x = _CGRectGetMaxX(aRect) - 1.5;
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, x, _CGRectGetMinY(aRect) + 2.0);
|
||||||
|
CGContextAddLineToPoint(context, x, _CGRectGetMaxY(aRect) - 1.0);
|
||||||
|
|
||||||
|
y = _CGRectGetMaxY(aRect) - 1.5;
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y);
|
||||||
|
CGContextAddLineToPoint(context, _CGRectGetMinX(aRect) + 2.0, y);
|
||||||
|
|
||||||
|
x = _CGRectGetMinX(aRect) + 0.5;
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, x, _CGRectGetMaxY(aRect));
|
||||||
|
CGContextAddLineToPoint(context, x, _CGRectGetMinY(aRect));
|
||||||
|
|
||||||
|
CGContextStrokePath(context);
|
||||||
|
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
CGContextSetStrokeColor(context, [CPColor whiteColor]);
|
||||||
|
|
||||||
|
var rect = _CGRectOffset(aRect, 1.0, 1.0);
|
||||||
|
|
||||||
|
rect.size.width -= 1.0;
|
||||||
|
rect.size.height -= 1.0;
|
||||||
|
CGContextStrokeRect(context, _CGRectInset(rect, 0.5, 0.5));
|
||||||
|
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
CGContextSetStrokeColor(context, [CPColor colorWithWhite:192.0 / 255.0 alpha:1.0]);
|
||||||
|
|
||||||
|
y = _CGRectGetMinY(aRect) + 2.5;
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, _CGRectGetMinX(aRect) + 2.0, y);
|
||||||
|
CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect) - 2.0, y);
|
||||||
|
CGContextStrokePath(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// CPResponder Overrides
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Handles a scroll wheel event from the user.
|
Handles a scroll wheel event from the user.
|
||||||
@param anEvent the scroll wheel event
|
@param anEvent the scroll wheel event
|
||||||
*/
|
*/
|
||||||
- (void)scrollWheel:(CPEvent)anEvent
|
- (void)scrollWheel:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
[self _respondToScrollWheelEventWithDeltaX:[anEvent deltaX] deltaY:[anEvent deltaY]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_respondToScrollWheelEventWithDeltaX:(float)deltaX deltaY:(float)deltaY
|
||||||
|
{
|
||||||
|
var documentFrame = [[self documentView] frame],
|
||||||
|
contentBounds = [_contentView bounds],
|
||||||
|
contentFrame = [_contentView frame],
|
||||||
|
enclosingScrollView = [self enclosingScrollView];
|
||||||
|
|
||||||
|
// We want integral bounds!
|
||||||
|
contentBounds.origin.x = ROUND(contentBounds.origin.x + deltaX);
|
||||||
|
contentBounds.origin.y = ROUND(contentBounds.origin.y + deltaY);
|
||||||
|
|
||||||
|
var constrainedOrigin = [_contentView constrainScrollPoint:CGPointCreateCopy(contentBounds.origin)],
|
||||||
|
extraX = contentBounds.origin.x - constrainedOrigin.x,
|
||||||
|
extraY = contentBounds.origin.y - constrainedOrigin.y;
|
||||||
|
|
||||||
|
[_contentView scrollToPoint:constrainedOrigin];
|
||||||
|
[_headerClipView scrollToPoint:CGPointMake(constrainedOrigin.x, 0.0)];
|
||||||
|
|
||||||
|
if (extraX || extraY)
|
||||||
|
[enclosingScrollView _respondToScrollWheelEventWithDeltaX:extraX deltaY:extraY];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)scrollPageUp:(id)sender
|
||||||
|
{
|
||||||
|
var contentBounds = [_contentView bounds];
|
||||||
|
[self moveByOffset:CGSizeMake(0.0, -(_CGRectGetHeight(contentBounds) - _verticalPageScroll))];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)scrollPageDown:(id)sender
|
||||||
|
{
|
||||||
|
var contentBounds = [_contentView bounds];
|
||||||
|
[self moveByOffset:CGSizeMake(0.0, _CGRectGetHeight(contentBounds) - _verticalPageScroll)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveLeft:(id)sender
|
||||||
|
{
|
||||||
|
[self moveByOffset:CGSizeMake(-_horizontalLineScroll, 0.0)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveRight:(id)sender
|
||||||
|
{
|
||||||
|
[self moveByOffset:CGSizeMake(_horizontalLineScroll, 0.0)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveUp:(id)sender
|
||||||
|
{
|
||||||
|
[self moveByOffset:CGSizeMake(0.0, -_verticalLineScroll)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveDown:(id)sender
|
||||||
|
{
|
||||||
|
[self moveByOffset:CGSizeMake(0.0, _verticalLineScroll)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moveByOffset:(CGSize)aSize
|
||||||
{
|
{
|
||||||
var documentFrame = [[self documentView] frame],
|
var documentFrame = [[self documentView] frame],
|
||||||
contentBounds = [_contentView bounds];
|
contentBounds = [_contentView bounds];
|
||||||
|
|
||||||
// We want integral bounds!
|
contentBounds.origin.x += aSize.width;
|
||||||
contentBounds.origin.x = ROUND(contentBounds.origin.x + [anEvent deltaX] * _horizontalLineScroll);
|
contentBounds.origin.y += aSize.height;
|
||||||
contentBounds.origin.y = ROUND(contentBounds.origin.y + [anEvent deltaY] * _verticalLineScroll);
|
|
||||||
|
|
||||||
[_contentView scrollToPoint:contentBounds.origin];
|
|
||||||
[_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0.0)];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)keyDown:(CPEvent)anEvent
|
|
||||||
{
|
|
||||||
var keyCode = [anEvent keyCode],
|
|
||||||
documentFrame = [[self documentView] frame],
|
|
||||||
contentBounds = [_contentView bounds];
|
|
||||||
|
|
||||||
switch (keyCode)
|
|
||||||
{
|
|
||||||
case 33: /*pageup*/
|
|
||||||
contentBounds.origin.y -= _CGRectGetHeight(contentBounds) - _verticalPageScroll;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 34: /*pagedown*/
|
|
||||||
contentBounds.origin.y += _CGRectGetHeight(contentBounds) - _verticalPageScroll;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 38: /*up arrow*/
|
|
||||||
contentBounds.origin.y -= _verticalLineScroll;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 40: /*down arrow*/
|
|
||||||
contentBounds.origin.y += _verticalLineScroll;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 37: /*left arrow*/
|
|
||||||
contentBounds.origin.x -= _horizontalLineScroll;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 49: /*right arrow*/
|
|
||||||
contentBounds.origin.x += _horizontalLineScroll;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: return [super keyDown:anEvent];
|
|
||||||
}
|
|
||||||
|
|
||||||
[_contentView scrollToPoint:contentBounds.origin];
|
[_contentView scrollToPoint:contentBounds.origin];
|
||||||
[_headerClipView scrollToPoint:CGPointMake(contentBounds.origin, 0)];
|
[_headerClipView scrollToPoint:CGPointMake(contentBounds.origin, 0)];
|
||||||
@@ -716,16 +1008,20 @@
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
var CPScrollViewContentViewKey = @"CPScrollViewContentView",
|
||||||
CPScrollViewVLineScrollKey = "CPScrollViewVLineScroll",
|
CPScrollViewHeaderClipViewKey = @"CPScrollViewHeaderClipViewKey",
|
||||||
CPScrollViewHLineScrollKey = "CPScrollViewHLineScroll",
|
CPScrollViewVLineScrollKey = @"CPScrollViewVLineScroll",
|
||||||
CPScrollViewVPageScrollKey = "CPScrollViewVPageScroll",
|
CPScrollViewHLineScrollKey = @"CPScrollViewHLineScroll",
|
||||||
CPScrollViewHPageScrollKey = "CPScrollViewHPageScroll",
|
CPScrollViewVPageScrollKey = @"CPScrollViewVPageScroll",
|
||||||
CPScrollViewHasVScrollerKey = "CPScrollViewHasVScroller",
|
CPScrollViewHPageScrollKey = @"CPScrollViewHPageScroll",
|
||||||
CPScrollViewHasHScrollerKey = "CPScrollViewHasHScroller",
|
CPScrollViewHasVScrollerKey = @"CPScrollViewHasVScroller",
|
||||||
CPScrollViewVScrollerKey = "CPScrollViewVScroller",
|
CPScrollViewHasHScrollerKey = @"CPScrollViewHasHScroller",
|
||||||
CPScrollViewHScrollerKey = "CPScrollViewHScroller",
|
CPScrollViewVScrollerKey = @"CPScrollViewVScroller",
|
||||||
CPScrollViewAutohidesScrollerKey = "CPScrollViewAutohidesScroller";
|
CPScrollViewHScrollerKey = @"CPScrollViewHScroller",
|
||||||
|
CPScrollViewAutohidesScrollerKey = @"CPScrollViewAutohidesScroller",
|
||||||
|
CPScrollViewCornerViewKey = @"CPScrollViewCornerViewKey",
|
||||||
|
CPScrollViewBottomCornerViewKey = @"CPScrollViewBottomCornerViewKey",
|
||||||
|
CPScrollViewBorderTypeKey = @"CPScrollViewBorderTypeKey";
|
||||||
|
|
||||||
@implementation CPScrollView (CPCoding)
|
@implementation CPScrollView (CPCoding)
|
||||||
|
|
||||||
@@ -740,6 +1036,13 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
|||||||
_horizontalPageScroll = [aCoder decodeFloatForKey:CPScrollViewHPageScrollKey];
|
_horizontalPageScroll = [aCoder decodeFloatForKey:CPScrollViewHPageScrollKey];
|
||||||
|
|
||||||
_contentView = [aCoder decodeObjectForKey:CPScrollViewContentViewKey];
|
_contentView = [aCoder decodeObjectForKey:CPScrollViewContentViewKey];
|
||||||
|
_headerClipView = [aCoder decodeObjectForKey:CPScrollViewHeaderClipViewKey];
|
||||||
|
|
||||||
|
if (!_headerClipView)
|
||||||
|
{
|
||||||
|
_headerClipView = [[CPClipView alloc] init];
|
||||||
|
[self addSubview:_headerClipView];
|
||||||
|
}
|
||||||
|
|
||||||
_verticalScroller = [aCoder decodeObjectForKey:CPScrollViewVScrollerKey];
|
_verticalScroller = [aCoder decodeObjectForKey:CPScrollViewVScrollerKey];
|
||||||
_horizontalScroller = [aCoder decodeObjectForKey:CPScrollViewHScrollerKey];
|
_horizontalScroller = [aCoder decodeObjectForKey:CPScrollViewHScrollerKey];
|
||||||
@@ -748,6 +1051,11 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
|||||||
_hasHorizontalScroller = [aCoder decodeBoolForKey:CPScrollViewHasHScrollerKey];
|
_hasHorizontalScroller = [aCoder decodeBoolForKey:CPScrollViewHasHScrollerKey];
|
||||||
_autohidesScrollers = [aCoder decodeBoolForKey:CPScrollViewAutohidesScrollerKey];
|
_autohidesScrollers = [aCoder decodeBoolForKey:CPScrollViewAutohidesScrollerKey];
|
||||||
|
|
||||||
|
_borderType = [aCoder decodeIntForKey:CPScrollViewBorderTypeKey];
|
||||||
|
|
||||||
|
_cornerView = [aCoder decodeObjectForKey:CPScrollViewCornerViewKey];
|
||||||
|
_bottomCornerView = [aCoder decodeObjectForKey:CPScrollViewBottomCornerViewKey];
|
||||||
|
|
||||||
// Do to the anything goes nature of decoding, our subviews may not exist yet, so layout at the end of the run loop when we're sure everything is in a correct state.
|
// 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]];
|
[[CPRunLoop currentRunLoop] performSelector:@selector(reflectScrolledClipView:) target:self argument:_contentView order:0 modes:[CPDefaultRunLoopMode]];
|
||||||
}
|
}
|
||||||
@@ -760,6 +1068,7 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
|||||||
[super encodeWithCoder:aCoder];
|
[super encodeWithCoder:aCoder];
|
||||||
|
|
||||||
[aCoder encodeObject:_contentView forKey:CPScrollViewContentViewKey];
|
[aCoder encodeObject:_contentView forKey:CPScrollViewContentViewKey];
|
||||||
|
[aCoder encodeObject:_headerClipView forKey:CPScrollViewHeaderClipViewKey];
|
||||||
|
|
||||||
[aCoder encodeObject:_verticalScroller forKey:CPScrollViewVScrollerKey];
|
[aCoder encodeObject:_verticalScroller forKey:CPScrollViewVScrollerKey];
|
||||||
[aCoder encodeObject:_horizontalScroller forKey:CPScrollViewHScrollerKey];
|
[aCoder encodeObject:_horizontalScroller forKey:CPScrollViewHScrollerKey];
|
||||||
@@ -772,6 +1081,11 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
|||||||
[aCoder encodeBool:_hasVerticalScroller forKey:CPScrollViewHasVScrollerKey];
|
[aCoder encodeBool:_hasVerticalScroller forKey:CPScrollViewHasVScrollerKey];
|
||||||
[aCoder encodeBool:_hasHorizontalScroller forKey:CPScrollViewHasHScrollerKey];
|
[aCoder encodeBool:_hasHorizontalScroller forKey:CPScrollViewHasHScrollerKey];
|
||||||
[aCoder encodeBool:_autohidesScrollers forKey:CPScrollViewAutohidesScrollerKey];
|
[aCoder encodeBool:_autohidesScrollers forKey:CPScrollViewAutohidesScrollerKey];
|
||||||
|
|
||||||
|
[aCoder encodeObject:_cornerView forKey:CPScrollViewCornerViewKey];
|
||||||
|
[aCoder encodeObject:_bottomCornerView forKey:CPScrollViewBottomCornerViewKey];
|
||||||
|
|
||||||
|
[aCoder encodeInt:_borderType forKey:CPScrollViewBorderTypeKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+56
-25
@@ -22,8 +22,6 @@
|
|||||||
|
|
||||||
@import "CPControl.j"
|
@import "CPControl.j"
|
||||||
|
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
|
|
||||||
// CPScroller Constants
|
// CPScroller Constants
|
||||||
CPScrollerNoPart = 0;
|
CPScrollerNoPart = 0;
|
||||||
@@ -72,24 +70,25 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
|||||||
CGPoint _trackingStartPoint;
|
CGPoint _trackingStartPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPString)themeClass
|
+ (CPString)defaultThemeClass
|
||||||
{
|
{
|
||||||
return "scroller";
|
return "scroller";
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)themeAttributes
|
+ (id)themeAttributes
|
||||||
{
|
{
|
||||||
return [CPDictionary dictionaryWithObjects:[ nil, nil, nil, nil,
|
return [CPDictionary dictionaryWithJSObject:{
|
||||||
_CGSizeMakeZero(), _CGSizeMakeZero(), _CGInsetMakeZero(), _CGInsetMakeZero(), _CGSizeMakeZero()]
|
@"scroller-width": 15.0,
|
||||||
forKeys:[ @"knob-slot-color",
|
@"knob-slot-color": [CPColor lightGrayColor],
|
||||||
@"decrement-line-color",
|
@"decrement-line-color": [CPNull null],
|
||||||
@"increment-line-color",
|
@"increment-line-color": [CPNull null],
|
||||||
@"knob-color",
|
@"knob-color": [CPColor grayColor],
|
||||||
@"decrement-line-size",
|
@"decrement-line-size":_CGSizeMakeZero(),
|
||||||
@"increment-line-size",
|
@"increment-line-size":_CGSizeMakeZero(),
|
||||||
@"track-inset",
|
@"track-inset":_CGInsetMakeZero(),
|
||||||
@"knob-inset",
|
@"knob-inset": _CGInsetMakeZero(),
|
||||||
@"minimum-knob-length"]];
|
@"minimum-knob-length":21.0
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -121,7 +120,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
|||||||
*/
|
*/
|
||||||
+ (float)scrollerWidth
|
+ (float)scrollerWidth
|
||||||
{
|
{
|
||||||
return 15.0;//[self scrollerWidthForControlSize:CPRegularControlSize];
|
return [[[CPScroller alloc] init] currentValueForThemeAttribute:@"scroller-width"];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -130,7 +129,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
|||||||
*/
|
*/
|
||||||
+ (float)scrollerWidthForControlSize:(CPControlSize)aControlSize
|
+ (float)scrollerWidthForControlSize:(CPControlSize)aControlSize
|
||||||
{
|
{
|
||||||
return 15.0;//_CPScrollerWidths[aControlSize];
|
return [self scrollerWidth];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -242,14 +241,14 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
|||||||
{
|
{
|
||||||
_usableParts = CPNoScrollerParts;
|
_usableParts = CPNoScrollerParts;
|
||||||
|
|
||||||
_partRects[CPScrollerDecrementPage] = _CGRectMakeZero();
|
_partRects[CPScrollerDecrementPage] = CGRectMakeZero();
|
||||||
_partRects[CPScrollerKnob] = _CGRectMakeZero();
|
_partRects[CPScrollerKnob] = CGRectMakeZero();
|
||||||
_partRects[CPScrollerIncrementPage] = _CGRectMakeZero();
|
_partRects[CPScrollerIncrementPage] = CGRectMakeZero();
|
||||||
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
|
_partRects[CPScrollerDecrementLine] = CGRectMakeZero();
|
||||||
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
|
_partRects[CPScrollerIncrementLine] = CGRectMakeZero();
|
||||||
|
|
||||||
// In this case, the slot is the entirety of the scroller.
|
// In this case, the slot is the entirety of the scroller.
|
||||||
_partRects[CPScrollerKnobSlot] = _CGRectMakeCopy(bounds);
|
_partRects[CPScrollerKnobSlot] = CGRectMakeCopy(bounds);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -280,14 +279,23 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
|||||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, effectiveDecrementLineHeight, width - trackInset.left - trackInset.right, slotHeight);
|
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, effectiveDecrementLineHeight, width - trackInset.left - trackInset.right, slotHeight);
|
||||||
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
||||||
_partRects[CPScrollerIncrementLine] = _CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height);
|
_partRects[CPScrollerIncrementLine] = _CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height);
|
||||||
}
|
|
||||||
|
|
||||||
|
if (height < knobHeight + decrementLineSize.height + incrementLineSize.height + trackInset.top + trackInset.bottom)
|
||||||
|
_partRects[CPScrollerKnob] = _CGRectMakeZero();
|
||||||
|
|
||||||
|
if (height < decrementLineSize.height + incrementLineSize.height - 2)
|
||||||
|
{
|
||||||
|
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
|
||||||
|
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
|
||||||
|
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, 0, width - trackInset.left - trackInset.right, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"],
|
var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"],
|
||||||
incrementLineSize = [self currentValueForThemeAttribute:"increment-line-size"],
|
incrementLineSize = [self currentValueForThemeAttribute:"increment-line-size"],
|
||||||
effectiveDecrementLineWidth = decrementLineSize.width + trackInset.left,
|
effectiveDecrementLineWidth = decrementLineSize.width + trackInset.left,
|
||||||
effectiveIncrementLineWidth = incrementLineSize.width + trackInset.right;
|
effectiveIncrementLineWidth = incrementLineSize.width + trackInset.right,
|
||||||
slotWidth = width - effectiveDecrementLineWidth - effectiveIncrementLineWidth,
|
slotWidth = width - effectiveDecrementLineWidth - effectiveIncrementLineWidth,
|
||||||
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
|
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
|
||||||
knobWidth = MAX(minimumKnobLength, (slotWidth * _knobProportion)),
|
knobWidth = MAX(minimumKnobLength, (slotWidth * _knobProportion)),
|
||||||
@@ -300,6 +308,16 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
|||||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotWidth, height - trackInset.top - trackInset.bottom);
|
_partRects[CPScrollerKnobSlot] = _CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotWidth, height - trackInset.top - trackInset.bottom);
|
||||||
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
||||||
_partRects[CPScrollerIncrementLine] = _CGRectMake(width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.height);
|
_partRects[CPScrollerIncrementLine] = _CGRectMake(width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.height);
|
||||||
|
|
||||||
|
if (width < knobWidth + decrementLineSize.width + incrementLineSize.width + trackInset.left + trackInset.right)
|
||||||
|
_partRects[CPScrollerKnob] = _CGRectMakeZero();
|
||||||
|
|
||||||
|
if (width < decrementLineSize.width + incrementLineSize.width - 2)
|
||||||
|
{
|
||||||
|
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
|
||||||
|
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
|
||||||
|
_partRects[CPScrollerKnobSlot] = _CGRectMake(0.0, 0.0, width, slotHeight);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,7 +449,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
|||||||
[self setFloatValue:0.0];
|
[self setFloatValue:0.0];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||||
delta = ![self isVertical] ? location.x - _trackingStartPoint.x : location.y - _trackingStartPoint.y;
|
delta = ![self isVertical] ? location.x - _trackingStartPoint.x : location.y - _trackingStartPoint.y;
|
||||||
|
|
||||||
[self setFloatValue:_trackingFloatValue + delta / remainder];
|
[self setFloatValue:_trackingFloatValue + delta / remainder];
|
||||||
@@ -588,6 +606,19 @@ var CPScrollerControlSizeKey = "CPScrollerControlSize",
|
|||||||
_hitPart = CPScrollerNoPart;
|
_hitPart = CPScrollerNoPart;
|
||||||
|
|
||||||
[self _calculateIsVertical];
|
[self _calculateIsVertical];
|
||||||
|
|
||||||
|
// Adjust the size of the scroller if the size from cib
|
||||||
|
// isn't equal to the scrollerWidth
|
||||||
|
var frame = [self frame],
|
||||||
|
scrollerWidth = [CPScroller scrollerWidth];
|
||||||
|
|
||||||
|
if ([self isVertical] && CGRectGetWidth(frame) !== scrollerWidth)
|
||||||
|
frame.size.width = scrollerWidth;
|
||||||
|
|
||||||
|
if (![self isVertical] && CGRectGetHeight(frame) !== scrollerWidth)
|
||||||
|
frame.size.height = scrollerWidth;
|
||||||
|
|
||||||
|
[self setFrame:frame];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
|||||||
+244
-165
@@ -20,36 +20,28 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@import "CPButton.j"
|
||||||
@import "CPTextField.j"
|
@import "CPTextField.j"
|
||||||
|
|
||||||
#include "Platform/Platform.h"
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@global
|
|
||||||
@group Menu tags
|
|
||||||
*/
|
|
||||||
CPSearchFieldRecentsTitleMenuItemTag = 1000;
|
CPSearchFieldRecentsTitleMenuItemTag = 1000;
|
||||||
/*!
|
|
||||||
@global
|
|
||||||
@group Menu tags
|
|
||||||
*/
|
|
||||||
CPSearchFieldRecentsMenuItemTag = 1001;
|
CPSearchFieldRecentsMenuItemTag = 1001;
|
||||||
/*!
|
|
||||||
@global
|
|
||||||
@group Menu tags
|
|
||||||
*/
|
|
||||||
CPSearchFieldClearRecentsMenuItemTag = 1002;
|
CPSearchFieldClearRecentsMenuItemTag = 1002;
|
||||||
/*!
|
|
||||||
@global
|
|
||||||
@group Menu tags
|
|
||||||
*/
|
|
||||||
CPSearchFieldNoRecentsMenuItemTag = 1003;
|
CPSearchFieldNoRecentsMenuItemTag = 1003;
|
||||||
|
CPSearchFieldSeparatorMenuItemTag = 1004;
|
||||||
|
|
||||||
var CPSearchFieldSearchImage = nil,
|
var CPSearchFieldSearchImage = nil,
|
||||||
CPSearchFieldFindImage = nil,
|
CPSearchFieldFindImage = nil,
|
||||||
CPSearchFieldCancelImage = nil,
|
CPSearchFieldCancelImage = nil,
|
||||||
CPSearchFieldCancelPressedImage = nil;
|
CPSearchFieldCancelPressedImage = nil;
|
||||||
|
|
||||||
|
var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0,
|
||||||
|
CANCEL_BUTTON_DEFAULT_WIDTH = 22.0,
|
||||||
|
BUTTON_DEFAULT_HEIGHT = 22.0;
|
||||||
|
|
||||||
|
var RECENT_SEARCH_PREFIX = @" ";
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@class CPSearchField
|
@class CPSearchField
|
||||||
@@ -70,73 +62,68 @@ var CPSearchFieldSearchImage = nil,
|
|||||||
int _maximumRecents;
|
int _maximumRecents;
|
||||||
BOOL _sendsWholeSearchString;
|
BOOL _sendsWholeSearchString;
|
||||||
BOOL _sendsSearchStringImmediately;
|
BOOL _sendsSearchStringImmediately;
|
||||||
|
BOOL _canResignFirstResponder;
|
||||||
CPTimer _partialStringTimer;
|
CPTimer _partialStringTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (CPString)defaultThemeClass
|
||||||
|
{
|
||||||
|
return @"searchfield"
|
||||||
|
}
|
||||||
|
|
||||||
+ (void)initialize
|
+ (void)initialize
|
||||||
{
|
{
|
||||||
if (self != [CPSearchField class])
|
if (self != [CPSearchField class])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var bundle = [CPBundle bundleForClass:self];
|
var bundle = [CPBundle bundleForClass:self];
|
||||||
CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"]];
|
CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:_CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
|
||||||
CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"]];
|
CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"] size:_CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
|
||||||
CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"]];
|
CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"] size:_CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
|
||||||
CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"]];
|
CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:_CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CPRect)frame
|
- (id)initWithFrame:(CGRect)frame
|
||||||
{
|
{
|
||||||
self = [super initWithFrame:frame];
|
if (self = [super initWithFrame:frame])
|
||||||
if (self != nil)
|
|
||||||
{
|
{
|
||||||
_recentSearches = [CPArray array];
|
|
||||||
_maximumRecents = 10;
|
_maximumRecents = 10;
|
||||||
_sendsWholeSearchString = NO;
|
_sendsWholeSearchString = NO;
|
||||||
_sendsSearchStringImmediately = NO;
|
_sendsSearchStringImmediately = NO;
|
||||||
_recentsAutosaveName = nil;
|
_recentsAutosaveName = nil;
|
||||||
|
|
||||||
|
[self _init];
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
_cancelButton._DOMElement.style.cursor = "default";
|
||||||
|
_searchButton._DOMElement.style.cursor = "default";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_init
|
||||||
|
{
|
||||||
|
_recentSearches = [CPArray array];
|
||||||
|
|
||||||
[self setBezeled:YES];
|
[self setBezeled:YES];
|
||||||
[self setBezelStyle:CPTextFieldRoundedBezel];
|
[self setBezelStyle:CPTextFieldRoundedBezel];
|
||||||
[self setBordered:YES];
|
[self setBordered:YES];
|
||||||
[self setEditable:YES];
|
[self setEditable:YES];
|
||||||
[self setDelegate:self];
|
[self setDelegate:self];
|
||||||
|
[self setContinuous:YES];
|
||||||
|
|
||||||
_cancelButton = [[CPButton alloc] initWithFrame:CPMakeRect(frame.size.width - 27,(frame.size.height-22)/2,22,22)];
|
var bounds = [self bounds],
|
||||||
|
cancelButton = [[CPButton alloc] initWithFrame:[self cancelButtonRectForBounds:bounds]],
|
||||||
|
searchButton = [[CPButton alloc] initWithFrame:[self searchButtonRectForBounds:bounds]];
|
||||||
|
|
||||||
|
[self setCancelButton:cancelButton];
|
||||||
[self resetCancelButton];
|
[self resetCancelButton];
|
||||||
[_cancelButton setHidden:YES];
|
|
||||||
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
|
|
||||||
[self addSubview:_cancelButton];
|
|
||||||
|
|
||||||
_searchButton = [[CPButton alloc] initWithFrame:CPMakeRect(5,(frame.size.height-25)/2,25,25)];
|
[self setSearchButton:searchButton];
|
||||||
[self resetSearchButton];
|
[self resetSearchButton];
|
||||||
[self addSubview:_searchButton];
|
|
||||||
|
|
||||||
#if PLATFORM(DOM)
|
_canResignFirstResponder = YES;
|
||||||
_cancelButton._DOMElement.style.cursor = "default";
|
|
||||||
_searchButton._DOMElement.style.cursor = "default";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)copy
|
|
||||||
{
|
|
||||||
var copy = [super copy];
|
|
||||||
|
|
||||||
[copy setCancelButton:[_cancelButton copy]];
|
|
||||||
[copy setSearchButton:[_searchButton copy]];
|
|
||||||
[copy setSendsWholeSearchString:[_sendsWholeSearchString copy]];
|
|
||||||
[copy setSendsSearchStringImmediately:[_sendsSearchStringImmediately copy]];
|
|
||||||
[copy setMaximumRecents:_maximumRecents];
|
|
||||||
if (_recentsAutosaveName)
|
|
||||||
[copy setrecentsAutosaveName:[_recentsAutosaveName copy]];
|
|
||||||
if (_searchMenuTemplate)
|
|
||||||
[copy setSearchMenutemplate:[_searchMenuTemplate copy]];
|
|
||||||
|
|
||||||
return copy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Managing Buttons
|
// Managing Buttons
|
||||||
@@ -146,7 +133,15 @@ var CPSearchFieldSearchImage = nil,
|
|||||||
*/
|
*/
|
||||||
- (void)setSearchButton:(CPButton)button
|
- (void)setSearchButton:(CPButton)button
|
||||||
{
|
{
|
||||||
|
if (button != _searchButton)
|
||||||
|
{
|
||||||
|
[_searchButton removeFromSuperview];
|
||||||
_searchButton = button;
|
_searchButton = button;
|
||||||
|
|
||||||
|
[_searchButton setFrame:[self searchButtonRectForBounds:[self bounds]]];
|
||||||
|
[_searchButton setAutoresizingMask:CPViewMaxXMargin];
|
||||||
|
[self addSubview:_searchButton];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -164,30 +159,13 @@ var CPSearchFieldSearchImage = nil,
|
|||||||
*/
|
*/
|
||||||
- (void)resetSearchButton
|
- (void)resetSearchButton
|
||||||
{
|
{
|
||||||
var searchButtonImage,
|
var button = [self searchButton],
|
||||||
action,
|
searchButtonImage = (_searchMenuTemplate === nil) ? CPSearchFieldSearchImage : CPSearchFieldFindImage;
|
||||||
target,
|
|
||||||
button = [self searchButton];
|
|
||||||
|
|
||||||
if (_searchMenuTemplate === nil)
|
|
||||||
{
|
|
||||||
searchButtonImage = CPSearchFieldSearchImage;
|
|
||||||
action = @selector(_sendAction:);
|
|
||||||
target = self;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
searchButtonImage = CPSearchFieldFindImage;
|
|
||||||
action = @selector(_showMenu:);
|
|
||||||
target = self;
|
|
||||||
}
|
|
||||||
|
|
||||||
[button setBordered:NO];
|
[button setBordered:NO];
|
||||||
[button setImageScaling:CPScaleToFit];
|
[button setImageScaling:CPScaleToFit];
|
||||||
[button setImage:searchButtonImage];
|
[button setImage:searchButtonImage];
|
||||||
[button setAutoresizingMask:CPViewMaxXMargin];
|
[button setAutoresizingMask:CPViewMaxXMargin];
|
||||||
[button setTarget:target];
|
|
||||||
[button setAction:action];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -196,7 +174,18 @@ var CPSearchFieldSearchImage = nil,
|
|||||||
*/
|
*/
|
||||||
- (void)setCancelButton:(CPButton)button
|
- (void)setCancelButton:(CPButton)button
|
||||||
{
|
{
|
||||||
|
if (button != _cancelButton)
|
||||||
|
{
|
||||||
|
[_cancelButton removeFromSuperview];
|
||||||
_cancelButton = button;
|
_cancelButton = button;
|
||||||
|
|
||||||
|
[_cancelButton setFrame:[self cancelButtonRectForBounds:[self bounds]]];
|
||||||
|
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
|
||||||
|
[_cancelButton setTarget:self];
|
||||||
|
[_cancelButton setAction:@selector(_searchFieldCancel:)];
|
||||||
|
[self _updateCancelButtonVisibility];
|
||||||
|
[self addSubview:_cancelButton];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -231,23 +220,25 @@ var CPSearchFieldSearchImage = nil,
|
|||||||
@return The updated bounding rectangle to use for the search text field. The default value is the value passed into the rect parameter.
|
@return The updated bounding rectangle to use for the search text field. The default value is the value passed into the rect parameter.
|
||||||
Subclasses can override this method to return a new bounding rectangle for the text-field object. You might use this method to provide a custom layout for the search field control.
|
Subclasses can override this method to return a new bounding rectangle for the text-field object. You might use this method to provide a custom layout for the search field control.
|
||||||
*/
|
*/
|
||||||
- (CPRect)searchTextRectForBounds:(CPRect)rect
|
- (CGRect)searchTextRectForBounds:(CGRect)rect
|
||||||
{
|
{
|
||||||
var leftOffset = 0, width = rect.size.width;
|
var leftOffset = 0,
|
||||||
|
width = _CGRectGetWidth(rect),
|
||||||
|
bounds = [self bounds];
|
||||||
|
|
||||||
if (_searchButton)
|
if (_searchButton)
|
||||||
{
|
{
|
||||||
var searchRect = [_searchButton frame];
|
var searchBounds = [self searchButtonRectForBounds:bounds];
|
||||||
leftOffset = searchRect.origin.x + searchRect.size.width;
|
leftOffset = _CGRectGetMaxX(searchBounds) + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_cancelButton)
|
if (_cancelButton)
|
||||||
{
|
{
|
||||||
var cancelRect = [_cancelButton frame];
|
var cancelRect = [self cancelButtonRectForBounds:bounds];
|
||||||
width = cancelRect.origin.x - leftOffset;
|
width = _CGRectGetMinX(cancelRect) - leftOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CPMakeRect(leftOffset,rect.origin.y,width,rect.size.height);
|
return _CGRectMake(leftOffset, _CGRectGetMinY(rect), width, _CGRectGetHeight(rect));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -255,9 +246,9 @@ var CPSearchFieldSearchImage = nil,
|
|||||||
@param rect The current bounding rectangle for the search button.
|
@param rect The current bounding rectangle for the search button.
|
||||||
Subclasses can override this method to return a new bounding rectangle for the search button. You might use this method to provide a custom layout for the search field control.
|
Subclasses can override this method to return a new bounding rectangle for the search button. You might use this method to provide a custom layout for the search field control.
|
||||||
*/
|
*/
|
||||||
- (CPRect)searchButtonRectForBounds:(CPRect)rect
|
- (CGRect)searchButtonRectForBounds:(CGRect)rect
|
||||||
{
|
{
|
||||||
return [_searchButton frame];
|
return _CGRectMake(5, (_CGRectGetHeight(rect) - BUTTON_DEFAULT_HEIGHT) / 2, SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -265,9 +256,9 @@ var CPSearchFieldSearchImage = nil,
|
|||||||
@param rect The updated bounding rectangle to use for the cancel button. The default value is the value passed into the rect parameter.
|
@param rect The updated bounding rectangle to use for the cancel button. The default value is the value passed into the rect parameter.
|
||||||
Subclasses can override this method to return a new bounding rectangle for the cancel button. You might use this method to provide a custom layout for the search field control.
|
Subclasses can override this method to return a new bounding rectangle for the cancel button. You might use this method to provide a custom layout for the search field control.
|
||||||
*/
|
*/
|
||||||
- (CPRect)cancelButtonRectForBounds:(CPRect)rect
|
- (CGRect)cancelButtonRectForBounds:(CGRect)rect
|
||||||
{
|
{
|
||||||
return [_cancelButton frame];
|
return _CGRectMake(_CGRectGetWidth(rect) - CANCEL_BUTTON_DEFAULT_WIDTH - 5, (_CGRectGetHeight(rect) - CANCEL_BUTTON_DEFAULT_WIDTH) / 2, BUTTON_DEFAULT_HEIGHT, BUTTON_DEFAULT_HEIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Managing Menu Templates
|
// Managing Menu Templates
|
||||||
@@ -285,9 +276,9 @@ var CPSearchFieldSearchImage = nil,
|
|||||||
@param menu The menu template to use.
|
@param menu The menu template to use.
|
||||||
The receiver looks for the tag constants described in ŇMenu tagsÓ to determine how to populate the menu with items related to recent searches. See ŇConfiguring a Search MenuÓ for a sample of how you might set up the search menu template.
|
The receiver looks for the tag constants described in ŇMenu tagsÓ to determine how to populate the menu with items related to recent searches. See ŇConfiguring a Search MenuÓ for a sample of how you might set up the search menu template.
|
||||||
*/
|
*/
|
||||||
- (void)setSearchMenuTemplate:(CPMenu)menu
|
- (void)setSearchMenuTemplate:(CPMenu)aMenu
|
||||||
{
|
{
|
||||||
_searchMenuTemplate = menu;
|
_searchMenuTemplate = aMenu;
|
||||||
|
|
||||||
[self resetSearchButton];
|
[self resetSearchButton];
|
||||||
[self _loadRecentSearchList];
|
[self _loadRecentSearchList];
|
||||||
@@ -404,7 +395,7 @@ var CPSearchFieldSearchImage = nil,
|
|||||||
|
|
||||||
// Private methods and subclassing
|
// Private methods and subclassing
|
||||||
|
|
||||||
- (CPRect)contentRectForBounds:(CPRect)bounds
|
- (CGRect)contentRectForBounds:(CGRect)bounds
|
||||||
{
|
{
|
||||||
var superbounds = [super contentRectForBounds:bounds];
|
var superbounds = [super contentRectForBounds:bounds];
|
||||||
return [self searchTextRectForBounds:superbounds];
|
return [self searchTextRectForBounds:superbounds];
|
||||||
@@ -478,37 +469,78 @@ var CPSearchFieldSearchImage = nil,
|
|||||||
[self _updateSearchMenu];
|
[self _updateSearchMenu];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)trackMouse:(CPEvent)event
|
- (CPView)hitTest:(CGPoint)aPoint
|
||||||
{
|
{
|
||||||
var rect,
|
// Make sure a hit anywhere within the search field returns the search field itself
|
||||||
point,
|
if (_CGRectContainsPoint([self frame], aPoint))
|
||||||
location = [event locationInWindow];
|
return self;
|
||||||
|
else
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)resignFirstResponder
|
||||||
|
{
|
||||||
|
return _canResignFirstResponder && [super resignFirstResponder];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseDown:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
var location = [anEvent locationInWindow],
|
||||||
point = [self convertPoint:location fromView:nil];
|
point = [self convertPoint:location fromView:nil];
|
||||||
|
|
||||||
rect = [self searchButtonRectForBounds:[self frame]];
|
if (_CGRectContainsPoint([self searchButtonRectForBounds:[self bounds]], point))
|
||||||
if (CPRectContainsPoint(rect,point))
|
|
||||||
{
|
{
|
||||||
return [[self searchButton] trackMouse:event];
|
if (_searchMenuTemplate == nil)
|
||||||
|
[self _sendAction:self];
|
||||||
|
else
|
||||||
|
[self _showMenu];
|
||||||
|
}
|
||||||
|
else if (_CGRectContainsPoint([self cancelButtonRectForBounds:[self bounds]], point))
|
||||||
|
[_cancelButton mouseDown:anEvent];
|
||||||
|
else
|
||||||
|
[super mouseDown:anEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
rect = [self cancelButtonRectForBounds:[self frame]];
|
/*!
|
||||||
if (CPRectContainsPoint(rect,point))
|
Provides the common case items for a recent searches menu. If there are not recent searches,
|
||||||
|
displays a single disabled item:
|
||||||
|
|
||||||
|
No Recent Searches
|
||||||
|
|
||||||
|
If there are 1 more recent searches, it displays:
|
||||||
|
|
||||||
|
Recent Searches
|
||||||
|
recent search 1
|
||||||
|
recent search 2
|
||||||
|
etc.
|
||||||
|
---------------------
|
||||||
|
Clear Recent Searches
|
||||||
|
|
||||||
|
If you wish to add items before or after the template, you can. If you put items
|
||||||
|
before, a separator will automatically be placed before the default template item.
|
||||||
|
If you add items after the default template, it is your responsibility to add a separator.
|
||||||
|
|
||||||
|
To add a custom item:
|
||||||
|
|
||||||
|
item = [[CPMenuItem alloc] initWithTitle:@"google"
|
||||||
|
action:@selector(google:)
|
||||||
|
keyEquivalent:@""];
|
||||||
|
[item setTag:700];
|
||||||
|
[item setTarget:self];
|
||||||
|
[template addItem:item];
|
||||||
|
|
||||||
|
Be sure that your custom items do not use tags in the range 1000-1004 inclusive.
|
||||||
|
If you wish to maintain state in custom menu items that you add, you will need to maintain
|
||||||
|
the item state yourself, then in the action method of the custom items, modify the items
|
||||||
|
in the search menu template and send [searchField setSearchMenuTemplate:template] to update the menu.
|
||||||
|
*/
|
||||||
|
- (CPMenu)defaultSearchMenuTemplate
|
||||||
{
|
{
|
||||||
return [[self cancelButton] trackMouse:event];
|
var template = [[CPMenu alloc] init],
|
||||||
}
|
item;
|
||||||
|
|
||||||
return [super trackMouse:event];
|
item = [[CPMenuItem alloc] initWithTitle:@"Recent Searches"
|
||||||
}
|
action:nil
|
||||||
|
|
||||||
- (CPMenu)_defaultSearchMenuTemplate
|
|
||||||
{
|
|
||||||
var template, item;
|
|
||||||
|
|
||||||
template = [[CPMenu alloc] init];
|
|
||||||
|
|
||||||
item = [[CPMenuItem alloc] initWithTitle:@"Recent searches"
|
|
||||||
action:NULL
|
|
||||||
keyEquivalent:@""];
|
keyEquivalent:@""];
|
||||||
[item setTag:CPSearchFieldRecentsTitleMenuItemTag];
|
[item setTag:CPSearchFieldRecentsTitleMenuItemTag];
|
||||||
[item setEnabled:NO];
|
[item setEnabled:NO];
|
||||||
@@ -521,15 +553,15 @@ var CPSearchFieldSearchImage = nil,
|
|||||||
[item setTarget:self];
|
[item setTarget:self];
|
||||||
[template addItem:item];
|
[template addItem:item];
|
||||||
|
|
||||||
item = [[CPMenuItem alloc] initWithTitle:@"Clear recent searches"
|
item = [[CPMenuItem alloc] initWithTitle:@"Clear Recent Searches"
|
||||||
action:@selector(_searchFieldClearRecents:)
|
action:@selector(_searchFieldClearRecents:)
|
||||||
keyEquivalent:@""];
|
keyEquivalent:@""];
|
||||||
[item setTag:CPSearchFieldClearRecentsMenuItemTag];
|
[item setTag:CPSearchFieldClearRecentsMenuItemTag];
|
||||||
[item setTarget:self];
|
[item setTarget:self];
|
||||||
[template addItem:item];
|
[template addItem:item];
|
||||||
|
|
||||||
item = [[CPMenuItem alloc] initWithTitle:@"No recent searches"
|
item = [[CPMenuItem alloc] initWithTitle:@"No Recent Searches"
|
||||||
action:NULL
|
action:nil
|
||||||
keyEquivalent:@""];
|
keyEquivalent:@""];
|
||||||
[item setTag:CPSearchFieldNoRecentsMenuItemTag];
|
[item setTag:CPSearchFieldNoRecentsMenuItemTag];
|
||||||
[item setEnabled:NO];
|
[item setEnabled:NO];
|
||||||
@@ -543,61 +575,96 @@ var CPSearchFieldSearchImage = nil,
|
|||||||
if (_searchMenuTemplate === nil)
|
if (_searchMenuTemplate === nil)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var i, menu = [[CPMenu alloc] init],
|
var menu = [[CPMenu alloc] init],
|
||||||
countOfRecents = [_recentSearches count],
|
countOfRecents = [_recentSearches count],
|
||||||
numberOfItems = [_searchMenuTemplate numberOfItems];
|
numberOfItems = [_searchMenuTemplate numberOfItems];
|
||||||
|
|
||||||
for (i = 0; i < numberOfItems; i++)
|
for (var i = 0; i < numberOfItems; i++)
|
||||||
{
|
{
|
||||||
var item = [_searchMenuTemplate itemAtIndex:i],
|
var item = [[_searchMenuTemplate itemAtIndex:i] copy];
|
||||||
tag = [item tag];
|
|
||||||
|
|
||||||
if (!(tag === CPSearchFieldRecentsTitleMenuItemTag && countOfRecents === 0) &&
|
switch ([item tag])
|
||||||
!(tag === CPSearchFieldClearRecentsMenuItemTag && countOfRecents === 0) &&
|
|
||||||
!(tag === CPSearchFieldNoRecentsMenuItemTag && countOfRecents != 0) &&
|
|
||||||
!(tag === CPSearchFieldRecentsMenuItemTag))
|
|
||||||
{
|
{
|
||||||
var itemAction, itemTarget;
|
case CPSearchFieldRecentsTitleMenuItemTag:
|
||||||
switch (tag)
|
if (countOfRecents === 0)
|
||||||
{
|
continue;
|
||||||
case CPSearchFieldRecentsTitleMenuItemTag : itemAction = NULL; itemTarget = NULL; break;
|
|
||||||
case CPSearchFieldClearRecentsMenuItemTag : itemAction = @selector(_searchFieldClearRecents:); itemTarget = self; break;
|
|
||||||
case CPSearchFieldNoRecentsMenuItemTag : itemAction = NULL; itemTarget = NULL; break;
|
|
||||||
default: itemAction = [item action]; itemTarget = [item target]; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tag === CPSearchFieldClearRecentsMenuItemTag || tag === CPSearchFieldRecentsTitleMenuItemTag)
|
if ([menu numberOfItems] > 0)
|
||||||
{
|
[self _addSeparatorToMenu:menu];
|
||||||
var separator = [CPMenuItem separatorItem];
|
break;
|
||||||
[separator setEnabled:NO];
|
|
||||||
[menu addItem:separator];
|
|
||||||
}
|
|
||||||
|
|
||||||
var templateItem = [[CPMenuItem alloc] initWithTitle:[item title]
|
case CPSearchFieldRecentsMenuItemTag:
|
||||||
|
{
|
||||||
|
var itemAction = @selector(_searchFieldSearch:);
|
||||||
|
|
||||||
|
for (var recentIndex = 0; recentIndex < countOfRecents; ++recentIndex)
|
||||||
|
{
|
||||||
|
// RECENT_SEARCH_PREFIX is a hack until CPMenuItem -setIndentationLevel works
|
||||||
|
var recentItem = [[CPMenuItem alloc] initWithTitle:RECENT_SEARCH_PREFIX + [_recentSearches objectAtIndex:recentIndex]
|
||||||
action:itemAction
|
action:itemAction
|
||||||
keyEquivalent:[item keyEquivalent]];
|
keyEquivalent:[item keyEquivalent]];
|
||||||
[templateItem setTarget:itemTarget];
|
[item setTarget:self];
|
||||||
[templateItem setEnabled:([item isEnabled] && itemAction != NULL)];
|
[menu addItem:recentItem];
|
||||||
[templateItem setTag:tag];
|
|
||||||
[menu addItem:templateItem];
|
|
||||||
}
|
}
|
||||||
else if (tag === CPSearchFieldRecentsMenuItemTag)
|
|
||||||
{
|
continue;
|
||||||
var j;
|
|
||||||
for (j = 0; j < countOfRecents; j++)
|
|
||||||
{
|
|
||||||
var rencentItem = [[CPMenuItem alloc] initWithTitle:[_recentSearches objectAtIndex:j]
|
|
||||||
action:@selector(_searchFieldSearch:)
|
|
||||||
keyEquivalent:[item keyEquivalent]];
|
|
||||||
[rencentItem setTarget:self];
|
|
||||||
[menu addItem:rencentItem];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case CPSearchFieldClearRecentsMenuItemTag:
|
||||||
|
if (countOfRecents === 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ([menu numberOfItems] > 0)
|
||||||
|
[self _addSeparatorToMenu:menu];
|
||||||
|
|
||||||
|
[item setAction:@selector(_searchFieldClearRecents:)];
|
||||||
|
[item setTarget:self];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPSearchFieldNoRecentsMenuItemTag:
|
||||||
|
if (countOfRecents !== 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ([menu numberOfItems] > 0)
|
||||||
|
[self _addSeparatorToMenu:menu];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPSearchFieldSeparatorMenuItemTag:
|
||||||
|
item = [CPMenuItem separatorItem];
|
||||||
|
[item setEnabled:NO];
|
||||||
|
[menu addItem:item];
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[item setEnabled:([item isEnabled] && [item action] != nil && [item target] != nil)];
|
||||||
|
[menu addItem:item];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[menu setDelegate:self];
|
||||||
|
|
||||||
_searchMenu = menu;
|
_searchMenu = menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_showMenu:(id)sender
|
- (void)_addSeparatorToMenu:(CPMenu)aMenu
|
||||||
|
{
|
||||||
|
var separator = [CPMenuItem separatorItem];
|
||||||
|
[separator setEnabled:NO];
|
||||||
|
[aMenu addItem:separator];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)menuWillOpen:(CPMenu)menu
|
||||||
|
{
|
||||||
|
_canResignFirstResponder = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)menuDidClose:(CPMenu)menu
|
||||||
|
{
|
||||||
|
_canResignFirstResponder = YES;
|
||||||
|
|
||||||
|
[self becomeFirstResponder];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_showMenu
|
||||||
{
|
{
|
||||||
if (_searchMenu === nil || [_searchMenu numberOfItems] === 0 || ![self isEnabled])
|
if (_searchMenu === nil || [_searchMenu numberOfItems] === 0 || ![self isEnabled])
|
||||||
return;
|
return;
|
||||||
@@ -607,12 +674,14 @@ var CPSearchFieldSearchImage = nil,
|
|||||||
|
|
||||||
var anEvent = [CPEvent mouseEventWithType:CPRightMouseDown location:location modifierFlags:0 timestamp:[[CPApp currentEvent] timestamp] windowNumber:[[self window] windowNumber] context:nil eventNumber:1 clickCount:1 pressure:0];
|
var anEvent = [CPEvent mouseEventWithType:CPRightMouseDown location:location modifierFlags:0 timestamp:[[CPApp currentEvent] timestamp] windowNumber:[[self window] windowNumber] context:nil eventNumber:1 clickCount:1 pressure:0];
|
||||||
|
|
||||||
[CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:sender];
|
[self selectAll:nil];
|
||||||
|
[CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_sendPartialString
|
- (void)_sendPartialString
|
||||||
{
|
{
|
||||||
[[self target] performSelector:[self action] withObject:self];
|
[super sendAction:[self action] to:[self target]];
|
||||||
|
[_partialStringTimer invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_searchFieldCancel:(id)sender
|
- (void)_searchFieldCancel:(id)sender
|
||||||
@@ -624,13 +693,14 @@ var CPSearchFieldSearchImage = nil,
|
|||||||
|
|
||||||
- (void)_searchFieldSearch:(id)sender
|
- (void)_searchFieldSearch:(id)sender
|
||||||
{
|
{
|
||||||
var searchString = [sender title];
|
var searchString = [[sender title] substringFromIndex:[RECENT_SEARCH_PREFIX length]];
|
||||||
|
|
||||||
if ([sender tag] != CPSearchFieldRecentsMenuItemTag)
|
if ([sender tag] != CPSearchFieldRecentsMenuItemTag)
|
||||||
[self _addStringToRecentSearches:searchString];
|
[self _addStringToRecentSearches:searchString];
|
||||||
|
|
||||||
[self setObjectValue:searchString];
|
[self setObjectValue:searchString];
|
||||||
[self _sendPartialString];
|
[self _sendPartialString];
|
||||||
|
[self selectAll:nil];
|
||||||
|
|
||||||
[self _updateCancelButtonVisibility];
|
[self _updateCancelButtonVisibility];
|
||||||
}
|
}
|
||||||
@@ -639,6 +709,8 @@ var CPSearchFieldSearchImage = nil,
|
|||||||
{
|
{
|
||||||
[self setRecentSearches:[CPArray array]];
|
[self setRecentSearches:[CPArray array]];
|
||||||
[self _updateSearchMenu];
|
[self _updateSearchMenu];
|
||||||
|
[self setStringValue:@""];
|
||||||
|
[self _updateCancelButtonVisibility];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_registerForAutosaveNotification
|
- (void)_registerForAutosaveNotification
|
||||||
@@ -695,9 +767,7 @@ var CPSearchFieldSearchImage = nil,
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPSearchButtonKey = @"CPSearchButtonKey",
|
var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
|
||||||
CPCancelButtonKey = @"CPCancelButtonKey",
|
|
||||||
CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
|
|
||||||
CPSendsWholeSearchStringKey = @"CPSendsWholeSearchStringKey",
|
CPSendsWholeSearchStringKey = @"CPSendsWholeSearchStringKey",
|
||||||
CPSendsSearchStringImmediatelyKey = @"CPSendsSearchStringImmediatelyKey",
|
CPSendsSearchStringImmediatelyKey = @"CPSendsSearchStringImmediatelyKey",
|
||||||
CPMaximumRecentsKey = @"CPMaximumRecentsKey",
|
CPMaximumRecentsKey = @"CPMaximumRecentsKey",
|
||||||
@@ -707,34 +777,43 @@ var CPSearchButtonKey = @"CPSearchButtonKey",
|
|||||||
|
|
||||||
- (void)encodeWithCoder:(CPCoder)coder
|
- (void)encodeWithCoder:(CPCoder)coder
|
||||||
{
|
{
|
||||||
|
[_searchButton removeFromSuperview];
|
||||||
|
[_cancelButton removeFromSuperview];
|
||||||
|
|
||||||
[super encodeWithCoder:coder];
|
[super encodeWithCoder:coder];
|
||||||
|
|
||||||
[coder encodeObject:_searchButton forKey:CPSearchButtonKey];
|
if (_searchButton)
|
||||||
[coder encodeObject:_cancelButton forKey:CPCancelButtonKey];
|
[self addSubview:_searchButton];
|
||||||
|
if (_cancelButton)
|
||||||
|
[self addSubview:_cancelButton];
|
||||||
|
|
||||||
[coder encodeBool:_sendsWholeSearchString forKey:CPSendsWholeSearchStringKey];
|
[coder encodeBool:_sendsWholeSearchString forKey:CPSendsWholeSearchStringKey];
|
||||||
[coder encodeBool:_sendsSearchStringImmediately forKey:CPSendsSearchStringImmediatelyKey];
|
[coder encodeBool:_sendsSearchStringImmediately forKey:CPSendsSearchStringImmediatelyKey];
|
||||||
[coder encodeInt:_maximumRecents forKey:CPMaximumRecentsKey];
|
[coder encodeInt:_maximumRecents forKey:CPMaximumRecentsKey];
|
||||||
|
|
||||||
if (_recentsAutosaveName)
|
if (_recentsAutosaveName)
|
||||||
[coder encodeObject:_recentsAutosaveName forKey:CPRecentsAutosaveNameKey];
|
[coder encodeObject:_recentsAutosaveName forKey:CPRecentsAutosaveNameKey];
|
||||||
|
|
||||||
if (_searchMenuTemplate)
|
if (_searchMenuTemplate)
|
||||||
[coder encodeObject:_searchMenuTemplate forKey:CPSearchMenuTemplateKey];
|
[coder encodeObject:_searchMenuTemplate forKey:CPSearchMenuTemplateKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithCoder:(CPCoder)coder
|
- (id)initWithCoder:(CPCoder)coder
|
||||||
{
|
{
|
||||||
self = [super initWithCoder:coder];
|
if (self = [super initWithCoder:coder])
|
||||||
|
{
|
||||||
_searchButton = [coder decodeObjectForKey:CPSearchButtonKey];
|
|
||||||
_cancelButton = [coder decodeObjectForKey:CPCancelButtonKey];
|
|
||||||
_recentsAutosaveName = [coder decodeObjectForKey:CPRecentsAutosaveNameKey];
|
_recentsAutosaveName = [coder decodeObjectForKey:CPRecentsAutosaveNameKey];
|
||||||
_sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey];
|
_sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey];
|
||||||
_sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey];
|
_sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey];
|
||||||
_maximumRecents = [coder decodeIntForKey:CPMaximumRecentsKey];
|
_maximumRecents = [coder decodeIntForKey:CPMaximumRecentsKey];
|
||||||
|
|
||||||
var template = [coder decodeObjectForKey:CPSearchMenuTemplateKey];
|
var template = [coder decodeObjectForKey:CPSearchMenuTemplateKey];
|
||||||
|
|
||||||
if (template)
|
if (template)
|
||||||
[self setSearchMenuTemplate:template];
|
[self setSearchMenuTemplate:template];
|
||||||
|
|
||||||
[self setDelegate:self];
|
[self _init];
|
||||||
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
@import "CPTextField.j"
|
@import "CPTextField.j"
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
*/
|
*/
|
||||||
|
|||||||
+106
-99
@@ -24,22 +24,9 @@
|
|||||||
|
|
||||||
@import "CPControl.j"
|
@import "CPControl.j"
|
||||||
|
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPSegmentSwitchTracking
|
|
||||||
*/
|
|
||||||
CPSegmentSwitchTrackingSelectOne = 0;
|
CPSegmentSwitchTrackingSelectOne = 0;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPSegmentSwitchTracking
|
|
||||||
*/
|
|
||||||
CPSegmentSwitchTrackingSelectAny = 1;
|
CPSegmentSwitchTrackingSelectAny = 1;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPSegmentSwitchTracking
|
|
||||||
*/
|
|
||||||
CPSegmentSwitchTrackingMomentary = 2;
|
CPSegmentSwitchTrackingMomentary = 2;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -61,14 +48,14 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
BOOL _trackingHighlighted;
|
BOOL _trackingHighlighted;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPString)themeClass
|
+ (CPString)defaultThemeClass
|
||||||
{
|
{
|
||||||
return "segmented-control";
|
return "segmented-control";
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)themeAttributes
|
+ (id)themeAttributes
|
||||||
{
|
{
|
||||||
return [CPDictionary dictionaryWithObjects:[CPCenterTextAlignment, CPCenterVerticalTextAlignment, CPImageLeft, CPScaleNone, _CGInsetMakeZero(), _CGInsetMakeZero(), nil, nil, nil, nil, 1.0, 24.0]
|
return [CPDictionary dictionaryWithObjects:[CPCenterTextAlignment, CPCenterVerticalTextAlignment, CPImageLeft, CPScaleNone, _CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null], [CPNull null], [CPNull null], [CPNull null], 1.0, 24.0]
|
||||||
forKeys:[@"alignment", @"vertical-alignment", @"image-position", @"image-scaling", @"bezel-inset", @"content-inset", @"left-segment-bezel-color", @"right-segment-bezel-color", @"center-segment-bezel-color", @"divider-bezel-color", @"divider-thickness", @"default-height"]];
|
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"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +81,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (int)selectedTag
|
- (int)selectedTag
|
||||||
{
|
{
|
||||||
return _segments[_selectedSegment].tag;
|
return [_segments[_selectedSegment] tag];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specifying the number of segments
|
// Specifying the number of segments
|
||||||
@@ -195,7 +182,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
selected = NO;
|
selected = NO;
|
||||||
|
|
||||||
for (; index < _segments.length; ++index)
|
for (; index < _segments.length; ++index)
|
||||||
if (_segments[index].selected)
|
if ([_segments[index] selected])
|
||||||
if (selected)
|
if (selected)
|
||||||
[self setSelected:NO forSegment:index];
|
[self setSelected:NO forSegment:index];
|
||||||
else
|
else
|
||||||
@@ -207,7 +194,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
var index = 0;
|
var index = 0;
|
||||||
|
|
||||||
for (; index < _segments.length; ++index)
|
for (; index < _segments.length; ++index)
|
||||||
if (_segments[index].selected)
|
if ([_segments[index] selected])
|
||||||
[self setSelected:NO forSegment:index];
|
[self setSelected:NO forSegment:index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -229,7 +216,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (void)setWidth:(float)aWidth forSegment:(unsigned)aSegment
|
- (void)setWidth:(float)aWidth forSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
_segments[aSegment].width = aWidth;
|
[_segments[aSegment] setWidth:aWidth];
|
||||||
|
|
||||||
[self tileWithChangedSegment:aSegment];
|
[self tileWithChangedSegment:aSegment];
|
||||||
}
|
}
|
||||||
@@ -241,7 +228,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (float)widthForSegment:(unsigned)aSegment
|
- (float)widthForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
return _segments[aSegment].width;
|
return [_segments[aSegment] width];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -252,9 +239,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (void)setImage:(CPImage)anImage forSegment:(unsigned)aSegment
|
- (void)setImage:(CPImage)anImage forSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
var segment = _segments[aSegment];
|
[_segments[aSegment] setImage:anImage];
|
||||||
|
|
||||||
segment.image = anImage;
|
|
||||||
|
|
||||||
[self tileWithChangedSegment:aSegment];
|
[self tileWithChangedSegment:aSegment];
|
||||||
}
|
}
|
||||||
@@ -266,7 +251,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (CPImage)imageForSegment:(unsigned)aSegment
|
- (CPImage)imageForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
return _segments[aSegment].image;
|
return [_segments[aSegment] image];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -277,9 +262,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (void)setLabel:(CPString)aLabel forSegment:(unsigned)aSegment
|
- (void)setLabel:(CPString)aLabel forSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
var segment = _segments[aSegment];
|
[_segments[aSegment] setLabel:aLabel];
|
||||||
|
|
||||||
_segments[aSegment].label = aLabel;
|
|
||||||
|
|
||||||
[self tileWithChangedSegment:aSegment];
|
[self tileWithChangedSegment:aSegment];
|
||||||
}
|
}
|
||||||
@@ -291,7 +274,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (CPString)labelForSegment:(unsigned)aSegment
|
- (CPString)labelForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
return _segments[aSegment].label;
|
return [_segments[aSegment] label];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -302,7 +285,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (void)setMenu:(CPMenu)aMenu forSegment:(unsigned)aSegment
|
- (void)setMenu:(CPMenu)aMenu forSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
_segments[aSegment].menu = aMenu;
|
[_segments[aSegment] setMenu:aMenu];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -312,7 +295,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (CPMenu)menuForSegment:(unsigned)aSegment
|
- (CPMenu)menuForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
return _segments[aSegment].menu;
|
return [_segments[aSegment] menu];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -327,10 +310,10 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
var segment = _segments[aSegment];
|
var segment = _segments[aSegment];
|
||||||
|
|
||||||
// If we're already in this state, bail.
|
// If we're already in this state, bail.
|
||||||
if (segment.selected == isSelected)
|
if ([segment selected] == isSelected)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
segment.selected = isSelected;
|
[segment setSelected:isSelected];
|
||||||
|
|
||||||
_themeStates[aSegment] = isSelected ? CPThemeStateSelected : CPThemeStateNormal;
|
_themeStates[aSegment] = isSelected ? CPThemeStateSelected : CPThemeStateNormal;
|
||||||
|
|
||||||
@@ -343,7 +326,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
|
|
||||||
if (_trackingMode == CPSegmentSwitchTrackingSelectOne && oldSelectedSegment != aSegment && oldSelectedSegment != -1)
|
if (_trackingMode == CPSegmentSwitchTrackingSelectOne && oldSelectedSegment != aSegment && oldSelectedSegment != -1)
|
||||||
{
|
{
|
||||||
_segments[oldSelectedSegment].selected = NO;
|
[_segments[oldSelectedSegment] setSelected:NO];
|
||||||
_themeStates[oldSelectedSegment] = CPThemeStateNormal;
|
_themeStates[oldSelectedSegment] = CPThemeStateNormal;
|
||||||
|
|
||||||
[self drawSegmentBezel:oldSelectedSegment highlight:NO];
|
[self drawSegmentBezel:oldSelectedSegment highlight:NO];
|
||||||
@@ -364,7 +347,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (BOOL)isSelectedForSegment:(unsigned)aSegment
|
- (BOOL)isSelectedForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
return _segments[aSegment].selected;
|
return [_segments[aSegment] selected];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -375,7 +358,12 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
|
- (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
_segments[aSegment].enabled = isEnabled;
|
[_segments[aSegment] setEnabled:isEnabled];
|
||||||
|
|
||||||
|
if (isEnabled)
|
||||||
|
_themeStates[aSegment] &= ~CPThemeStateDisabled;
|
||||||
|
else
|
||||||
|
_themeStates[aSegment] |= CPThemeStateDisabled;
|
||||||
|
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
@@ -388,7 +376,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (BOOL)isEnabledForSegment:(unsigned)aSegment
|
- (BOOL)isEnabledForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
return _segments[aSegment].enabled;
|
return [_segments[aSegment] enabled];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -398,7 +386,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (void)setTag:(int)aTag forSegment:(unsigned)aSegment
|
- (void)setTag:(int)aTag forSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
_segments[aSegment].tag = aTag;
|
[_segments[aSegment] setTag:aTag];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -407,7 +395,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
*/
|
*/
|
||||||
- (int)tagForSegment:(unsigned)aSegment
|
- (int)tagForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
return _segments[aSegment].tag;
|
return [_segments[aSegment] tag];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drawings
|
// Drawings
|
||||||
@@ -462,30 +450,28 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
}
|
}
|
||||||
else if (aName === "right-segment-bezel")
|
else if (aName === "right-segment-bezel")
|
||||||
{
|
{
|
||||||
var lastSegmentLeftOffset = [self _leftOffsetForSegment:[self _indexOfLastSegment]];
|
return CPRectMake(CGRectGetWidth([self bounds]) - contentInset.right,
|
||||||
|
|
||||||
return CPRectMake(lastSegmentLeftOffset + [self widthForSegment:[self _indexOfLastSegment]] - contentInset.right,
|
|
||||||
bezelInset.top,
|
bezelInset.top,
|
||||||
contentInset.right,
|
contentInset.right,
|
||||||
height);
|
height);
|
||||||
}
|
}
|
||||||
else if (aName.substring(0, "segment-bezel".length) == "segment-bezel")
|
else if (aName.indexOf("segment-bezel") === 0)
|
||||||
{
|
{
|
||||||
var segment = parseInt(aName.substring("segment-bezel-".length), 10),
|
var segment = parseInt(aName.substring("segment-bezel-".length), 10),
|
||||||
frame = CGRectCreateCopy(_segments[segment].frame);
|
frame = CGRectCreateCopy([_segments[segment] frame]);
|
||||||
|
|
||||||
if (segment == 0)
|
if (segment === 0)
|
||||||
{
|
{
|
||||||
frame.origin.x += contentInset.left;
|
frame.origin.x += contentInset.left;
|
||||||
frame.size.width -= contentInset.left;
|
frame.size.width -= contentInset.left;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (segment == _segments.length - 1)
|
if (segment === _segments.length - 1)
|
||||||
frame.size.width -= contentInset.right;
|
frame.size.width = CGRectGetWidth([self bounds]) - contentInset.right - frame.origin.x;
|
||||||
|
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
else if (aName.substring(0, "divider-bezel".length) == "divider-bezel")
|
else if (aName.indexOf("divider-bezel") === 0)
|
||||||
{
|
{
|
||||||
var segment = parseInt(aName.substring("divider-bezel-".length), 10),
|
var segment = parseInt(aName.substring("divider-bezel-".length), 10),
|
||||||
width = [self widthForSegment:segment],
|
width = [self widthForSegment:segment],
|
||||||
@@ -494,7 +480,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
|
|
||||||
return CGRectMake(left + width, bezelInset.top, thickness, height);
|
return CGRectMake(left + width, bezelInset.top, thickness, height);
|
||||||
}
|
}
|
||||||
else if (aName.substring(0, "segment-content".length) == "segment-content")
|
else if (aName.indexOf("segment-content") === 0)
|
||||||
{
|
{
|
||||||
var segment = parseInt(aName.substring("segment-content-".length), 10);
|
var segment = parseInt(aName.substring("segment-content-".length), 10);
|
||||||
|
|
||||||
@@ -506,7 +492,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
|
|
||||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||||
{
|
{
|
||||||
if (aName.substring(0, "segment-content".length) == "segment-content")
|
if ([aName hasPrefix:@"segment-content"])
|
||||||
return [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
return [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
||||||
|
|
||||||
return [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
return [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||||
@@ -517,19 +503,27 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
if (_segments.length <= 0)
|
if (_segments.length <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
|
var themeState = _themeStates[0];
|
||||||
inState:_themeStates[0]];
|
|
||||||
|
|
||||||
var leftBezelView = [self layoutEphemeralSubviewNamed:@"left-segment-bezel"
|
themeState |= _themeState & CPThemeStateDisabled;
|
||||||
|
|
||||||
|
var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
|
||||||
|
inState:themeState],
|
||||||
|
|
||||||
|
leftBezelView = [self layoutEphemeralSubviewNamed:@"left-segment-bezel"
|
||||||
positioned:CPWindowBelow
|
positioned:CPWindowBelow
|
||||||
relativeToEphemeralSubviewNamed:nil];
|
relativeToEphemeralSubviewNamed:nil];
|
||||||
|
|
||||||
[leftBezelView setBackgroundColor:leftCapColor];
|
[leftBezelView setBackgroundColor:leftCapColor];
|
||||||
|
|
||||||
var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color"
|
var themeState = _themeStates[_themeStates.length - 1];
|
||||||
inState:_themeStates[_themeStates.length - 1]];
|
|
||||||
|
|
||||||
var rightBezelView = [self layoutEphemeralSubviewNamed:@"right-segment-bezel"
|
themeState |= _themeState & CPThemeStateDisabled;
|
||||||
|
|
||||||
|
var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color"
|
||||||
|
inState:themeState],
|
||||||
|
|
||||||
|
rightBezelView = [self layoutEphemeralSubviewNamed:@"right-segment-bezel"
|
||||||
positioned:CPWindowBelow
|
positioned:CPWindowBelow
|
||||||
relativeToEphemeralSubviewNamed:nil];
|
relativeToEphemeralSubviewNamed:nil];
|
||||||
|
|
||||||
@@ -542,9 +536,9 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
themeState |= _themeState & CPThemeStateDisabled;
|
themeState |= _themeState & CPThemeStateDisabled;
|
||||||
|
|
||||||
var bezelColor = [self valueForThemeAttribute:@"center-segment-bezel-color"
|
var bezelColor = [self valueForThemeAttribute:@"center-segment-bezel-color"
|
||||||
inState:themeState];
|
inState:themeState],
|
||||||
|
|
||||||
var bezelView = [self layoutEphemeralSubviewNamed:"segment-bezel-"+i
|
bezelView = [self layoutEphemeralSubviewNamed:"segment-bezel-" + i
|
||||||
positioned:CPWindowBelow
|
positioned:CPWindowBelow
|
||||||
relativeToEphemeralSubviewNamed:nil];
|
relativeToEphemeralSubviewNamed:nil];
|
||||||
|
|
||||||
@@ -552,15 +546,13 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
|
|
||||||
|
|
||||||
// layout image/title views
|
// layout image/title views
|
||||||
var segment = _segments[i];
|
var segment = _segments[i],
|
||||||
|
contentView = [self layoutEphemeralSubviewNamed:@"segment-content-" + i
|
||||||
|
|
||||||
var contentView = [self layoutEphemeralSubviewNamed:@"segment-content-"+i
|
|
||||||
positioned:CPWindowAbove
|
positioned:CPWindowAbove
|
||||||
relativeToEphemeralSubviewNamed:@"segment-bezel-" + i];
|
relativeToEphemeralSubviewNamed:@"segment-bezel-" + i];
|
||||||
|
|
||||||
[contentView setText:segment.label];
|
[contentView setText:[segment label]];
|
||||||
[contentView setImage:segment.image];
|
[contentView setImage:[segment image]];
|
||||||
|
|
||||||
[contentView setFont:[self valueForThemeAttribute:@"font" inState:themeState]];
|
[contentView setFont:[self valueForThemeAttribute:@"font" inState:themeState]];
|
||||||
[contentView setTextColor:[self valueForThemeAttribute:@"text-color" inState:themeState]];
|
[contentView setTextColor:[self valueForThemeAttribute:@"text-color" inState:themeState]];
|
||||||
@@ -571,9 +563,9 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
[contentView setTextShadowOffset:[self valueForThemeAttribute:@"text-shadow-offset" inState:themeState]];
|
[contentView setTextShadowOffset:[self valueForThemeAttribute:@"text-shadow-offset" inState:themeState]];
|
||||||
[contentView setImageScaling:[self valueForThemeAttribute:@"image-scaling" inState:themeState]];
|
[contentView setImageScaling:[self valueForThemeAttribute:@"image-scaling" inState:themeState]];
|
||||||
|
|
||||||
if (segment.image && segment.label)
|
if ([segment image] && [segment label])
|
||||||
[contentView setImagePosition:[self valueForThemeAttribute:@"image-position" inState:themeState]];
|
[contentView setImagePosition:[self valueForThemeAttribute:@"image-position" inState:themeState]];
|
||||||
else if (segment.image)
|
else if ([segment image])
|
||||||
[contentView setImagePosition:CPImageOnly];
|
[contentView setImagePosition:CPImageOnly];
|
||||||
|
|
||||||
if (i == count - 1)
|
if (i == count - 1)
|
||||||
@@ -586,9 +578,9 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
borderState |= _themeState & CPThemeStateDisabled;
|
borderState |= _themeState & CPThemeStateDisabled;
|
||||||
|
|
||||||
var borderColor = [self valueForThemeAttribute:@"divider-bezel-color"
|
var borderColor = [self valueForThemeAttribute:@"divider-bezel-color"
|
||||||
inState:borderState];
|
inState:borderState],
|
||||||
|
|
||||||
var borderView = [self layoutEphemeralSubviewNamed:"divider-bezel-"+i
|
borderView = [self layoutEphemeralSubviewNamed:"divider-bezel-" + i
|
||||||
positioned:CPWindowBelow
|
positioned:CPWindowBelow
|
||||||
relativeToEphemeralSubviewNamed:nil];
|
relativeToEphemeralSubviewNamed:nil];
|
||||||
|
|
||||||
@@ -612,43 +604,48 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var segment = _segments[aSegment],
|
var segment = _segments[aSegment],
|
||||||
segmentWidth = segment.width,
|
segmentWidth = [segment width],
|
||||||
themeState = _themeStates[aSegment] | (_themeState & CPThemeStateDisabled),
|
themeState = _themeStates[aSegment] | (_themeState & CPThemeStateDisabled),
|
||||||
contentInset = [self valueForThemeAttribute:@"content-inset" inState:themeState],
|
contentInset = [self valueForThemeAttribute:@"content-inset" inState:themeState],
|
||||||
font = [self valueForThemeAttribute:@"font" inState:themeState];
|
font = [self valueForThemeAttribute:@"font" inState:themeState];
|
||||||
|
|
||||||
if (!segmentWidth)
|
if (!segmentWidth)
|
||||||
{
|
{
|
||||||
if (segment.image && segment.label)
|
if ([segment image] && [segment label])
|
||||||
segmentWidth = [segment.label sizeWithFont:font].width + [segment.image size].width + contentInset.left + contentInset.right;
|
segmentWidth = [[segment label] sizeWithFont:font].width + [[segment image] size].width + contentInset.left + contentInset.right;
|
||||||
else if (segment.image)
|
else if (segment.image)
|
||||||
segmentWidth = [segment.image size].width + contentInset.left + contentInset.right;
|
segmentWidth = [[segment image] size].width + contentInset.left + contentInset.right;
|
||||||
else if (segment.label)
|
else if (segment.label)
|
||||||
segmentWidth = [segment.label sizeWithFont:font].width + contentInset.left + contentInset.right;
|
segmentWidth = [[segment label] sizeWithFont:font].width + contentInset.left + contentInset.right;
|
||||||
else
|
else
|
||||||
segmentWidth = 0.0;
|
segmentWidth = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var delta = segmentWidth - CGRectGetWidth(segment.frame);
|
var delta = segmentWidth - CGRectGetWidth([segment frame]);
|
||||||
|
|
||||||
if (!delta)
|
if (!delta)
|
||||||
return;
|
{
|
||||||
|
[self setNeedsLayout];
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
|
||||||
// Update Contorl Size
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update control size
|
||||||
var frame = [self frame];
|
var frame = [self frame];
|
||||||
|
|
||||||
[self setFrameSize:CGSizeMake(CGRectGetWidth(frame) + delta, CGRectGetHeight(frame))];
|
[self setFrameSize:CGSizeMake(CGRectGetWidth(frame) + delta, CGRectGetHeight(frame))];
|
||||||
|
|
||||||
// Update Segment Width
|
// Update segment width
|
||||||
segment.width = segmentWidth;
|
[segment setWidth:segmentWidth];
|
||||||
segment.frame = [self frameForSegment:aSegment];;
|
[segment setFrame:[self frameForSegment:aSegment]];
|
||||||
|
|
||||||
// Update Following Segments Widths
|
// Update following segments widths
|
||||||
var index = aSegment + 1;
|
var index = aSegment + 1;
|
||||||
|
|
||||||
for (; index < _segments.length; ++index)
|
for (; index < _segments.length; ++index)
|
||||||
{
|
{
|
||||||
_segments[index].frame.origin.x += delta;
|
[_segments[index] frame].origin.x += delta;
|
||||||
|
|
||||||
[self drawSegmentBezel:index highlight:NO];
|
[self drawSegmentBezel:index highlight:NO];
|
||||||
[self drawSegment:index highlight:NO];
|
[self drawSegment:index highlight:NO];
|
||||||
@@ -701,9 +698,18 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
count = _segments.length;
|
count = _segments.length;
|
||||||
|
|
||||||
while (count--)
|
while (count--)
|
||||||
if (CGRectContainsPoint(_segments[count].frame, aPoint))
|
if (CGRectContainsPoint([_segments[count] frame], aPoint))
|
||||||
return count;
|
return count;
|
||||||
|
|
||||||
|
if (_segments.length)
|
||||||
|
{
|
||||||
|
var adjustedLastFrame = CGRectCreateCopy([_segments[_segments.length - 1] frame]);
|
||||||
|
adjustedLastFrame.size.width = CGRectGetWidth([self bounds]) - adjustedLastFrame.origin.x;
|
||||||
|
|
||||||
|
if (CGRectContainsPoint(adjustedLastFrame, aPoint))
|
||||||
|
return _segments.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -734,7 +740,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
if (_trackingSegment == -1)
|
if (_trackingSegment == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (CGRectContainsPoint(_segments[_trackingSegment].frame, location))
|
if (_trackingSegment === [self testSegment:location])
|
||||||
{
|
{
|
||||||
if (_trackingMode == CPSegmentSwitchTrackingSelectAny)
|
if (_trackingMode == CPSegmentSwitchTrackingSelectAny)
|
||||||
{
|
{
|
||||||
@@ -764,20 +770,22 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type == CPLeftMouseDown)
|
if (type == CPLeftMouseDown)
|
||||||
|
{
|
||||||
|
var trackingSegment = [self testSegment:location];
|
||||||
|
if (trackingSegment > -1 && [self isEnabledForSegment:trackingSegment])
|
||||||
{
|
{
|
||||||
_trackingHighlighted = YES;
|
_trackingHighlighted = YES;
|
||||||
_trackingSegment = [self testSegment:location];
|
_trackingSegment = trackingSegment;
|
||||||
|
|
||||||
[self drawSegmentBezel:_trackingSegment highlight:YES];
|
[self drawSegmentBezel:_trackingSegment highlight:YES];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else if (type == CPLeftMouseDragged)
|
else if (type == CPLeftMouseDragged)
|
||||||
{
|
{
|
||||||
if (_trackingSegment == -1)
|
if (_trackingSegment == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var highlighted = CGRectContainsPoint(_segments[_trackingSegment].frame, location);
|
var highlighted = [self testSegment:location] === _trackingSegment;
|
||||||
|
|
||||||
if (highlighted != _trackingHighlighted)
|
if (highlighted != _trackingHighlighted)
|
||||||
{
|
{
|
||||||
_trackingHighlighted = highlighted;
|
_trackingHighlighted = highlighted;
|
||||||
@@ -836,7 +844,7 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
|
|||||||
|
|
||||||
for (var i = 0; i < _segments.length; i++)
|
for (var i = 0; i < _segments.length; i++)
|
||||||
{
|
{
|
||||||
_themeStates[i] = _segments[i].selected ? CPThemeStateSelected : CPThemeStateNormal;
|
_themeStates[i] = [_segments[i] selected] ? CPThemeStateSelected : CPThemeStateNormal;
|
||||||
[self tileWithChangedSegment:i];
|
[self tileWithChangedSegment:i];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -844,7 +852,7 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
|
|||||||
remainingWidth = FLOOR(difference / _segments.length);
|
remainingWidth = FLOOR(difference / _segments.length);
|
||||||
|
|
||||||
for (var i = 0; i < _segments.length; i++)
|
for (var i = 0; i < _segments.length; i++)
|
||||||
[self setWidth:_segments[i].width + remainingWidth forSegment:i];
|
[self setWidth:[_segments[i] width] + remainingWidth forSegment:i];
|
||||||
|
|
||||||
[self tileWithChangedSegment:0];
|
[self tileWithChangedSegment:0];
|
||||||
}
|
}
|
||||||
@@ -867,15 +875,15 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
|
|||||||
|
|
||||||
@implementation _CPSegmentItem : CPObject
|
@implementation _CPSegmentItem : CPObject
|
||||||
{
|
{
|
||||||
CPImage image;
|
CPImage image @accessors;
|
||||||
CPString label;
|
CPString label @accessors;
|
||||||
CPMenu menu;
|
CPMenu menu @accessors;
|
||||||
BOOL selected;
|
BOOL selected @accessors;
|
||||||
BOOL enabled;
|
BOOL enabled @accessors;
|
||||||
int tag;
|
int tag @accessors;
|
||||||
int width;
|
int width @accessors;
|
||||||
|
|
||||||
CGRect frame;
|
CGRect frame @accessors;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
@@ -886,8 +894,8 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
|
|||||||
label = @"";
|
label = @"";
|
||||||
menu = nil;
|
menu = nil;
|
||||||
selected = NO;
|
selected = NO;
|
||||||
enabled = NO;
|
enabled = YES;
|
||||||
tag = 0;
|
tag = -1;
|
||||||
width = 0;
|
width = 0;
|
||||||
|
|
||||||
frame = CGRectMakeZero();
|
frame = CGRectMakeZero();
|
||||||
@@ -939,4 +947,3 @@ var CPSegmentItemImageKey = "CPSegmentItemImageKey",
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
+25
-2
@@ -28,8 +28,6 @@
|
|||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
|
||||||
|
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
CPLightShadow = 0;
|
CPLightShadow = 0;
|
||||||
CPHeavyShadow = 1;
|
CPHeavyShadow = 1;
|
||||||
|
|
||||||
@@ -93,6 +91,31 @@ var LIGHT_LEFT_INSET = 3.0,
|
|||||||
]]];
|
]]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (id)shadowViewEnclosingView:(CPView)aView
|
||||||
|
{
|
||||||
|
return [self shadowViewEnclosingView:aView withWeight:CPLightShadow];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)shadowViewEnclosingView:(CPView)aView withWeight:(CPShadowWeight)aWeight
|
||||||
|
{
|
||||||
|
var shadowView = [[CPShadowView alloc] initWithFrame:[aView frame]];
|
||||||
|
[shadowView setWeight:aWeight];
|
||||||
|
|
||||||
|
var size = [shadowView frame].size,
|
||||||
|
width = size.width - [shadowView leftInset] - [shadowView rightInset],
|
||||||
|
height = size.height - [shadowView topInset] - [shadowView bottomInset],
|
||||||
|
enclosingView = [aView superview];
|
||||||
|
|
||||||
|
[shadowView setHitTests:[aView hitTests]];
|
||||||
|
[shadowView setAutoresizingMask:[aView autoresizingMask]];
|
||||||
|
[aView removeFromSuperview];
|
||||||
|
[shadowView addSubview:aView];
|
||||||
|
[aView setFrame:CGRectMake([shadowView leftInset], [shadowView topInset], width, height)]
|
||||||
|
[enclosingView addSubview:shadowView];
|
||||||
|
|
||||||
|
return shadowView;
|
||||||
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
{
|
{
|
||||||
self = [super initWithFrame:aFrame];
|
self = [super initWithFrame:aFrame];
|
||||||
|
|||||||
+16
-6
@@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
@import "CPControl.j"
|
@import "CPControl.j"
|
||||||
|
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
/*! SLIDER STATES */
|
/*! SLIDER STATES */
|
||||||
|
|
||||||
@@ -42,14 +41,14 @@ CPCircularSlider = 1;
|
|||||||
BOOL _isVertical;
|
BOOL _isVertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPString)themeClass
|
+ (CPString)defaultThemeClass
|
||||||
{
|
{
|
||||||
return "slider";
|
return "slider";
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)themeAttributes
|
+ (id)themeAttributes
|
||||||
{
|
{
|
||||||
return [CPDictionary dictionaryWithObjects:[nil, _CGSizeMakeZero(), 0.0, nil]
|
return [CPDictionary dictionaryWithObjects:[[CPNull null], _CGSizeMakeZero(), 0.0, [CPNull null]]
|
||||||
forKeys:[@"knob-color", @"knob-size", @"track-width", @"track-color"]];
|
forKeys:[@"knob-color", @"knob-size", @"track-width", @"track-color"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +197,7 @@ CPCircularSlider = 1;
|
|||||||
else if ([self isVertical])
|
else if ([self isVertical])
|
||||||
{
|
{
|
||||||
knobRect.origin.x = _CGRectGetMidX(trackRect) - knobSize.width / 2.0;
|
knobRect.origin.x = _CGRectGetMidX(trackRect) - knobSize.width / 2.0;
|
||||||
knobRect.origin.y = (([self doubleValue] - _minValue) / (_maxValue - _minValue)) * (_CGRectGetHeight(trackRect) - knobSize.height);
|
knobRect.origin.y = ((_maxValue - [self doubleValue]) / (_maxValue - _minValue)) * (_CGRectGetHeight(trackRect) - knobSize.height);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -320,7 +319,7 @@ CPCircularSlider = 1;
|
|||||||
|
|
||||||
var minValue = [self minValue];
|
var minValue = [self minValue];
|
||||||
|
|
||||||
return MAX(0.0, MIN(1.0, (aPoint.y - _CGRectGetMinY(trackRect)) / _CGRectGetHeight(trackRect))) * ([self maxValue] - minValue) + minValue;
|
return MAX(0.0, MIN(1.0, (_CGRectGetMaxY(trackRect) - aPoint.y) / _CGRectGetHeight(trackRect))) * ([self maxValue] - minValue) + minValue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -342,7 +341,6 @@ CPCircularSlider = 1;
|
|||||||
|
|
||||||
if (_CGRectContainsPoint(knobRect, aPoint))
|
if (_CGRectContainsPoint(knobRect, aPoint))
|
||||||
_dragOffset = _CGSizeMake(_CGRectGetMidX(knobRect) - aPoint.x, _CGRectGetMidY(knobRect) - aPoint.y);
|
_dragOffset = _CGSizeMake(_CGRectGetMidX(knobRect) - aPoint.x, _CGRectGetMidY(knobRect) - aPoint.y);
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var trackRect = [self trackRectForBounds:bounds];
|
var trackRect = [self trackRectForBounds:bounds];
|
||||||
@@ -396,6 +394,18 @@ CPCircularSlider = 1;
|
|||||||
_sendActionOn &= ~CPLeftMouseDraggedMask;
|
_sendActionOn &= ~CPLeftMouseDraggedMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)takeValueFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
|
||||||
|
{
|
||||||
|
var count = objects.length,
|
||||||
|
value = [objects[0] valueForKeyPath:aKeyPath];
|
||||||
|
|
||||||
|
[self setObjectValue:value];
|
||||||
|
|
||||||
|
while (count-- > 1)
|
||||||
|
if (value !== ([objects[count] valueForKeyPath:aKeyPath]))
|
||||||
|
return [self setFloatValue:1.0];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPSliderMinValueKey = "CPSliderMinValueKey",
|
var CPSliderMinValueKey = "CPSliderMinValueKey",
|
||||||
|
|||||||
+100
-148
@@ -20,8 +20,10 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@import "CPView.j"
|
||||||
@import "CPColorPicker.j"
|
@import "CPColorPicker.j"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ignore
|
@ignore
|
||||||
*/
|
*/
|
||||||
@@ -45,14 +47,15 @@
|
|||||||
CPTextField _saturationLabel;
|
CPTextField _saturationLabel;
|
||||||
CPTextField _brightnessLabel;
|
CPTextField _brightnessLabel;
|
||||||
CPTextField _hexLabel;
|
CPTextField _hexLabel;
|
||||||
|
CPTextField _hexValue;
|
||||||
|
|
||||||
DOMElement _redValue;
|
CPTextField _hexValue;
|
||||||
DOMElement _greenValue;
|
CPTextField _redValue;
|
||||||
DOMElement _blueValue;
|
CPTextField _greenValue;
|
||||||
DOMElement _hueValue;
|
CPTextField _blueValue;
|
||||||
DOMElement _saturationValue;
|
CPTextField _hueValue;
|
||||||
DOMElement _brightnessValue;
|
CPTextField _saturationValue;
|
||||||
DOMElement _hexValue;
|
CPTextField _brightnessValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
|
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
|
||||||
@@ -82,71 +85,13 @@
|
|||||||
[_redSlider setAction: @selector(sliderChanged:)];
|
[_redSlider setAction: @selector(sliderChanged:)];
|
||||||
[_redSlider setAutoresizingMask: CPViewWidthSizable];
|
[_redSlider setAutoresizingMask: CPViewWidthSizable];
|
||||||
|
|
||||||
var updateFunction = function(aDOMEvent)
|
|
||||||
{
|
|
||||||
if(isNaN(this.value))
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch(this)
|
|
||||||
{
|
|
||||||
case _redValue: [_redSlider setFloatValue:MAX(MIN(ROUND(this.value), 255) / 255.0, 0)];
|
|
||||||
//[self sliderChanged: _redSlider];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case _greenValue: [_greenSlider setFloatValue:MAX(MIN(ROUND(this.value), 255) / 255.0, 0)];
|
|
||||||
//[self sliderChanged: _greenSlider];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case _blueValue: [_blueSlider setFloatValue:MAX(MIN(ROUND(this.value), 255) / 255.0, 0)];
|
|
||||||
//[self sliderChanged: _blueSlider];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case _hueValue: [_hueSlider setFloatValue:MAX(MIN(ROUND(this.value), 360), 0)];
|
|
||||||
//[self sliderChanged: _hueSlider];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case _saturationValue: [_saturationSlider setFloatValue:MAX(MIN(ROUND(this.value), 100), 0)];
|
|
||||||
//[self sliderChanged: _saturationSlider];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case _brightnessValue: [_brightnessSlider setFloatValue:MAX(MIN(ROUND(this.value), 100), 0)];
|
|
||||||
//[self sliderChanged: _brightnessSlider];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.blur();
|
|
||||||
};
|
|
||||||
|
|
||||||
var keypressFunction = function(aDOMEvent)
|
|
||||||
{
|
|
||||||
aDOMEvent = aDOMEvent || window.event;
|
|
||||||
if (aDOMEvent.keyCode == 13)
|
|
||||||
{
|
|
||||||
updateFunction(aDOMEvent);
|
|
||||||
|
|
||||||
if(aDOMEvent.preventDefault)
|
|
||||||
aDOMEvent.preventDefault();
|
|
||||||
else if(aDOMEvent.stopPropagation)
|
|
||||||
aDOMEvent.stopPropagation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// red value input box
|
// red value input box
|
||||||
var redValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 35, 45, 20)];
|
_redValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 30, 45, 29)];
|
||||||
[redValue setAutoresizingMask: CPViewMinXMargin];
|
[_redValue setAutoresizingMask: CPViewMinXMargin];
|
||||||
|
[_redValue setEditable: YES];
|
||||||
_redValue = document.createElement("input");
|
[_redValue setBezeled: YES];
|
||||||
_redValue.style.width = "40px";
|
[_redValue setDelegate: self];
|
||||||
_redValue.style.backgroundColor = "transparent";
|
[_contentView addSubview: _redValue];
|
||||||
_redValue.style.border = "1px solid black";
|
|
||||||
_redValue.style.color = "black";
|
|
||||||
_redValue.style.position = "absolute";
|
|
||||||
_redValue.style.top = "0px";
|
|
||||||
_redValue.style.left = "0px";
|
|
||||||
_redValue.onchange = updateFunction;
|
|
||||||
|
|
||||||
redValue._DOMElement.appendChild(_redValue);
|
|
||||||
[_contentView addSubview: redValue];
|
|
||||||
|
|
||||||
_greenLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 58, 15, 20)];
|
_greenLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 58, 15, 20)];
|
||||||
[_greenLabel setStringValue: "G"];
|
[_greenLabel setStringValue: "G"];
|
||||||
@@ -160,14 +105,12 @@
|
|||||||
[_greenSlider setAutoresizingMask: CPViewWidthSizable];
|
[_greenSlider setAutoresizingMask: CPViewWidthSizable];
|
||||||
|
|
||||||
// green value input box
|
// green value input box
|
||||||
var greenValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 58, 45, 20)];
|
_greenValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 53, 45, 29)];
|
||||||
[greenValue setAutoresizingMask: CPViewMinXMargin];
|
[_greenValue setAutoresizingMask: CPViewMinXMargin];
|
||||||
|
[_greenValue setEditable: YES];
|
||||||
_greenValue = _redValue.cloneNode(false);
|
[_greenValue setBezeled: YES];
|
||||||
_greenValue.onchange = updateFunction;
|
[_greenValue setDelegate: self];
|
||||||
|
[_contentView addSubview: _greenValue];
|
||||||
greenValue._DOMElement.appendChild(_greenValue);
|
|
||||||
[_contentView addSubview: greenValue];
|
|
||||||
|
|
||||||
_blueLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 81, 15, 20)];
|
_blueLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 81, 15, 20)];
|
||||||
[_blueLabel setStringValue: "B"];
|
[_blueLabel setStringValue: "B"];
|
||||||
@@ -181,14 +124,12 @@
|
|||||||
[_blueSlider setAutoresizingMask: CPViewWidthSizable];
|
[_blueSlider setAutoresizingMask: CPViewWidthSizable];
|
||||||
|
|
||||||
// blue value input box
|
// blue value input box
|
||||||
var blueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 81, 45, 20)];
|
_blueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 76, 45, 29)];
|
||||||
[blueValue setAutoresizingMask: CPViewMinXMargin];
|
[_blueValue setAutoresizingMask: CPViewMinXMargin];
|
||||||
|
[_blueValue setEditable: YES];
|
||||||
_blueValue = _redValue.cloneNode(false);
|
[_blueValue setBezeled: YES];
|
||||||
_blueValue.onchange = updateFunction;
|
[_blueValue setDelegate: self];
|
||||||
|
[_contentView addSubview: _blueValue];
|
||||||
blueValue._DOMElement.appendChild(_blueValue);
|
|
||||||
[_contentView addSubview: blueValue];
|
|
||||||
|
|
||||||
_hsbLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 120, 190, 20)];
|
_hsbLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 120, 190, 20)];
|
||||||
[_hsbLabel setStringValue: "Hue, Saturation, Brightness"];
|
[_hsbLabel setStringValue: "Hue, Saturation, Brightness"];
|
||||||
@@ -205,15 +146,13 @@
|
|||||||
[_hueSlider setAction: @selector(sliderChanged:)];
|
[_hueSlider setAction: @selector(sliderChanged:)];
|
||||||
[_hueSlider setAutoresizingMask: CPViewWidthSizable];
|
[_hueSlider setAutoresizingMask: CPViewWidthSizable];
|
||||||
|
|
||||||
//red value input box
|
// hue value input box
|
||||||
var hueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 145, 45, 20)];
|
_hueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 140, 45, 29)];
|
||||||
[hueValue setAutoresizingMask: CPViewMinXMargin];
|
[_hueValue setAutoresizingMask: CPViewMinXMargin];
|
||||||
|
[_hueValue setEditable: YES];
|
||||||
_hueValue = _redValue.cloneNode(false);
|
[_hueValue setBezeled: YES];
|
||||||
_hueValue.onchange = updateFunction;
|
[_hueValue setDelegate: self];
|
||||||
|
[_contentView addSubview: _hueValue];
|
||||||
hueValue._DOMElement.appendChild(_hueValue);
|
|
||||||
[_contentView addSubview: hueValue];
|
|
||||||
|
|
||||||
_saturationLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 168, 15, 20)];
|
_saturationLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 168, 15, 20)];
|
||||||
[_saturationLabel setStringValue: "S"];
|
[_saturationLabel setStringValue: "S"];
|
||||||
@@ -226,15 +165,13 @@
|
|||||||
[_saturationSlider setAction: @selector(sliderChanged:)];
|
[_saturationSlider setAction: @selector(sliderChanged:)];
|
||||||
[_saturationSlider setAutoresizingMask: CPViewWidthSizable];
|
[_saturationSlider setAutoresizingMask: CPViewWidthSizable];
|
||||||
|
|
||||||
//green value input box
|
// saturation value input box
|
||||||
var saturationValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 168, 45, 20)];
|
_saturationValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 163, 45, 29)];
|
||||||
[saturationValue setAutoresizingMask: CPViewMinXMargin];
|
[_saturationValue setAutoresizingMask: CPViewMinXMargin];
|
||||||
|
[_saturationValue setEditable: YES];
|
||||||
_saturationValue = _redValue.cloneNode(false);
|
[_saturationValue setBezeled: YES];
|
||||||
_saturationValue.onchange = updateFunction;
|
[_saturationValue setDelegate: self];
|
||||||
|
[_contentView addSubview: _saturationValue];
|
||||||
saturationValue._DOMElement.appendChild(_saturationValue);
|
|
||||||
[_contentView addSubview: saturationValue];
|
|
||||||
|
|
||||||
_brightnessLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 191, 15, 20)];
|
_brightnessLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 191, 15, 20)];
|
||||||
[_brightnessLabel setStringValue: "B"];
|
[_brightnessLabel setStringValue: "B"];
|
||||||
@@ -247,48 +184,24 @@
|
|||||||
[_brightnessSlider setAction: @selector(sliderChanged:)];
|
[_brightnessSlider setAction: @selector(sliderChanged:)];
|
||||||
[_brightnessSlider setAutoresizingMask: CPViewWidthSizable];
|
[_brightnessSlider setAutoresizingMask: CPViewWidthSizable];
|
||||||
|
|
||||||
//blue value input box
|
// brightness value input box
|
||||||
var brightnessValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 191, 45, 20)];
|
_brightnessValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 186, 45, 29)];
|
||||||
[brightnessValue setAutoresizingMask: CPViewMinXMargin];
|
[_brightnessValue setAutoresizingMask: CPViewMinXMargin];
|
||||||
|
[_brightnessValue setEditable: YES];
|
||||||
_brightnessValue = _redValue.cloneNode(false);
|
[_brightnessValue setBezeled: YES];
|
||||||
_brightnessValue.onchange = updateFunction;
|
[_brightnessValue setDelegate: self];
|
||||||
|
[_contentView addSubview: _brightnessValue];
|
||||||
brightnessValue._DOMElement.appendChild(_brightnessValue);
|
|
||||||
[_contentView addSubview: brightnessValue];
|
|
||||||
|
|
||||||
_hexLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 230, 30, 20)];
|
_hexLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 230, 30, 20)];
|
||||||
[_hexLabel setStringValue: "Hex"];
|
[_hexLabel setStringValue: "Hex"];
|
||||||
[_hexLabel setTextColor:[CPColor blackColor]];
|
[_hexLabel setTextColor:[CPColor blackColor]];
|
||||||
|
|
||||||
//hex input box
|
//hex input box
|
||||||
_hexValue = _redValue.cloneNode(false);
|
_hexValue = [[CPTextField alloc] initWithFrame: CGRectMake(32, 225, 80, 29)];
|
||||||
_hexValue.style.top = "228px";
|
[_hexValue setEditable: YES];
|
||||||
_hexValue.style.width = "80px";
|
[_hexValue setBezeled: YES];
|
||||||
_hexValue.style.left = "35px";
|
[_hexValue setDelegate: self];
|
||||||
_hexValue.onkeypress = function(aDOMEvent)
|
[_contentView addSubview: _hexValue];
|
||||||
{
|
|
||||||
aDOMEvent = aDOMEvent || window.event;
|
|
||||||
if (aDOMEvent.keyCode == 13)
|
|
||||||
{
|
|
||||||
var newColor = [CPColor colorWithHexString: this.value];
|
|
||||||
|
|
||||||
if(newColor)
|
|
||||||
{
|
|
||||||
[self setColor: newColor];
|
|
||||||
[[self colorPanel] setColor: newColor];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(aDOMEvent.preventDefault)
|
|
||||||
aDOMEvent.preventDefault();
|
|
||||||
else if(aDOMEvent.stopPropagation)
|
|
||||||
aDOMEvent.stopPropagation();
|
|
||||||
|
|
||||||
this.blur();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
_contentView._DOMElement.appendChild(_hexValue);
|
|
||||||
|
|
||||||
[_contentView addSubview: _rgbLabel];
|
[_contentView addSubview: _rgbLabel];
|
||||||
[_contentView addSubview: _redLabel];
|
[_contentView addSubview: _redLabel];
|
||||||
@@ -380,7 +293,7 @@
|
|||||||
|
|
||||||
- (void)updateHex:(CPColor)aColor
|
- (void)updateHex:(CPColor)aColor
|
||||||
{
|
{
|
||||||
_hexValue.value = [aColor hexString];
|
[_hexValue setStringValue:[aColor hexString]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateRGBSliders:(CPColor)aColor
|
- (void)updateRGBSliders:(CPColor)aColor
|
||||||
@@ -394,13 +307,13 @@
|
|||||||
|
|
||||||
- (void)updateLabels
|
- (void)updateLabels
|
||||||
{
|
{
|
||||||
_hueValue.value = ROUND([_hueSlider floatValue]);
|
[_hueValue setStringValue: ROUND([_hueSlider floatValue])];
|
||||||
_saturationValue.value = ROUND([_saturationSlider floatValue]);
|
[_saturationValue setStringValue: ROUND([_saturationSlider floatValue])];
|
||||||
_brightnessValue.value = ROUND([_brightnessSlider floatValue]);
|
[_brightnessValue setStringValue: ROUND([_brightnessSlider floatValue])];
|
||||||
|
|
||||||
_redValue.value = ROUND([_redSlider floatValue] * 255);
|
[_redValue setStringValue: ROUND([_redSlider floatValue] * 255)];
|
||||||
_greenValue.value = ROUND([_greenSlider floatValue] * 255);
|
[_greenValue setStringValue: ROUND([_greenSlider floatValue] * 255)];
|
||||||
_blueValue.value = ROUND([_blueSlider floatValue] * 255);
|
[_blueValue setStringValue: ROUND([_blueSlider floatValue] * 255)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPImage)provideNewButtonImage
|
- (CPImage)provideNewButtonImage
|
||||||
@@ -413,4 +326,43 @@
|
|||||||
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:CPColorPicker] pathForResource:"slider_button_h.png"] size:CGSizeMake(32, 32)];
|
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:CPColorPicker] pathForResource:"slider_button_h.png"] size:CGSizeMake(32, 32)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)controlTextDidEndEditing:(CPNotification)aNotification
|
||||||
|
{
|
||||||
|
var field = [aNotification object],
|
||||||
|
value = [[field stringValue] stringByTrimmingWhitespace];
|
||||||
|
if (field === _hexValue) {
|
||||||
|
var newColor = [CPColor colorWithHexString: value];
|
||||||
|
if (newColor) {
|
||||||
|
[self setColor: newColor];
|
||||||
|
[[self colorPanel] setColor: newColor];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch(field) {
|
||||||
|
case _redValue: [_redSlider setFloatValue:MAX(MIN(ROUND(value), 255) / 255.0, 0)];
|
||||||
|
[self sliderChanged: _redSlider];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case _greenValue: [_greenSlider setFloatValue:MAX(MIN(ROUND(value), 255) / 255.0, 0)];
|
||||||
|
[self sliderChanged: _greenSlider];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case _blueValue: [_blueSlider setFloatValue:MAX(MIN(ROUND(value), 255) / 255.0, 0)];
|
||||||
|
[self sliderChanged: _blueSlider];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case _hueValue: [_hueSlider setFloatValue:MAX(MIN(ROUND(value), 360), 0)];
|
||||||
|
[self sliderChanged: _hueSlider];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case _saturationValue: [_saturationSlider setFloatValue:MAX(MIN(ROUND(value), 100), 0)];
|
||||||
|
[self sliderChanged: _saturationSlider];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case _brightnessValue: [_brightnessSlider setFloatValue:MAX(MIN(ROUND(value), 100), 0)];
|
||||||
|
[self sliderChanged: _brightnessSlider];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+200
-38
@@ -20,13 +20,10 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@import "CPButtonBar.j"
|
||||||
@import "CPImage.j"
|
@import "CPImage.j"
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
|
||||||
#include "Platform/Platform.h"
|
|
||||||
#include "Platform/DOM/CPDOMDisplayServer.h"
|
|
||||||
|
|
||||||
|
|
||||||
CPSplitViewDidResizeSubviewsNotification = @"CPSplitViewDidResizeSubviewsNotification";
|
CPSplitViewDidResizeSubviewsNotification = @"CPSplitViewDidResizeSubviewsNotification";
|
||||||
CPSplitViewWillResizeSubviewsNotification = @"CPSplitViewWillResizeSubviewsNotification";
|
CPSplitViewWillResizeSubviewsNotification = @"CPSplitViewWillResizeSubviewsNotification";
|
||||||
@@ -46,6 +43,7 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
|
|
||||||
int _currentDivider;
|
int _currentDivider;
|
||||||
float _initialOffset;
|
float _initialOffset;
|
||||||
|
float _preCollapsePosition;
|
||||||
|
|
||||||
CPString _originComponent;
|
CPString _originComponent;
|
||||||
CPString _sizeComponent;
|
CPString _sizeComponent;
|
||||||
@@ -55,6 +53,19 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
int _drawingDivider;
|
int _drawingDivider;
|
||||||
|
|
||||||
BOOL _needsResizeSubviews;
|
BOOL _needsResizeSubviews;
|
||||||
|
|
||||||
|
CPArray _buttonBars;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPString)defaultThemeClass
|
||||||
|
{
|
||||||
|
return @"splitview";
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)themeAttributes
|
||||||
|
{
|
||||||
|
return [CPDictionary dictionaryWithObjects:[10.0, 1.0, [CPColor grayColor]]
|
||||||
|
forKeys:[@"divider-thickness", @"pane-divider-thickness", @"pane-divider-color"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -77,6 +88,7 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
_currentDivider = CPNotFound;
|
_currentDivider = CPNotFound;
|
||||||
|
|
||||||
_DOMDividerElements = [];
|
_DOMDividerElements = [];
|
||||||
|
_buttonBars = [];
|
||||||
|
|
||||||
[self _setVertical:YES];
|
[self _setVertical:YES];
|
||||||
}
|
}
|
||||||
@@ -86,7 +98,7 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
|
|
||||||
- (float)dividerThickness
|
- (float)dividerThickness
|
||||||
{
|
{
|
||||||
return _isPaneSplitter ? 1.0 : 10.0;
|
return [self currentValueForThemeAttribute:[self isPaneSplitter] ? @"pane-divider-thickness" : @"divider-thickness"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isVertical
|
- (BOOL)isVertical
|
||||||
@@ -147,9 +159,8 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
|
|
||||||
_isPaneSplitter = shouldBePaneSplitter;
|
_isPaneSplitter = shouldBePaneSplitter;
|
||||||
|
|
||||||
#if PLATFORM(DOM)
|
if (_DOMDividerElements[_drawingDivider])
|
||||||
_DOMDividerElements = [];
|
[self _setupDOMDivider];
|
||||||
#endif
|
|
||||||
|
|
||||||
// The divider changes size when pane splitter mode is toggled, so the
|
// The divider changes size when pane splitter mode is toggled, so the
|
||||||
// subviews need to change size too.
|
// subviews need to change size too.
|
||||||
@@ -160,7 +171,6 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
- (void)didAddSubview:(CPView)aSubview
|
- (void)didAddSubview:(CPView)aSubview
|
||||||
{
|
{
|
||||||
_needsResizeSubviews = YES;
|
_needsResizeSubviews = YES;
|
||||||
// [self adjustSubviews];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isSubviewCollapsed:(CPView)subview
|
- (BOOL)isSubviewCollapsed:(CPView)subview
|
||||||
@@ -183,9 +193,8 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
|
|
||||||
- (CGRect)effectiveRectOfDividerAtIndex:(int)aDivider
|
- (CGRect)effectiveRectOfDividerAtIndex:(int)aDivider
|
||||||
{
|
{
|
||||||
var realRect = [self rectOfDividerAtIndex:aDivider];
|
var realRect = [self rectOfDividerAtIndex:aDivider],
|
||||||
|
padding = 2;
|
||||||
var padding = 2;
|
|
||||||
|
|
||||||
realRect.size[_sizeComponent] += padding * 2;
|
realRect.size[_sizeComponent] += padding * 2;
|
||||||
realRect.origin[_originComponent] -= padding;
|
realRect.origin[_originComponent] -= padding;
|
||||||
@@ -210,15 +219,24 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
if (!_DOMDividerElements[_drawingDivider])
|
if (!_DOMDividerElements[_drawingDivider])
|
||||||
{
|
{
|
||||||
_DOMDividerElements[_drawingDivider] = document.createElement("div");
|
_DOMDividerElements[_drawingDivider] = document.createElement("div");
|
||||||
_DOMDividerElements[_drawingDivider].style.cursor = "move";
|
|
||||||
_DOMDividerElements[_drawingDivider].style.position = "absolute";
|
_DOMDividerElements[_drawingDivider].style.position = "absolute";
|
||||||
_DOMDividerElements[_drawingDivider].style.backgroundRepeat = "repeat";
|
_DOMDividerElements[_drawingDivider].style.backgroundRepeat = "repeat";
|
||||||
|
|
||||||
CPDOMDisplayServerAppendChild(_DOMElement, _DOMDividerElements[_drawingDivider]);
|
CPDOMDisplayServerAppendChild(_DOMElement, _DOMDividerElements[_drawingDivider]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[self _setupDOMDivider];
|
||||||
|
CPDOMDisplayServerSetStyleLeftTop(_DOMDividerElements[_drawingDivider], NULL, _CGRectGetMinX(aRect), _CGRectGetMinY(aRect));
|
||||||
|
CPDOMDisplayServerSetStyleSize(_DOMDividerElements[_drawingDivider], _CGRectGetWidth(aRect), _CGRectGetHeight(aRect));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_setupDOMDivider
|
||||||
|
{
|
||||||
if (_isPaneSplitter)
|
if (_isPaneSplitter)
|
||||||
{
|
{
|
||||||
_DOMDividerElements[_drawingDivider].style.backgroundColor = "#A5A5A5";
|
_DOMDividerElements[_drawingDivider].style.backgroundColor = [[self currentValueForThemeAttribute:@"pane-divider-color"] cssString];
|
||||||
_DOMDividerElements[_drawingDivider].style.backgroundImage = "";
|
_DOMDividerElements[_drawingDivider].style.backgroundImage = "";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -228,11 +246,6 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CPDOMDisplayServerSetStyleLeftTop(_DOMDividerElements[_drawingDivider], NULL, _CGRectGetMinX(aRect), _CGRectGetMinY(aRect));
|
|
||||||
CPDOMDisplayServerSetStyleSize(_DOMDividerElements[_drawingDivider], _CGRectGetWidth(aRect), _CGRectGetHeight(aRect));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)viewWillDraw
|
- (void)viewWillDraw
|
||||||
{
|
{
|
||||||
[self _adjustSubviewsWithCalculatedSize];
|
[self _adjustSubviewsWithCalculatedSize];
|
||||||
@@ -271,15 +284,25 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
var frame = [_subviews[anIndex] frame],
|
var frame = [_subviews[anIndex] frame],
|
||||||
startPosition = frame.origin[_originComponent] + frame.size[_sizeComponent],
|
startPosition = frame.origin[_originComponent] + frame.size[_sizeComponent],
|
||||||
effectiveRect = [self effectiveRectOfDividerAtIndex:anIndex],
|
effectiveRect = [self effectiveRectOfDividerAtIndex:anIndex],
|
||||||
|
buttonBar = _buttonBars[anIndex],
|
||||||
|
buttonBarRect = null,
|
||||||
additionalRect = null;
|
additionalRect = null;
|
||||||
|
|
||||||
|
if (buttonBar != null)
|
||||||
|
{
|
||||||
|
buttonBarRect = [buttonBar resizeControlFrame];
|
||||||
|
buttonBarRect.origin = [self convertPoint:buttonBarRect.origin fromView:buttonBar];
|
||||||
|
}
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(splitView:effectiveRect:forDrawnRect:ofDividerAtIndex:)])
|
if ([_delegate respondsToSelector:@selector(splitView:effectiveRect:forDrawnRect:ofDividerAtIndex:)])
|
||||||
effectiveRect = [_delegate splitView:self effectiveRect:effectiveRect forDrawnRect:effectiveRect ofDividerAtIndex:anIndex];
|
effectiveRect = [_delegate splitView:self effectiveRect:effectiveRect forDrawnRect:effectiveRect ofDividerAtIndex:anIndex];
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(splitView:additionalEffectiveRectOfDividerAtIndex:)])
|
if ([_delegate respondsToSelector:@selector(splitView:additionalEffectiveRectOfDividerAtIndex:)])
|
||||||
additionalRect = [_delegate splitView:self additionalEffectiveRectOfDividerAtIndex:anIndex];
|
additionalRect = [_delegate splitView:self additionalEffectiveRectOfDividerAtIndex:anIndex];
|
||||||
|
|
||||||
return CGRectContainsPoint(effectiveRect, aPoint) || (additionalRect && CGRectContainsPoint(additionalRect, aPoint));
|
return CGRectContainsPoint(effectiveRect, aPoint) ||
|
||||||
|
(additionalRect && CGRectContainsPoint(additionalRect, aPoint)) ||
|
||||||
|
(buttonBarRect && CGRectContainsPoint(buttonBarRect, aPoint));
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPView)hitTest:(CGPoint)aPoint
|
- (CPView)hitTest:(CGPoint)aPoint
|
||||||
@@ -287,9 +310,9 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
if ([self isHidden] || ![self hitTests] || !CGRectContainsPoint([self frame], aPoint))
|
if ([self isHidden] || ![self hitTests] || !CGRectContainsPoint([self frame], aPoint))
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
var point = [self convertPoint:aPoint fromView:[self superview]];
|
var point = [self convertPoint:aPoint fromView:[self superview]],
|
||||||
|
count = [_subviews count] - 1;
|
||||||
|
|
||||||
var count = [_subviews count] - 1;
|
|
||||||
for (var i = 0; i < count; i++)
|
for (var i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
if ([self cursorAtPoint:point hitDividerAtIndex:i])
|
if ([self cursorAtPoint:point hitDividerAtIndex:i])
|
||||||
@@ -312,6 +335,7 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
if (_currentDivider != CPNotFound)
|
if (_currentDivider != CPNotFound)
|
||||||
{
|
{
|
||||||
_currentDivider = CPNotFound;
|
_currentDivider = CPNotFound;
|
||||||
|
[self _updateResizeCursor:anEvent];
|
||||||
[self _postNotificationDidResize];
|
[self _postNotificationDidResize];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,14 +365,14 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
if ([_delegate splitView:self canCollapseSubview:_subviews[i]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i] forDoubleClickOnDividerAtIndex:i])
|
if ([_delegate splitView:self canCollapseSubview:_subviews[i]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i] forDoubleClickOnDividerAtIndex:i])
|
||||||
{
|
{
|
||||||
if ([self isSubviewCollapsed:_subviews[i]])
|
if ([self isSubviewCollapsed:_subviews[i]])
|
||||||
[self setPosition:(minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
|
[self setPosition:_preCollapsePosition ? _preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
|
||||||
else
|
else
|
||||||
[self setPosition:minPosition ofDividerAtIndex:i];
|
[self setPosition:minPosition ofDividerAtIndex:i];
|
||||||
}
|
}
|
||||||
else if ([_delegate splitView:self canCollapseSubview:_subviews[i + 1]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i + 1] forDoubleClickOnDividerAtIndex:i])
|
else if ([_delegate splitView:self canCollapseSubview:_subviews[i + 1]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i + 1] forDoubleClickOnDividerAtIndex:i])
|
||||||
{
|
{
|
||||||
if ([self isSubviewCollapsed:_subviews[i + 1]])
|
if ([self isSubviewCollapsed:_subviews[i + 1]])
|
||||||
[self setPosition:(minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
|
[self setPosition:_preCollapsePosition ? _preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
|
||||||
else
|
else
|
||||||
[self setPosition:maxPosition ofDividerAtIndex:i];
|
[self setPosition:maxPosition ofDividerAtIndex:i];
|
||||||
}
|
}
|
||||||
@@ -372,6 +396,8 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||||
|
|
||||||
[self setPosition:(point[_originComponent] + _initialOffset) ofDividerAtIndex:_currentDivider];
|
[self setPosition:(point[_originComponent] + _initialOffset) ofDividerAtIndex:_currentDivider];
|
||||||
|
// Cursor might change if we reach a resize limit.
|
||||||
|
[self _updateResizeCursor:anEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
[CPApp setTarget:self selector:@selector(trackDivider:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
[CPApp setTarget:self selector:@selector(trackDivider:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||||
@@ -383,6 +409,82 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
[self trackDivider:anEvent];
|
[self trackDivider:anEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)viewDidMoveToWindow
|
||||||
|
{
|
||||||
|
// Enable split view resize cursors. Commented out pending CPTrackingArea implementation.
|
||||||
|
//[[self window] setAcceptsMouseMovedEvents:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseEntered:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
// Tracking code handles cursor by itself.
|
||||||
|
if (_currentDivider == CPNotFound)
|
||||||
|
[self _updateResizeCursor:anEvent];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseMoved:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
if (_currentDivider == CPNotFound)
|
||||||
|
[self _updateResizeCursor:anEvent];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseExited:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
if (_currentDivider == CPNotFound)
|
||||||
|
// FIXME: we should use CPCursor push/pop (if previous currentCursor != arrow).
|
||||||
|
[[CPCursor arrowCursor] set];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_updateResizeCursor:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||||
|
|
||||||
|
if ([anEvent type] === CPLeftMouseUp && ![[self window] acceptsMouseMovedEvents])
|
||||||
|
{
|
||||||
|
[[CPCursor arrowCursor] set];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0, count = [_subviews count] - 1; i < count; i++)
|
||||||
|
{
|
||||||
|
// If we are currently tracking, keep the resize cursor active even outside of hit areas.
|
||||||
|
if (_currentDivider === i || (_currentDivider == CPNotFound && [self cursorAtPoint:point hitDividerAtIndex:i]))
|
||||||
|
{
|
||||||
|
var frame = [_subviews[i] frame],
|
||||||
|
size = frame.size[_sizeComponent],
|
||||||
|
startPosition = frame.origin[_originComponent] + size,
|
||||||
|
canShrink = [self _realPositionForPosition:startPosition - 1 ofDividerAtIndex:i] < startPosition,
|
||||||
|
canGrow = [self _realPositionForPosition:startPosition + 1 ofDividerAtIndex:i] > startPosition,
|
||||||
|
cursor = [CPCursor arrowCursor];
|
||||||
|
|
||||||
|
if (size === 0)
|
||||||
|
canGrow = YES; // Subview is collapsed.
|
||||||
|
else if (!canShrink &&
|
||||||
|
[_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)] &&
|
||||||
|
[_delegate splitView:self canCollapseSubview:_subviews[i]])
|
||||||
|
canShrink = YES; // Subview is collapsible.
|
||||||
|
|
||||||
|
if (_isVertical && canShrink && canGrow)
|
||||||
|
cursor = [CPCursor resizeLeftRightCursor];
|
||||||
|
else if (_isVertical && canShrink)
|
||||||
|
cursor = [CPCursor resizeLeftCursor];
|
||||||
|
else if (_isVertical && canGrow)
|
||||||
|
cursor = [CPCursor resizeRightCursor];
|
||||||
|
else if (canShrink && canGrow)
|
||||||
|
cursor = [CPCursor resizeUpDownCursor];
|
||||||
|
else if (canShrink)
|
||||||
|
cursor = [CPCursor resizeUpCursor];
|
||||||
|
else if (canGrow)
|
||||||
|
cursor = [CPCursor resizeDownCursor];
|
||||||
|
|
||||||
|
[cursor set];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[CPCursor arrowCursor] set];
|
||||||
|
}
|
||||||
|
|
||||||
- (float)maxPossiblePositionOfDividerAtIndex:(int)dividerIndex
|
- (float)maxPossiblePositionOfDividerAtIndex:(int)dividerIndex
|
||||||
{
|
{
|
||||||
var frame = [_subviews[dividerIndex + 1] frame];
|
var frame = [_subviews[dividerIndex + 1] frame];
|
||||||
@@ -405,10 +507,8 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setPosition:(float)position ofDividerAtIndex:(int)dividerIndex
|
- (int)_realPositionForPosition:(float)position ofDividerAtIndex:(int)dividerIndex
|
||||||
{
|
{
|
||||||
[self _adjustSubviewsWithCalculatedSize];
|
|
||||||
|
|
||||||
// not sure where this should override other positions?
|
// not sure where this should override other positions?
|
||||||
if ([_delegate respondsToSelector:@selector(splitView:constrainSplitPosition:ofSubviewAt:)])
|
if ([_delegate respondsToSelector:@selector(splitView:constrainSplitPosition:ofSubviewAt:)])
|
||||||
position = [_delegate splitView:self constrainSplitPosition:position ofSubviewAt:dividerIndex];
|
position = [_delegate splitView:self constrainSplitPosition:position ofSubviewAt:dividerIndex];
|
||||||
@@ -424,23 +524,40 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
if ([_delegate respondsToSelector:@selector(splitView:constrainMaxCoordinate:ofSubviewAt:)])
|
if ([_delegate respondsToSelector:@selector(splitView:constrainMaxCoordinate:ofSubviewAt:)])
|
||||||
actualMax = [_delegate splitView:self constrainMaxCoordinate:proposedMax ofSubviewAt:dividerIndex];
|
actualMax = [_delegate splitView:self constrainMaxCoordinate:proposedMax ofSubviewAt:dividerIndex];
|
||||||
|
|
||||||
var frame = [self frame],
|
var viewA = _subviews[dividerIndex],
|
||||||
viewA = _subviews[dividerIndex],
|
realPosition = MAX(MIN(position, actualMax), actualMin);
|
||||||
frameA = [viewA frame],
|
|
||||||
viewB = _subviews[dividerIndex + 1],
|
|
||||||
frameB = [viewB frame];
|
|
||||||
|
|
||||||
var realPosition = MAX(MIN(position, actualMax), actualMin);
|
|
||||||
|
|
||||||
if (position < proposedMin + (actualMin - proposedMin) / 2)
|
if (position < proposedMin + (actualMin - proposedMin) / 2)
|
||||||
if ([_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)])
|
if ([_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)])
|
||||||
if ([_delegate splitView:self canCollapseSubview:viewA])
|
if ([_delegate splitView:self canCollapseSubview:viewA])
|
||||||
realPosition = proposedMin;
|
realPosition = proposedMin;
|
||||||
|
|
||||||
|
return realPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setPosition:(float)position ofDividerAtIndex:(int)dividerIndex
|
||||||
|
{
|
||||||
|
[self _adjustSubviewsWithCalculatedSize];
|
||||||
|
|
||||||
|
var realPosition = [self _realPositionForPosition:position ofDividerAtIndex:dividerIndex];
|
||||||
|
|
||||||
|
var viewA = _subviews[dividerIndex],
|
||||||
|
frameA = [viewA frame],
|
||||||
|
viewB = _subviews[dividerIndex + 1],
|
||||||
|
frameB = [viewB frame];
|
||||||
|
|
||||||
|
_preCollapsePosition = 0;
|
||||||
|
|
||||||
|
var preSize = frameA.size[_sizeComponent];
|
||||||
frameA.size[_sizeComponent] = realPosition - frameA.origin[_originComponent];
|
frameA.size[_sizeComponent] = realPosition - frameA.origin[_originComponent];
|
||||||
|
if (preSize !== 0 && frameA.size[_sizeComponent] === 0)
|
||||||
|
_preCollapsePosition = preSize;
|
||||||
[_subviews[dividerIndex] setFrame:frameA];
|
[_subviews[dividerIndex] setFrame:frameA];
|
||||||
|
|
||||||
|
preSize = frameB.size[_sizeComponent];
|
||||||
frameB.size[_sizeComponent] = frameB.origin[_originComponent] + frameB.size[_sizeComponent] - realPosition - [self dividerThickness];
|
frameB.size[_sizeComponent] = frameB.origin[_originComponent] + frameB.size[_sizeComponent] - realPosition - [self dividerThickness];
|
||||||
|
if (preSize !== 0 && frameB.size[_sizeComponent] === 0)
|
||||||
|
_preCollapsePosition = preSize;
|
||||||
frameB.origin[_originComponent] = realPosition + [self dividerThickness];
|
frameB.origin[_originComponent] = realPosition + [self dividerThickness];
|
||||||
[_subviews[dividerIndex + 1] setFrame:frameB];
|
[_subviews[dividerIndex + 1] setFrame:frameB];
|
||||||
|
|
||||||
@@ -515,8 +632,6 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
}
|
}
|
||||||
else if (totalSizableSpace && !isSizable)
|
else if (totalSizableSpace && !isSizable)
|
||||||
viewFrame.size[_sizeComponent] = [view frame].size[_sizeComponent];
|
viewFrame.size[_sizeComponent] = [view frame].size[_sizeComponent];
|
||||||
else
|
|
||||||
alert("SHOULD NEVER GET HERE");
|
|
||||||
|
|
||||||
bounds.origin[_originComponent] += viewFrame.size[_sizeComponent] + dividerThickness;
|
bounds.origin[_originComponent] += viewFrame.size[_sizeComponent] + dividerThickness;
|
||||||
|
|
||||||
@@ -547,6 +662,47 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
object:self];
|
object:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the button bar who's resize control should act as a control for this splitview.
|
||||||
|
Each divider can have at most one button bar assigned to it, and that button bar must be
|
||||||
|
a subview of one of the split view's subviews.
|
||||||
|
|
||||||
|
Calling this method with nil as the button bar will remove any currently assigned button bar
|
||||||
|
for the divider at that index. Indexes will not be adjusted as new subviews are added, so you
|
||||||
|
should usually call this method after adding all the desired subviews to the split view.
|
||||||
|
|
||||||
|
This method will automatically configure the hasResizeControl and resizeControlIsLeftAligned
|
||||||
|
parameters of the button bar, and will override any currently set values.
|
||||||
|
*/
|
||||||
|
- (void)setButtonBar:(CPButtonBar)aButtonBar forDividerAtIndex:(unsigned)dividerIndex
|
||||||
|
{
|
||||||
|
if (!aButtonBar)
|
||||||
|
{
|
||||||
|
_buttonBars[dividerIndex] = nil;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var view = [aButtonBar superview],
|
||||||
|
subview = aButtonBar;
|
||||||
|
|
||||||
|
while (view && view !== self)
|
||||||
|
{
|
||||||
|
subview = view;
|
||||||
|
view = [view superview];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view !== self)
|
||||||
|
[CPException raise:CPInvalidArgumentException
|
||||||
|
reason:@"CPSplitView button bar must be a subview of the split view."];
|
||||||
|
|
||||||
|
var viewIndex = [[self subviews] indexOfObject:subview];
|
||||||
|
|
||||||
|
[aButtonBar setHasResizeControl:YES];
|
||||||
|
[aButtonBar setResizeControlIsLeftAligned:dividerIndex < viewIndex];
|
||||||
|
|
||||||
|
_buttonBars[dividerIndex] = aButtonBar;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)_postNotificationWillResize
|
- (void)_postNotificationWillResize
|
||||||
{
|
{
|
||||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPSplitViewWillResizeSubviewsNotification object:self];
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPSplitViewWillResizeSubviewsNotification object:self];
|
||||||
@@ -561,7 +717,8 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
|
|
||||||
var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
|
var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
|
||||||
CPSplitViewIsVerticalKey = "CPSplitViewIsVerticalKey",
|
CPSplitViewIsVerticalKey = "CPSplitViewIsVerticalKey",
|
||||||
CPSplitViewIsPaneSplitterKey = "CPSplitViewIsPaneSplitterKey";
|
CPSplitViewIsPaneSplitterKey = "CPSplitViewIsPaneSplitterKey",
|
||||||
|
CPSplitViewButtonBarsKey = "CPSplitViewButtonBarsKey";
|
||||||
|
|
||||||
@implementation CPSplitView (CPCoding)
|
@implementation CPSplitView (CPCoding)
|
||||||
|
|
||||||
@@ -579,7 +736,9 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
|
|||||||
|
|
||||||
_DOMDividerElements = [];
|
_DOMDividerElements = [];
|
||||||
|
|
||||||
_delegate = [aCoder decodeObjectForKey:CPSplitViewDelegateKey];;
|
_buttonBars = [aCoder decodeObjectForKey:CPSplitViewButtonBarsKey] || [];
|
||||||
|
|
||||||
|
_delegate = [aCoder decodeObjectForKey:CPSplitViewDelegateKey];
|
||||||
|
|
||||||
_isPaneSplitter = [aCoder decodeBoolForKey:CPSplitViewIsPaneSplitterKey];
|
_isPaneSplitter = [aCoder decodeBoolForKey:CPSplitViewIsPaneSplitterKey];
|
||||||
[self _setVertical:[aCoder decodeBoolForKey:CPSplitViewIsVerticalKey]];
|
[self _setVertical:[aCoder decodeBoolForKey:CPSplitViewIsVerticalKey]];
|
||||||
@@ -596,6 +755,9 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
|
|||||||
{
|
{
|
||||||
[super encodeWithCoder:aCoder];
|
[super encodeWithCoder:aCoder];
|
||||||
|
|
||||||
|
//FIXME how should we handle this?
|
||||||
|
//[aCoder encodeObject:_buttonBars forKey:CPSplitViewButtonBarsKey];
|
||||||
|
|
||||||
[aCoder encodeConditionalObject:_delegate forKey:CPSplitViewDelegateKey];
|
[aCoder encodeConditionalObject:_delegate forKey:CPSplitViewDelegateKey];
|
||||||
|
|
||||||
[aCoder encodeBool:_isVertical forKey:CPSplitViewIsVerticalKey];
|
[aCoder encodeBool:_isVertical forKey:CPSplitViewIsVerticalKey];
|
||||||
|
|||||||
@@ -25,8 +25,20 @@
|
|||||||
@import "CPPlatformString.j"
|
@import "CPPlatformString.j"
|
||||||
|
|
||||||
|
|
||||||
|
var CPStringSizeWithFontInWidthCache = {};
|
||||||
|
|
||||||
|
CPStringSizeCachingEnabled = YES;
|
||||||
|
|
||||||
@implementation CPString (CPStringDrawing)
|
@implementation CPString (CPStringDrawing)
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns a dictionary with the items "ascender", "descender", "lineHeight"
|
||||||
|
*/
|
||||||
|
+ (CPDictionary)metricsOfFont:(CPFont)aFont
|
||||||
|
{
|
||||||
|
return [CPPlatformString metricsOfFont:aFont];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the string
|
Returns the string
|
||||||
*/
|
*/
|
||||||
@@ -42,7 +54,19 @@
|
|||||||
|
|
||||||
- (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth
|
- (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth
|
||||||
{
|
{
|
||||||
|
if (!CPStringSizeCachingEnabled)
|
||||||
return [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
|
return [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
|
||||||
|
|
||||||
|
var cacheKey = self + [aFont cssString] + aWidth,
|
||||||
|
size = CPStringSizeWithFontInWidthCache[cacheKey];
|
||||||
|
|
||||||
|
if (size === undefined)
|
||||||
|
{
|
||||||
|
size = [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
|
||||||
|
CPStringSizeWithFontInWidthCache[cacheKey] = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CGSizeMakeCopy(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+181
-520
@@ -1,32 +1,8 @@
|
|||||||
/*
|
@import "CPBox.j"
|
||||||
* CPTabView.j
|
@import "CPSegmentedControl.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 "CPImageView.j"
|
|
||||||
@import "CPTabViewItem.j"
|
@import "CPTabViewItem.j"
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Places tabs on top with a bezeled border.
|
Places tabs on top with a bezeled border.
|
||||||
@global
|
@global
|
||||||
@@ -34,7 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
CPTopTabsBezelBorder = 0;
|
CPTopTabsBezelBorder = 0;
|
||||||
//CPLeftTabsBezelBorder = 1;
|
//CPLeftTabsBezelBorder = 1;
|
||||||
//CPBottomTabsBezelBorder = 2;
|
CPBottomTabsBezelBorder = 2;
|
||||||
//CPRightTabsBezelBorder = 3;
|
//CPRightTabsBezelBorder = 3;
|
||||||
/*
|
/*
|
||||||
Displays no tabs and has a bezeled border.
|
Displays no tabs and has a bezeled border.
|
||||||
@@ -55,173 +31,55 @@ CPNoTabsLineBorder = 5;
|
|||||||
*/
|
*/
|
||||||
CPNoTabsNoBorder = 6;
|
CPNoTabsNoBorder = 6;
|
||||||
|
|
||||||
var CPTabViewBezelBorderLeftImage = nil,
|
|
||||||
CPTabViewBackgroundCenterImage = nil,
|
|
||||||
CPTabViewBezelBorderRightImage = nil,
|
|
||||||
CPTabViewBezelBorderColor = nil,
|
|
||||||
CPTabViewBezelBorderBackgroundColor = nil;
|
|
||||||
|
|
||||||
var LEFT_INSET = 7.0,
|
|
||||||
RIGHT_INSET = 7.0;
|
|
||||||
|
|
||||||
var CPTabViewDidSelectTabViewItemSelector = 1,
|
var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||||
CPTabViewShouldSelectTabViewItemSelector = 2,
|
CPTabViewShouldSelectTabViewItemSelector = 2,
|
||||||
CPTabViewWillSelectTabViewItemSelector = 4,
|
CPTabViewWillSelectTabViewItemSelector = 4,
|
||||||
CPTabViewDidChangeNumberOfTabViewItemsSelector = 8;
|
CPTabViewDidChangeNumberOfTabViewItemsSelector = 8;
|
||||||
|
|
||||||
/*!
|
var HEIGHT_OF_SEGMENTED_CONTROL = 24;
|
||||||
@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
|
|
||||||
(one at a time) by clicking on the CPTabViewItem's tab at the top of the tab view.
|
|
||||||
|
|
||||||
THe currently selected CPTabViewItem is the view that is displayed.
|
|
||||||
*/
|
|
||||||
@implementation CPTabView : CPView
|
@implementation CPTabView : CPView
|
||||||
{
|
{
|
||||||
CPView _labelsView;
|
CPArray items;
|
||||||
CPView _backgroundView;
|
|
||||||
CPView _separatorView;
|
|
||||||
|
|
||||||
CPView _auxiliaryView;
|
CPSegmentedControl tabs;
|
||||||
CPView _contentView;
|
CPBox box;
|
||||||
|
|
||||||
CPArray _tabViewItems;
|
CPNumber selectedIndex;
|
||||||
CPTabViewItem _selectedTabViewItem;
|
|
||||||
|
|
||||||
CPTabViewType _tabViewType;
|
CPTabViewType type;
|
||||||
|
|
||||||
id _delegate;
|
id delegate;
|
||||||
unsigned _delegateSelectors;
|
unsigned delegateSelectors;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
@ignore
|
|
||||||
*/
|
|
||||||
+ (void)initialize
|
|
||||||
{
|
|
||||||
if (self != CPTabView)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var bundle = [CPBundle bundleForClass:self],
|
|
||||||
|
|
||||||
emptyImage = [[CPImage alloc] initByReferencingFile:@"" size:CGSizeMake(7.0, 0.0)],
|
|
||||||
backgroundImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/CPTabViewBezelBackgroundCenter.png"] size:CGSizeMake(1.0, 1.0)],
|
|
||||||
|
|
||||||
bezelBorderLeftImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/CPTabViewBezelBorderLeft.png"] size:CGSizeMake(7.0, 1.0)],
|
|
||||||
bezerBorderImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/CPTabViewBezelBorder.png"] size:CGSizeMake(1.0, 1.0)],
|
|
||||||
bezelBorderRightImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/CPTabViewBezelBorderRight.png"] size:CGSizeMake(7.0, 1.0)];
|
|
||||||
|
|
||||||
CPTabViewBezelBorderBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
|
||||||
[
|
|
||||||
emptyImage,
|
|
||||||
emptyImage,
|
|
||||||
emptyImage,
|
|
||||||
|
|
||||||
bezelBorderLeftImage,
|
|
||||||
backgroundImage,
|
|
||||||
bezelBorderRightImage,
|
|
||||||
|
|
||||||
bezelBorderLeftImage,
|
|
||||||
bezerBorderImage,
|
|
||||||
bezelBorderRightImage
|
|
||||||
]]];
|
|
||||||
|
|
||||||
CPTabViewBezelBorderColor = [CPColor colorWithPatternImage:bezerBorderImage];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
@ignore
|
|
||||||
*/
|
|
||||||
+ (CPColor)bezelBorderColor
|
|
||||||
{
|
|
||||||
return CPTabViewBezelBorderColor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
{
|
{
|
||||||
self = [super initWithFrame:aFrame];
|
self = [super initWithFrame:aFrame];
|
||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_tabViewType = CPTopTabsBezelBorder;
|
items = [CPArray array];
|
||||||
_tabViewItems = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
tabs = [[CPSegmentedControl alloc] initWithFrame:CGRectMake(0, 0, 0, HEIGHT_OF_SEGMENTED_CONTROL)];
|
||||||
|
[tabs setHitTests:NO];
|
||||||
|
|
||||||
|
box = [[CPBox alloc] initWithFrame:CGRectMake(0, HEIGHT_OF_SEGMENTED_CONTROL / 2, CGRectGetWidth(aFrame),
|
||||||
|
CGRectGetHeight(aFrame) - HEIGHT_OF_SEGMENTED_CONTROL)];
|
||||||
|
|
||||||
|
selectedIndex = CPNotFound;
|
||||||
|
|
||||||
|
[self setTabViewType:CPTopTabsBezelBorder];
|
||||||
|
[self setBackgroundColor:[CPColor colorWithCalibratedWhite:0.95 alpha:1.0]];
|
||||||
|
|
||||||
|
[self addSubview:box];
|
||||||
|
[self addSubview:tabs];
|
||||||
|
|
||||||
|
[box setAutoresizingMask:CPViewWidthSizable];
|
||||||
|
[tabs setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin];
|
||||||
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidMoveToWindow
|
|
||||||
{
|
|
||||||
if (_tabViewType != CPTopTabsBezelBorder || _labelsView)
|
|
||||||
return;
|
|
||||||
|
|
||||||
[self _createBezelBorder];
|
|
||||||
[self layoutSubviews];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* @ignore */
|
|
||||||
- (void)_createBezelBorder
|
|
||||||
{
|
|
||||||
var bounds = [self bounds];
|
|
||||||
|
|
||||||
_labelsView = [[_CPTabLabelsView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(bounds), 0.0)];
|
|
||||||
|
|
||||||
[_labelsView setTabView:self];
|
|
||||||
[_labelsView setAutoresizingMask:CPViewWidthSizable];
|
|
||||||
|
|
||||||
[self addSubview:_labelsView];
|
|
||||||
|
|
||||||
_backgroundView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
|
||||||
|
|
||||||
[_backgroundView setBackgroundColor:CPTabViewBezelBorderBackgroundColor];
|
|
||||||
|
|
||||||
[_backgroundView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
|
||||||
|
|
||||||
[self addSubview:_backgroundView];
|
|
||||||
|
|
||||||
_separatorView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
|
||||||
|
|
||||||
[_separatorView setBackgroundColor:[[self class] bezelBorderColor]];
|
|
||||||
[_separatorView setAutoresizingMask:CPViewWidthSizable | CPViewMaxYMargin];
|
|
||||||
|
|
||||||
[self addSubview:_separatorView];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Lays out the subviews
|
|
||||||
@ignore
|
|
||||||
*/
|
|
||||||
- (void)layoutSubviews
|
|
||||||
{
|
|
||||||
if (_tabViewType == CPTopTabsBezelBorder)
|
|
||||||
{
|
|
||||||
var backgroundRect = [self bounds],
|
|
||||||
labelsViewHeight = [_CPTabLabelsView height];
|
|
||||||
|
|
||||||
backgroundRect.origin.y += labelsViewHeight;
|
|
||||||
backgroundRect.size.height -= labelsViewHeight;
|
|
||||||
|
|
||||||
[_backgroundView setFrame:backgroundRect];
|
|
||||||
|
|
||||||
var auxiliaryViewHeight = 5.0;
|
|
||||||
|
|
||||||
if (_auxiliaryView)
|
|
||||||
{
|
|
||||||
auxiliaryViewHeight = CGRectGetHeight([_auxiliaryView frame]);
|
|
||||||
|
|
||||||
[_auxiliaryView setFrame:CGRectMake(LEFT_INSET, labelsViewHeight, CGRectGetWidth(backgroundRect) - LEFT_INSET - RIGHT_INSET, auxiliaryViewHeight)];
|
|
||||||
}
|
|
||||||
|
|
||||||
[_separatorView setFrame:CGRectMake(LEFT_INSET, labelsViewHeight + auxiliaryViewHeight, CGRectGetWidth(backgroundRect) - LEFT_INSET - RIGHT_INSET, 1.0)];
|
|
||||||
}
|
|
||||||
|
|
||||||
// CPNoTabsNoBorder
|
|
||||||
[_contentView setFrame:[self contentRect]];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adding and Removing Tabs
|
// Adding and Removing Tabs
|
||||||
/*!
|
/*!
|
||||||
Adds a CPTabViewItem to the tab view.
|
Adds a CPTabViewItem to the tab view.
|
||||||
@@ -229,7 +87,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (void)addTabViewItem:(CPTabViewItem)aTabViewItem
|
- (void)addTabViewItem:(CPTabViewItem)aTabViewItem
|
||||||
{
|
{
|
||||||
[self insertTabViewItem:aTabViewItem atIndex:[_tabViewItems count]];
|
[self insertTabViewItem:aTabViewItem atIndex:[items count]];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -240,18 +98,13 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (void)insertTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(unsigned)anIndex
|
- (void)insertTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(unsigned)anIndex
|
||||||
{
|
{
|
||||||
if (!_labelsView && _tabViewType == CPTopTabsBezelBorder)
|
[items insertObject:aTabViewItem atIndex:anIndex];
|
||||||
[self _createBezelBorder];
|
|
||||||
|
|
||||||
[_tabViewItems insertObject:aTabViewItem atIndex:anIndex];
|
[self _updateItems];
|
||||||
|
[self _repositionTabs];
|
||||||
|
|
||||||
[_labelsView tabView:self didAddTabViewItem:aTabViewItem];
|
if (delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
|
||||||
|
[delegate tabViewDidChangeNumberOfTabViewItems:self];
|
||||||
if ([_tabViewItems count] == 1)
|
|
||||||
[self selectFirstTabViewItem:self];
|
|
||||||
|
|
||||||
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
|
|
||||||
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -260,14 +113,19 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (void)removeTabViewItem:(CPTabViewItem)aTabViewItem
|
- (void)removeTabViewItem:(CPTabViewItem)aTabViewItem
|
||||||
{
|
{
|
||||||
var index = [self indexOfTabViewItem:aTabViewItem];
|
for (var i = 0; i < [items count]; i++)
|
||||||
|
{
|
||||||
|
if ([items objectAtIndex:i] === aTabViewItem)
|
||||||
|
{
|
||||||
|
[items removeObjectAtIndex:i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[_tabViewItems removeObjectIdenticalTo:aTabViewItem];
|
[self _updateItems];
|
||||||
|
[self _repositionTabs];
|
||||||
|
|
||||||
[_labelsView tabView:self didRemoveTabViewItemAtIndex:index];
|
if (delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
|
||||||
|
[delegate tabViewDidChangeNumberOfTabViewItems:self];
|
||||||
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
|
|
||||||
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accessing Tabs
|
// Accessing Tabs
|
||||||
@@ -277,7 +135,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (int)indexOfTabViewItem:(CPTabViewItem)aTabViewItem
|
- (int)indexOfTabViewItem:(CPTabViewItem)aTabViewItem
|
||||||
{
|
{
|
||||||
return [_tabViewItems indexOfObjectIdenticalTo:aTabViewItem];
|
return [items indexOfObjectIdenticalTo:aTabViewItem];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -286,14 +144,11 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (int)indexOfTabViewItemWithIdentifier:(CPString)anIdentifier
|
- (int)indexOfTabViewItemWithIdentifier:(CPString)anIdentifier
|
||||||
{
|
{
|
||||||
var index = 0,
|
for (var index = [items count]; index >= 0; index--)
|
||||||
count = [_tabViewItems count];
|
if ([[items[index] identifier] isEqual:anIdentifier])
|
||||||
|
|
||||||
for (; index < count; ++index)
|
|
||||||
if ([[_tabViewItems[index] identifier] isEqual:anIdentifier])
|
|
||||||
return index;
|
return index;
|
||||||
|
|
||||||
return index;
|
return CPNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -301,7 +156,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (unsigned)numberOfTabViewItems
|
- (unsigned)numberOfTabViewItems
|
||||||
{
|
{
|
||||||
return [_tabViewItems count];
|
return [items count];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -309,7 +164,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (CPTabViewItem)tabViewItemAtIndex:(unsigned)anIndex
|
- (CPTabViewItem)tabViewItemAtIndex:(unsigned)anIndex
|
||||||
{
|
{
|
||||||
return _tabViewItems[anIndex];
|
return [items objectAtIndex:anIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -317,7 +172,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (CPArray)tabViewItems
|
- (CPArray)tabViewItems
|
||||||
{
|
{
|
||||||
return _tabViewItems;
|
return [items copy]; // Copy?
|
||||||
}
|
}
|
||||||
|
|
||||||
// Selecting a Tab
|
// Selecting a Tab
|
||||||
@@ -327,9 +182,9 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (void)selectFirstTabViewItem:(id)aSender
|
- (void)selectFirstTabViewItem:(id)aSender
|
||||||
{
|
{
|
||||||
var count = [_tabViewItems count];
|
if ([items count] === 0)
|
||||||
|
return; // throw?
|
||||||
|
|
||||||
if (count)
|
|
||||||
[self selectTabViewItemAtIndex:0];
|
[self selectTabViewItemAtIndex:0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,10 +194,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (void)selectLastTabViewItem:(id)aSender
|
- (void)selectLastTabViewItem:(id)aSender
|
||||||
{
|
{
|
||||||
var count = [_tabViewItems count];
|
if ([items count] === 0)
|
||||||
|
return; // throw?
|
||||||
|
|
||||||
if (count)
|
[self selectTabViewItemAtIndex:[items count] - 1];
|
||||||
[self selectTabViewItemAtIndex:count - 1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -351,13 +206,16 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (void)selectNextTabViewItem:(id)aSender
|
- (void)selectNextTabViewItem:(id)aSender
|
||||||
{
|
{
|
||||||
if (!_selectedTabViewItem)
|
if (selectedIndex === CPNotFound)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var index = [self indexOfTabViewItem:_selectedTabViewItem],
|
var nextIndex = selectedIndex + 1;
|
||||||
count = [_tabViewItems count];
|
|
||||||
|
|
||||||
[self selectTabViewItemAtIndex:index + 1 % count];
|
if (nextIndex === [items count])
|
||||||
|
// does nothing. According to spec at (http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Reference/ApplicationKit/Classes/NSTabView_Class/Reference/Reference.html#//apple_ref/occ/instm/NSTabView/selectNextTabViewItem:)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self selectTabViewItemAtIndex:nextIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -366,13 +224,15 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (void)selectPreviousTabViewItem:(id)aSender
|
- (void)selectPreviousTabViewItem:(id)aSender
|
||||||
{
|
{
|
||||||
if (!_selectedTabViewItem)
|
if (selectedIndex === CPNotFound)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var index = [self indexOfTabViewItem:_selectedTabViewItem],
|
var previousIndex = selectedIndex - 1;
|
||||||
count = [_tabViewItems count];
|
|
||||||
|
|
||||||
[self selectTabViewItemAtIndex:index == 0 ? count : index - 1];
|
if (previousIndex < 0)
|
||||||
|
return; // does nothing. See above.
|
||||||
|
|
||||||
|
[self selectTabViewItemAtIndex:previousIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -381,41 +241,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (void)selectTabViewItem:(CPTabViewItem)aTabViewItem
|
- (void)selectTabViewItem:(CPTabViewItem)aTabViewItem
|
||||||
{
|
{
|
||||||
if ((_delegateSelectors & CPTabViewShouldSelectTabViewItemSelector) && ![_delegate tabView:self shouldSelectTabViewItem:aTabViewItem])
|
[self selectTabViewItemAtIndex:[self indexOfTabViewItem:aTabViewItem]];
|
||||||
return;
|
|
||||||
|
|
||||||
if (_delegateSelectors & CPTabViewWillSelectTabViewItemSelector)
|
|
||||||
[_delegate tabView:self willSelectTabViewItem:aTabViewItem];
|
|
||||||
|
|
||||||
if (_selectedTabViewItem)
|
|
||||||
{
|
|
||||||
_selectedTabViewItem._tabState = CPBackgroundTab;
|
|
||||||
[_labelsView tabView:self didChangeStateOfTabViewItem:_selectedTabViewItem];
|
|
||||||
|
|
||||||
[_contentView removeFromSuperview];
|
|
||||||
[_auxiliaryView removeFromSuperview];
|
|
||||||
}
|
|
||||||
_selectedTabViewItem = aTabViewItem;
|
|
||||||
|
|
||||||
_selectedTabViewItem._tabState = CPSelectedTab;
|
|
||||||
|
|
||||||
_contentView = [_selectedTabViewItem view];
|
|
||||||
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
|
||||||
|
|
||||||
_auxiliaryView = [_selectedTabViewItem auxiliaryView];
|
|
||||||
[_auxiliaryView setAutoresizingMask:CPViewWidthSizable];
|
|
||||||
|
|
||||||
[self addSubview:_contentView];
|
|
||||||
|
|
||||||
if (_auxiliaryView)
|
|
||||||
[self addSubview:_auxiliaryView];
|
|
||||||
|
|
||||||
[_labelsView tabView:self didChangeStateOfTabViewItem:_selectedTabViewItem];
|
|
||||||
|
|
||||||
[self layoutSubviews];
|
|
||||||
|
|
||||||
if (_delegateSelectors & CPTabViewDidSelectTabViewItemSelector)
|
|
||||||
[_delegate tabView:self didSelectTabViewItem:aTabViewItem];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -424,7 +250,24 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (void)selectTabViewItemAtIndex:(unsigned)anIndex
|
- (void)selectTabViewItemAtIndex:(unsigned)anIndex
|
||||||
{
|
{
|
||||||
[self selectTabViewItem:_tabViewItems[anIndex]];
|
var aTabViewItem = [items objectAtIndex:anIndex];
|
||||||
|
|
||||||
|
if (anIndex === selectedIndex)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var aTabViewItem = [self tabViewItemAtIndex:anIndex];
|
||||||
|
|
||||||
|
if ((delegateSelectors & CPTabViewShouldSelectTabViewItemSelector) && ![delegate tabView:self shouldSelectTabViewItem:aTabViewItem])
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (delegateSelectors & CPTabViewWillSelectTabViewItemSelector)
|
||||||
|
[delegate tabView:self willSelectTabViewItem:aTabViewItem];
|
||||||
|
|
||||||
|
[tabs selectSegmentWithTag:anIndex];
|
||||||
|
[self _setSelectedIndex:anIndex];
|
||||||
|
|
||||||
|
if (delegateSelectors & CPTabViewDidSelectTabViewItemSelector)
|
||||||
|
[delegate tabView:self didSelectTabViewItem:aTabViewItem];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -432,7 +275,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (CPTabViewItem)selectedTabViewItem
|
- (CPTabViewItem)selectedTabViewItem
|
||||||
{
|
{
|
||||||
return _selectedTabViewItem;
|
return [items objectAtIndex:selectedIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -442,22 +285,33 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (void)setTabViewType:(CPTabViewType)aTabViewType
|
- (void)setTabViewType:(CPTabViewType)aTabViewType
|
||||||
{
|
{
|
||||||
if (_tabViewType == aTabViewType)
|
if (type === aTabViewType)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_tabViewType = aTabViewType;
|
if ((type === CPTopTabsBezelBorder || type === CPBottomTabsBezelBorder)
|
||||||
|
&& (aTabViewType !== CPTopTabsBezelBorder && aTabViewType !== CPBottomTabsBezelBorder))
|
||||||
|
[tabs removeFromSuperview];
|
||||||
|
|
||||||
if (_tabViewType == CPNoTabsBezelBorder || _tabViewType == CPNoTabsLineBorder || _tabViewType == CPNoTabsNoBorder)
|
if ((type === CPNoTabsBezelBorder || type === CPNoTabsLineBorder || type === CPNoTabsNoBorder)
|
||||||
[_labelsView removeFromSuperview];
|
&& (aTabViewType !== CPNoTabsBezelBorder && aTabViewType !== CPNoTabsBezelBorder && aTabViewType !== CPNoTabsNoBorder))
|
||||||
else if (![_labelsView superview])
|
[self addSubview:tabs];
|
||||||
[self addSubview:_labelsView];
|
|
||||||
|
|
||||||
if (_tabViewType == CPNoTabsLineBorder || _tabViewType == CPNoTabsNoBorder)
|
type = aTabViewType;
|
||||||
[_backgroundView removeFromSuperview];
|
|
||||||
else if (![_backgroundView superview])
|
|
||||||
[self addSubview:_backgroundView];
|
|
||||||
|
|
||||||
[self layoutSubviews];
|
switch (type)
|
||||||
|
{
|
||||||
|
case CPTopTabsBezelBorder:
|
||||||
|
case CPBottomTabsBezelBorder:
|
||||||
|
case CPNoTabsBezelBorder:
|
||||||
|
[box setBorderType:CPBezelBorder];
|
||||||
|
break;
|
||||||
|
case CPNoTabsLineBorder:
|
||||||
|
[box setBorderType:CPLineBorder];
|
||||||
|
break;
|
||||||
|
case CPNoTabsNoBorder:
|
||||||
|
[box setBorderType:CPNoBorder];
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -465,31 +319,15 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (CPTabViewType)tabViewType
|
- (CPTabViewType)tabViewType
|
||||||
{
|
{
|
||||||
return _tabViewType;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determining the Size
|
|
||||||
/*!
|
/*!
|
||||||
Returns the content rectangle.
|
Returns the receiver's delegate.
|
||||||
*/
|
*/
|
||||||
- (CGRect)contentRect
|
- (id)delegate
|
||||||
{
|
{
|
||||||
var contentRect = CGRectMakeCopy([self bounds]);
|
return delegate;
|
||||||
|
|
||||||
if (_tabViewType == CPTopTabsBezelBorder)
|
|
||||||
{
|
|
||||||
var labelsViewHeight = [_CPTabLabelsView height],
|
|
||||||
auxiliaryViewHeight = _auxiliaryView ? CGRectGetHeight([_auxiliaryView frame]) : 5.0,
|
|
||||||
separatorViewHeight = 1.0;
|
|
||||||
|
|
||||||
contentRect.origin.y += labelsViewHeight + auxiliaryViewHeight + separatorViewHeight;
|
|
||||||
contentRect.size.height -= labelsViewHeight + auxiliaryViewHeight + separatorViewHeight * 2.0; // 2 for the bottom border as well.
|
|
||||||
|
|
||||||
contentRect.origin.x += LEFT_INSET;
|
|
||||||
contentRect.size.width -= LEFT_INSET + RIGHT_INSET;
|
|
||||||
}
|
|
||||||
|
|
||||||
return contentRect;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -498,35 +336,74 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (void)setDelegate:(id)aDelegate
|
- (void)setDelegate:(id)aDelegate
|
||||||
{
|
{
|
||||||
if (_delegate == aDelegate)
|
if (delegate == aDelegate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_delegate = aDelegate;
|
delegate = aDelegate;
|
||||||
|
|
||||||
_delegateSelectors = 0;
|
delegateSelectors = 0;
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(tabView:shouldSelectTabViewItem:)])
|
if ([delegate respondsToSelector:@selector(tabView:shouldSelectTabViewItem:)])
|
||||||
_delegateSelectors |= CPTabViewShouldSelectTabViewItemSelector;
|
delegateSelectors |= CPTabViewShouldSelectTabViewItemSelector;
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(tabView:willSelectTabViewItem:)])
|
if ([delegate respondsToSelector:@selector(tabView:willSelectTabViewItem:)])
|
||||||
_delegateSelectors |= CPTabViewWillSelectTabViewItemSelector;
|
delegateSelectors |= CPTabViewWillSelectTabViewItemSelector;
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(tabView:didSelectTabViewItem:)])
|
if ([delegate respondsToSelector:@selector(tabView:didSelectTabViewItem:)])
|
||||||
_delegateSelectors |= CPTabViewDidSelectTabViewItemSelector;
|
delegateSelectors |= CPTabViewDidSelectTabViewItemSelector;
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(tabViewDidChangeNumberOfTabViewItems:)])
|
if ([delegate respondsToSelector:@selector(tabViewDidChangeNumberOfTabViewItems:)])
|
||||||
_delegateSelectors |= CPTabViewDidChangeNumberOfTabViewItemsSelector;
|
delegateSelectors |= CPTabViewDidChangeNumberOfTabViewItemsSelector;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
- (void)setBackgroundColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
[box setBackgroundColor:aColor];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)mouseDown:(CPEvent)anEvent
|
- (void)mouseDown:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
var location = [_labelsView convertPoint:[anEvent locationInWindow] fromView:nil],
|
var segmentIndex = [tabs testSegment:[tabs convertPoint:[anEvent locationInWindow] fromView:nil]];
|
||||||
tabViewItem = [_labelsView representedTabViewItemAtPoint:location];
|
|
||||||
|
|
||||||
if (tabViewItem)
|
if (segmentIndex != CPNotFound)
|
||||||
[self selectTabViewItem:tabViewItem];
|
{
|
||||||
|
[self selectTabViewItemAtIndex:segmentIndex];
|
||||||
|
[tabs trackSegment:anEvent];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_repositionTabs
|
||||||
|
{
|
||||||
|
var horizontalCenterOfSelf = CGRectGetWidth([self bounds]) / 2,
|
||||||
|
verticalCenterOfTabs = CGRectGetHeight([tabs bounds]) / 2;
|
||||||
|
|
||||||
|
if (type === CPBottomTabsBezelBorder)
|
||||||
|
[tabs setCenter:CGPointMake(horizontalCenterOfSelf, CGRectGetHeight([self bounds]) - verticalCenterOfTabs)];
|
||||||
|
else
|
||||||
|
[tabs setCenter:CGPointMake(horizontalCenterOfSelf, verticalCenterOfTabs)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_setSelectedIndex:(CPNumber)index
|
||||||
|
{
|
||||||
|
selectedIndex = index;
|
||||||
|
|
||||||
|
[box setContentView:[[items objectAtIndex:selectedIndex] view]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_updateItems
|
||||||
|
{
|
||||||
|
[tabs setSegmentCount:[items count]];
|
||||||
|
|
||||||
|
for (var i = 0; i < [items count]; i++)
|
||||||
|
{
|
||||||
|
[tabs setLabel:[[items objectAtIndex:i] label] forSegment:i];
|
||||||
|
[tabs setTag:i forSegment:i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedIndex === CPNotFound)
|
||||||
|
{
|
||||||
|
[self selectFirstTabViewItem:self];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -542,15 +419,12 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
|||||||
{
|
{
|
||||||
if (self = [super initWithCoder:aCoder])
|
if (self = [super initWithCoder:aCoder])
|
||||||
{
|
{
|
||||||
_tabViewType = [aCoder decodeIntForKey:CPTabViewTypeKey];
|
type = [aCoder decodeIntForKey:CPTabViewTypeKey];
|
||||||
_tabViewItems = [];
|
items = [];
|
||||||
|
|
||||||
// FIXME: this is somewhat hacky
|
var encodedItems = [aCoder decodeObjectForKey:CPTabViewItemsKey];
|
||||||
[self _createBezelBorder];
|
for (var i = 0; encodedItems && i < encodedItems.length; i++)
|
||||||
|
[self insertTabViewItem:encodedItems[i] atIndex:i];
|
||||||
var items = [aCoder decodeObjectForKey:CPTabViewItemsKey];
|
|
||||||
for (var i = 0; items && i < items.length; i++)
|
|
||||||
[self insertTabViewItem:items[i] atIndex:i];
|
|
||||||
|
|
||||||
var selected = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
|
var selected = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
|
||||||
if (selected)
|
if (selected)
|
||||||
@@ -564,227 +438,14 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
|||||||
|
|
||||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
{
|
{
|
||||||
var actualSubviews = _subviews;
|
|
||||||
_subviews = [];
|
|
||||||
[super encodeWithCoder:aCoder];
|
[super encodeWithCoder:aCoder];
|
||||||
_subviews = actualSubviews;
|
|
||||||
|
|
||||||
[aCoder encodeObject:_tabViewItems forKey:CPTabViewItemsKey];;
|
[aCoder encodeObject:items forKey:CPTabViewItemsKey];;
|
||||||
[aCoder encodeObject:_selectedTabViewItem forKey:CPTabViewSelectedItemKey];
|
[aCoder encodeObject:[self selectedTabViewItem] forKey:CPTabViewSelectedItemKey];
|
||||||
|
|
||||||
[aCoder encodeInt:_tabViewType forKey:CPTabViewTypeKey];
|
[aCoder encodeInt:type forKey:CPTabViewTypeKey];
|
||||||
|
|
||||||
[aCoder encodeConditionalObject:_delegate forKey:CPTabViewDelegateKey];
|
[aCoder encodeConditionalObject:delegate forKey:CPTabViewDelegateKey];
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
var _CPTabLabelsViewBackgroundColor = nil,
|
|
||||||
_CPTabLabelsViewInsideMargin = 10.0,
|
|
||||||
_CPTabLabelsViewOutsideMargin = 15.0;
|
|
||||||
|
|
||||||
/* @ignore */
|
|
||||||
@implementation _CPTabLabelsView : CPView
|
|
||||||
{
|
|
||||||
CPTabView _tabView;
|
|
||||||
CPDictionary _tabLabels;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)initialize
|
|
||||||
{
|
|
||||||
if (self != [_CPTabLabelsView class])
|
|
||||||
return;
|
|
||||||
|
|
||||||
var bundle = [CPBundle bundleForClass:self];
|
|
||||||
|
|
||||||
_CPTabLabelsViewBackgroundColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
|
||||||
[
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelsViewLeft.png"] size:CGSizeMake(12.0, 26.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelsViewCenter.png"] size:CGSizeMake(1.0, 26.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelsViewRight.png"] size:CGSizeMake(12.0, 26.0)]
|
|
||||||
] isVertical:NO]];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (float)height
|
|
||||||
{
|
|
||||||
return 26.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
|
||||||
{
|
|
||||||
self = [super initWithFrame:aFrame];
|
|
||||||
|
|
||||||
if (self)
|
|
||||||
{
|
|
||||||
_tabLabels = [];
|
|
||||||
|
|
||||||
[self setBackgroundColor:_CPTabLabelsViewBackgroundColor];
|
|
||||||
|
|
||||||
[self setFrameSize:CGSizeMake(CGRectGetWidth(aFrame), 26.0)];
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setTabView:(CPTabView)aTabView
|
|
||||||
{
|
|
||||||
_tabView = aTabView;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPTabView)tabView
|
|
||||||
{
|
|
||||||
return _tabView;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)tabView:(CPTabView)aTabView didAddTabViewItem:(CPTabViewItem)aTabViewItem
|
|
||||||
{
|
|
||||||
var label = [[_CPTabLabel alloc] initWithFrame:CGRectMakeZero()];
|
|
||||||
|
|
||||||
[label setTabViewItem:aTabViewItem];
|
|
||||||
|
|
||||||
_tabLabels.push(label);
|
|
||||||
|
|
||||||
[self addSubview:label];
|
|
||||||
|
|
||||||
[self layoutSubviews];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)tabView:(CPTabView)aTabView didRemoveTabViewItemAtIndex:(unsigned)index
|
|
||||||
{
|
|
||||||
var label = _tabLabels[index];
|
|
||||||
|
|
||||||
[_tabLabels removeObjectAtIndex:index];
|
|
||||||
|
|
||||||
[label removeFromSuperview];
|
|
||||||
|
|
||||||
[self layoutSubviews];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void)tabView:(CPTabView)aTabView didChangeStateOfTabViewItem:(CPTabViewItem)aTabViewItem
|
|
||||||
{
|
|
||||||
[_tabLabels[[aTabView indexOfTabViewItem:aTabViewItem]] setTabState:[aTabViewItem tabState]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPTabViewItem)representedTabViewItemAtPoint:(CGPoint)aPoint
|
|
||||||
{
|
|
||||||
var index = 0,
|
|
||||||
count = _tabLabels.length;
|
|
||||||
|
|
||||||
for (; index < count; ++index)
|
|
||||||
{
|
|
||||||
var label = _tabLabels[index];
|
|
||||||
|
|
||||||
if (CGRectContainsPoint([label frame], aPoint))
|
|
||||||
return [label tabViewItem];
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)layoutSubviews
|
|
||||||
{
|
|
||||||
var index = 0,
|
|
||||||
count = _tabLabels.length,
|
|
||||||
width = (_CGRectGetWidth([self bounds]) - (count - 1) * _CPTabLabelsViewInsideMargin - 2 * _CPTabLabelsViewOutsideMargin) / count,
|
|
||||||
x = _CPTabLabelsViewOutsideMargin;
|
|
||||||
|
|
||||||
for (; index < count; ++index)
|
|
||||||
{
|
|
||||||
var label = _tabLabels[index],
|
|
||||||
frame = _CGRectMake(x, 8.0, width, 18.0);
|
|
||||||
|
|
||||||
[label setFrame:frame];
|
|
||||||
|
|
||||||
x = _CGRectGetMaxX(frame) + _CPTabLabelsViewInsideMargin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setFrameSize:(CGSize)aSize
|
|
||||||
{
|
|
||||||
if (CGSizeEqualToSize([self frame].size, aSize))
|
|
||||||
return;
|
|
||||||
|
|
||||||
[super setFrameSize:aSize];
|
|
||||||
|
|
||||||
[self layoutSubviews];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
var _CPTabLabelBackgroundColor = nil,
|
|
||||||
_CPTabLabelSelectedBackgroundColor = nil;
|
|
||||||
|
|
||||||
/* @ignore */
|
|
||||||
@implementation _CPTabLabel : CPView
|
|
||||||
{
|
|
||||||
CPTabViewItem _tabViewItem;
|
|
||||||
CPTextField _labelField;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)initialize
|
|
||||||
{
|
|
||||||
if (self != [_CPTabLabel class])
|
|
||||||
return;
|
|
||||||
|
|
||||||
var bundle = [CPBundle bundleForClass:self];
|
|
||||||
|
|
||||||
_CPTabLabelBackgroundColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
|
||||||
[
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelBackgroundLeft.png"] size:CGSizeMake(6.0, 18.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelBackgroundCenter.png"] size:CGSizeMake(1.0, 18.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelBackgroundRight.png"] size:CGSizeMake(6.0, 18.0)]
|
|
||||||
] isVertical:NO]];
|
|
||||||
|
|
||||||
_CPTabLabelSelectedBackgroundColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
|
||||||
[
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelSelectedLeft.png"] size:CGSizeMake(3.0, 18.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelSelectedCenter.png"] size:CGSizeMake(1.0, 18.0)],
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelSelectedRight.png"] size:CGSizeMake(3.0, 18.0)]
|
|
||||||
] isVertical:NO]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
|
||||||
{
|
|
||||||
self = [super initWithFrame:aFrame];
|
|
||||||
|
|
||||||
if (self)
|
|
||||||
{
|
|
||||||
_labelField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
|
||||||
|
|
||||||
[_labelField setAlignment:CPCenterTextAlignment];
|
|
||||||
[_labelField setFrame:CGRectMake(5.0, 0.0, CGRectGetWidth(aFrame) - 10.0, 20.0)];
|
|
||||||
[_labelField setAutoresizingMask:CPViewWidthSizable];
|
|
||||||
[_labelField setFont:[CPFont boldSystemFontOfSize:11.0]];
|
|
||||||
|
|
||||||
[self addSubview:_labelField];
|
|
||||||
|
|
||||||
[self setTabState:CPBackgroundTab];
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setTabState:(CPTabState)aTabState
|
|
||||||
{
|
|
||||||
[self setBackgroundColor:aTabState == CPSelectedTab ? _CPTabLabelSelectedBackgroundColor : _CPTabLabelBackgroundColor];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setTabViewItem:(CPTabViewItem)aTabViewItem
|
|
||||||
{
|
|
||||||
_tabViewItem = aTabViewItem;
|
|
||||||
|
|
||||||
[self update];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPTabViewItem)tabViewItem
|
|
||||||
{
|
|
||||||
return _tabViewItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)update
|
|
||||||
{
|
|
||||||
[_labelField setStringValue:[_tabViewItem label]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+11
-1
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
@import <AppKit/CPView.j>
|
@import "CPView.j"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -58,6 +58,8 @@ CPPressedTab = 2;
|
|||||||
|
|
||||||
CPView _view;
|
CPView _view;
|
||||||
CPView _auxiliaryView;
|
CPView _auxiliaryView;
|
||||||
|
|
||||||
|
CPTabView _tabView;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
@@ -168,6 +170,14 @@ CPPressedTab = 2;
|
|||||||
return _tabView;
|
return _tabView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
*/
|
||||||
|
- (void)_setTabView:(CPTabView)aView
|
||||||
|
{
|
||||||
|
_tabView = aView;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPTabViewItemIdentifierKey = "CPTabViewItemIdentifierKey",
|
var CPTabViewItemIdentifierKey = "CPTabViewItemIdentifierKey",
|
||||||
|
|||||||
+153
-38
@@ -22,27 +22,16 @@
|
|||||||
|
|
||||||
@import <Foundation/CPDictionary.j>
|
@import <Foundation/CPDictionary.j>
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
@import <Foundation/CPIndexSet.j>
|
||||||
@import <Foundation/CPSortDescriptor.j>
|
@import <Foundation/CPSortDescriptor.j>
|
||||||
@import <Foundation/CPString.j>
|
@import <Foundation/CPString.j>
|
||||||
|
|
||||||
@import "CPTableHeaderView.j"
|
@import "CPTableHeaderView.j"
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@class CPTableColumn
|
|
||||||
*/
|
|
||||||
CPTableColumnNoResizing = 0;
|
CPTableColumnNoResizing = 0;
|
||||||
/*
|
CPTableColumnAutoresizingMask = 1 << 0;
|
||||||
@global
|
CPTableColumnUserResizingMask = 1 << 1;
|
||||||
@class CPTableColumn
|
|
||||||
*/
|
|
||||||
CPTableColumnAutoresizingMask = 1;
|
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@class CPTableColumn
|
|
||||||
*/
|
|
||||||
CPTableColumnUserResizingMask = 2;
|
|
||||||
|
|
||||||
@implementation CPTableColumn : CPObject
|
@implementation CPTableColumn : CPObject
|
||||||
{
|
{
|
||||||
@@ -54,12 +43,15 @@ CPTableColumnUserResizingMask = 2;
|
|||||||
float _width;
|
float _width;
|
||||||
float _minWidth;
|
float _minWidth;
|
||||||
float _maxWidth;
|
float _maxWidth;
|
||||||
|
unsigned _resizingMask;
|
||||||
|
|
||||||
id _identifier;
|
id _identifier;
|
||||||
BOOL _isEditable;
|
BOOL _isEditable;
|
||||||
CPSortDescriptor _sortDescriptorPrototype;
|
CPSortDescriptor _sortDescriptorPrototype;
|
||||||
BOOL _isHidden;
|
BOOL _isHidden;
|
||||||
CPString _headerToolTip;
|
CPString _headerToolTip;
|
||||||
|
|
||||||
|
BOOL _disableResizingPosting @accessors(property=disableResizingPosting);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
@@ -78,15 +70,21 @@ CPTableColumnUserResizingMask = 2;
|
|||||||
_width = 100.0;
|
_width = 100.0;
|
||||||
_minWidth = 10.0;
|
_minWidth = 10.0;
|
||||||
_maxWidth = 1000000.0;
|
_maxWidth = 1000000.0;
|
||||||
|
_resizingMask = CPTableColumnAutoresizingMask | CPTableColumnUserResizingMask;
|
||||||
|
_disableResizingPosting = NO;
|
||||||
|
|
||||||
[self setIdentifier:anIdentifier];
|
[self setIdentifier:anIdentifier];
|
||||||
[self setHeaderView:[CPTextField new]];
|
|
||||||
|
var header = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
[self setHeaderView:header];
|
||||||
|
|
||||||
[self setDataView:[CPTextField new]];
|
[self setDataView:[CPTextField new]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)setTableView:(CPTableView)aTableView
|
- (void)setTableView:(CPTableView)aTableView
|
||||||
{
|
{
|
||||||
_tableView = aTableView;
|
_tableView = aTableView;
|
||||||
@@ -117,18 +115,23 @@ CPTableColumnUserResizingMask = 2;
|
|||||||
|
|
||||||
if (tableView)
|
if (tableView)
|
||||||
{
|
{
|
||||||
var index = [[tableView tableColumns] indexOfObjectIdenticalTo:self];
|
var index = [[tableView tableColumns] indexOfObjectIdenticalTo:self],
|
||||||
|
dirtyTableColumnRangeIndex = tableView._dirtyTableColumnRangeIndex;
|
||||||
|
|
||||||
// FIXME: THIS IS HORRIBLE. Don't just reload everything when a table column changes, just relayout the changed widths.
|
if (dirtyTableColumnRangeIndex < 0)
|
||||||
tableView._reloadAllRows = YES;
|
tableView._dirtyTableColumnRangeIndex = index;
|
||||||
tableView._dirtyTableColumnRangeIndex = tableView._dirtyTableColumnRangeIndex < 0 ? index : MIN(index, tableView._dirtyTableColumnRangeIndex);
|
else
|
||||||
|
tableView._dirtyTableColumnRangeIndex = MIN(index, tableView._dirtyTableColumnRangeIndex);
|
||||||
|
|
||||||
|
var rows = tableView._exposedRows,
|
||||||
|
columns = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(index, [tableView._exposedColumns lastIndex] - index + 1)];
|
||||||
|
|
||||||
|
// FIXME: Would be faster with some sort of -setNeedsDisplayInColumns: that updates a dirtyTableColumnForDisplay cache; then marked columns would relayout their data views at display time.
|
||||||
|
[tableView _layoutDataViewsInRows:rows columns:columns];
|
||||||
[tableView tile];
|
[tableView tile];
|
||||||
|
|
||||||
[[CPNotificationCenter defaultCenter]
|
if (!_disableResizingPosting)
|
||||||
postNotificationName:CPTableViewColumnDidResizeNotification
|
[self _postDidResizeNotificationWithOldWidth:oldWidth];
|
||||||
object:tableView
|
|
||||||
userInfo:[CPDictionary dictionaryWithObjects:[self, oldWidth] forKeys:[@"CPTableColumn", "CPOldWidth"]]];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +171,7 @@ CPTableColumnUserResizingMask = 2;
|
|||||||
_maxWidth = aMaxWidth;
|
_maxWidth = aMaxWidth;
|
||||||
|
|
||||||
var width = [self width],
|
var width = [self width],
|
||||||
newWidth = MAX(width, [self maxWidth]);
|
newWidth = MIN(width, [self maxWidth]);
|
||||||
|
|
||||||
if (width !== newWidth)
|
if (width !== newWidth)
|
||||||
[self setWidth:newWidth];
|
[self setWidth:newWidth];
|
||||||
@@ -184,7 +187,7 @@ CPTableColumnUserResizingMask = 2;
|
|||||||
_resizingMask = aResizingMask;
|
_resizingMask = aResizingMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (float)resizingMask
|
- (unsigned)resizingMask
|
||||||
{
|
{
|
||||||
return _resizingMask;
|
return _resizingMask;
|
||||||
}
|
}
|
||||||
@@ -221,14 +224,29 @@ CPTableColumnUserResizingMask = 2;
|
|||||||
return _headerView;
|
return _headerView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
This method set's the "prototype" view which will be used to create all table cells in this column.
|
||||||
|
|
||||||
|
It creates a snapshot of aView, using keyed archiving, which is then copied over and over for each
|
||||||
|
individual cell that is shown. As a result, changes made after calling this method won't be reflected.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
[tableColumn setDataView:someView]; // snapshot taken
|
||||||
|
[[tableColumn dataView] setSomething:x]; //won't work
|
||||||
|
|
||||||
|
This doesn't work because the snapshot is taken before the new property is applied. Instead, do:
|
||||||
|
|
||||||
|
[someView setSomething:x];
|
||||||
|
[tableColumn setDataView:someView];
|
||||||
|
*/
|
||||||
- (void)setDataView:(CPView)aView
|
- (void)setDataView:(CPView)aView
|
||||||
{
|
{
|
||||||
if (_dataView === aView)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_dataView)
|
if (_dataView)
|
||||||
_dataViewData[[_dataView UID]] = nil;
|
_dataViewData[[_dataView UID]] = nil;
|
||||||
|
|
||||||
|
[aView setThemeState:CPThemeStateTableDataView];
|
||||||
|
|
||||||
_dataView = aView;
|
_dataView = aView;
|
||||||
_dataViewData[[aView UID]] = [CPKeyedArchiver archivedDataWithRootObject:aView];
|
_dataViewData[[aView UID]] = [CPKeyedArchiver archivedDataWithRootObject:aView];
|
||||||
}
|
}
|
||||||
@@ -267,6 +285,10 @@ return x.pop();
|
|||||||
// unarchive the data view cache
|
// unarchive the data view cache
|
||||||
var newDataView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[dataViewUID]];
|
var newDataView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[dataViewUID]];
|
||||||
newDataView.identifier = dataViewUID;
|
newDataView.identifier = dataViewUID;
|
||||||
|
|
||||||
|
// make sure only we have control over the size and placement
|
||||||
|
[newDataView setAutoresizingMask:CPViewNotSizable];
|
||||||
|
|
||||||
return newDataView;
|
return newDataView;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,7 +344,14 @@ newDataView.identifier = dataViewUID;
|
|||||||
|
|
||||||
- (void)setHidden:(BOOL)shouldBeHidden
|
- (void)setHidden:(BOOL)shouldBeHidden
|
||||||
{
|
{
|
||||||
|
shouldBeHidden = !!shouldBeHidden
|
||||||
|
if (_isHidden === shouldBeHidden)
|
||||||
|
return;
|
||||||
|
|
||||||
_isHidden = shouldBeHidden;
|
_isHidden = shouldBeHidden;
|
||||||
|
|
||||||
|
[[self headerView] setHidden:shouldBeHidden];
|
||||||
|
[[self tableView] _tableColumnVisibilityDidChange:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isHidden
|
- (BOOL)isHidden
|
||||||
@@ -346,6 +375,84 @@ newDataView.identifier = dataViewUID;
|
|||||||
return _headerToolTip;
|
return _headerToolTip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)_postDidResizeNotificationWithOldWidth:(float)oldWidth
|
||||||
|
{
|
||||||
|
[[CPNotificationCenter defaultCenter]
|
||||||
|
postNotificationName:CPTableViewColumnDidResizeNotification
|
||||||
|
object:[self tableView]
|
||||||
|
userInfo:[CPDictionary dictionaryWithObjects:[self, oldWidth] forKeys:[@"CPTableColumn", "CPOldWidth"]]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation CPTableColumn (Bindings)
|
||||||
|
|
||||||
|
- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options
|
||||||
|
{
|
||||||
|
[super bind:aBinding toObject:anObject withKeyPath:aKeyPath options:options];
|
||||||
|
|
||||||
|
if (![aBinding isEqual:@"someListOfExceptedBindings(notAcceptedBindings)"])
|
||||||
|
[[self tableView] _establishBindingsIfUnbound:anObject];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)prepareDataView:(CPView)aDataView forRow:(unsigned)aRow
|
||||||
|
{
|
||||||
|
var bindingsDictionary = [CPKeyValueBinding allBindingsForObject:self],
|
||||||
|
keys = [bindingsDictionary allKeys];
|
||||||
|
|
||||||
|
for (var i = 0, count = [keys count]; i < count; i++)
|
||||||
|
{
|
||||||
|
var bindingName = keys[i],
|
||||||
|
bindingPath = [aDataView _replacementKeyPathForBinding:bindingName],
|
||||||
|
binding = [bindingsDictionary objectForKey:bindingName],
|
||||||
|
bindingInfo = binding._info,
|
||||||
|
destination = [bindingInfo objectForKey:CPObservedObjectKey],
|
||||||
|
keyPath = [bindingInfo objectForKey:CPObservedKeyPathKey],
|
||||||
|
dotIndex = keyPath.lastIndexOf("."),
|
||||||
|
value;
|
||||||
|
|
||||||
|
if (dotIndex === CPNotFound)
|
||||||
|
value = [[destination valueForKeyPath:keyPath] objectAtIndex:aRow];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Optimize the prototypical use case where the key path describes a value
|
||||||
|
in an array. Without this optimization, we call CPArray's valueForKey
|
||||||
|
which generates as many values as objects in the array, of which we then
|
||||||
|
pick one and throw away the rest.
|
||||||
|
|
||||||
|
The optimization is to get the array and access the value directly. This
|
||||||
|
turns the operation into a single access regardless of how long the model
|
||||||
|
array is.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var firstPart = keyPath.substring(0, dotIndex),
|
||||||
|
secondPart = keyPath.substring(dotIndex + 1),
|
||||||
|
firstValue = [destination valueForKeyPath:firstPart];
|
||||||
|
|
||||||
|
if ([firstValue isKindOfClass:CPArray])
|
||||||
|
value = [[firstValue objectAtIndex:aRow] valueForKeyPath:secondPart];
|
||||||
|
else
|
||||||
|
value = [[firstValue valueForKeyPath:secondPart] objectAtIndex:aRow];
|
||||||
|
}
|
||||||
|
|
||||||
|
value = [binding transformValue:value withOptions:[bindingInfo objectForKey:CPOptionsKey]];
|
||||||
|
|
||||||
|
// console.log(bindingName+" : "+keyPath+" : "+aRow+" : "+[[destination valueForKeyPath:keyPath] objectAtIndex:aRow]);
|
||||||
|
[aDataView setValue:value forKey:bindingPath];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- (void)objectValue
|
||||||
|
//{
|
||||||
|
// return nil;
|
||||||
|
//}
|
||||||
|
|
||||||
|
- (void)setValue:(CPArray)content
|
||||||
|
{
|
||||||
|
[[self tableView] reloadData];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
||||||
@@ -354,7 +461,10 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
|||||||
CPTableColumnWidthKey = @"CPTableColumnWidthKey",
|
CPTableColumnWidthKey = @"CPTableColumnWidthKey",
|
||||||
CPTableColumnMinWidthKey = @"CPTableColumnMinWidthKey",
|
CPTableColumnMinWidthKey = @"CPTableColumnMinWidthKey",
|
||||||
CPTableColumnMaxWidthKey = @"CPTableColumnMaxWidthKey",
|
CPTableColumnMaxWidthKey = @"CPTableColumnMaxWidthKey",
|
||||||
CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey";
|
CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey",
|
||||||
|
CPTableColumnIsHiddenKey = @"CPTableColumnIsHiddenKey",
|
||||||
|
CPSortDescriptorPrototypeKey = @"CPSortDescriptorPrototypeKey",
|
||||||
|
CPTableColumnIsEditableKey = @"CPTableColumnIsEditableKey";
|
||||||
|
|
||||||
@implementation CPTableColumn (CPCoding)
|
@implementation CPTableColumn (CPCoding)
|
||||||
|
|
||||||
@@ -371,14 +481,15 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
|||||||
_maxWidth = [aCoder decodeFloatForKey:CPTableColumnMaxWidthKey];
|
_maxWidth = [aCoder decodeFloatForKey:CPTableColumnMaxWidthKey];
|
||||||
|
|
||||||
[self setIdentifier:[aCoder decodeObjectForKey:CPTableColumnIdentifierKey]];
|
[self setIdentifier:[aCoder decodeObjectForKey:CPTableColumnIdentifierKey]];
|
||||||
// [self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
|
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
|
||||||
// [self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
|
[self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
|
||||||
|
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
|
||||||
|
|
||||||
[self setHeaderView:[CPTextField new]];
|
_resizingMask = [aCoder decodeIntForKey:CPTableColumnResizingMaskKey];
|
||||||
[self setDataView:[CPTextField new]];
|
_isHidden = [aCoder decodeBoolForKey:CPTableColumnIsHiddenKey];
|
||||||
|
_isEditable = [aCoder decodeBoolForKey:CPTableColumnIsEditableKey];
|
||||||
|
|
||||||
|
_sortDescriptorPrototype = [aCoder decodeObjectForKey:CPSortDescriptorPrototypeKey];
|
||||||
// _resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -392,10 +503,14 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
|||||||
[aCoder encodeObject:_minWidth forKey:CPTableColumnMinWidthKey];
|
[aCoder encodeObject:_minWidth forKey:CPTableColumnMinWidthKey];
|
||||||
[aCoder encodeObject:_maxWidth forKey:CPTableColumnMaxWidthKey];
|
[aCoder encodeObject:_maxWidth forKey:CPTableColumnMaxWidthKey];
|
||||||
|
|
||||||
// [aCoder encodeObject:_headerView forKey:CPTableColumnHeaderViewKey];
|
[aCoder encodeObject:_headerView forKey:CPTableColumnHeaderViewKey];
|
||||||
// [aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
|
[aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
|
||||||
|
|
||||||
// [aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
|
[aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
|
||||||
|
[aCoder encodeBool:_isHidden forKey:CPTableColumnIsHiddenKey];
|
||||||
|
[aCoder encodeBool:_isEditable forKey:CPTableColumnIsEditableKey];
|
||||||
|
|
||||||
|
[aCoder encodeObject:_sortDescriptorPrototype forKey:CPSortDescriptorPrototypeKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+603
-63
@@ -20,126 +20,666 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@import <Foundation/CPIndexSet.j>
|
||||||
|
|
||||||
@import "CPTableColumn.j"
|
@import "CPTableColumn.j"
|
||||||
@import "CPTableView.j"
|
@import "CPTableView.j"
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
|
||||||
|
|
||||||
|
@implementation _CPTableColumnHeaderView : CPView
|
||||||
|
{
|
||||||
|
_CPImageAndTextView _textField;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPString)defaultThemeClass
|
||||||
|
{
|
||||||
|
return @"columnHeader";
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)themeAttributes
|
||||||
|
{
|
||||||
|
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null], CGInsetMakeZero(), [CPNull null], [CPNull null], [CPNull null], CGSizeMakeZero()]
|
||||||
|
forKeys:[@"background-color", @"text-alignment", @"text-inset", @"text-color", @"text-font", @"text-shadow-color", @"text-shadow-offset"]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)initWithFrame:(CGRect)frame
|
||||||
|
{
|
||||||
|
self = [super initWithFrame:frame];
|
||||||
|
if (self)
|
||||||
|
[self _init];
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_init
|
||||||
|
{
|
||||||
|
_textField = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
||||||
|
|
||||||
|
[_textField setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||||
|
|
||||||
|
[_textField setLineBreakMode:CPLineBreakByTruncatingTail];
|
||||||
|
[_textField setAlignment:CPLeftTextAlignment];
|
||||||
|
[_textField setVerticalAlignment:CPCenterVerticalTextAlignment];
|
||||||
|
|
||||||
|
[self addSubview:_textField];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)layoutSubviews
|
||||||
|
{
|
||||||
|
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
|
||||||
|
|
||||||
|
var inset = [self currentValueForThemeAttribute:@"text-inset"],
|
||||||
|
bounds = [self bounds];
|
||||||
|
|
||||||
|
[_textField setFrame:_CGRectMake(inset.right, inset.top, bounds.size.width - inset.right - inset.left, bounds.size.height - inset.top - inset.bottom)];
|
||||||
|
[_textField setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
|
||||||
|
[_textField setFont:[self currentValueForThemeAttribute:@"text-font"]];
|
||||||
|
[_textField setTextShadowColor:[self currentValueForThemeAttribute:@"text-shadow-color"]];
|
||||||
|
[_textField setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]];
|
||||||
|
[_textField setAlignment:[self currentValueForThemeAttribute:@"text-alignment"]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setStringValue:(CPString)string
|
||||||
|
{
|
||||||
|
[_textField setText:string];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)stringValue
|
||||||
|
{
|
||||||
|
return [_textField text];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)textField
|
||||||
|
{
|
||||||
|
return _textField;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sizeToFit
|
||||||
|
{
|
||||||
|
[_textField sizeToFit];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFont:(CPFont)aFont
|
||||||
|
{
|
||||||
|
[_textField setFont:aFont];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_setIndicatorImage:(CPImage)anImage
|
||||||
|
{
|
||||||
|
if (anImage)
|
||||||
|
{
|
||||||
|
[_textField setImage:anImage];
|
||||||
|
[_textField setImagePosition:CPImageRight];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[_textField setImagePosition:CPNoImage];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringValueKey",
|
||||||
|
_CPTableColumnHeaderViewFontKey = @"_CPTableColumnHeaderViewFontKey",
|
||||||
|
_CPTableColumnHeaderViewImageKey = @"_CPTableColumnHeaderViewImageKey";
|
||||||
|
|
||||||
|
@implementation _CPTableColumnHeaderView (CPCoding)
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
if (self = [super initWithCoder:aCoder])
|
||||||
|
{
|
||||||
|
[self _init];
|
||||||
|
[self _setIndicatorImage:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewImageKey]];
|
||||||
|
[self setStringValue:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewStringValueKey]];
|
||||||
|
[self setFont:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewFontKey]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
[super encodeWithCoder:aCoder];
|
||||||
|
|
||||||
|
[aCoder encodeObject:[_textField text] forKey:_CPTableColumnHeaderViewStringValueKey];
|
||||||
|
[aCoder encodeObject:[_textField image] forKey:_CPTableColumnHeaderViewImageKey];
|
||||||
|
[aCoder encodeObject:[_textField font] forKey:_CPTableColumnHeaderViewFontKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@implementation CPTableHeaderView : CPView
|
@implementation CPTableHeaderView : CPView
|
||||||
{
|
{
|
||||||
int _resizedColumn @accessors(readonly, property=resizedColumn);
|
CGPoint _mouseDownLocation;
|
||||||
int _draggedColumn @accessors(readonly, property=draggedColumn);
|
CGPoint _previousTrackingLocation;
|
||||||
|
int _activeColumn;
|
||||||
|
int _pressedColumn;
|
||||||
|
|
||||||
float _draggedDistance @accessors(readonly, property=draggedDistance);
|
BOOL _isResizing;
|
||||||
|
BOOL _isDragging;
|
||||||
|
BOOL _isTrackingColumn;
|
||||||
|
BOOL _drawsColumnLines;
|
||||||
|
|
||||||
|
float _columnOldWidth;
|
||||||
|
|
||||||
CPTableView _tableView @accessors(property=tableView);
|
CPTableView _tableView @accessors(property=tableView);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)initWithFrame:(CGRect)aFrame
|
+ (CPString)defaultThemeClass
|
||||||
|
{
|
||||||
|
return @"tableHeaderRow";
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)themeAttributes
|
||||||
|
{
|
||||||
|
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPColor grayColor]]
|
||||||
|
forKeys:[@"background-color", @"divider-color"]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_init
|
||||||
|
{
|
||||||
|
_mouseDownLocation = _CGPointMakeZero();
|
||||||
|
_previousTrackingLocation = _CGPointMakeZero();
|
||||||
|
_activeColumn = -1;
|
||||||
|
_pressedColumn = -1;
|
||||||
|
|
||||||
|
_isResizing = NO;
|
||||||
|
_isDragging = NO;
|
||||||
|
_isTrackingColumn = NO;
|
||||||
|
_drawsColumnLines = YES;
|
||||||
|
|
||||||
|
_columnOldWidth = 0.0;
|
||||||
|
|
||||||
|
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
{
|
{
|
||||||
self = [super initWithFrame:aFrame];
|
self = [super initWithFrame:aFrame];
|
||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
[self _init];
|
||||||
_resizedColumn = CPNotFound;
|
|
||||||
_draggedColumn = CPNotFound;
|
|
||||||
_draggedDistance = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)columnAtPoint:(CGPoint)aPoint
|
- (int)columnAtPoint:(CGPoint)aPoint
|
||||||
{
|
{
|
||||||
if (!CGRectContainsPoint([self bounds], aPoint))
|
return [_tableView columnAtPoint:CGPointMake(aPoint.x, aPoint.y)];
|
||||||
return CPNotFound;
|
|
||||||
|
|
||||||
// at this point, we can essentially ignore height, because all columns have equal heights
|
|
||||||
// and that height is equal to the height of our own bounds, which we know we are inside of
|
|
||||||
|
|
||||||
var index = 0,
|
|
||||||
count = [[_tableView tableColumns] count],
|
|
||||||
tableSpacing = [_tableView intercellSpacing],
|
|
||||||
tableColumns = [_tableView tableColumns],
|
|
||||||
leftOffset = 0,
|
|
||||||
pointX = aPoint.x;
|
|
||||||
|
|
||||||
for (; index < count; index++)
|
|
||||||
{
|
|
||||||
var width = [tableColumns[index] width] + tableSpacing.width;
|
|
||||||
|
|
||||||
if (pointX >= leftOffset && pointX < leftOffset + width)
|
|
||||||
return index;
|
|
||||||
|
|
||||||
leftOffset += width;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CPNotFound;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)headerRectOfColumn:(int)aColumnIndex
|
- (CGRect)headerRectOfColumn:(int)aColumnIndex
|
||||||
|
{
|
||||||
|
var headerRect = [self bounds],
|
||||||
|
columnRect = [_tableView rectOfColumn:aColumnIndex];
|
||||||
|
|
||||||
|
headerRect.origin.x = _CGRectGetMinX(columnRect);
|
||||||
|
headerRect.size.width = _CGRectGetWidth(columnRect);
|
||||||
|
|
||||||
|
return headerRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDrawsColumnLines:(BOOL)aFlag
|
||||||
|
{
|
||||||
|
_drawsColumnLines = aFlag;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)drawsColumnLines
|
||||||
|
{
|
||||||
|
return _drawsColumnLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)_cursorRectForColumn:(int)column
|
||||||
|
{
|
||||||
|
if (column == -1 || !([_tableView._tableColumns[column] resizingMask] & CPTableColumnUserResizingMask))
|
||||||
|
return _CGRectMakeZero();
|
||||||
|
|
||||||
|
var rect = [self headerRectOfColumn:column];
|
||||||
|
|
||||||
|
rect.origin.x = _CGRectGetMaxX(rect) - 5;
|
||||||
|
rect.size.width = 20;
|
||||||
|
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_setPressedColumn:(CPInteger)column
|
||||||
|
{
|
||||||
|
if (_pressedColumn != -1)
|
||||||
|
{
|
||||||
|
var headerView = [_tableView._tableColumns[_pressedColumn] headerView];
|
||||||
|
[headerView unsetThemeState:CPThemeStateHighlighted];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (column != -1)
|
||||||
|
{
|
||||||
|
var headerView = [_tableView._tableColumns[column] headerView];
|
||||||
|
[headerView setThemeState:CPThemeStateHighlighted];
|
||||||
|
}
|
||||||
|
|
||||||
|
_pressedColumn = column;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseDown:(CPEvent)theEvent
|
||||||
|
{
|
||||||
|
[self trackMouse:theEvent];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)trackMouse:(CPEvent)theEvent
|
||||||
|
{
|
||||||
|
var type = [theEvent type],
|
||||||
|
currentLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil];
|
||||||
|
|
||||||
|
// Take the right columns resize tracking area into account
|
||||||
|
currentLocation.x -= 5.0;
|
||||||
|
|
||||||
|
var columnIndex = [self columnAtPoint:currentLocation],
|
||||||
|
shouldResize = [self shouldResizeTableColumn:columnIndex at:_CGPointMake(currentLocation.x + 5.0, currentLocation.y)];
|
||||||
|
|
||||||
|
if (type === CPLeftMouseUp)
|
||||||
|
{
|
||||||
|
if (shouldResize)
|
||||||
|
[self stopResizingTableColumn:_activeColumn at:currentLocation];
|
||||||
|
else if ([self _shouldStopTrackingTableColumn:columnIndex at:currentLocation])
|
||||||
|
{
|
||||||
|
[_tableView _didClickTableColumn:columnIndex modifierFlags:[theEvent modifierFlags]];
|
||||||
|
[self stopTrackingTableColumn:columnIndex at:currentLocation];
|
||||||
|
|
||||||
|
_isTrackingColumn = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self _updateResizeCursor:[CPApp currentEvent]];
|
||||||
|
|
||||||
|
_activeColumn = CPNotFound;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === CPLeftMouseDown)
|
||||||
|
{
|
||||||
|
if (columnIndex === -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_mouseDownLocation = currentLocation;
|
||||||
|
_activeColumn = columnIndex;
|
||||||
|
|
||||||
|
[_tableView _sendDelegateDidMouseDownInHeader:columnIndex];
|
||||||
|
|
||||||
|
if (shouldResize)
|
||||||
|
[self startResizingTableColumn:columnIndex at:currentLocation];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[self startTrackingTableColumn:columnIndex at:currentLocation];
|
||||||
|
_isTrackingColumn = YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type === CPLeftMouseDragged)
|
||||||
|
{
|
||||||
|
if (shouldResize)
|
||||||
|
[self continueResizingTableColumn:_activeColumn at:currentLocation];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_activeColumn === columnIndex && _CGRectContainsPoint([self headerRectOfColumn:columnIndex], currentLocation))
|
||||||
|
{
|
||||||
|
if (_isTrackingColumn && _pressedColumn !== -1)
|
||||||
|
{
|
||||||
|
if (![self continueTrackingTableColumn:columnIndex at:currentLocation])
|
||||||
|
return; // Stop tracking the column, because it's being dragged
|
||||||
|
} else
|
||||||
|
[self startTrackingTableColumn:columnIndex at:currentLocation];
|
||||||
|
|
||||||
|
} else if (_isTrackingColumn && _pressedColumn !== -1)
|
||||||
|
[self stopTrackingTableColumn:_activeColumn at:currentLocation];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_previousTrackingLocation = currentLocation;
|
||||||
|
[CPApp setTarget:self selector:@selector(trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)startTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
[self _setPressedColumn:aColumnIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)continueTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
if ([self _shouldDragTableColumn:aColumnIndex at:aPoint])
|
||||||
|
{
|
||||||
|
var columnRect = [self headerRectOfColumn:aColumnIndex],
|
||||||
|
offset = _CGPointMakeZero(),
|
||||||
|
view = [_tableView _dragViewForColumn:aColumnIndex event:[CPApp currentEvent] offset:offset],
|
||||||
|
viewLocation = _CGPointMakeZero();
|
||||||
|
|
||||||
|
viewLocation.x = ( _CGRectGetMinX(columnRect) + offset.x ) + ( aPoint.x - _mouseDownLocation.x );
|
||||||
|
viewLocation.y = _CGRectGetMinY(columnRect) + offset.y;
|
||||||
|
|
||||||
|
[self dragView:view at:viewLocation offset:_CGSizeMakeZero() event:[CPApp currentEvent]
|
||||||
|
pasteboard:[CPPasteboard pasteboardWithName:CPDragPboard] source:self slideBack:YES];
|
||||||
|
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)_shouldStopTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
return _isTrackingColumn && _activeColumn === aColumnIndex &&
|
||||||
|
_CGRectContainsPoint([self headerRectOfColumn:aColumnIndex], aPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)stopTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
[self _setPressedColumn:CPNotFound];
|
||||||
|
[self _updateResizeCursor:[CPApp currentEvent]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)_shouldDragTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
return [_tableView allowsColumnReordering] && ABS(aPoint.x - _mouseDownLocation.x) >= 10.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)_headerRectOfLastVisibleColumn
|
||||||
{
|
{
|
||||||
var tableColumns = [_tableView tableColumns],
|
var tableColumns = [_tableView tableColumns],
|
||||||
tableSpacing = [_tableView intercellSpacing],
|
columnIndex = [tableColumns count];
|
||||||
bounds = [self bounds];
|
|
||||||
|
|
||||||
if (aColumnIndex < 0 || aColumnIndex > [tableColumns count])
|
while (columnIndex--)
|
||||||
[CPException raise:"invalid" reason:"tried to get headerRectOfColumn: on invalid column"];
|
{
|
||||||
|
var tableColumn = [tableColumns objectAtIndex:columnIndex];
|
||||||
|
|
||||||
bounds.size.width = [tableColumns[aColumnIndex] width] + tableSpacing.width;
|
if (![tableColumn isHidden])
|
||||||
|
return [self headerRectOfColumn:columnIndex];
|
||||||
|
}
|
||||||
|
|
||||||
while (--aColumnIndex >= 0)
|
return nil;
|
||||||
bounds.origin.x += [tableColumns[aColumnIndex] width] + tableSpacing.width;
|
}
|
||||||
|
|
||||||
return bounds;
|
- (void)_constrainDragView:(CPView)theDragView at:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
var tableColumns = [_tableView tableColumns],
|
||||||
|
lastColumnRect = [self _headerRectOfLastVisibleColumn],
|
||||||
|
activeColumnRect = [self headerRectOfColumn:_activeColumn],
|
||||||
|
dragWindow = [theDragView window],
|
||||||
|
frame = [dragWindow frame];
|
||||||
|
|
||||||
|
// Convert the frame origin from the global coordinate system to the windows' coordinate system
|
||||||
|
frame.origin = [[self window] convertGlobalToBase:frame.origin];
|
||||||
|
// the from the window to the view
|
||||||
|
frame.origin = [self convertPoint:frame.origin fromView:nil];
|
||||||
|
|
||||||
|
// This effectively clamps the value between the minimum and maximum
|
||||||
|
frame.origin.x = MAX(0.0, MIN(_CGRectGetMinX(frame), _CGRectGetMaxX(lastColumnRect) - _CGRectGetWidth(activeColumnRect)));
|
||||||
|
|
||||||
|
// Make sure the column cannot move vertically
|
||||||
|
frame.origin.y = _CGRectGetMinY(lastColumnRect);
|
||||||
|
|
||||||
|
// Convert the calculated origin back to the window coordinate system
|
||||||
|
frame.origin = [self convertPoint:frame.origin toView:nil];
|
||||||
|
// Then back to the global coordinate system
|
||||||
|
frame.origin = [[self window] convertBaseToGlobal:frame.origin];
|
||||||
|
|
||||||
|
[dragWindow setFrame:frame];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_moveColumn:(int)aFromIndex toColumn:(int)aToIndex
|
||||||
|
{
|
||||||
|
[_tableView moveColumn:aFromIndex toColumn:aToIndex];
|
||||||
|
_activeColumn = aToIndex;
|
||||||
|
_pressedColumn = _activeColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)draggedView:(CPView)aView beganAt:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
_isDragging = YES;
|
||||||
|
|
||||||
|
var column = [[_tableView tableColumns] objectAtIndex:_activeColumn];
|
||||||
|
|
||||||
|
[[column headerView] setHidden:YES];
|
||||||
|
[_tableView _setDraggedColumn:column];
|
||||||
|
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)draggedView:(CPView)aView movedTo:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
[self _constrainDragView:aView at:aPoint];
|
||||||
|
|
||||||
|
var dragWindow = [aView window],
|
||||||
|
dragWindowFrame = [dragWindow frame];
|
||||||
|
|
||||||
|
var hoverPoint = CGPointCreateCopy(aPoint);
|
||||||
|
|
||||||
|
if (aPoint.x < _previousTrackingLocation.x)
|
||||||
|
hoverPoint = _CGPointMake(_CGRectGetMinX(dragWindowFrame), _CGRectGetMinY(dragWindowFrame));
|
||||||
|
else if (aPoint.x > _previousTrackingLocation.x)
|
||||||
|
hoverPoint = _CGPointMake(_CGRectGetMaxX(dragWindowFrame), _CGRectGetMinY(dragWindowFrame));
|
||||||
|
|
||||||
|
// Convert the hover point from the global coordinate system to windows' coordinate system
|
||||||
|
hoverPoint = [[self window] convertGlobalToBase:hoverPoint];
|
||||||
|
// then to the view
|
||||||
|
hoverPoint = [self convertPoint:hoverPoint fromView:nil];
|
||||||
|
|
||||||
|
var hoveredColumn = [self columnAtPoint:hoverPoint];
|
||||||
|
|
||||||
|
if (hoveredColumn !== -1)
|
||||||
|
{
|
||||||
|
var columnRect = [self headerRectOfColumn:hoveredColumn],
|
||||||
|
columnCenterPoint = [self convertPoint:CGPointMake(_CGRectGetMidX(columnRect), _CGRectGetMidY(columnRect)) fromView:self];
|
||||||
|
if (hoveredColumn < _activeColumn && hoverPoint.x < columnCenterPoint.x)
|
||||||
|
[self _moveColumn:_activeColumn toColumn:hoveredColumn];
|
||||||
|
else if (hoveredColumn > _activeColumn && hoverPoint.x > columnCenterPoint.x)
|
||||||
|
[self _moveColumn:_activeColumn toColumn:hoveredColumn];
|
||||||
|
}
|
||||||
|
|
||||||
|
_previousTrackingLocation = aPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)draggedView:(CPImage)aView endedAt:(CGPoint)aLocation operation:(CPDragOperation)anOperation
|
||||||
|
{
|
||||||
|
_isDragging = NO;
|
||||||
|
_isTrackingColumn = NO; // We need to do this explicitly because the mouse up section of trackMouse is never reached
|
||||||
|
|
||||||
|
[_tableView _setDraggedColumn:nil];
|
||||||
|
[[[[_tableView tableColumns] objectAtIndex:_activeColumn] headerView] setHidden:NO];
|
||||||
|
[self stopTrackingTableColumn:_activeColumn at:aLocation];
|
||||||
|
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)shouldResizeTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
if (_isResizing)
|
||||||
|
return YES;
|
||||||
|
|
||||||
|
if (_isTrackingColumn)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
return [_tableView allowsColumnResizing] && _CGRectContainsPoint([self _cursorRectForColumn:aColumnIndex], aPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)startResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
_isResizing = YES;
|
||||||
|
|
||||||
|
var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex];
|
||||||
|
|
||||||
|
[tableColumn setDisableResizingPosting:YES];
|
||||||
|
[_tableView setDisableAutomaticResizing:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)continueResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex],
|
||||||
|
newWidth = [tableColumn width] + aPoint.x - _previousTrackingLocation.x;
|
||||||
|
|
||||||
|
if (newWidth < [tableColumn minWidth])
|
||||||
|
[[CPCursor resizeRightCursor] set];
|
||||||
|
else if (newWidth > [tableColumn maxWidth])
|
||||||
|
[[CPCursor resizeLeftCursor] set];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_tableView._lastColumnShouldSnap = NO;
|
||||||
|
[tableColumn setWidth:newWidth];
|
||||||
|
|
||||||
|
[[CPCursor resizeLeftRightCursor] set];
|
||||||
|
[self setNeedsLayout];
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)stopResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex];
|
||||||
|
[tableColumn _postDidResizeNotificationWithOldWidth:_columnOldWidth];
|
||||||
|
[tableColumn setDisableResizingPosting:NO];
|
||||||
|
[_tableView setDisableAutomaticResizing:NO];
|
||||||
|
|
||||||
|
_isResizing = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_updateResizeCursor:(CPEvent)theEvent
|
||||||
|
{
|
||||||
|
// never get stuck in resize cursor mode (FIXME take out when we turn on tracking rects)
|
||||||
|
if (![_tableView allowsColumnResizing] || ([theEvent type] === CPLeftMouseUp && ![[self window] acceptsMouseMovedEvents]))
|
||||||
|
{
|
||||||
|
[[CPCursor arrowCursor] set];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
|
||||||
|
mouseOverLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y),
|
||||||
|
overColumn = [self columnAtPoint:mouseOverLocation];
|
||||||
|
|
||||||
|
if (overColumn >= 0 && _CGRectContainsPoint([self _cursorRectForColumn:overColumn], mouseLocation))
|
||||||
|
{
|
||||||
|
var tableColumn = [[_tableView tableColumns] objectAtIndex:overColumn],
|
||||||
|
width = [tableColumn width];
|
||||||
|
|
||||||
|
if (width == [tableColumn minWidth])
|
||||||
|
[[CPCursor resizeRightCursor] set];
|
||||||
|
else if (width == [tableColumn maxWidth])
|
||||||
|
[[CPCursor resizeLeftCursor] set];
|
||||||
|
else
|
||||||
|
[[CPCursor resizeLeftRightCursor] set];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[[CPCursor arrowCursor] set];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseEntered:(CPEvent)theEvent
|
||||||
|
{
|
||||||
|
[self _updateResizeCursor:theEvent];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseMoved:(CPEvent)theEvent
|
||||||
|
{
|
||||||
|
[self _updateResizeCursor:theEvent];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseExited:(CPEvent)theEvent
|
||||||
|
{
|
||||||
|
// FIXME: we should use CPCursor push/pop (if previous currentCursor != arrow).
|
||||||
|
[[CPCursor arrowCursor] set];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)layoutSubviews
|
- (void)layoutSubviews
|
||||||
{
|
{
|
||||||
var tableColumns = [_tableView tableColumns],
|
var tableColumns = [_tableView tableColumns],
|
||||||
count = [tableColumns count],
|
count = [tableColumns count];
|
||||||
columnRect = [self bounds],
|
|
||||||
spacing = [_tableView intercellSpacing];
|
|
||||||
|
|
||||||
for (i = 0; i < count; ++i)
|
for (var i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
var column = [tableColumns objectAtIndex:i],
|
var column = [tableColumns objectAtIndex:i],
|
||||||
headerView = [column headerView];
|
headerView = [column headerView];
|
||||||
|
|
||||||
columnRect.size.width = [column width] + spacing.width;
|
var frame = [self headerRectOfColumn:i];
|
||||||
|
frame.size.height -= 0.5;
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
frame.origin.x += 0.5;
|
||||||
|
frame.size.width -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
[headerView setFrame:columnRect];
|
[headerView setFrame:frame];
|
||||||
|
|
||||||
columnRect.origin.x += [column width] + spacing.width;
|
|
||||||
|
|
||||||
|
if([headerView superview] != self)
|
||||||
[self addSubview:headerView];
|
[self addSubview:headerView];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)drawRect:(CGRect)aRect
|
- (void)drawRect:(CGRect)aRect
|
||||||
{
|
{
|
||||||
[[_tableView gridColor] setStroke];
|
if (!_tableView || ![self drawsColumnLines])
|
||||||
|
return;
|
||||||
|
|
||||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||||
exposedColumnIndexes = exposedColumnIndexes = [_tableView columnIndexesInRect:aRect],
|
exposedColumnIndexes = [_tableView columnIndexesInRect:aRect],
|
||||||
columnsArray = [];
|
columnsArray = [],
|
||||||
|
tableColumns = [_tableView tableColumns],
|
||||||
|
exposedTableColumns = _tableView._exposedColumns,
|
||||||
|
firstIndex = [exposedTableColumns firstIndex],
|
||||||
|
exposedRange = CPMakeRange(firstIndex, [exposedTableColumns lastIndex] - firstIndex + 1);
|
||||||
|
|
||||||
[exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:nil];
|
CGContextSetLineWidth(context, 1);
|
||||||
|
CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:@"divider-color"]);
|
||||||
|
|
||||||
|
[exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:exposedRange];
|
||||||
|
|
||||||
var columnArrayIndex = 0,
|
var columnArrayIndex = 0,
|
||||||
columnArrayCount = columnsArray.length;
|
columnArrayCount = columnsArray.length,
|
||||||
|
columnMaxX;
|
||||||
for(; columnArrayIndex < columnArrayCount; ++columnArrayIndex)
|
|
||||||
{
|
|
||||||
// grab each column rect and add horizontal lines
|
|
||||||
var columnToStroke = [self headerRectOfColumn:columnArrayIndex];
|
|
||||||
|
|
||||||
CGContextBeginPath(context);
|
CGContextBeginPath(context);
|
||||||
CGContextMoveToPoint(context, ROUND(columnToStroke.origin.x + columnToStroke.size.width) - 0.5, ROUND(columnToStroke.origin.y) - 0.5);
|
for(; columnArrayIndex < columnArrayCount; columnArrayIndex++)
|
||||||
CGContextAddLineToPoint(context, ROUND(columnToStroke.origin.x + columnToStroke.size.width) - 0.5, ROUND(columnToStroke.origin.y + columnToStroke.size.height) - 0.5);
|
{
|
||||||
CGContextSetLineWidth(context, 1);
|
// grab each column rect and add vertical lines
|
||||||
CGContextStrokePath(context);
|
var columnIndex = columnsArray[columnArrayIndex],
|
||||||
|
columnToStroke = [self headerRectOfColumn:columnIndex];
|
||||||
|
|
||||||
|
columnMaxX = _CGRectGetMaxX(columnToStroke);
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMinY(columnToStroke)));
|
||||||
|
CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMaxY(columnToStroke)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CGContextClosePath(context);
|
||||||
|
CGContextStrokePath(context);
|
||||||
|
|
||||||
|
/*if (_isDragging)
|
||||||
|
{
|
||||||
|
CGContextSetFillColor(context, [CPColor grayColor]);
|
||||||
|
CGContextFillRect(context, [self headerRectOfColumn:_activeColumn])
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey",
|
||||||
|
CPTableHeaderViewDrawsColumnLines = @"CPTableHeaderViewDrawsColumnLines";
|
||||||
|
|
||||||
|
@implementation CPTableHeaderView (CPCoding)
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
if (self = [super initWithCoder:aCoder])
|
||||||
|
{
|
||||||
|
[self _init];
|
||||||
|
_tableView = [aCoder decodeObjectForKey:CPTableHeaderViewTableViewKey];
|
||||||
|
_drawsColumnLines = [aCoder decodeBoolForKey:CPTableHeaderViewDrawsColumnLines];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
[super encodeWithCoder:aCoder];
|
||||||
|
[aCoder encodeObject:_tableView forKey:CPTableHeaderViewTableViewKey];
|
||||||
|
[aCoder encodeBool:_drawsColumnLines forKey:CPTableHeaderViewDrawsColumnLines];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+2304
-242
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* CPText.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Alexander Ljungberg.
|
||||||
|
* Copyright 2010, WireLoad, LLC.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
CPEnterCharacter = "\u0003";
|
||||||
|
CPBackspaceCharacter = "\u0008";
|
||||||
|
CPTabCharacter = "\u0009";
|
||||||
|
CPNewlineCharacter = "\u000a";
|
||||||
|
CPFormFeedCharacter = "\u000c";
|
||||||
|
CPCarriageReturnCharacter = "\u000d";
|
||||||
|
CPBackTabCharacter = "\u0019";
|
||||||
|
CPDeleteCharacter = "\u007f";
|
||||||
+342
-65
@@ -24,18 +24,8 @@
|
|||||||
@import "CPControl.j"
|
@import "CPControl.j"
|
||||||
@import "CPStringDrawing.j"
|
@import "CPStringDrawing.j"
|
||||||
@import "CPCompatibility.j"
|
@import "CPCompatibility.j"
|
||||||
|
@import "_CPImageAndTextView.j"
|
||||||
|
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
|
||||||
#include "Platform/Platform.h"
|
|
||||||
#include "Platform/DOM/CPDOMDisplayServer.h"
|
|
||||||
|
|
||||||
|
|
||||||
CPLineBreakByWordWrapping = 0;
|
|
||||||
CPLineBreakByCharWrapping = 1;
|
|
||||||
CPLineBreakByClipping = 2;
|
|
||||||
CPLineBreakByTruncatingHead = 3;
|
|
||||||
CPLineBreakByTruncatingTail = 4;
|
|
||||||
CPLineBreakByTruncatingMiddle = 5;
|
|
||||||
|
|
||||||
CPTextFieldSquareBezel = 0; /*! A textfield bezel with a squared corners. */
|
CPTextFieldSquareBezel = 0; /*! A textfield bezel with a squared corners. */
|
||||||
CPTextFieldRoundedBezel = 1; /*! A textfield bezel with rounded corners. */
|
CPTextFieldRoundedBezel = 1; /*! A textfield bezel with rounded corners. */
|
||||||
@@ -87,12 +77,15 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
BOOL _isEditable;
|
BOOL _isEditable;
|
||||||
BOOL _isSelectable;
|
BOOL _isSelectable;
|
||||||
BOOL _isSecure;
|
BOOL _isSecure;
|
||||||
|
BOOL _willBecomeFirstResponderByClick;
|
||||||
|
|
||||||
BOOL _drawsBackground;
|
BOOL _drawsBackground;
|
||||||
|
|
||||||
CPColor _textFieldBackgroundColor;
|
CPColor _textFieldBackgroundColor;
|
||||||
|
|
||||||
id _placeholderString;
|
id _placeholderString;
|
||||||
|
id _originalPlaceholderString;
|
||||||
|
BOOL _currentValueIsPlaceholder;
|
||||||
|
|
||||||
id _delegate;
|
id _delegate;
|
||||||
|
|
||||||
@@ -162,14 +155,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
return textField;
|
return textField;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPString)themeClass
|
+ (CPString)defaultThemeClass
|
||||||
{
|
{
|
||||||
return "textfield";
|
return "textfield";
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)themeAttributes
|
+ (id)themeAttributes
|
||||||
{
|
{
|
||||||
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMake(2.0, 2.0, 2.0, 2.0), nil]
|
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMake(2.0, 2.0, 2.0, 2.0), [CPNull null]]
|
||||||
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
|
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,11 +269,22 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
#pragma mark Controlling Editability and Selectability
|
#pragma mark Controlling Editability and Selectability
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether or not the receiver text field can be edited
|
Sets whether or not the receiver text field can be edited. If NO, any
|
||||||
|
ongoing edit is ended.
|
||||||
*/
|
*/
|
||||||
- (void)setEditable:(BOOL)shouldBeEditable
|
- (void)setEditable:(BOOL)shouldBeEditable
|
||||||
{
|
{
|
||||||
|
if (_isEditable === shouldBeEditable)
|
||||||
|
return;
|
||||||
|
|
||||||
_isEditable = shouldBeEditable;
|
_isEditable = shouldBeEditable;
|
||||||
|
|
||||||
|
if (shouldBeEditable)
|
||||||
|
_isSelectable = YES;
|
||||||
|
|
||||||
|
// We only allow first responder status if the field is editable and enabled.
|
||||||
|
if (!shouldBeEditable && [[self window] firstResponder] === self)
|
||||||
|
[[self window] makeFirstResponder:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -291,6 +295,19 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
return _isEditable;
|
return _isEditable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets whether the field reacts to events. If NO, any ongoing edit is
|
||||||
|
ended.
|
||||||
|
*/
|
||||||
|
- (void)setEnabled:(BOOL)shouldBeEnabled
|
||||||
|
{
|
||||||
|
[super setEnabled:shouldBeEnabled];
|
||||||
|
|
||||||
|
// We only allow first responder status if the field is editable and enabled.
|
||||||
|
if (!shouldBeEnabled && [[self window] firstResponder] === self)
|
||||||
|
[[self window] makeFirstResponder:nil];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether the field's text is selectable by the user.
|
Sets whether the field's text is selectable by the user.
|
||||||
@param aFlag \c YES makes the text selectable
|
@param aFlag \c YES makes the text selectable
|
||||||
@@ -490,6 +507,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
window.setTimeout(function()
|
window.setTimeout(function()
|
||||||
{
|
{
|
||||||
element.focus();
|
element.focus();
|
||||||
|
|
||||||
|
// Select the text if the textfield became first responder through keyboard interaction
|
||||||
|
if (!_willBecomeFirstResponderByClick)
|
||||||
|
[self selectText:self];
|
||||||
|
|
||||||
|
_willBecomeFirstResponderByClick = NO;
|
||||||
|
|
||||||
|
[self textDidFocus:[CPNotification notificationWithName:CPTextFieldDidFocusNotification object:self userInfo:nil]];
|
||||||
CPTextFieldInputOwner = self;
|
CPTextFieldInputOwner = self;
|
||||||
}, 0.0);
|
}, 0.0);
|
||||||
|
|
||||||
@@ -501,14 +526,12 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
|
|
||||||
if (document.attachEvent)
|
if (document.attachEvent)
|
||||||
{
|
{
|
||||||
CPTextFieldCachedSelectStartFunction = document.body.onselectstart;
|
CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart;
|
||||||
CPTextFieldCachedDragFunction = document.body.ondrag;
|
CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag;
|
||||||
|
|
||||||
document.body.ondrag = function () {};
|
[[self window] platformWindow]._DOMBodyElement.ondrag = function () {};
|
||||||
document.body.onselectstart = function () {};
|
[[self window] platformWindow]._DOMBodyElement.onselectstart = function () {};
|
||||||
}
|
}
|
||||||
|
|
||||||
[self textDidFocus:[CPNotification notificationWithName:CPTextFieldDidFocusNotification object:self userInfo:nil]];
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
@@ -527,7 +550,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
|
|
||||||
var element = [self _inputElement];
|
var element = [self _inputElement];
|
||||||
|
|
||||||
[self setObjectValue:element.value];
|
if ([self stringValue] !== element.value)
|
||||||
|
[self _setStringValue:element.value];
|
||||||
|
|
||||||
CPTextFieldInputResigning = YES;
|
CPTextFieldInputResigning = YES;
|
||||||
element.blur();
|
element.blur();
|
||||||
@@ -545,11 +569,11 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
|
|
||||||
if (document.attachEvent)
|
if (document.attachEvent)
|
||||||
{
|
{
|
||||||
|
[[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
|
||||||
|
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
|
||||||
|
|
||||||
CPTextFieldCachedSelectStartFunction = nil;
|
CPTextFieldCachedSelectStartFunction = nil;
|
||||||
CPTextFieldCachedDragFunction = nil;
|
CPTextFieldCachedDragFunction = nil;
|
||||||
|
|
||||||
document.body.ondrag = CPTextFieldCachedDragFunction
|
|
||||||
document.body.onselectstart = CPTextFieldCachedSelectStartFunction
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -569,25 +593,62 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Text fields require panels to become key window, so this returns \c YES.
|
||||||
|
*/
|
||||||
|
- (BOOL)needsPanelToBecomeKey
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)mouseDown:(CPEvent)anEvent
|
- (void)mouseDown:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
// Don't track! (ever?)
|
// Don't track! (ever?)
|
||||||
if ([self isEditable] && [self isEnabled])
|
if ([self isEditable] && [self isEnabled])
|
||||||
return [[self window] makeFirstResponder:self];
|
{
|
||||||
|
_willBecomeFirstResponderByClick = YES;
|
||||||
|
[[self window] makeFirstResponder:self];
|
||||||
|
}
|
||||||
|
else if ([self isSelectable])
|
||||||
|
{
|
||||||
|
if (document.attachEvent)
|
||||||
|
{
|
||||||
|
CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart;
|
||||||
|
CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag;
|
||||||
|
|
||||||
|
[[self window] platformWindow]._DOMBodyElement.ondrag = function () {};
|
||||||
|
[[self window] platformWindow]._DOMBodyElement.onselectstart = function () {};
|
||||||
|
}
|
||||||
|
return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return [[self nextResponder] mouseDown:anEvent];
|
return [[self nextResponder] mouseDown:anEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseUp:(CPEvent)anEvent
|
- (void)mouseUp:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
if (![self isEditable] || ![self isEnabled])
|
if (![self isSelectable] && (![self isEditable] || ![self isEnabled]))
|
||||||
[[self nextResponder] mouseUp:anEvent];
|
[[self nextResponder] mouseUp:anEvent];
|
||||||
|
else if ([self isSelectable])
|
||||||
|
{
|
||||||
|
if (document.attachEvent)
|
||||||
|
{
|
||||||
|
[[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
|
||||||
|
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
|
||||||
|
|
||||||
|
CPTextFieldCachedSelectStartFunction = nil
|
||||||
|
CPTextFieldCachedDragFunction = nil;
|
||||||
|
}
|
||||||
|
return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseDragged:(CPEvent)anEvent
|
- (void)mouseDragged:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
if (![self isEditable] || ![self isEnabled])
|
if (![self isSelectable] && (![self isEditable] || ![self isEnabled]))
|
||||||
[[self nextResponder] mouseDragged:anEvent];
|
[[self nextResponder] mouseDragged:anEvent];
|
||||||
|
else if ([self isSelectable])
|
||||||
|
return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)keyUp:(CPEvent)anEvent
|
- (void)keyUp:(CPEvent)anEvent
|
||||||
@@ -624,25 +685,12 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
|
|
||||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
|
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
|
||||||
}
|
}
|
||||||
else if ([anEvent keyCode] === CPTabKeyCode)
|
|
||||||
{
|
|
||||||
if ([anEvent modifierFlags] & CPShiftKeyMask)
|
|
||||||
[[self window] selectPreviousKeyView:self];
|
|
||||||
else
|
|
||||||
[[self window] selectNextKeyView:self];
|
|
||||||
|
|
||||||
if ([[[self window] firstResponder] respondsToSelector:@selector(selectText:)])
|
|
||||||
[[[self window] firstResponder] selectText:self];
|
|
||||||
|
|
||||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||||
|
|
||||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)textDidBlur:(CPNotification)note
|
- (void)textDidBlur:(CPNotification)note
|
||||||
{
|
{
|
||||||
// this looks to prevent false propagation of notifications for other objects
|
// this looks to prevent false propagation of notifications for other objects
|
||||||
@@ -661,6 +709,15 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
[[CPNotificationCenter defaultCenter] postNotification:note];
|
[[CPNotificationCenter defaultCenter] postNotification:note];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)sendAction:(SEL)anAction to:(id)anObject
|
||||||
|
{
|
||||||
|
// Don't reverse set our empty value
|
||||||
|
if (!_currentValueIsPlaceholder)
|
||||||
|
[self _reverseSetBinding];
|
||||||
|
|
||||||
|
[CPApp sendAction:anAction to:anObject from:self];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the string the text field.
|
Returns the string the text field.
|
||||||
*/
|
*/
|
||||||
@@ -685,7 +742,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
[super setObjectValue:aValue];
|
[super setObjectValue:aValue];
|
||||||
|
|
||||||
#if PLATFORM(DOM)
|
#if PLATFORM(DOM)
|
||||||
if (CPTextFieldInputOwner === self)
|
|
||||||
|
if (CPTextFieldInputOwner === self || [[self window] firstResponder] === self)
|
||||||
[self _inputElement].value = aValue;
|
[self _inputElement].value = aValue;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -729,43 +787,101 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
return _placeholderString;
|
return _placeholderString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)_setCurrentValueIsPlaceholder:(BOOL)isPlaceholder
|
||||||
|
{
|
||||||
|
// The initial _currentValueIsPlaceholder is null so convert it to NO for comparison purposes.
|
||||||
|
if (!!_currentValueIsPlaceholder === isPlaceholder)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (isPlaceholder)
|
||||||
|
{
|
||||||
|
// Save the original placeholder value so we can restore it later
|
||||||
|
// Only do this if the placeholder is not already overridden because the bindings logic might call this method
|
||||||
|
// several times and we don't want the bindings placeholder to ever become the original placeholder
|
||||||
|
if (!_currentValueIsPlaceholder)
|
||||||
|
_originalPlaceholderString = [self placeholderString];
|
||||||
|
|
||||||
|
// Set the current string value as the current placeholder and clear the string value
|
||||||
|
[self setPlaceholderString:[self stringValue]];
|
||||||
|
[self setStringValue:@""];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Restore the original placeholder, the actual textfield value is already correct
|
||||||
|
// because it was set using setValue:forKey:
|
||||||
|
[self setPlaceholderString:_originalPlaceholderString];
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentValueIsPlaceholder = isPlaceholder;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Size to fit has two behavior, depending on if the receiver is an editable text field or not.
|
For non-bezeled text fields (typically a label), sizeToFit has two behaviors, depending
|
||||||
|
on the line break mode of the receiver.
|
||||||
|
|
||||||
For non-editable text fields (typically, a label), sizeToFit will change the frame of the
|
For non-bezeled receivers with a non-wrapping line break mode, sizeToFit will change the frame of the
|
||||||
receiver to perfectly fit the current text in stringValue in the current font, and respecting
|
receiver to perfectly fit the current text in stringValue in the current font, respecting
|
||||||
the current theme values for content-inset, min-size, and max-size.
|
the current theme value for content-inset. For receivers with a wrapping line break mode,
|
||||||
|
sizeToFit will wrap the text within the current width (respecting the current content-inset),
|
||||||
|
so it will ONLY change the HEIGHT.
|
||||||
|
|
||||||
For editable text fields, sizeToFit will ONLY change the HEIGHT of the text field. It will not
|
For bezeled text fields (typically editable fields), sizeToFit will ONLY change the HEIGHT
|
||||||
change the width of the text field. You can use setFrameSize: with the current height to set the
|
of the text field. It will not change the width of the text field. sizeToFit will attempt to
|
||||||
width, and you can get the size of a string with [CPString sizeWithFont:].
|
change the height to fit a single line of text, respecting the current theme values for min-size,
|
||||||
|
max-size and content-inset.
|
||||||
|
|
||||||
The logic behind this decision is that most of the time you do not know what content will be placed
|
The logic behind this decision is that most of the time you do not know what content will be placed
|
||||||
in an editable text field, so you want to just choose a fixed width and leave it at that size.
|
in a bezeled text field, so you want to just choose a fixed width and leave it at that size.
|
||||||
However, since you don't know how tall it needs to be if you change the font, sizeToFit will still be
|
However, since you don't know how tall it needs to be if you change the font, sizeToFit will still be
|
||||||
useful for making the textfield an appropriate height.
|
useful for making the textfield an appropriate height.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
- (void)sizeToFit
|
- (void)sizeToFit
|
||||||
{
|
{
|
||||||
var size = [([self stringValue] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]],
|
[self setFrameSize:[self _minimumFrameSize]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGSize)_minimumFrameSize
|
||||||
|
{
|
||||||
|
var frameSize = [self frameSize],
|
||||||
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
|
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||||
minSize = [self currentValueForThemeAttribute:@"min-size"],
|
minSize = [self currentValueForThemeAttribute:@"min-size"],
|
||||||
maxSize = [self currentValueForThemeAttribute:@"max-size"];
|
maxSize = [self currentValueForThemeAttribute:@"max-size"],
|
||||||
|
lineBreakMode = [self lineBreakMode],
|
||||||
|
text = ([self stringValue] || @" "),
|
||||||
|
textSize = _CGSizeMakeCopy(frameSize),
|
||||||
|
font = [self currentValueForThemeAttribute:@"font"];
|
||||||
|
|
||||||
size.width = MAX(size.width + contentInset.left + contentInset.right, minSize.width);
|
textSize.width -= contentInset.left + contentInset.right;
|
||||||
size.height = MAX(size.height + contentInset.top + contentInset.bottom, minSize.height);
|
textSize.height -= contentInset.top + contentInset.bottom;
|
||||||
|
|
||||||
if (maxSize.width >= 0.0)
|
if (frameSize.width !== 0 &&
|
||||||
size.width = MIN(size.width, maxSize.width);
|
![self isBezeled] &&
|
||||||
|
(lineBreakMode === CPLineBreakByWordWrapping || lineBreakMode === CPLineBreakByCharWrapping))
|
||||||
|
{
|
||||||
|
textSize = [text sizeWithFont:font inWidth:textSize.width];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
textSize = [text sizeWithFont:font];
|
||||||
|
|
||||||
if (maxSize.height >= 0.0)
|
frameSize.height = textSize.height + contentInset.top + contentInset.bottom;
|
||||||
size.height = MIN(size.height, maxSize.height);
|
|
||||||
|
|
||||||
if ([self isEditable])
|
if ([self isBezeled])
|
||||||
size.width = CGRectGetWidth([self frame]);
|
{
|
||||||
|
frameSize.height = MAX(frameSize.height, minSize.height);
|
||||||
|
|
||||||
[self setFrameSize:size];
|
if (maxSize.width > 0.0)
|
||||||
|
frameSize.width = MIN(frameSize.width, maxSize.width);
|
||||||
|
|
||||||
|
if (maxSize.height > 0.0)
|
||||||
|
frameSize.height = MIN(frameSize.height, maxSize.height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
frameSize.width = textSize.width + contentInset.left + contentInset.right;
|
||||||
|
|
||||||
|
frameSize.width = MAX(frameSize.width, minSize.width);
|
||||||
|
|
||||||
|
return frameSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -780,20 +896,144 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
{
|
{
|
||||||
if ([[self window] firstResponder] === self)
|
if ([[self window] firstResponder] === self)
|
||||||
window.setTimeout(function() { element.select(); }, 0);
|
window.setTimeout(function() { element.select(); }, 0);
|
||||||
else
|
else if ([self window] !== nil && [[self window] makeFirstResponder:self])
|
||||||
{
|
|
||||||
[[self window] makeFirstResponder:self];
|
|
||||||
window.setTimeout(function() {[self selectText:sender];}, 0);
|
window.setTimeout(function() {[self selectText:sender];}, 0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)copy:(id)sender
|
||||||
|
{
|
||||||
|
if (![CPPlatform isBrowser])
|
||||||
|
{
|
||||||
|
var selectedRange = [self selectedRange];
|
||||||
|
|
||||||
|
if (selectedRange.length < 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var pasteboard = [CPPasteboard generalPasteboard],
|
||||||
|
stringValue = [self stringValue],
|
||||||
|
stringForPasting = [stringValue substringWithRange:selectedRange];
|
||||||
|
|
||||||
|
[pasteboard declareTypes:[CPStringPboardType] owner:nil];
|
||||||
|
[pasteboard setString:stringForPasting forType:CPStringPboardType];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)cut:(id)sender
|
||||||
|
{
|
||||||
|
if (![CPPlatform isBrowser])
|
||||||
|
{
|
||||||
|
[self copy:sender];
|
||||||
|
[self deleteBackward:sender];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)paste:(id)sender
|
||||||
|
{
|
||||||
|
if (![CPPlatform isBrowser])
|
||||||
|
{
|
||||||
|
var pasteboard = [CPPasteboard generalPasteboard];
|
||||||
|
|
||||||
|
if (![[pasteboard types] containsObject:CPStringPboardType])
|
||||||
|
return;
|
||||||
|
|
||||||
|
[self deleteBackward:sender];
|
||||||
|
|
||||||
|
var selectedRange = [self selectedRange],
|
||||||
|
stringValue = [self stringValue],
|
||||||
|
pasteString = [pasteboard stringForType:CPStringPboardType],
|
||||||
|
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
|
||||||
|
|
||||||
|
[self setStringValue:newValue];
|
||||||
|
[self setSelectedRange:CPMakeRange(selectedRange.location + pasteString.length, 0)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPRange)selectedRange
|
||||||
|
{
|
||||||
|
if ([[self window] firstResponder] !== self)
|
||||||
|
return CPMakeRange(0, 0);
|
||||||
|
|
||||||
|
// we wrap this in try catch because firefox will throw an exception in certain instances
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var inputElement = [self _inputElement],
|
||||||
|
selectionStart = inputElement.selectionStart,
|
||||||
|
selectionEnd = inputElement.selectionEnd;
|
||||||
|
|
||||||
|
if ([selectionStart isKindOfClass:CPNumber])
|
||||||
|
return CPMakeRange(selectionStart, selectionEnd - selectionStart);
|
||||||
|
|
||||||
|
// browsers which don't support selectionStart/selectionEnd (aka IE).
|
||||||
|
var theDocument = inputElement.ownerDocument || inputElement.document,
|
||||||
|
selectionRange = theDocument.selection.createRange(),
|
||||||
|
range = inputElement.createTextRange();
|
||||||
|
|
||||||
|
if (range.inRange(selectionRange))
|
||||||
|
{
|
||||||
|
range.setEndPoint('EndToStart', selectionRange);
|
||||||
|
return CPMakeRange(range.text.length, selectionRange.text.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e)
|
||||||
|
{
|
||||||
|
// fall through to the return
|
||||||
|
}
|
||||||
|
|
||||||
|
return CGMakeRange(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setSelectedRange:(CPRange)aRange
|
||||||
|
{
|
||||||
|
if (![[self window] firstResponder] === self)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var inputElement = [self _inputElement];
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if ([inputElement.selectionStart isKindOfClass:CPNumber])
|
||||||
|
{
|
||||||
|
inputElement.selectionStart = aRange.location;
|
||||||
|
inputElement.selectionEnd = CPMaxRange(aRange);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// browsers which don't support selectionStart/selectionEnd (aka IE).
|
||||||
|
var theDocument = inputElement.ownerDocument || inputElement.document,
|
||||||
|
existingRange = theDocument.selection.createRange(),
|
||||||
|
range = inputElement.createTextRange();
|
||||||
|
|
||||||
|
if (range.inRange(existingRange))
|
||||||
|
{
|
||||||
|
range.collapse(true);
|
||||||
|
range.move('character', aRange.location);
|
||||||
|
range.moveEnd('character', aRange.length);
|
||||||
|
range.select();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)selectAll:(id)sender
|
- (void)selectAll:(id)sender
|
||||||
{
|
{
|
||||||
[self selectText:sender];
|
[self selectText:sender];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)deleteBackward:(id)sender
|
||||||
|
{
|
||||||
|
var selectedRange = [self selectedRange],
|
||||||
|
stringValue = [self stringValue],
|
||||||
|
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
|
||||||
|
|
||||||
|
[self setStringValue:newValue];
|
||||||
|
[self setSelectedRange:CPMakeRange(selectedRange.location, 0)];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark Setting the Delegate
|
#pragma mark Setting the Delegate
|
||||||
|
|
||||||
- (void)setDelegate:(id)aDelegate
|
- (void)setDelegate:(id)aDelegate
|
||||||
@@ -869,7 +1109,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
return bounds;
|
return bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)bezelRectForBounds:(CFRect)bounds
|
- (CGRect)bezelRectForBounds:(CGRect)bounds
|
||||||
{
|
{
|
||||||
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
|
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
|
||||||
|
|
||||||
@@ -910,6 +1150,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
var view = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
var view = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
||||||
//[view setImagePosition:CPNoImage];
|
//[view setImagePosition:CPNoImage];
|
||||||
|
|
||||||
|
[view setHitTests:NO];
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -957,6 +1199,22 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)takeValueFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
|
||||||
|
{
|
||||||
|
var count = objects.length,
|
||||||
|
value = [objects[0] valueForKeyPath:aKeyPath];
|
||||||
|
|
||||||
|
[self setStringValue:value];
|
||||||
|
[self setPlaceholderString:@""];
|
||||||
|
|
||||||
|
while (count-- > 1)
|
||||||
|
if (value !== [objects[count] valueForKeyPath:aKeyPath])
|
||||||
|
{
|
||||||
|
[self setPlaceholderString:@"Multiple Values"];
|
||||||
|
[self setStringValue:@""];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var secureStringForString = function(aString)
|
var secureStringForString = function(aString)
|
||||||
@@ -976,6 +1234,7 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
|
|||||||
CPTextFieldBezelStyleKey = "CPTextFieldBezelStyleKey",
|
CPTextFieldBezelStyleKey = "CPTextFieldBezelStyleKey",
|
||||||
CPTextFieldDrawsBackgroundKey = "CPTextFieldDrawsBackgroundKey",
|
CPTextFieldDrawsBackgroundKey = "CPTextFieldDrawsBackgroundKey",
|
||||||
CPTextFieldLineBreakModeKey = "CPTextFieldLineBreakModeKey",
|
CPTextFieldLineBreakModeKey = "CPTextFieldLineBreakModeKey",
|
||||||
|
CPTextFieldAlignmentKey = "CPTextFieldAlignmentKey",
|
||||||
CPTextFieldBackgroundColorKey = "CPTextFieldBackgroundColorKey",
|
CPTextFieldBackgroundColorKey = "CPTextFieldBackgroundColorKey",
|
||||||
CPTextFieldPlaceholderStringKey = "CPTextFieldPlaceholderStringKey";
|
CPTextFieldPlaceholderStringKey = "CPTextFieldPlaceholderStringKey";
|
||||||
|
|
||||||
@@ -999,7 +1258,22 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
|
|||||||
|
|
||||||
[self setTextFieldBackgroundColor:[aCoder decodeObjectForKey:CPTextFieldBackgroundColorKey]];
|
[self setTextFieldBackgroundColor:[aCoder decodeObjectForKey:CPTextFieldBackgroundColorKey]];
|
||||||
|
|
||||||
|
[self setLineBreakMode:[aCoder decodeIntForKey:CPTextFieldLineBreakModeKey]];
|
||||||
|
[self setAlignment:[aCoder decodeIntForKey:CPTextFieldAlignmentKey]];
|
||||||
|
|
||||||
[self setPlaceholderString:[aCoder decodeObjectForKey:CPTextFieldPlaceholderStringKey]];
|
[self setPlaceholderString:[aCoder decodeObjectForKey:CPTextFieldPlaceholderStringKey]];
|
||||||
|
|
||||||
|
// Make sure the frame is big enough
|
||||||
|
var minSize = [self _minimumFrameSize];
|
||||||
|
minSize.width = MAX(CGRectGetWidth([self frame]), minSize.width);
|
||||||
|
minSize.height = MAX(CGRectGetHeight([self frame]), minSize.height);
|
||||||
|
|
||||||
|
// Only size multiline bezeled textfields if it's to small to fit the content
|
||||||
|
if ([self isBezeled])
|
||||||
|
if ([self lineBreakMode] === CPLineBreakByCharWrapping || [self lineBreakMode] == CPLineBreakByWordWrapping)
|
||||||
|
minSize.height = MAX(CGRectGetHeight([self frame]), minSize.height);
|
||||||
|
|
||||||
|
[self setFrameSize:minSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -1020,6 +1294,9 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
|
|||||||
|
|
||||||
[aCoder encodeObject:_textFieldBackgroundColor forKey:CPTextFieldBackgroundColorKey];
|
[aCoder encodeObject:_textFieldBackgroundColor forKey:CPTextFieldBackgroundColorKey];
|
||||||
|
|
||||||
|
[aCoder encodeInt:[self lineBreakMode] forKey:CPTextFieldLineBreakModeKey];
|
||||||
|
[aCoder encodeInt:[self alignment] forKey:CPTextFieldAlignmentKey];
|
||||||
|
|
||||||
[aCoder encodeObject:_placeholderString forKey:CPTextFieldPlaceholderStringKey];
|
[aCoder encodeObject:_placeholderString forKey:CPTextFieldPlaceholderStringKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+177
-9
@@ -22,10 +22,12 @@
|
|||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
@import <Foundation/CPString.j>
|
@import <Foundation/CPString.j>
|
||||||
|
@import <Foundation/CPKeyedUnarchiver.j>
|
||||||
|
|
||||||
|
|
||||||
var CPThemesByName = { },
|
var CPThemesByName = { },
|
||||||
CPThemeDefaultTheme = nil;
|
CPThemeDefaultTheme = nil,
|
||||||
|
CPThemeDefaultHudTheme = nil;
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -48,6 +50,27 @@ var CPThemesByName = { },
|
|||||||
return CPThemeDefaultTheme;
|
return CPThemeDefaultTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the default HUD theme. If set to nil, the default described in defaultHudTheme
|
||||||
|
will be used.
|
||||||
|
*/
|
||||||
|
+ (void)setDefaultHudTheme:(CPTheme)aTheme
|
||||||
|
{
|
||||||
|
CPThemeDefaultHudTheme = aTheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
The default HUD theme is (sometimes) used for windows with the CPHUDBackgroundWindowMask
|
||||||
|
style mask. The default is theme with the name of the default theme with -HUD appended
|
||||||
|
at the end.
|
||||||
|
*/
|
||||||
|
+ (CPTheme)defaultHudTheme
|
||||||
|
{
|
||||||
|
if (!CPThemeDefaultHudTheme)
|
||||||
|
CPThemeDefaultHudTheme = [CPTheme themeNamed:[[self defaultTheme] name] + "-HUD"];
|
||||||
|
return CPThemeDefaultHudTheme;
|
||||||
|
}
|
||||||
|
|
||||||
+ (CPTheme)themeNamed:(CPString)aName
|
+ (CPTheme)themeNamed:(CPString)aName
|
||||||
{
|
{
|
||||||
return CPThemesByName[aName];
|
return CPThemesByName[aName];
|
||||||
@@ -73,9 +96,110 @@ var CPThemesByName = { },
|
|||||||
return _name;
|
return _name;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (_CPThemeAttribute)_attributeWithName:(CPString)aName forClass:(CPString)aClass
|
/*!
|
||||||
|
Returns an array of names of themed classes defined in this theme, as found in its
|
||||||
|
ThemeDescriptors.j file.
|
||||||
|
|
||||||
|
NOTE: The names are not class names (such as "CPButton"), but the names returned
|
||||||
|
by the class' +defaultThemeClass method. For example, the name for CPCheckBox is "check-box",
|
||||||
|
as defined in CPCheckBox::themeClass.
|
||||||
|
*/
|
||||||
|
- (CPArray)classNames
|
||||||
{
|
{
|
||||||
var attributes = [_attributes objectForKey:aClass];
|
return [_attributes allKeys];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns a dictionary of all theme attributes defined for the given class, as found in the
|
||||||
|
theme's ThemeDescriptors.j file. The keys of the dictionary are attribute names, and the values
|
||||||
|
are instances of _CPThemeAttribute.
|
||||||
|
|
||||||
|
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
|
||||||
|
|
||||||
|
@param aClass The themed class whose attributes you want to retrieve
|
||||||
|
@return A dictionary of attributes or nil
|
||||||
|
*/
|
||||||
|
- (CPDictionary)attributesForClass:(id)aClass
|
||||||
|
{
|
||||||
|
if (!aClass)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
var className = nil;
|
||||||
|
|
||||||
|
if ([aClass isKindOfClass:[CPString class]])
|
||||||
|
{
|
||||||
|
// See if it is a class name
|
||||||
|
var theClass = CPClassFromString(aClass);
|
||||||
|
|
||||||
|
if (theClass)
|
||||||
|
aClass = theClass;
|
||||||
|
else
|
||||||
|
className = aClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!className)
|
||||||
|
{
|
||||||
|
if ([aClass isKindOfClass:[CPView class]])
|
||||||
|
{
|
||||||
|
if ([aClass respondsToSelector:@selector(defaultThemeClass)])
|
||||||
|
className = [aClass defaultThemeClass];
|
||||||
|
else if ([aClass respondsToSelector:@selector(themeClass)])
|
||||||
|
{
|
||||||
|
CPLog.warn(@"%@ themeClass is deprecated in favor of defaultThemeClass",CPStringFromClass([anObject class]));
|
||||||
|
className = [aClass themeClass];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[CPException raise:CPInvalidArgumentException reason:@"aClass must be a class object or a string."];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [_attributes objectForKey:className];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns an array of names of all theme attributes defined for the given class, as found in the
|
||||||
|
theme's ThemeDescriptors.j file.
|
||||||
|
|
||||||
|
The \c aClass parameter can be one of the following:
|
||||||
|
|
||||||
|
- A class instance, for example the result of [CPCheckBox class]. The class must be a subclass
|
||||||
|
of CPView.
|
||||||
|
- A class name, for example "CPCheckBox".
|
||||||
|
- A themed class name, for example "check-box".
|
||||||
|
|
||||||
|
If \c aClass does not refer to a themed class in this theme, nil is returned.
|
||||||
|
|
||||||
|
@param aClass The themed class whose attributes you want to retrieve
|
||||||
|
@return An array of attribute names or nil
|
||||||
|
*/
|
||||||
|
- (CPDictionary)attributeNamesForClass:(id)aClass
|
||||||
|
{
|
||||||
|
var attributes = [self attributesForClass:aClass];
|
||||||
|
|
||||||
|
if (attributes)
|
||||||
|
return [attributes allKeys];
|
||||||
|
else
|
||||||
|
return [CPArray array];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns a theme attribute defined for the given class, as found in the
|
||||||
|
theme's ThemeDescriptors.j file.
|
||||||
|
|
||||||
|
\c aName should be the attribute name as you would pass to the method
|
||||||
|
CPView::valueForThemeAttribute:.
|
||||||
|
|
||||||
|
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
|
||||||
|
|
||||||
|
@param aName The name of the attribute you want to retrieve
|
||||||
|
@param aClass The themed class in which to look for the attribute
|
||||||
|
@return An instance of _CPThemeAttribute or nil
|
||||||
|
*/
|
||||||
|
- (_CPThemeAttribute)attributeWithName:(CPString)aName forClass:(id)aClass
|
||||||
|
{
|
||||||
|
var attributes = [self attributesForClass:aClass];
|
||||||
|
|
||||||
if (!attributes)
|
if (!attributes)
|
||||||
return nil;
|
return nil;
|
||||||
@@ -83,12 +207,53 @@ var CPThemesByName = { },
|
|||||||
return [attributes objectForKey:aName];
|
return [attributes objectForKey:aName];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the value for a theme attribute in its normal state, as defined for the given class
|
||||||
|
in the theme's ThemeDescriptors.j file.
|
||||||
|
|
||||||
|
\c aName should be the attribute name as you would pass to the method
|
||||||
|
CPView::valueForThemeAttribute:.
|
||||||
|
|
||||||
|
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
|
||||||
|
|
||||||
|
@param aName The name of the attribute whose value you want to retrieve
|
||||||
|
@param aClass The themed class in which to look for the attribute
|
||||||
|
@return A value or nil
|
||||||
|
*/
|
||||||
|
- (id)valueForAttributeWithName:(CPString)aName forClass:(id)aClass
|
||||||
|
{
|
||||||
|
return [self valueForAttributeWithName:aName inState:CPThemeStateNormal forClass:aClass];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the value for a theme attribute in a given state, as defined for the given class
|
||||||
|
in the theme's ThemeDescriptors.j file. This is the equivalent of the method
|
||||||
|
CPView::valueForThemeAttribute:inState:, but retrieves the value from the theme definition as
|
||||||
|
opposed to a single view's current theme state.
|
||||||
|
|
||||||
|
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
|
||||||
|
|
||||||
|
@param aName The name of the attribute whose value you want to retrieve
|
||||||
|
@param aState The state qualifier for the attribute
|
||||||
|
@param aClass The themed class in which to look for the attribute
|
||||||
|
@return A value or nil
|
||||||
|
*/
|
||||||
|
- (id)valueForAttributeWithName:(CPString)aName inState:(CPThemeState)aState forClass:(id)aClass
|
||||||
|
{
|
||||||
|
var attribute = [self attributeWithName:aName forClass:aClass];
|
||||||
|
|
||||||
|
if (!attribute)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
return [attribute valueForState:aState];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)takeThemeFromObject:(id)anObject
|
- (void)takeThemeFromObject:(id)anObject
|
||||||
{
|
{
|
||||||
var attributes = [anObject _themeAttributeDictionary],
|
var attributes = [anObject _themeAttributeDictionary],
|
||||||
attributeName = nil,
|
attributeName = nil,
|
||||||
attributeNames = [attributes keyEnumerator],
|
attributeNames = [attributes keyEnumerator],
|
||||||
objectThemeClass = [[anObject class] themeClass];
|
objectThemeClass = [anObject themeClass];
|
||||||
|
|
||||||
while (attributeName = [attributeNames nextObject])
|
while (attributeName = [attributeNames nextObject])
|
||||||
[self _recordAttribute:[attributes objectForKey:attributeName] forClass:objectThemeClass];
|
[self _recordAttribute:[attributes objectForKey:attributeName] forClass:objectThemeClass];
|
||||||
@@ -242,6 +407,9 @@ CPThemeStateNormal = CPThemeStates["normal"] = 0;
|
|||||||
CPThemeStateDisabled = CPThemeState("disabled");
|
CPThemeStateDisabled = CPThemeState("disabled");
|
||||||
CPThemeStateHighlighted = CPThemeState("highlighted");
|
CPThemeStateHighlighted = CPThemeState("highlighted");
|
||||||
CPThemeStateSelected = CPThemeState("selected");
|
CPThemeStateSelected = CPThemeState("selected");
|
||||||
|
CPThemeStateTableDataView = CPThemeState("tableDataView");
|
||||||
|
CPThemeStateSelectedDataView = CPThemeStateSelectedTableDataView = CPThemeState("selectedTableDataView");
|
||||||
|
CPThemeStateGroupRow = CPThemeState("CPThemeStateGroupRow");
|
||||||
CPThemeStateBezeled = CPThemeState("bezeled");
|
CPThemeStateBezeled = CPThemeState("bezeled");
|
||||||
CPThemeStateBordered = CPThemeState("bordered");
|
CPThemeStateBordered = CPThemeState("bordered");
|
||||||
CPThemeStateEditable = CPThemeState("editable");
|
CPThemeStateEditable = CPThemeState("editable");
|
||||||
@@ -254,10 +422,10 @@ CPThemeStateCircular = CPThemeState("circular");
|
|||||||
{
|
{
|
||||||
CPString _name;
|
CPString _name;
|
||||||
id _defaultValue;
|
id _defaultValue;
|
||||||
CPDictionary _values;
|
CPDictionary _values @accessors(readonly, getter=values);
|
||||||
|
|
||||||
JSObject _cache;
|
JSObject _cache;
|
||||||
CPThemeAttribute _parentAttribute;
|
_CPThemeAttribute _parentAttribute;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithName:(CPString)aName defaultValue:(id)aDefaultValue
|
- (id)initWithName:(CPString)aName defaultValue:(id)aDefaultValue
|
||||||
@@ -378,7 +546,7 @@ CPThemeStateCircular = CPThemeState("circular");
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setParentAttribute:(CPThemeAttribute)anAttribute
|
- (void)setParentAttribute:(_CPThemeAttribute)anAttribute
|
||||||
{
|
{
|
||||||
if (_parentAttribute === anAttribute)
|
if (_parentAttribute === anAttribute)
|
||||||
return;
|
return;
|
||||||
@@ -387,7 +555,7 @@ CPThemeStateCircular = CPThemeState("circular");
|
|||||||
_parentAttribute = anAttribute;
|
_parentAttribute = anAttribute;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
|
- (_CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
|
||||||
{
|
{
|
||||||
var mergedAttribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue];
|
var mergedAttribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue];
|
||||||
|
|
||||||
@@ -551,7 +719,7 @@ function CPThemeAttributeDecode(aCoder, anAttributeName, aDefaultValue, aTheme,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (aTheme && aClass)
|
if (aTheme && aClass)
|
||||||
[attribute setParentAttribute:[aTheme _attributeWithName:anAttributeName forClass:aClass]];
|
[attribute setParentAttribute:[aTheme attributeWithName:anAttributeName forClass:aClass]];
|
||||||
|
|
||||||
return attribute;
|
return attribute;
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-9
@@ -22,9 +22,10 @@
|
|||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
@import <AppKit/CPTheme.j>
|
@import "CPTheme.j"
|
||||||
@import <AppKit/_CPCibCustomResource.j>
|
@import "_CPCibCustomResource.j"
|
||||||
@import <AppKit/_CPCibKeyedUnarchiver.j>
|
@import "_CPCibKeyedUnarchiver.j"
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -33,7 +34,7 @@
|
|||||||
@implementation CPThemeBlend : CPObject
|
@implementation CPThemeBlend : CPObject
|
||||||
{
|
{
|
||||||
CPBundle _bundle;
|
CPBundle _bundle;
|
||||||
CPArray _themes @accessors(readonly, getter=themes);
|
CPArray _themes;
|
||||||
id _loadDelegate;
|
id _loadDelegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,12 +44,34 @@
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_bundle = [[CPBundle alloc] initWithPath:aURL + "/Info.plist"];
|
_bundle = [[CPBundle alloc] initWithPath:aURL];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns an array of names of the keyed theme archives that make up this blend.
|
||||||
|
Each item in the array will have the extension ".keyedtheme".
|
||||||
|
*/
|
||||||
|
- (CPArray)themes
|
||||||
|
{
|
||||||
|
return _themes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns an array of names of the themes that make up this blend.
|
||||||
|
*/
|
||||||
|
- (CPArray)themeNames
|
||||||
|
{
|
||||||
|
var names = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < _themes.length; ++i)
|
||||||
|
names.push(_themes[i].substring(0, _themes[i].indexOf(".keyedtheme")));
|
||||||
|
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)loadWithDelegate:(id)aDelegate
|
- (void)loadWithDelegate:(id)aDelegate
|
||||||
{
|
{
|
||||||
_loadDelegate = aDelegate;
|
_loadDelegate = aDelegate;
|
||||||
@@ -58,14 +81,15 @@
|
|||||||
|
|
||||||
- (void)bundleDidFinishLoading:(CPBundle)aBundle
|
- (void)bundleDidFinishLoading:(CPBundle)aBundle
|
||||||
{
|
{
|
||||||
var themes = [_bundle objectForInfoDictionaryKey:@"CPKeyedThemes"],
|
_themes = [_bundle objectForInfoDictionaryKey:@"CPKeyedThemes"];
|
||||||
count = themes.length;
|
|
||||||
|
var count = _themes.length;
|
||||||
|
|
||||||
while (count--)
|
while (count--)
|
||||||
{
|
{
|
||||||
var path = [aBundle pathForResource:themes[count]],
|
var path = [aBundle pathForResource:_themes[count]],
|
||||||
unarchiver = [[_CPThemeKeyedUnarchiver alloc]
|
unarchiver = [[_CPThemeKeyedUnarchiver alloc]
|
||||||
initForReadingWithData:[CPData dataWithString:objj_files[path].contents]
|
initForReadingWithData:[[CPURL URLWithString:path] staticResourceData]
|
||||||
bundle:_bundle];
|
bundle:_bundle];
|
||||||
|
|
||||||
[unarchiver decodeObjectForKey:@"root"];
|
[unarchiver decodeObjectForKey:@"root"];
|
||||||
|
|||||||
Executable
+1250
File diff suppressed because it is too large
Load Diff
+130
-38
@@ -28,8 +28,6 @@
|
|||||||
@import "CPPopUpButton.j"
|
@import "CPPopUpButton.j"
|
||||||
@import "CPToolbarItem.j"
|
@import "CPToolbarItem.j"
|
||||||
|
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@global
|
@global
|
||||||
@@ -220,7 +218,7 @@ var CPToolbarConfigurationsByIdentifier = nil;
|
|||||||
*/
|
*/
|
||||||
- (void)setDelegate:(id)aDelegate
|
- (void)setDelegate:(id)aDelegate
|
||||||
{
|
{
|
||||||
if (_delegate == aDelegate)
|
if (_delegate === aDelegate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_delegate = aDelegate;
|
_delegate = aDelegate;
|
||||||
@@ -252,34 +250,45 @@ var CPToolbarConfigurationsByIdentifier = nil;
|
|||||||
/* @ignore */
|
/* @ignore */
|
||||||
- (void)_reloadToolbarItems
|
- (void)_reloadToolbarItems
|
||||||
{
|
{
|
||||||
if (!_delegate)
|
// As of OS X 10.5 (Leopard), toolbar items can be set in IB and a
|
||||||
return;
|
// toolbar delegate is optional. Toolbar items can be combined from
|
||||||
|
// both IB and a delegate (see Apple's NSToolbar guide for IB, for more details).
|
||||||
|
|
||||||
var count = [_itemIdentifiers count];
|
// _defaultItems may have been loaded from Cib
|
||||||
|
_itemIdentifiers = [_defaultItems valueForKey:@"itemIdentifier"] || [];
|
||||||
|
|
||||||
if (!count)
|
if (_delegate)
|
||||||
{
|
{
|
||||||
_itemIdentifiers = [[_delegate toolbarDefaultItemIdentifiers:self] mutableCopy];
|
var itemIdentifiersFromDelegate = [[_delegate toolbarDefaultItemIdentifiers:self] mutableCopy];
|
||||||
count = [_itemIdentifiers count];
|
|
||||||
|
if (itemIdentifiersFromDelegate)
|
||||||
|
_itemIdentifiers = [_itemIdentifiers arrayByAddingObjectsFromArray:itemIdentifiersFromDelegate];
|
||||||
}
|
}
|
||||||
|
|
||||||
_items = [];
|
var index = 0,
|
||||||
|
count = [_itemIdentifiers count];
|
||||||
|
|
||||||
var index = 0;
|
_items = [];
|
||||||
|
|
||||||
for (; index < count; ++index)
|
for (; index < count; ++index)
|
||||||
{
|
{
|
||||||
var identifier = _itemIdentifiers[index],
|
var identifier = _itemIdentifiers[index],
|
||||||
item = [CPToolbarItem _standardItemWithItemIdentifier:identifier];
|
item = [CPToolbarItem _standardItemWithItemIdentifier:identifier];
|
||||||
|
|
||||||
|
// May come from a Cib.
|
||||||
if (!item)
|
if (!item)
|
||||||
|
item = [_identifiedItems objectForKey:identifier];
|
||||||
|
|
||||||
|
if (!item && _delegate)
|
||||||
item = [_delegate toolbar:self itemForItemIdentifier:identifier willBeInsertedIntoToolbar:YES];
|
item = [_delegate toolbar:self itemForItemIdentifier:identifier willBeInsertedIntoToolbar:YES];
|
||||||
|
|
||||||
item = [item copy];
|
item = [item copy];
|
||||||
|
|
||||||
if (item == nil)
|
if (item === nil)
|
||||||
[CPException raise:CPInvalidArgumentException
|
[CPException raise:CPInvalidArgumentException
|
||||||
reason:sprintf(@"_delegate %s returned nil toolbar item returned for identifier %s", _delegate, identifier)];
|
reason:@"Toolbar delegate " + _delegate + " returned nil toolbar item for identifier \"" + identifier + "\""];
|
||||||
|
|
||||||
|
item._toolbar = self;
|
||||||
|
|
||||||
[_items addObject:item];
|
[_items addObject:item];
|
||||||
}
|
}
|
||||||
@@ -318,7 +327,11 @@ var CPToolbarConfigurationsByIdentifier = nil;
|
|||||||
return _itemsSortedByVisibilityPriority;
|
return _itemsSortedByVisibilityPriority;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)validateVisibleToolbarItems
|
/*!
|
||||||
|
Validates the visible toolbar items by sending a validate message to
|
||||||
|
each visible toolbar item.
|
||||||
|
*/
|
||||||
|
- (void)validateVisibleItems
|
||||||
{
|
{
|
||||||
var toolbarItems = [self visibleItems],
|
var toolbarItems = [self visibleItems],
|
||||||
count = [toolbarItems count];
|
count = [toolbarItems count];
|
||||||
@@ -339,7 +352,7 @@ var CPToolbarConfigurationsByIdentifier = nil;
|
|||||||
item = [[_delegate toolbar:self itemForItemIdentifier:identifier willBeInsertedIntoToolbar:toolbar] copy];
|
item = [[_delegate toolbar:self itemForItemIdentifier:identifier willBeInsertedIntoToolbar:toolbar] copy];
|
||||||
if (!item)
|
if (!item)
|
||||||
[CPException raise:CPInvalidArgumentException
|
[CPException raise:CPInvalidArgumentException
|
||||||
reason:sprintf(@"_delegate %s returned nil toolbar item returned for identifier %s", _delegate, identifier)];
|
reason:@"Toolbar delegate " + _delegate + " returned nil toolbar item for identifier " + identifier];
|
||||||
}
|
}
|
||||||
|
|
||||||
[_identifiedItems setObject:item forKey:identifier];
|
[_identifiedItems setObject:item forKey:identifier];
|
||||||
@@ -361,26 +374,60 @@ var CPToolbarConfigurationsByIdentifier = nil;
|
|||||||
/* @ignore */
|
/* @ignore */
|
||||||
- (id)_defaultToolbarItems
|
- (id)_defaultToolbarItems
|
||||||
{
|
{
|
||||||
if (!_defaultItems)
|
if (!_defaultItems && [_delegate respondsToSelector:@selector(toolbarDefaultItemIdentifiers:)])
|
||||||
if ([_delegate respondsToSelector:@selector(toolbarDefaultItemIdentifiers:)])
|
{
|
||||||
_defaultItems = [self _itemsWithIdentifiers:[_delegate toolbarDefaultItemIdentifiers:self]];
|
_defaultItems = [];
|
||||||
|
|
||||||
|
var identifiers = [_delegate toolbarDefaultItemIdentifiers:self],
|
||||||
|
index = 0,
|
||||||
|
count = [identifiers count];
|
||||||
|
|
||||||
|
for (; index < count; ++index)
|
||||||
|
[_defaultItems addObject:[self _itemForItemIdentifier:identifiers[index] willBeInsertedIntoToolbar:NO]];
|
||||||
|
}
|
||||||
|
|
||||||
return _defaultItems;
|
return _defaultItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Notifies the toolbar that an item has been changed. This will cause the toolbar to reload its items.
|
||||||
|
@param anItem the item that has been changed
|
||||||
|
*/
|
||||||
|
- (void)toolbarItemDidChange:(CPToolbarItem)anItem
|
||||||
|
{
|
||||||
|
if ([_identifiedItems objectForKey:[anItem itemIdentifier]])
|
||||||
|
[_identifiedItems setObject:anItem forKey:[anItem itemIdentifier]];
|
||||||
|
|
||||||
|
var index = 0,
|
||||||
|
count = [_items count];
|
||||||
|
|
||||||
|
for (; index <= count; ++index)
|
||||||
|
{
|
||||||
|
var item = _items[index];
|
||||||
|
|
||||||
|
if ([item itemIdentifier] === [anItem itemIdentifier])
|
||||||
|
{
|
||||||
|
_items[index] = anItem;
|
||||||
|
_itemsSortedByVisibilityPriority = [_items sortedArrayUsingFunction:_CPToolbarItemVisibilityPriorityCompare context:NULL];
|
||||||
|
|
||||||
|
[_toolbarView reloadToolbarItems];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
var CPToolbarIdentifierKey = "CPToolbarIdentifierKey",
|
var CPToolbarIdentifierKey = @"CPToolbarIdentifierKey",
|
||||||
CPToolbarDisplayModeKey = "CPToolbarDisplayModeKey",
|
CPToolbarDisplayModeKey = @"CPToolbarDisplayModeKey",
|
||||||
CPToolbarShowsBaselineSeparatorKey = "CPToolbarShowsBaselineSeparatorKey",
|
CPToolbarShowsBaselineSeparatorKey = @"CPToolbarShowsBaselineSeparatorKey",
|
||||||
CPToolbarAllowsUserCustomizationKey = "CPToolbarAllowsUserCustomizationKey",
|
CPToolbarAllowsUserCustomizationKey = @"CPToolbarAllowsUserCustomizationKey",
|
||||||
CPToolbarIsVisibleKey = "CPToolbarIsVisibleKey",
|
CPToolbarIsVisibleKey = @"CPToolbarIsVisibleKey",
|
||||||
CPToolbarDelegateKey = "CPToolbarDelegateKey",
|
CPToolbarDelegateKey = @"CPToolbarDelegateKey",
|
||||||
CPToolbarIdentifiedItemsKey = "CPToolbarIdentifiedItemsKey",
|
CPToolbarIdentifiedItemsKey = @"CPToolbarIdentifiedItemsKey",
|
||||||
CPToolbarDefaultItemsKey = "CPToolbarDefaultItemsKey",
|
CPToolbarDefaultItemsKey = @"CPToolbarDefaultItemsKey",
|
||||||
CPToolbarAllowedItemsKey = "CPToolbarAllowedItemsKey",
|
CPToolbarAllowedItemsKey = @"CPToolbarAllowedItemsKey",
|
||||||
CPToolbarSelectableItemsKey = "CPToolbarSelectableItemsKey";
|
CPToolbarSelectableItemsKey = @"CPToolbarSelectableItemsKey";
|
||||||
|
|
||||||
@implementation CPToolbar (CPCoding)
|
@implementation CPToolbar (CPCoding)
|
||||||
|
|
||||||
@@ -405,10 +452,30 @@ var CPToolbarIdentifierKey = "CPToolbarIdentifierKey",
|
|||||||
_allowedItems = [aCoder decodeObjectForKey:CPToolbarAllowedItemsKey];
|
_allowedItems = [aCoder decodeObjectForKey:CPToolbarAllowedItemsKey];
|
||||||
_selectableItems = [aCoder decodeObjectForKey:CPToolbarSelectableItemsKey];
|
_selectableItems = [aCoder decodeObjectForKey:CPToolbarSelectableItemsKey];
|
||||||
|
|
||||||
|
[[_identifiedItems allValues] makeObjectsPerformSelector:@selector(_setToolbar:) withObject:self];
|
||||||
|
|
||||||
_items = [];
|
_items = [];
|
||||||
|
|
||||||
[CPToolbar _addToolbar:self forIdentifier:_identifier];
|
[CPToolbar _addToolbar:self forIdentifier:_identifier];
|
||||||
|
|
||||||
|
// This won't come from a Cib, but can come from manual encoding.
|
||||||
[self setDelegate:[aCoder decodeObjectForKey:CPToolbarDelegateKey]];
|
[self setDelegate:[aCoder decodeObjectForKey:CPToolbarDelegateKey]];
|
||||||
|
|
||||||
|
// Because we don't know if a delegate will be set later (it is optional
|
||||||
|
// as of OS X 10.5), we need to call -_reloadToolbarItems here.
|
||||||
|
// In order to load any toolbar items that may have been configured in the
|
||||||
|
// Cib. Unfortunatelly this means that if there is a delegate
|
||||||
|
// specified, it will be read later and the resulting call to -setDelegate:
|
||||||
|
// will cause -_reloadToolbarItems] to run again :-(
|
||||||
|
// FIXME: Can we make this better?
|
||||||
|
|
||||||
|
// Do this at the end of the run loop to allow all the cib-stuff to
|
||||||
|
// finish (establishing connections, etc.).
|
||||||
|
[[CPRunLoop currentRunLoop]
|
||||||
|
performSelector:@selector(_reloadToolbarItems)
|
||||||
|
target:self
|
||||||
|
argument:nil
|
||||||
|
order:0 modes:[CPDefaultRunLoopMode]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -475,7 +542,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
|||||||
|
|
||||||
+ (void)initialize
|
+ (void)initialize
|
||||||
{
|
{
|
||||||
if (self != [_CPToolbarView class])
|
if (self !== [_CPToolbarView class])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var bundle = [CPBundle bundleForClass:self];
|
var bundle = [CPBundle bundleForClass:self];
|
||||||
@@ -501,6 +568,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
|||||||
|
|
||||||
[_additionalItemsButton setImagePosition:CPImageOnly];
|
[_additionalItemsButton setImagePosition:CPImageOnly];
|
||||||
[[_additionalItemsButton menu] setShowsStateColumn:NO];
|
[[_additionalItemsButton menu] setShowsStateColumn:NO];
|
||||||
|
[[_additionalItemsButton menu] setAutoenablesItems:NO];
|
||||||
|
|
||||||
[_additionalItemsButton setAlternateImage:_CPToolbarViewExtraItemsAlternateImage];
|
[_additionalItemsButton setAlternateImage:_CPToolbarViewExtraItemsAlternateImage];
|
||||||
}
|
}
|
||||||
@@ -731,19 +799,17 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
|||||||
|
|
||||||
hasNonSeparatorItem = YES;
|
hasNonSeparatorItem = YES;
|
||||||
|
|
||||||
[_additionalItemsButton addItemWithTitle:[item label]];
|
var menuItem = [[CPMenuItem alloc] initWithTitle:[item label] action:[item action] keyEquivalent:nil];
|
||||||
|
|
||||||
var menuItem = [_additionalItemsButton itemArray][index + 1];
|
|
||||||
|
|
||||||
[menuItem setImage:[item image]];
|
[menuItem setImage:[item image]];
|
||||||
|
|
||||||
[menuItem setTarget:[item target]];
|
[menuItem setTarget:[item target]];
|
||||||
[menuItem setAction:[item action]];
|
[menuItem setEnabled:[item isEnabled]];
|
||||||
|
|
||||||
|
[_additionalItemsButton addItem:menuItem];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
[_additionalItemsButton removeFromSuperview];
|
[_additionalItemsButton removeFromSuperview];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)reloadToolbarItems
|
- (void)reloadToolbarItems
|
||||||
@@ -837,7 +903,16 @@ var TOP_MARGIN = 5.0,
|
|||||||
|
|
||||||
_toolbar = aToolbar;
|
_toolbar = aToolbar;
|
||||||
|
|
||||||
[_toolbarItem addObserver:self forKeyPath:"enabled" options:0 context:NULL];
|
var keyPaths = [@"label", @"image", @"alternateImage", @"minSize", @"maxSize", @"target", @"action", @"enabled"],
|
||||||
|
index = 0,
|
||||||
|
count = [keyPaths count];
|
||||||
|
|
||||||
|
for (; index < count; ++index)
|
||||||
|
[_toolbarItem
|
||||||
|
addObserver:self
|
||||||
|
forKeyPath:keyPaths[index]
|
||||||
|
options:0
|
||||||
|
context:NULL];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -904,7 +979,7 @@ var TOP_MARGIN = 5.0,
|
|||||||
{
|
{
|
||||||
_imageView = [[CPImageView alloc] initWithFrame:[self bounds]];
|
_imageView = [[CPImageView alloc] initWithFrame:[self bounds]];
|
||||||
|
|
||||||
[_imageView setImageScaling:CPScaleNone];
|
[_imageView setImageScaling:CPScaleProportionally];
|
||||||
|
|
||||||
[self addSubview:_imageView];
|
[self addSubview:_imageView];
|
||||||
}
|
}
|
||||||
@@ -918,6 +993,8 @@ var TOP_MARGIN = 5.0,
|
|||||||
[_labelField setStringValue:[_toolbarItem label]];
|
[_labelField setStringValue:[_toolbarItem label]];
|
||||||
[_labelField sizeToFit]; // FIXME
|
[_labelField sizeToFit]; // FIXME
|
||||||
|
|
||||||
|
[self setEnabled:[_toolbarItem isEnabled]];
|
||||||
|
|
||||||
_labelSize = [_labelField frame].size;
|
_labelSize = [_labelField frame].size;
|
||||||
|
|
||||||
_minSize = CGSizeMake(MAX(_labelSize.width, minSize.width), _labelSize.height + minSize.height + LABEL_MARGIN + TOP_MARGIN);
|
_minSize = CGSizeMake(MAX(_labelSize.width, minSize.width), _labelSize.height + minSize.height + LABEL_MARGIN + TOP_MARGIN);
|
||||||
@@ -983,6 +1060,8 @@ var TOP_MARGIN = 5.0,
|
|||||||
[_imageView setAlphaValue:0.5];
|
[_imageView setAlphaValue:0.5];
|
||||||
[_labelField setAlphaValue:0.5];
|
[_labelField setAlphaValue:0.5];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[_toolbar tile];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPColor)FIXME_labelColor
|
- (CPColor)FIXME_labelColor
|
||||||
@@ -1027,14 +1106,27 @@ var TOP_MARGIN = 5.0,
|
|||||||
[_labelField setTextShadowColor:[self FIXME_labelShadowColor]];
|
[_labelField setTextShadowColor:[self FIXME_labelShadowColor]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)sendAction:(SEL)anAction to:(id)aSender
|
||||||
|
{
|
||||||
|
[CPApp sendAction:anAction to:aSender from:_toolbarItem];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)observeValueForKeyPath:(CPString)aKeyPath
|
- (void)observeValueForKeyPath:(CPString)aKeyPath
|
||||||
ofObject:(id)anObject
|
ofObject:(id)anObject
|
||||||
change:(CPDictionary)aChange
|
change:(CPDictionary)aChange
|
||||||
context:(id)aContext
|
context:(id)aContext
|
||||||
{
|
{
|
||||||
// FIXME: Not clear if -synchronizeWindowTitleWithDocumentName is the best way to go.
|
|
||||||
if (aKeyPath === "enabled")
|
if (aKeyPath === "enabled")
|
||||||
[self setEnabled:[anObject isEnabled]];
|
[self setEnabled:[anObject isEnabled]];
|
||||||
|
|
||||||
|
else if (aKeyPath === @"target")
|
||||||
|
[self setTarget:[anObject target]];
|
||||||
|
|
||||||
|
else if (aKeyPath === @"action")
|
||||||
|
[self setAction:[anObject action]];
|
||||||
|
|
||||||
|
else
|
||||||
|
[self updateFromItem];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+122
-51
@@ -23,38 +23,22 @@
|
|||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
@import <Foundation/CPString.j>
|
@import <Foundation/CPString.j>
|
||||||
|
|
||||||
@import <AppKit/CPImage.j>
|
@import "CPImage.j"
|
||||||
@import <AppKit/CPView.j>
|
@import "CPView.j"
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@class CPToolbarItem
|
|
||||||
*/
|
|
||||||
CPToolbarItemVisibilityPriorityStandard = 0;
|
CPToolbarItemVisibilityPriorityStandard = 0;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@class CPToolbarItem
|
|
||||||
*/
|
|
||||||
CPToolbarItemVisibilityPriorityLow = -1000;
|
CPToolbarItemVisibilityPriorityLow = -1000;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@class CPToolbarItem
|
|
||||||
*/
|
|
||||||
CPToolbarItemVisibilityPriorityHigh = 1000;
|
CPToolbarItemVisibilityPriorityHigh = 1000;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@class CPToolbarItem
|
|
||||||
*/
|
|
||||||
CPToolbarItemVisibilityPriorityUser = 2000;
|
CPToolbarItemVisibilityPriorityUser = 2000;
|
||||||
|
|
||||||
CPToolbarSeparatorItemIdentifier = @"CPToolbarSeparatorItemIdentifier";
|
CPToolbarSeparatorItemIdentifier = @"CPToolbarSeparatorItem";
|
||||||
CPToolbarSpaceItemIdentifier = @"CPToolbarSpaceItemIdentifier";
|
CPToolbarSpaceItemIdentifier = @"CPToolbarSpaceItem";
|
||||||
CPToolbarFlexibleSpaceItemIdentifier = @"CPToolbarFlexibleSpaceItemIdentifier";
|
CPToolbarFlexibleSpaceItemIdentifier = @"CPToolbarFlexibleSpaceItem";
|
||||||
CPToolbarShowColorsItemIdentifier = @"CPToolbarShowColorsItemIdentifier";
|
CPToolbarShowColorsItemIdentifier = @"CPToolbarShowColorsItem";
|
||||||
CPToolbarShowFontsItemIdentifier = @"CPToolbarShowFontsItemIdentifier";
|
CPToolbarShowFontsItemIdentifier = @"CPToolbarShowFontsItem";
|
||||||
CPToolbarCustomizeToolbarItemIdentifier = @"CPToolbarCustomizeToolbarItemIdentifier";
|
CPToolbarCustomizeToolbarItemIdentifier = @"CPToolbarCustomizeToolbarItem";
|
||||||
CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -114,6 +98,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
|||||||
_maxSize = CGSizeMakeZero();
|
_maxSize = CGSizeMakeZero();
|
||||||
|
|
||||||
_visibilityPriority = CPToolbarItemVisibilityPriorityStandard;
|
_visibilityPriority = CPToolbarItemVisibilityPriorityStandard;
|
||||||
|
_autovalidates = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -136,6 +121,12 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
|||||||
return _toolbar;
|
return _toolbar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* @ignore */
|
||||||
|
- (void)_setToolbar:(CPToolbar)aToolbar
|
||||||
|
{
|
||||||
|
_toolbar = aToolbar;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the item's label
|
Returns the item's label
|
||||||
*/
|
*/
|
||||||
@@ -190,7 +181,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
|||||||
- (void)setToolTip:(CPString)aToolTip
|
- (void)setToolTip:(CPString)aToolTip
|
||||||
{
|
{
|
||||||
if ([_view respondsToSelector:@selector(setToolTip:)])
|
if ([_view respondsToSelector:@selector(setToolTip:)])
|
||||||
[view setToolTip:aToolTip];
|
[_view setToolTip:aToolTip];
|
||||||
|
|
||||||
_toolTip = aToolTip;
|
_toolTip = aToolTip;
|
||||||
}
|
}
|
||||||
@@ -315,8 +306,8 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
|||||||
if (!_image)
|
if (!_image)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_minSize.width == 0 && _minSize.height == 0 &&
|
if (_minSize.width === 0 && _minSize.height === 0 &&
|
||||||
_maxSize.width == 0 && _maxSize.height == 0)
|
_maxSize.width === 0 && _maxSize.height === 0)
|
||||||
{
|
{
|
||||||
var imageSize = [_image size];
|
var imageSize = [_image size];
|
||||||
|
|
||||||
@@ -395,6 +386,9 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
|||||||
*/
|
*/
|
||||||
- (void)setMinSize:(CGSize)aMinSize
|
- (void)setMinSize:(CGSize)aMinSize
|
||||||
{
|
{
|
||||||
|
if(!aMinSize.height || !aMinSize.width)
|
||||||
|
return;
|
||||||
|
|
||||||
_minSize = CGSizeMakeCopy(aMinSize);
|
_minSize = CGSizeMakeCopy(aMinSize);
|
||||||
|
|
||||||
// Try to provide some sanity: Make maxSize >= minSize
|
// Try to provide some sanity: Make maxSize >= minSize
|
||||||
@@ -415,6 +409,9 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
|||||||
*/
|
*/
|
||||||
- (void)setMaxSize:(CGSize)aMaxSize
|
- (void)setMaxSize:(CGSize)aMaxSize
|
||||||
{
|
{
|
||||||
|
if(!aMaxSize.height || !aMaxSize.width)
|
||||||
|
return;
|
||||||
|
|
||||||
_maxSize = CGSizeMakeCopy(aMaxSize);
|
_maxSize = CGSizeMakeCopy(aMaxSize);
|
||||||
|
|
||||||
// Try to provide some sanity: Make minSize <= maxSize
|
// Try to provide some sanity: Make minSize <= maxSize
|
||||||
@@ -453,6 +450,9 @@ CPToolbarItemVisibilityPriorityUser
|
|||||||
|
|
||||||
- (void)validate
|
- (void)validate
|
||||||
{
|
{
|
||||||
|
var action = [self action],
|
||||||
|
target = [self target];
|
||||||
|
|
||||||
// View items do not do any target-action analysis.
|
// View items do not do any target-action analysis.
|
||||||
if (_view)
|
if (_view)
|
||||||
{
|
{
|
||||||
@@ -462,13 +462,9 @@ CPToolbarItemVisibilityPriorityUser
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var action = [self action];
|
|
||||||
|
|
||||||
if (!action)
|
if (!action)
|
||||||
return [self setEnabled:NO];
|
return [self setEnabled:NO];
|
||||||
|
|
||||||
var target = [self target];
|
|
||||||
|
|
||||||
if (target && ![target respondsToSelector:action])
|
if (target && ![target respondsToSelector:action])
|
||||||
return [self setEnabled:NO];
|
return [self setEnabled:NO];
|
||||||
|
|
||||||
@@ -495,6 +491,86 @@ CPToolbarItemVisibilityPriorityUser
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
var CPToolbarItemItemIdentifierKey = @"CPToolbarItemItemIdentifierKey",
|
||||||
|
CPToolbarItemLabelKey = @"CPToolbarItemLabelKey",
|
||||||
|
CPToolbarItemPaletteLabelKey = @"CPToolbarItemPaletteLabelKey",
|
||||||
|
CPToolbarItemToolTipKey = @"CPToolbarItemToolTipKey",
|
||||||
|
CPToolbarItemTagKey = @"CPToolbarItemTagKey",
|
||||||
|
CPToolbarItemTargetKey = @"CPToolbarItemTargetKey",
|
||||||
|
CPToolbarItemActionKey = @"CPToolbarItemActionKey",
|
||||||
|
CPToolbarItemEnabledKey = @"CPToolbarItemEnabledKey",
|
||||||
|
CPToolbarItemImageKey = @"CPToolbarItemImageKey",
|
||||||
|
CPToolbarItemAlternateImageKey = @"CPToolbarItemAlternateImageKey",
|
||||||
|
CPToolbarItemViewKey = @"CPToolbarItemViewKey",
|
||||||
|
CPToolbarItemMinSizeKey = @"CPToolbarItemMinSizeKey",
|
||||||
|
CPToolbarItemMaxSizeKey = @"CPToolbarItemMaxSizeKey",
|
||||||
|
CPToolbarItemVisibilityPriorityKey = @"CPToolbarItemVisibilityPriorityKey",
|
||||||
|
CPToolbarItemAutovalidatesKey = @"CPToolbarItemAutovalidatesKey";
|
||||||
|
|
||||||
|
@implementation CPToolbarItem (CPCoding)
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_itemIdentifier = [aCoder decodeObjectForKey:CPToolbarItemItemIdentifierKey];
|
||||||
|
|
||||||
|
_minSize = [aCoder decodeSizeForKey:CPToolbarItemMinSizeKey];
|
||||||
|
_maxSize = [aCoder decodeSizeForKey:CPToolbarItemMaxSizeKey];
|
||||||
|
|
||||||
|
[self setLabel:[aCoder decodeObjectForKey:CPToolbarItemLabelKey]];
|
||||||
|
[self setPaletteLabel:[aCoder decodeObjectForKey:CPToolbarItemPaletteLabelKey]];
|
||||||
|
[self setToolTip:[aCoder decodeObjectForKey:CPToolbarItemToolTipKey]];
|
||||||
|
|
||||||
|
[self setTag:[aCoder decodeObjectForKey:CPToolbarItemTagKey]];
|
||||||
|
[self setTarget:[aCoder decodeObjectForKey:CPToolbarItemTargetKey]];
|
||||||
|
[self setAction:CPSelectorFromString([aCoder decodeObjectForKey:CPToolbarItemActionKey])];
|
||||||
|
|
||||||
|
[self setEnabled:[aCoder decodeBoolForKey:CPToolbarItemEnabledKey]];
|
||||||
|
|
||||||
|
[self setImage:[aCoder decodeObjectForKey:CPToolbarItemImageKey]];
|
||||||
|
[self setAlternateImage:[aCoder decodeObjectForKey:CPToolbarItemAlternateImageKey]];
|
||||||
|
|
||||||
|
[self setView:[aCoder decodeObjectForKey:CPToolbarItemViewKey]];
|
||||||
|
|
||||||
|
[self setVisibilityPriority:[aCoder decodeIntForKey:CPToolbarItemVisibilityPriorityKey]];
|
||||||
|
[self setAutovalidates:[aCoder decodeBoolForKey:CPToolbarItemAutovalidatesKey]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
[aCoder encodeObject:_itemIdentifier forKey:CPToolbarItemItemIdentifierKey];
|
||||||
|
|
||||||
|
[aCoder encodeObject:[self label] forKey:CPToolbarItemLabelKey];
|
||||||
|
[aCoder encodeObject:[self paletteLabel] forKey:CPToolbarItemPaletteLabelKey];
|
||||||
|
|
||||||
|
[aCoder encodeObject:[self toolTip] forKey:CPToolbarItemToolTipKey];
|
||||||
|
|
||||||
|
[aCoder encodeObject:[self tag] forKey:CPToolbarItemTagKey];
|
||||||
|
[aCoder encodeObject:[self target] forKey:CPToolbarItemTargetKey];
|
||||||
|
[aCoder encodeObject:[self action] forKey:CPToolbarItemActionKey];
|
||||||
|
|
||||||
|
[aCoder encodeObject:[self isEnabled] forKey:CPToolbarItemEnabledKey];
|
||||||
|
|
||||||
|
[aCoder encodeObject:[self image] forKey:CPToolbarItemImageKey];
|
||||||
|
[aCoder encodeObject:[self alternateImage] forKey:CPToolbarItemAlternateImageKey];
|
||||||
|
|
||||||
|
[aCoder encodeObject:[self view] forKey:CPToolbarItemViewKey];
|
||||||
|
|
||||||
|
[aCoder encodeSize:[self minSize] forKey:CPToolbarItemMinSizeKey];
|
||||||
|
[aCoder encodeSize:[self maxSize] forKey:CPToolbarItemMaxSizeKey];
|
||||||
|
|
||||||
|
[aCoder encodeObject:[self visibilityPriority] forKey:CPToolbarItemVisibilityPriorityKey];
|
||||||
|
[aCoder encodeBool:[self autovalidates] forKey:CPToolbarItemAutovalidatesKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@implementation CPToolbarItem (CPCopying)
|
@implementation CPToolbarItem (CPCopying)
|
||||||
|
|
||||||
- (id)copy
|
- (id)copy
|
||||||
@@ -504,6 +580,8 @@ CPToolbarItemVisibilityPriorityUser
|
|||||||
if (_view)
|
if (_view)
|
||||||
[copy setView:[CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:_view]]];
|
[copy setView:[CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:_view]]];
|
||||||
|
|
||||||
|
[copy _setToolbar:_toolbar];
|
||||||
|
|
||||||
[copy setLabel:_label];
|
[copy setLabel:_label];
|
||||||
[copy setPaletteLabel:_paletteLabel];
|
[copy setPaletteLabel:_paletteLabel];
|
||||||
[copy setToolTip:[self toolTip]];
|
[copy setToolTip:[self toolTip]];
|
||||||
@@ -520,7 +598,8 @@ CPToolbarItemVisibilityPriorityUser
|
|||||||
[copy setMinSize:_minSize];
|
[copy setMinSize:_minSize];
|
||||||
[copy setMaxSize:_maxSize];
|
[copy setMaxSize:_maxSize];
|
||||||
|
|
||||||
[copy setVisibilityPriority:_visibilityPriority];
|
[copy setVisibilityPriority:[self visibilityPriority]];
|
||||||
|
[copy setAutovalidates:[self autovalidates]];
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
@@ -534,26 +613,12 @@ CPToolbarItemVisibilityPriorityUser
|
|||||||
/* @ignore */
|
/* @ignore */
|
||||||
+ (CPToolbarItem)_standardItemWithItemIdentifier:(CPString)anItemIdentifier
|
+ (CPToolbarItem)_standardItemWithItemIdentifier:(CPString)anItemIdentifier
|
||||||
{
|
{
|
||||||
var item = [[CPToolbarItem alloc] initWithItemIdentifier:anItemIdentifier];
|
|
||||||
|
|
||||||
switch (anItemIdentifier)
|
switch (anItemIdentifier)
|
||||||
{
|
{
|
||||||
case CPToolbarSeparatorItemIdentifier: [item setMinSize:CGSizeMake(2.0, 0.0)];
|
case CPToolbarSeparatorItemIdentifier: return [_CPToolbarSeparatorItem new];
|
||||||
[item setMaxSize:CGSizeMake(2.0, 100000.0)];
|
case CPToolbarSpaceItemIdentifier: return [_CPToolbarSpaceItem new];
|
||||||
|
case CPToolbarFlexibleSpaceItemIdentifier: return [_CPToolbarFlexibleSpaceItem new];
|
||||||
return item;
|
case CPToolbarShowColorsItemIdentifier: return [_CPToolbarShowColorsItem new];
|
||||||
|
|
||||||
case CPToolbarSpaceItemIdentifier: [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)];
|
|
||||||
[item setMaxSize:CGSizeMake(10000.0, 32.0)];
|
|
||||||
|
|
||||||
return item;
|
|
||||||
|
|
||||||
case CPToolbarShowColorsItemIdentifier: return nil;
|
|
||||||
case CPToolbarShowFontsItemIdentifier: return nil;
|
case CPToolbarShowFontsItemIdentifier: return nil;
|
||||||
case CPToolbarCustomizeToolbarItemIdentifier: return nil;
|
case CPToolbarCustomizeToolbarItemIdentifier: return nil;
|
||||||
case CPToolbarPrintItemIdentifier: return nil;
|
case CPToolbarPrintItemIdentifier: return nil;
|
||||||
@@ -563,3 +628,9 @@ CPToolbarItemVisibilityPriorityUser
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@import "_CPToolbarFlexibleSpaceItem.j"
|
||||||
|
@import "_CPToolbarShowColorsItem.j"
|
||||||
|
@import "_CPToolbarSeparatorItem.j"
|
||||||
|
@import "_CPToolbarSpaceItem.j"
|
||||||
|
|
||||||
|
|||||||
+242
-8
@@ -7,7 +7,7 @@
|
|||||||
id _representedObject @accessors(readonly, property=representedObject);
|
id _representedObject @accessors(readonly, property=representedObject);
|
||||||
|
|
||||||
CPTreeNode _parentNode @accessors(readonly, property=parentNode);
|
CPTreeNode _parentNode @accessors(readonly, property=parentNode);
|
||||||
CPMutableArray _childNodes @accessors(readonly, property=childNodes);
|
CPMutableArray _childNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)treeNodeWithRepresentedObject:(id)anObject
|
+ (id)treeNodeWithRepresentedObject:(id)anObject
|
||||||
@@ -33,16 +33,23 @@
|
|||||||
return [_childNodes count] <= 0;
|
return [_childNodes count] <= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CPArray)childNodes
|
||||||
|
{
|
||||||
|
return [_childNodes copy];
|
||||||
|
}
|
||||||
|
|
||||||
- (CPMutableArray)mutableChildNodes
|
- (CPMutableArray)mutableChildNodes
|
||||||
{
|
{
|
||||||
return [self mutableArrayValueForKey:@"childNodes"];
|
return [self mutableArrayValueForKey:@"childNodes"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)insertObject:(id)anObject inChildNodesAtIndex:(CPInteger)anIndex
|
- (void)insertObject:(id)aTreeNode inChildNodesAtIndex:(CPInteger)anIndex
|
||||||
{
|
{
|
||||||
anObject._parentNode = self;
|
[[aTreeNode._parentNode mutableChildNodes] removeObjectIdenticalTo:aTreeNode];
|
||||||
|
|
||||||
[_childNodes addObject:anObject];
|
aTreeNode._parentNode = self;
|
||||||
|
|
||||||
|
[_childNodes insertObject:aTreeNode atIndex:anIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)removeObjectFromChildNodesAtIndex:(CPInteger)anIndex
|
- (void)removeObjectFromChildNodesAtIndex:(CPInteger)anIndex
|
||||||
@@ -52,13 +59,14 @@
|
|||||||
[_childNodes removeObjectAtIndex:anIndex];
|
[_childNodes removeObjectAtIndex:anIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)replaceObjectFromChildNodesAtIndex:(CPInteger)anIndex withObject:(id)anObject
|
- (void)replaceObjectFromChildNodesAtIndex:(CPInteger)anIndex withObject:(id)aTreeNode
|
||||||
{
|
{
|
||||||
var oldObject = [_childNodes objectAtIndex:anIndex];
|
var oldTreeNode = [_childNodes objectAtIndex:anIndex];
|
||||||
|
|
||||||
oldObject._parentNode = nil;
|
oldTreeNode._parentNode = nil;
|
||||||
|
aTreeNode._parentNode = self;
|
||||||
|
|
||||||
[_childNodes replaceObjectAtIndex:anIndex withObject:anObject];
|
[_childNodes replaceObjectAtIndex:anIndex withObject:aTreeNode];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)objectInChildNodesAtIndex:(CPInteger)anIndex
|
- (id)objectInChildNodesAtIndex:(CPInteger)anIndex
|
||||||
@@ -79,4 +87,230 @@
|
|||||||
[_childNodes[count] sortWithSortDescriptors:sortDescriptors recursively:YES];
|
[_childNodes[count] sortWithSortDescriptors:sortDescriptors recursively:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CPEnumerator)preOrder
|
||||||
|
{
|
||||||
|
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorPreOrder];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPEnumerator)inOrder
|
||||||
|
{
|
||||||
|
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorInOrder];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPEnumerator)postOrder
|
||||||
|
{
|
||||||
|
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorPostOrder];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPEnumerator)levelOrder
|
||||||
|
{
|
||||||
|
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorLevelOrder];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
|
||||||
|
{
|
||||||
|
if (aState.state !== 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// FIXME: Change this to inorder when implemented?
|
||||||
|
var count = [[self preOrder] countByEnumeratingWithState:aState objects:objects count:aCount];
|
||||||
|
|
||||||
|
// Dangerous?
|
||||||
|
aState.state = YES;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey",
|
||||||
|
CPTreeNodeParentNodeKey = @"CPTreeNodeParentNodeKey",
|
||||||
|
CPTreeNodeChildNodesKey = @"CPTreeNodeChildNodesKey";
|
||||||
|
|
||||||
|
@implementation CPTreeNode (CPCoding)
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_representedObject = [aCoder decodeObjectForKey:CPTreeNodeRepresentedObjectKey];
|
||||||
|
_parentNode = [aCoder decodeObjectForKey:CPTreeNodeParentNodeKey];
|
||||||
|
_childNodes = [aCoder decodeObjectForKey:CPTreeNodeChildNodesKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
[aCoder encodeObject:_representedObject forKey:CPTreeNodeRepresentedObjectKey];
|
||||||
|
[aCoder encodeConditionalObject:_parentNode forKey:CPTreeNodeParentNodeKey];
|
||||||
|
[aCoder encodeObject:_childNodes forKey:CPTreeNodeChildNodesKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var _CPTreeNodeEnumeratorPreOrder = 0,
|
||||||
|
_CPTreeNodeEnumeratorInOrder = 1,
|
||||||
|
_CPTreeNodeEnumeratorPostOrder = 2,
|
||||||
|
_CPTreeNodeEnumeratorLevelOrder = 3;
|
||||||
|
|
||||||
|
@implementation _CPTreeNodeEnumerator : CPEnumerator
|
||||||
|
{
|
||||||
|
int _order;
|
||||||
|
Object _state;
|
||||||
|
CPTreeNode _treeNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (_CPTreeNodeEnumerator)enumeratorWithTreeNode:(CPTreeNode)aTreeNode order:(int)anOrder
|
||||||
|
{
|
||||||
|
return [[self alloc] initWithTreeNode:aTreeNode order:anOrder];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithTreeNode:(CPTreeNode)aTreeNode order:(int)anOrder
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_order = anOrder
|
||||||
|
_state = [self _newState];
|
||||||
|
_treeNode = aTreeNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)_newState
|
||||||
|
{
|
||||||
|
return { stack:[_treeNode], visited:[CPSet set] };
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)_preOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
|
||||||
|
{
|
||||||
|
var stack = state.stack;
|
||||||
|
|
||||||
|
if (stack.length <= 0)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
if (shouldReturnAllObjects)
|
||||||
|
var allObjects = [];
|
||||||
|
|
||||||
|
while (stack.length)
|
||||||
|
{
|
||||||
|
var currentNode = stack.pop(),
|
||||||
|
childNodes = currentNode._childNodes,
|
||||||
|
count = childNodes.length;
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
stack.push(childNodes[count]);
|
||||||
|
|
||||||
|
if (shouldReturnAllObjects)
|
||||||
|
allObjects.push(currentNode);
|
||||||
|
else
|
||||||
|
return currentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return allObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)_inOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
|
||||||
|
{
|
||||||
|
// Implement.
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)_postOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
|
||||||
|
{
|
||||||
|
var stack = state.stack;
|
||||||
|
|
||||||
|
if (stack.length <= 0)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
var visited = state.visited;
|
||||||
|
|
||||||
|
if (shouldReturnAllObjects)
|
||||||
|
var allObjects = [];
|
||||||
|
|
||||||
|
while (stack.length)
|
||||||
|
{
|
||||||
|
var currentNode = [stack lastObject],
|
||||||
|
childNodes = currentNode._childNodes,
|
||||||
|
originalCount = stack.length,
|
||||||
|
count = childNodes.length;
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
{
|
||||||
|
var treeNode = childNodes[count];
|
||||||
|
|
||||||
|
if ([visited containsObject:treeNode])
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
stack.push(treeNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (originalCount === stack.length)
|
||||||
|
{
|
||||||
|
[visited addObject:currentNode];
|
||||||
|
|
||||||
|
if (shouldReturnAllObjects)
|
||||||
|
allObjects.push(stack.pop());
|
||||||
|
else
|
||||||
|
return stack.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return allObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)_levelOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
|
||||||
|
{
|
||||||
|
// Implement.
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)nextObject
|
||||||
|
{
|
||||||
|
if (_order === _CPTreeNodeEnumeratorPreOrder)
|
||||||
|
return [self _preOrderFromState:[self _newState] allObjects:NO];
|
||||||
|
|
||||||
|
else if (_order === _CPTreeNodeEnumeratorInOrder)
|
||||||
|
return [self _inOrderFromState:[self _newState] allObjects:NO];
|
||||||
|
|
||||||
|
else if (_order === _CPTreeNodeEnumeratorPostOrder)
|
||||||
|
return [self _postOrderFromState:[self _newState] allObjects:NO];
|
||||||
|
|
||||||
|
//else if (_order === _CPTreeNodeEnumeratorLevelOrder)
|
||||||
|
return [self _levelOrderFromState:[self _newState] allObjects:NO];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPArray)allObjects
|
||||||
|
{
|
||||||
|
if (_order === _CPTreeNodeEnumeratorPreOrder)
|
||||||
|
return [self _preOrderFromState:[self _newState] allObjects:YES];
|
||||||
|
|
||||||
|
else if (_order === _CPTreeNodeEnumeratorInOrder)
|
||||||
|
return [self _inOrderFromState:[self _newState] allObjects:YES];
|
||||||
|
|
||||||
|
else if (_order === _CPTreeNodeEnumeratorPostOrder)
|
||||||
|
return [self _postOrderFromState:[self _newState] allObjects:YES];
|
||||||
|
|
||||||
|
//else if (_order === _CPTreeNodeEnumeratorLevelOrder)
|
||||||
|
return [self _levelOrderFromState:[self _newState] allObjects:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
|
||||||
|
{
|
||||||
|
if (aState.state !== 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var count = [[self allObjects] countByEnumeratingWithState:aState objects:objects count:aCount];
|
||||||
|
|
||||||
|
// Dangerous?
|
||||||
|
aState.state = YES;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+287
-37
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
@import <Foundation/CPArray.j>
|
@import <Foundation/CPArray.j>
|
||||||
@import <Foundation/CPObjJRuntime.j>
|
@import <Foundation/CPObjJRuntime.j>
|
||||||
|
@import <Foundation/CPSet.j>
|
||||||
|
|
||||||
@import "CGAffineTransform.j"
|
@import "CGAffineTransform.j"
|
||||||
@import "CGGeometry.j"
|
@import "CGGeometry.j"
|
||||||
@@ -34,11 +35,6 @@
|
|||||||
@import "_CPDisplayServer.j"
|
@import "_CPDisplayServer.j"
|
||||||
|
|
||||||
|
|
||||||
#include "Platform/Platform.h"
|
|
||||||
#include "CoreGraphics/CGAffineTransform.h"
|
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
|
||||||
#include "Platform/DOM/CPDOMDisplayServer.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@global
|
@global
|
||||||
@group CPViewAutoresizingMasks
|
@group CPViewAutoresizingMasks
|
||||||
@@ -94,7 +90,8 @@ var DOMElementPrototype = nil,
|
|||||||
BackgroundTrivialColor = 0,
|
BackgroundTrivialColor = 0,
|
||||||
BackgroundVerticalThreePartImage = 1,
|
BackgroundVerticalThreePartImage = 1,
|
||||||
BackgroundHorizontalThreePartImage = 2,
|
BackgroundHorizontalThreePartImage = 2,
|
||||||
BackgroundNinePartImage = 3;
|
BackgroundNinePartImage = 3,
|
||||||
|
BackgroundTransparentColor = 4;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
var CPViewFlags = { },
|
var CPViewFlags = { },
|
||||||
@@ -139,6 +136,7 @@ var CPViewFlags = { },
|
|||||||
|
|
||||||
BOOL _isHidden;
|
BOOL _isHidden;
|
||||||
BOOL _hitTests;
|
BOOL _hitTests;
|
||||||
|
BOOL _clipsToBounds;
|
||||||
|
|
||||||
BOOL _postsFrameChangedNotifications;
|
BOOL _postsFrameChangedNotifications;
|
||||||
BOOL _postsBoundsChangedNotifications;
|
BOOL _postsBoundsChangedNotifications;
|
||||||
@@ -176,6 +174,7 @@ var CPViewFlags = { },
|
|||||||
|
|
||||||
// Theming Support
|
// Theming Support
|
||||||
CPTheme _theme;
|
CPTheme _theme;
|
||||||
|
CPString _themeClass;
|
||||||
JSObject _themeAttributes;
|
JSObject _themeAttributes;
|
||||||
unsigned _themeState;
|
unsigned _themeState;
|
||||||
|
|
||||||
@@ -238,6 +237,16 @@ var CPViewFlags = { },
|
|||||||
return [CPSet setWithObjects:@"frameOrigin", @"frameSize"];
|
return [CPSet setWithObjects:@"frameOrigin", @"frameSize"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (CPSet)keyPathsForValuesAffectingBounds
|
||||||
|
{
|
||||||
|
return [CPSet setWithObjects:@"boundsOrigin", @"boundsSize"];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPMenu)defaultMenu
|
||||||
|
{
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
{
|
{
|
||||||
return [self initWithFrame:CGRectMakeZero()];
|
return [self initWithFrame:CGRectMakeZero()];
|
||||||
@@ -267,6 +276,7 @@ var CPViewFlags = { },
|
|||||||
|
|
||||||
_autoresizingMask = CPViewNotSizable;
|
_autoresizingMask = CPViewNotSizable;
|
||||||
_autoresizesSubviews = YES;
|
_autoresizesSubviews = YES;
|
||||||
|
_clipsToBounds = YES;
|
||||||
|
|
||||||
_opacity = 1.0;
|
_opacity = 1.0;
|
||||||
_isHidden = NO;
|
_isHidden = NO;
|
||||||
@@ -308,7 +318,7 @@ var CPViewFlags = { },
|
|||||||
*/
|
*/
|
||||||
- (CPArray)subviews
|
- (CPArray)subviews
|
||||||
{
|
{
|
||||||
return _subviews;
|
return [_subviews copy];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -441,7 +451,7 @@ var CPViewFlags = { },
|
|||||||
|
|
||||||
[_superview willRemoveSubview:self];
|
[_superview willRemoveSubview:self];
|
||||||
|
|
||||||
[[_superview subviews] removeObject:self];
|
[_superview._subviews removeObject:self];
|
||||||
|
|
||||||
#if PLATFORM(DOM)
|
#if PLATFORM(DOM)
|
||||||
CPDOMDisplayServerRemoveChild(_superview._DOMElement, _DOMElement);
|
CPDOMDisplayServerRemoveChild(_superview._DOMElement, _DOMElement);
|
||||||
@@ -468,6 +478,75 @@ var CPViewFlags = { },
|
|||||||
[self _insertSubview:aView atIndex:index];
|
[self _insertSubview:aView atIndex:index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setSubviews:(CPArray)newSubviews
|
||||||
|
{
|
||||||
|
if (!newSubviews)
|
||||||
|
[CPException raise:CPInvalidArgumentException reason:"newSubviews cannot be nil in -[CPView setSubviews:]"];
|
||||||
|
|
||||||
|
// Trivial Case 0: Same array somehow
|
||||||
|
if ([_subviews isEqual:newSubviews])
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Trivial Case 1: No current subviews, simply add all new subviews.
|
||||||
|
if ([_subviews count] === 0)
|
||||||
|
{
|
||||||
|
var index = 0,
|
||||||
|
count = [newSubviews count];
|
||||||
|
|
||||||
|
for (; index < count; ++index)
|
||||||
|
[self addSubview:newSubviews[index]];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trivial Case 2: No new subviews, simply remove all current subviews.
|
||||||
|
if ([newSubviews count] === 0)
|
||||||
|
{
|
||||||
|
var count = [_subviews count];
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
[_subviews[count] removeFromSuperview];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find out the views that were removed.
|
||||||
|
var removedSubviews = [CPMutableSet setWithArray:_subviews];
|
||||||
|
|
||||||
|
[removedSubviews removeObjectsInArray:newSubviews];
|
||||||
|
[removedSubviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||||
|
|
||||||
|
// Find out which views need to be added.
|
||||||
|
var addedSubviews = [CPMutableSet setWithArray:newSubviews];
|
||||||
|
|
||||||
|
[addedSubviews removeObjectsInArray:_subviews];
|
||||||
|
|
||||||
|
var addedSubview = nil,
|
||||||
|
addedSubviewEnumerator = [addedSubviews objectEnumerator];
|
||||||
|
|
||||||
|
while (addedSubview = [addedSubviewEnumerator nextObject])
|
||||||
|
[self addSubview:addedSubview];
|
||||||
|
|
||||||
|
// If the order is fine, no need to reorder.
|
||||||
|
if ([_subviews isEqual:newSubviews])
|
||||||
|
return;
|
||||||
|
|
||||||
|
_subviews = [newSubviews copy];
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
var index = 0,
|
||||||
|
count = [_subviews count];
|
||||||
|
|
||||||
|
for (; index < count; ++index)
|
||||||
|
{
|
||||||
|
var subview = _subviews[index];
|
||||||
|
|
||||||
|
CPDOMDisplayServerRemoveChild(_DOMElement, subview._DOMElement);
|
||||||
|
CPDOMDisplayServerAppendChild(_DOMElement, subview._DOMElement);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
- (void)_setWindow:(CPWindow)aWindow
|
- (void)_setWindow:(CPWindow)aWindow
|
||||||
{
|
{
|
||||||
@@ -594,7 +673,7 @@ var CPViewFlags = { },
|
|||||||
return _tag;
|
return _tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewWithTag:(CPInteger)aTag
|
- (CPView)viewWithTag:(CPInteger)aTag
|
||||||
{
|
{
|
||||||
if ([self tag] == aTag)
|
if ([self tag] == aTag)
|
||||||
return self;
|
return self;
|
||||||
@@ -755,6 +834,12 @@ var CPViewFlags = { },
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_backgroundType !== BackgroundTrivialColor)
|
if (_backgroundType !== BackgroundTrivialColor)
|
||||||
|
{
|
||||||
|
if (_backgroundType === BackgroundTransparentColor)
|
||||||
|
{
|
||||||
|
CPDOMDisplayServerSetStyleSize(_DOMImageParts[0], size.width, size.height);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
var images = [[_backgroundColor patternImage] imageSlices];
|
var images = [[_backgroundColor patternImage] imageSlices];
|
||||||
|
|
||||||
@@ -762,12 +847,10 @@ var CPViewFlags = { },
|
|||||||
{
|
{
|
||||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], size.width, size.height - _DOMImageSizes[0].height - _DOMImageSizes[2].height);
|
CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], size.width, size.height - _DOMImageSizes[0].height - _DOMImageSizes[2].height);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (_backgroundType === BackgroundHorizontalThreePartImage)
|
else if (_backgroundType === BackgroundHorizontalThreePartImage)
|
||||||
{
|
{
|
||||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], size.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, size.height);
|
CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], size.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, size.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (_backgroundType === BackgroundNinePartImage)
|
else if (_backgroundType === BackgroundNinePartImage)
|
||||||
{
|
{
|
||||||
var width = size.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width,
|
var width = size.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width,
|
||||||
@@ -780,6 +863,7 @@ var CPViewFlags = { },
|
|||||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[7], width, _DOMImageSizes[7].height);
|
CPDOMDisplayServerSetStyleSize(_DOMImageParts[7], width, _DOMImageSizes[7].height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (_postsFrameChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications)
|
if (_postsFrameChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications)
|
||||||
@@ -816,6 +900,16 @@ var CPViewFlags = { },
|
|||||||
return _CGRectMakeCopy(_bounds);
|
return _CGRectMakeCopy(_bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CGPoint)boundsOrigin
|
||||||
|
{
|
||||||
|
return _CGPointMakeCopy(_bounds.origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGSize)boundsSize
|
||||||
|
{
|
||||||
|
return _CGSizeMakeCopy(_bounds.size);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the location of the receiver inside its frame. The method
|
Sets the location of the receiver inside its frame. The method
|
||||||
posts a CPViewBoundsDidChangeNotification to the
|
posts a CPViewBoundsDidChangeNotification to the
|
||||||
@@ -1088,7 +1182,31 @@ var CPViewFlags = { },
|
|||||||
}
|
}
|
||||||
while (view = [view superview]);
|
while (view = [view superview]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[self _notifyViewDidHide];
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[self _notifyViewDidUnhide];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_notifyViewDidHide
|
||||||
|
{
|
||||||
|
[self viewDidHide];
|
||||||
|
|
||||||
|
var count = [_subviews count];
|
||||||
|
while (count--)
|
||||||
|
[_subviews[count] _notifyViewDidHide];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_notifyViewDidUnhide
|
||||||
|
{
|
||||||
|
[self viewDidUnhide];
|
||||||
|
|
||||||
|
var count = [_subviews count];
|
||||||
|
while (count--)
|
||||||
|
[_subviews[count] _notifyViewDidUnhide];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -1099,6 +1217,23 @@ var CPViewFlags = { },
|
|||||||
return _isHidden;
|
return _isHidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setClipsToBounds:(BOOL)shouldClip
|
||||||
|
{
|
||||||
|
if (_clipsToBounds === shouldClip)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_clipsToBounds = shouldClip;
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
_DOMElement.style.overflow = _clipsToBounds ? "hidden" : "visible";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)clipsToBounds
|
||||||
|
{
|
||||||
|
return _clipsToBounds;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the opacity of the receiver. The value must be in the range of 0.0 to 1.0, where 0.0 is
|
Sets the opacity of the receiver. The value must be in the range of 0.0 to 1.0, where 0.0 is
|
||||||
completely transparent and 1.0 is completely opaque.
|
completely transparent and 1.0 is completely opaque.
|
||||||
@@ -1115,7 +1250,7 @@ var CPViewFlags = { },
|
|||||||
|
|
||||||
if (CPFeatureIsCompatible(CPOpacityRequiresFilterFeature))
|
if (CPFeatureIsCompatible(CPOpacityRequiresFilterFeature))
|
||||||
{
|
{
|
||||||
if (anAlphaValue == 1.0)
|
if (anAlphaValue === 1.0)
|
||||||
try { _DOMElement.style.removeAttribute("filter") } catch (anException) { }
|
try { _DOMElement.style.removeAttribute("filter") } catch (anException) { }
|
||||||
else
|
else
|
||||||
_DOMElement.style.filter = "alpha(opacity=" + anAlphaValue * 100 + ")";
|
_DOMElement.style.filter = "alpha(opacity=" + anAlphaValue * 100 + ")";
|
||||||
@@ -1149,6 +1284,34 @@ var CPViewFlags = { },
|
|||||||
return view !== nil;
|
return view !== nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Called when the return value of isHiddenOrHasHiddenAncestor becomes YES,
|
||||||
|
e.g. when this view becomes hidden due to a setHidden:YES message to
|
||||||
|
itself or to one of its superviews.
|
||||||
|
|
||||||
|
Note: in the current implementation, viewDidHide may be called multiple
|
||||||
|
times if additional superviews are hidden, even if
|
||||||
|
isHiddenOrHasHiddenAncestor was already YES.
|
||||||
|
*/
|
||||||
|
- (void)viewDidHide
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Called when the return value of isHiddenOrHasHiddenAncestor becomes NO,
|
||||||
|
e.g. when this view stops being hidden due to a setHidden:NO message to
|
||||||
|
itself or to one of its superviews.
|
||||||
|
|
||||||
|
Note: in the current implementation, viewDidUnhide may be called multiple
|
||||||
|
times if additional superviews are unhidden, even if
|
||||||
|
isHiddenOrHasHiddenAncestor was already NO.
|
||||||
|
*/
|
||||||
|
- (void)viewDidUnhide
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns whether the receiver should be sent a \c -mouseDown: message for \c anEvent.<br/>
|
Returns whether the receiver should be sent a \c -mouseDown: message for \c anEvent.<br/>
|
||||||
Returns \c YES by default.
|
Returns \c YES by default.
|
||||||
@@ -1202,6 +1365,14 @@ var CPViewFlags = { },
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns \c YES if this view requires a panel to become key. Normally only text fields, so this returns \c NO.
|
||||||
|
*/
|
||||||
|
- (BOOL)needsPanelToBecomeKey
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns \c YES if mouse events aren't needed by the receiver and can be sent to the superview. The
|
Returns \c YES if mouse events aren't needed by the receiver and can be sent to the superview. The
|
||||||
default implementation returns \c NO if the view is opaque.
|
default implementation returns \c NO if the view is opaque.
|
||||||
@@ -1217,6 +1388,22 @@ var CPViewFlags = { },
|
|||||||
[super mouseDown:anEvent];
|
[super mouseDown:anEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)rightMouseDown:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
var menu = [self menuForEvent:anEvent];
|
||||||
|
if (menu)
|
||||||
|
[CPMenu popUpContextMenu:menu withEvent:anEvent forView:self];
|
||||||
|
else if ([[self nextResponder] isKindOfClass:CPView])
|
||||||
|
[super rightMouseDown:anEvent];
|
||||||
|
else
|
||||||
|
[[[anEvent window] platformWindow] _propagateContextMenuDOMEvent:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPMenu)menuForEvent:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
return [self menu] || [[self class] defaultMenu];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the background color of the receiver.
|
Sets the background color of the receiver.
|
||||||
@param aColor the new color for the receiver's background
|
@param aColor the new color for the receiver's background
|
||||||
@@ -1226,32 +1413,37 @@ var CPViewFlags = { },
|
|||||||
if (_backgroundColor == aColor)
|
if (_backgroundColor == aColor)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (aColor == [CPNull null])
|
||||||
|
aColor = nil;
|
||||||
|
|
||||||
_backgroundColor = aColor;
|
_backgroundColor = aColor;
|
||||||
|
|
||||||
#if PLATFORM(DOM)
|
#if PLATFORM(DOM)
|
||||||
var patternImage = [_backgroundColor patternImage],
|
var patternImage = [_backgroundColor patternImage],
|
||||||
|
colorExists = _backgroundColor && ([_backgroundColor patternImage] || [_backgroundColor alphaComponent] > 0.0),
|
||||||
|
colorHasAlpha = colorExists && [_backgroundColor alphaComponent] < 1.0,
|
||||||
|
supportsRGBA = CPFeatureIsCompatible(CPCSSRGBAFeature),
|
||||||
|
colorNeedsDOMElement = colorHasAlpha && !supportsRGBA,
|
||||||
amount = 0;
|
amount = 0;
|
||||||
|
|
||||||
if ([patternImage isThreePartImage])
|
if ([patternImage isThreePartImage])
|
||||||
{
|
{
|
||||||
_backgroundType = [patternImage isVertical] ? BackgroundVerticalThreePartImage : BackgroundHorizontalThreePartImage;
|
_backgroundType = [patternImage isVertical] ? BackgroundVerticalThreePartImage : BackgroundHorizontalThreePartImage;
|
||||||
|
|
||||||
amount = 3 - _DOMImageParts.length;
|
amount = 3 - _DOMImageParts.length;
|
||||||
}
|
}
|
||||||
else if ([patternImage isNinePartImage])
|
else if ([patternImage isNinePartImage])
|
||||||
{
|
{
|
||||||
_backgroundType = BackgroundNinePartImage;
|
_backgroundType = BackgroundNinePartImage;
|
||||||
|
|
||||||
amount = 9 - _DOMImageParts.length;
|
amount = 9 - _DOMImageParts.length;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_backgroundType = BackgroundTrivialColor;
|
_backgroundType = colorNeedsDOMElement ? BackgroundTransparentColor : BackgroundTrivialColor;
|
||||||
|
amount = (colorNeedsDOMElement ? 1 : 0) - _DOMImageParts.length;
|
||||||
amount = 0 - _DOMImageParts.length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (amount > 0)
|
if (amount > 0)
|
||||||
|
{
|
||||||
while (amount--)
|
while (amount--)
|
||||||
{
|
{
|
||||||
var DOMElement = DOMElementPrototype.cloneNode(false);
|
var DOMElement = DOMElementPrototype.cloneNode(false);
|
||||||
@@ -1261,20 +1453,34 @@ var CPViewFlags = { },
|
|||||||
_DOMImageParts.push(DOMElement);
|
_DOMImageParts.push(DOMElement);
|
||||||
_DOMElement.appendChild(DOMElement);
|
_DOMElement.appendChild(DOMElement);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
amount = -amount;
|
amount = -amount;
|
||||||
|
|
||||||
while (amount--)
|
while (amount--)
|
||||||
_DOMElement.removeChild(_DOMImageParts.pop());
|
_DOMElement.removeChild(_DOMImageParts.pop());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_backgroundType == BackgroundTrivialColor)
|
if (_backgroundType === BackgroundTrivialColor || _backgroundType === BackgroundTransparentColor)
|
||||||
|
{
|
||||||
|
var colorCSS = colorExists ? [_backgroundColor cssString] : "";
|
||||||
|
|
||||||
// Opera doesn't like DOM properties set to nil.
|
if (colorNeedsDOMElement)
|
||||||
// https://trac.280north.com/ticket/7
|
{
|
||||||
_DOMElement.style.background = _backgroundColor ? [_backgroundColor cssString] : "";
|
_DOMElement.style.background = "";
|
||||||
|
_DOMImageParts[0].style.background = [_backgroundColor cssString];
|
||||||
|
|
||||||
|
if (CPFeatureIsCompatible(CPOpacityRequiresFilterFeature))
|
||||||
|
_DOMImageParts[0].style.filter = "alpha(opacity=" + [_backgroundColor alphaComponent] * 100 + ")";
|
||||||
|
else
|
||||||
|
_DOMImageParts[0].style.opacity = [_backgroundColor alphaComponent];
|
||||||
|
|
||||||
|
var size = [self bounds].size;
|
||||||
|
CPDOMDisplayServerSetStyleSize(_DOMImageParts[0], size.width, size.height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_DOMElement.style.background = colorCSS;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var slices = [patternImage imageSlices],
|
var slices = [patternImage imageSlices],
|
||||||
@@ -1289,6 +1495,14 @@ var CPViewFlags = { },
|
|||||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[count], size.width, size.height);
|
CPDOMDisplayServerSetStyleSize(_DOMImageParts[count], size.width, size.height);
|
||||||
|
|
||||||
_DOMImageParts[count].style.background = image ? "url(\"" + [image filename] + "\")" : "";
|
_DOMImageParts[count].style.background = image ? "url(\"" + [image filename] + "\")" : "";
|
||||||
|
|
||||||
|
if (!supportsRGBA)
|
||||||
|
{
|
||||||
|
if (CPFeatureIsCompatible(CPOpacityRequiresFilterFeature))
|
||||||
|
try { _DOMImageParts[count].style.removeAttribute("filter") } catch (anException) { }
|
||||||
|
else
|
||||||
|
_DOMImageParts[count].style.opacity = 1.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_backgroundType == BackgroundNinePartImage)
|
if (_backgroundType == BackgroundNinePartImage)
|
||||||
@@ -1517,7 +1731,7 @@ setBoundsOrigin:
|
|||||||
var theWindow = [self window];
|
var theWindow = [self window];
|
||||||
|
|
||||||
[theWindow _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
|
[theWindow _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
|
||||||
[_registeredDraggedTypes addObjectsFromArray:pasteboardTypes]
|
[_registeredDraggedTypes addObjectsFromArray:pasteboardTypes];
|
||||||
[theWindow _noteRegisteredDraggedTypes:_registeredDraggedTypes];
|
[theWindow _noteRegisteredDraggedTypes:_registeredDraggedTypes];
|
||||||
|
|
||||||
_registeredDraggedTypesArray = nil;
|
_registeredDraggedTypesArray = nil;
|
||||||
@@ -1629,12 +1843,17 @@ setBoundsOrigin:
|
|||||||
|
|
||||||
- (void)displayRectIgnoringOpacity:(CGRect)aRect inContext:(CPGraphicsContext)aGraphicsContext
|
- (void)displayRectIgnoringOpacity:(CGRect)aRect inContext:(CPGraphicsContext)aGraphicsContext
|
||||||
{
|
{
|
||||||
|
if ([self isHidden])
|
||||||
|
return;
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
[self lockFocus];
|
[self lockFocus];
|
||||||
|
|
||||||
CGContextClearRect([[CPGraphicsContext currentContext] graphicsPort], aRect);
|
CGContextClearRect([[CPGraphicsContext currentContext] graphicsPort], aRect);
|
||||||
|
|
||||||
[self drawRect:aRect];
|
[self drawRect:aRect];
|
||||||
[self unlockFocus];
|
[self unlockFocus];
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewWillDraw
|
- (void)viewWillDraw
|
||||||
@@ -1666,8 +1885,9 @@ setBoundsOrigin:
|
|||||||
_DOMContentsElement.style.width = ROUND(_CGRectGetWidth(_frame)) + "px";
|
_DOMContentsElement.style.width = ROUND(_CGRectGetWidth(_frame)) + "px";
|
||||||
_DOMContentsElement.style.height = ROUND(_CGRectGetHeight(_frame)) + "px";
|
_DOMContentsElement.style.height = ROUND(_CGRectGetHeight(_frame)) + "px";
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
CPDOMDisplayServerAppendChild(_DOMElement, _DOMContentsElement);
|
CPDOMDisplayServerAppendChild(_DOMElement, _DOMContentsElement);
|
||||||
|
#endif
|
||||||
_graphicsContext = [CPGraphicsContext graphicsContextWithGraphicsPort:graphicsPort flipped:YES];
|
_graphicsContext = [CPGraphicsContext graphicsContextWithGraphicsPort:graphicsPort flipped:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1863,12 +2083,11 @@ setBoundsOrigin:
|
|||||||
|
|
||||||
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
|
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
var subviews = [self subviews],
|
var count = [_subviews count];
|
||||||
count = [subviews count];
|
|
||||||
|
|
||||||
// Is reverse iteration correct here? It matches the other (correct) code like hit testing.
|
// Is reverse iteration correct here? It matches the other (correct) code like hit testing.
|
||||||
while (count--)
|
while (count--)
|
||||||
if ([subviews[count] performKeyEquivalent:anEvent])
|
if ([_subviews[count] performKeyEquivalent:anEvent])
|
||||||
return YES;
|
return YES;
|
||||||
|
|
||||||
return NO;
|
return NO;
|
||||||
@@ -2029,11 +2248,29 @@ setBoundsOrigin:
|
|||||||
|
|
||||||
#pragma mark Theme Attributes
|
#pragma mark Theme Attributes
|
||||||
|
|
||||||
+ (CPString)themeClass
|
+ (CPString)defaultThemeClass
|
||||||
{
|
{
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CPString)themeClass
|
||||||
|
{
|
||||||
|
if (_themeClass)
|
||||||
|
return _themeClass;
|
||||||
|
|
||||||
|
return [[self class] defaultThemeClass];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setThemeClass:(CPString)theClass
|
||||||
|
{
|
||||||
|
_themeClass = theClass;
|
||||||
|
|
||||||
|
[self _loadThemeAttributes];
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
+ (CPDictionary)themeAttributes
|
+ (CPDictionary)themeAttributes
|
||||||
{
|
{
|
||||||
return nil;
|
return nil;
|
||||||
@@ -2046,7 +2283,8 @@ setBoundsOrigin:
|
|||||||
|
|
||||||
var theClass = [self class],
|
var theClass = [self class],
|
||||||
CPViewClass = [CPView class],
|
CPViewClass = [CPView class],
|
||||||
attributes = [];
|
attributes = [],
|
||||||
|
nullValue = [CPNull null];
|
||||||
|
|
||||||
for (; theClass && theClass !== CPViewClass; theClass = [theClass superclass])
|
for (; theClass && theClass !== CPViewClass; theClass = [theClass superclass])
|
||||||
{
|
{
|
||||||
@@ -2070,9 +2308,10 @@ setBoundsOrigin:
|
|||||||
|
|
||||||
while (attributeCount--)
|
while (attributeCount--)
|
||||||
{
|
{
|
||||||
var attributeName = attributeKeys[attributeCount];
|
var attributeName = attributeKeys[attributeCount],
|
||||||
|
attributeValue = [attributeDictionary objectForKey:attributeName];
|
||||||
|
|
||||||
attributes.push([attributeDictionary objectForKey:attributeName]);
|
attributes.push(attributeValue === nullValue ? nil : attributeValue);
|
||||||
attributes.push(attributeName);
|
attributes.push(attributeName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2090,7 +2329,7 @@ setBoundsOrigin:
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var theme = [self theme],
|
var theme = [self theme],
|
||||||
themeClass = [theClass themeClass];
|
themeClass = [self themeClass];
|
||||||
|
|
||||||
_themeAttributes = {};
|
_themeAttributes = {};
|
||||||
|
|
||||||
@@ -2099,7 +2338,7 @@ setBoundsOrigin:
|
|||||||
var attributeName = attributes[count--],
|
var attributeName = attributes[count--],
|
||||||
attribute = [[_CPThemeAttribute alloc] initWithName:attributeName defaultValue:attributes[count]];
|
attribute = [[_CPThemeAttribute alloc] initWithName:attributeName defaultValue:attributes[count]];
|
||||||
|
|
||||||
[attribute setParentAttribute:[theme _attributeWithName:attributeName forClass:themeClass]];
|
[attribute setParentAttribute:[theme attributeWithName:attributeName forClass:themeClass]];
|
||||||
|
|
||||||
_themeAttributes[attributeName] = attribute;
|
_themeAttributes[attributeName] = attribute;
|
||||||
}
|
}
|
||||||
@@ -2126,11 +2365,11 @@ setBoundsOrigin:
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var theme = [self theme],
|
var theme = [self theme],
|
||||||
themeClass = [[self class] themeClass];
|
themeClass = [self themeClass];
|
||||||
|
|
||||||
for (var attributeName in _themeAttributes)
|
for (var attributeName in _themeAttributes)
|
||||||
if (_themeAttributes.hasOwnProperty(attributeName))
|
if (_themeAttributes.hasOwnProperty(attributeName))
|
||||||
[_themeAttributes[attributeName] setParentAttribute:[theme _attributeWithName:attributeName forClass:themeClass]];
|
[_themeAttributes[attributeName] setParentAttribute:[theme attributeWithName:attributeName forClass:themeClass]];
|
||||||
|
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
@@ -2200,7 +2439,7 @@ setBoundsOrigin:
|
|||||||
return [_themeAttributes[aName] value];
|
return [_themeAttributes[aName] value];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)currentValueForThemeAttribute:(CPString)aName
|
- (id)currentValueForThemeAttribute:(CPString)aName
|
||||||
{
|
{
|
||||||
if (!_themeAttributes || !_themeAttributes[aName])
|
if (!_themeAttributes || !_themeAttributes[aName])
|
||||||
[CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"];
|
[CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"];
|
||||||
@@ -2256,6 +2495,14 @@ setBoundsOrigin:
|
|||||||
return _ephemeralSubviewsForNames[aViewName];
|
return _ephemeralSubviewsForNames[aViewName];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CPView)ephemeralSubviewNamed:(CPString)aViewName
|
||||||
|
{
|
||||||
|
if (!_ephemeralSubviewsForNames)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
return (_ephemeralSubviewsForNames[aViewName] || nil);
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
||||||
@@ -2269,6 +2516,7 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
|||||||
CPViewSubviewsKey = @"CPViewSubviewsKey",
|
CPViewSubviewsKey = @"CPViewSubviewsKey",
|
||||||
CPViewSuperviewKey = @"CPViewSuperviewKey",
|
CPViewSuperviewKey = @"CPViewSuperviewKey",
|
||||||
CPViewTagKey = @"CPViewTagKey",
|
CPViewTagKey = @"CPViewTagKey",
|
||||||
|
CPViewThemeClassKey = @"CPViewThemeClassKey",
|
||||||
CPViewThemeStateKey = @"CPViewThemeStateKey",
|
CPViewThemeStateKey = @"CPViewThemeStateKey",
|
||||||
CPViewWindowKey = @"CPViewWindowKey",
|
CPViewWindowKey = @"CPViewWindowKey",
|
||||||
CPViewNextKeyViewKey = @"CPViewNextKeyViewKey",
|
CPViewNextKeyViewKey = @"CPViewNextKeyViewKey",
|
||||||
@@ -2348,11 +2596,12 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
|||||||
[self setupViewFlags];
|
[self setupViewFlags];
|
||||||
|
|
||||||
_theme = [CPTheme defaultTheme];
|
_theme = [CPTheme defaultTheme];
|
||||||
|
_themeClass = [aCoder decodeObjectForKey:CPViewThemeClassKey];
|
||||||
_themeState = CPThemeState([aCoder decodeIntForKey:CPViewThemeStateKey]);
|
_themeState = CPThemeState([aCoder decodeIntForKey:CPViewThemeStateKey]);
|
||||||
_themeAttributes = {};
|
_themeAttributes = {};
|
||||||
|
|
||||||
var theClass = [self class],
|
var theClass = [self class],
|
||||||
themeClass = [theClass themeClass],
|
themeClass = [self themeClass],
|
||||||
attributes = [theClass _themeAttributes],
|
attributes = [theClass _themeAttributes],
|
||||||
count = attributes.length;
|
count = attributes.length;
|
||||||
|
|
||||||
@@ -2435,6 +2684,7 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
|||||||
if (previousKeyView !== nil)
|
if (previousKeyView !== nil)
|
||||||
[aCoder encodeConditionalObject:previousKeyView forKey:CPViewPreviousKeyViewKey];
|
[aCoder encodeConditionalObject:previousKeyView forKey:CPViewPreviousKeyViewKey];
|
||||||
|
|
||||||
|
[aCoder encodeObject:[self themeClass] forKey:CPViewThemeClassKey];
|
||||||
[aCoder encodeInt:CPThemeStateName(_themeState) forKey:CPViewThemeStateKey];
|
[aCoder encodeInt:CPThemeStateName(_themeState) forKey:CPViewThemeStateKey];
|
||||||
|
|
||||||
for (var attributeName in _themeAttributes)
|
for (var attributeName in _themeAttributes)
|
||||||
|
|||||||
@@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
* CPViewAnimation.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Klaas Pieter Annema on September 3, 2009.
|
||||||
|
* Copyright 2009, Sofa BV
|
||||||
|
*
|
||||||
|
* 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 "CPAnimation.j"
|
||||||
|
|
||||||
|
|
||||||
|
CPViewAnimationTargetKey = @"CPViewAnimationTarget";
|
||||||
|
CPViewAnimationStartFrameKey = @"CPViewAnimationStartFrame";
|
||||||
|
CPViewAnimationEndFrameKey = @"CPViewAnimationEndFrame";
|
||||||
|
CPViewAnimationEffectKey = @"CPViewAnimationEffect";
|
||||||
|
|
||||||
|
CPViewAnimationFadeInEffect = @"CPViewAnimationFadeIn";
|
||||||
|
CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
|
||||||
|
|
||||||
|
@implementation CPViewAnimation : CPAnimation
|
||||||
|
{
|
||||||
|
CPArray _viewAnimations;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithViewAnimations:(CPArray)viewAnimations
|
||||||
|
{
|
||||||
|
if (self = [super initWithDuration:0.5 animationCurve:CPAnimationLinear])
|
||||||
|
{
|
||||||
|
[self setViewAnimations:viewAnimations];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)startAnimation
|
||||||
|
{
|
||||||
|
var animationIndex = [_viewAnimations count];
|
||||||
|
while (animationIndex--)
|
||||||
|
{
|
||||||
|
var dictionary = [_viewAnimations objectAtIndex:animationIndex],
|
||||||
|
view = [self _targetView:dictionary],
|
||||||
|
startFrame = [self _startFrame:dictionary];
|
||||||
|
|
||||||
|
[view setFrame:startFrame];
|
||||||
|
|
||||||
|
var effect = [self _effect:dictionary];
|
||||||
|
if (effect === CPViewAnimationFadeInEffect)
|
||||||
|
{
|
||||||
|
[view setAlphaValue:0.0];
|
||||||
|
[view setHidden:NO];
|
||||||
|
}
|
||||||
|
else if (effect === CPViewAnimationFadeOutEffect)
|
||||||
|
[view setAlphaValue:1.0];
|
||||||
|
}
|
||||||
|
|
||||||
|
[super startAnimation];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setCurrentProgress:(CPAnimationProgress)progress
|
||||||
|
{
|
||||||
|
[super setCurrentProgress:progress];
|
||||||
|
|
||||||
|
var animationIndex = [_viewAnimations count];
|
||||||
|
while (animationIndex--)
|
||||||
|
{
|
||||||
|
var dictionary = [_viewAnimations objectAtIndex:animationIndex],
|
||||||
|
view = [self _targetView:dictionary],
|
||||||
|
startFrame = [self _startFrame:dictionary],
|
||||||
|
endFrame = [self _endFrame:dictionary],
|
||||||
|
differenceFrame = _CGRectMakeZero();
|
||||||
|
|
||||||
|
differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x;
|
||||||
|
differenceFrame.origin.y = endFrame.origin.y - startFrame.origin.y;
|
||||||
|
differenceFrame.size.width = endFrame.size.width - startFrame.size.width;
|
||||||
|
differenceFrame.size.height = endFrame.size.height - startFrame.size.height;
|
||||||
|
|
||||||
|
var intermediateFrame = _CGRectMakeZero();
|
||||||
|
intermediateFrame.origin.x = startFrame.origin.x + differenceFrame.origin.x * progress;
|
||||||
|
intermediateFrame.origin.y = startFrame.origin.y + differenceFrame.origin.y * progress;
|
||||||
|
intermediateFrame.size.width = startFrame.size.width + differenceFrame.size.width * progress;
|
||||||
|
intermediateFrame.size.height = startFrame.size.height + differenceFrame.size.height * progress;
|
||||||
|
|
||||||
|
[view setFrame:intermediateFrame];
|
||||||
|
|
||||||
|
// Update the view's alpha value
|
||||||
|
var effect = [self _effect:dictionary];
|
||||||
|
if (effect === CPViewAnimationFadeInEffect)
|
||||||
|
[view setAlphaValue:1.0 * progress];
|
||||||
|
else if (effect === CPViewAnimationFadeOutEffect)
|
||||||
|
[view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * progress];
|
||||||
|
|
||||||
|
if (progress === 1.0)
|
||||||
|
[view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)stopAnimation
|
||||||
|
{
|
||||||
|
var animationIndex = [_viewAnimations count];
|
||||||
|
while (animationIndex--)
|
||||||
|
{
|
||||||
|
var dictionary = [_viewAnimations objectAtIndex:animationIndex],
|
||||||
|
view = [self _targetView:dictionary],
|
||||||
|
endFrame = [self _endFrame:dictionary];
|
||||||
|
|
||||||
|
[view setFrame:endFrame];
|
||||||
|
|
||||||
|
var effect = [self _effect:dictionary];
|
||||||
|
if (effect === CPViewAnimationFadeInEffect)
|
||||||
|
[view setAlphaValue:1.0];
|
||||||
|
else if (effect === CPViewAnimationFadeOutEffect)
|
||||||
|
[view setAlphaValue:0.0];
|
||||||
|
|
||||||
|
[view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0];
|
||||||
|
}
|
||||||
|
|
||||||
|
[super stopAnimation];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)_targetView:(CPDictionary)dictionary
|
||||||
|
{
|
||||||
|
var targetView = [dictionary valueForKey:CPViewAnimationTargetKey];
|
||||||
|
if (!targetView)
|
||||||
|
[CPException raise:CPInternalInconsistencyException reason:[CPString stringWithFormat:@"view animation: %@ does not have a target view", [dictionary description]]];
|
||||||
|
|
||||||
|
return targetView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)_startFrame:(CPDictionary)dictionary
|
||||||
|
{
|
||||||
|
var startFrame = [dictionary valueForKey:CPViewAnimationStartFrameKey];
|
||||||
|
if (!startFrame)
|
||||||
|
return [[self _targetView:dictionary] frame];
|
||||||
|
|
||||||
|
return startFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)_endFrame:(CPDictionary)dictionary
|
||||||
|
{
|
||||||
|
var endFrame = [dictionary valueForKey:CPViewAnimationEndFrameKey];
|
||||||
|
if (!endFrame)
|
||||||
|
return [[self _targetView:dictionary] frame];
|
||||||
|
|
||||||
|
return endFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)_effect:(CPDictionary)dictionary
|
||||||
|
{
|
||||||
|
return [dictionary valueForKey:CPViewAnimationEffectKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPArray)viewAnimations
|
||||||
|
{
|
||||||
|
return _viewAnimations;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setViewAnimations:(CPArray)viewAnimations
|
||||||
|
{
|
||||||
|
if (viewAnimations != _viewAnimations)
|
||||||
|
{
|
||||||
|
[self stopAnimation];
|
||||||
|
_viewAnimations = [viewAnimations copy];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -20,7 +20,12 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@import <AppKit/CPResponder.j>
|
@import <Foundation/CPArray.j>
|
||||||
|
|
||||||
|
@import "CPApplication.j"
|
||||||
|
@import "CPCib.j"
|
||||||
|
@import "CPResponder.j"
|
||||||
|
|
||||||
|
|
||||||
var CPViewControllerCachedCibs;
|
var CPViewControllerCachedCibs;
|
||||||
|
|
||||||
@@ -47,7 +52,8 @@ var CPViewControllerCachedCibs;
|
|||||||
*/
|
*/
|
||||||
@implementation CPViewController : CPResponder
|
@implementation CPViewController : CPResponder
|
||||||
{
|
{
|
||||||
CPView _view;
|
CPView _view @accessors(property=view);
|
||||||
|
BOOL _isLoading;
|
||||||
|
|
||||||
id _representedObject @accessors(property=representedObject);
|
id _representedObject @accessors(property=representedObject);
|
||||||
CPString _title @accessors(property=title);
|
CPString _title @accessors(property=title);
|
||||||
@@ -99,6 +105,8 @@ var CPViewControllerCachedCibs;
|
|||||||
_cibName = aCibNameOrNil;
|
_cibName = aCibNameOrNil;
|
||||||
_cibBundle = aCibBundleOrNil || [CPBundle mainBundle];
|
_cibBundle = aCibBundleOrNil || [CPBundle mainBundle];
|
||||||
_cibExternalNameTable = anExternalNameTable || [CPDictionary dictionaryWithObject:self forKey:CPCibOwner];
|
_cibExternalNameTable = anExternalNameTable || [CPDictionary dictionaryWithObject:self forKey:CPCibOwner];
|
||||||
|
|
||||||
|
_isLoading = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -111,10 +119,10 @@ var CPViewControllerCachedCibs;
|
|||||||
If you create your views manually, you must override this method and use it to create your view and assign it to the view property.
|
If you create your views manually, you must override this method and use it to create your view and assign it to the view property.
|
||||||
The default implementation for programmatic views is to create a plain view. You can invoke super to utilize this view.
|
The default implementation for programmatic views is to create a plain view. You can invoke super to utilize this view.
|
||||||
|
|
||||||
If you use Interface Builder to create your views and initialize the view controllerŃthat is, you initialize the view using the
|
If you use Interface Builder to create your views, you initialize the view using the
|
||||||
initWithCibName:bundle: methodŃthen you must not override this method. The consequences risk shattering the space-time continuum.
|
initWithCibName:bundle: method then you must not override this method. The consequences risk shattering the space-time continuum.
|
||||||
|
|
||||||
Note: The cib loading system is currently asynchronous.
|
Note: The cib loading system is currently synchronous.
|
||||||
*/
|
*/
|
||||||
- (void)loadView
|
- (void)loadView
|
||||||
{
|
{
|
||||||
@@ -138,13 +146,13 @@ var CPViewControllerCachedCibs;
|
|||||||
Returns the view that the controller manages.
|
Returns the view that the controller manages.
|
||||||
If this property is nil, the controller sends loadView to itself to create the view that it manages.
|
If this property is nil, the controller sends loadView to itself to create the view that it manages.
|
||||||
Subclasses should override the loadView method to create any custom views. The default value is nil.
|
Subclasses should override the loadView method to create any custom views. The default value is nil.
|
||||||
|
|
||||||
Note: An error will not be thrown if after -loadView, the view property is still nil. -view will simply return nil, but will continue to call -loadView on subsequent calls.
|
|
||||||
*/
|
*/
|
||||||
- (CPView)view
|
- (CPView)view
|
||||||
{
|
{
|
||||||
if (!_view)
|
if (!_view)
|
||||||
{
|
{
|
||||||
|
_isLoading = YES;
|
||||||
|
|
||||||
var cibOwner = [_cibExternalNameTable objectForKey:CPCibOwner];
|
var cibOwner = [_cibExternalNameTable objectForKey:CPCibOwner];
|
||||||
|
|
||||||
if ([cibOwner respondsToSelector:@selector(viewControllerWillLoadCib:)])
|
if ([cibOwner respondsToSelector:@selector(viewControllerWillLoadCib:)])
|
||||||
@@ -155,14 +163,35 @@ var CPViewControllerCachedCibs;
|
|||||||
if (_view === nil && [cibOwner isKindOfClass:[CPDocument class]])
|
if (_view === nil && [cibOwner isKindOfClass:[CPDocument class]])
|
||||||
[self setView:[cibOwner valueForKey:@"view"]];
|
[self setView:[cibOwner valueForKey:@"view"]];
|
||||||
|
|
||||||
|
if (!_view)
|
||||||
|
{
|
||||||
|
var reason = [CPString stringWithFormat:@"View for %@ could not be loaded from Cib or no view specified. Override loadView to load the view manually.", self];
|
||||||
|
|
||||||
|
[CPException raise:CPInternalInconsistencyException reason:reason];
|
||||||
|
}
|
||||||
|
|
||||||
if ([cibOwner respondsToSelector:@selector(viewControllerDidLoadCib:)])
|
if ([cibOwner respondsToSelector:@selector(viewControllerDidLoadCib:)])
|
||||||
[cibOwner viewControllerDidLoadCib:self];
|
[cibOwner viewControllerDidLoadCib:self];
|
||||||
|
|
||||||
|
_isLoading = NO;
|
||||||
|
[self viewDidLoad];
|
||||||
}
|
}
|
||||||
|
|
||||||
return _view;
|
return _view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
This method is called after the view controller has loaded its associated views into memory.
|
||||||
|
This method is called regardless of whether the views were stored in a nib file or created programmatically in the loadView method.
|
||||||
|
This method is most commonly used to perform additional initialization steps on views that are loaded from cib files.
|
||||||
|
*/
|
||||||
|
- (void)viewDidLoad
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Manually sets the view that the controller manages.
|
Manually sets the view that the controller manages.
|
||||||
Setting to nil will cause -loadView to be called on all subsequent calls of -view.
|
Setting to nil will cause -loadView to be called on all subsequent calls of -view.
|
||||||
@@ -171,7 +200,13 @@ var CPViewControllerCachedCibs;
|
|||||||
*/
|
*/
|
||||||
- (void)setView:(CPView)aView
|
- (void)setView:(CPView)aView
|
||||||
{
|
{
|
||||||
|
var viewWasLoaded = !_view;
|
||||||
|
|
||||||
_view = aView;
|
_view = aView;
|
||||||
|
|
||||||
|
// Make sure the viewDidLoad method is called if the view is set directly
|
||||||
|
if (!_isLoading && viewWasLoaded)
|
||||||
|
[self viewDidLoad];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+51
-7
@@ -20,9 +20,8 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@import <AppKit/CPView.j>
|
@import "CPView.j"
|
||||||
|
@import "CPScrollView.j"
|
||||||
#include "Platform/Platform.h"
|
|
||||||
|
|
||||||
|
|
||||||
// FIXME: implement these where possible:
|
// FIXME: implement these where possible:
|
||||||
@@ -74,6 +73,8 @@ CPWebViewScrollNative = 2;
|
|||||||
|
|
||||||
int _scrollMode;
|
int _scrollMode;
|
||||||
CGSize _scrollSize;
|
CGSize _scrollSize;
|
||||||
|
|
||||||
|
int _loadHTMLStringTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CPRect)frameRect frameName:(CPString)frameName groupName:(CPString)groupName
|
- (id)initWithFrame:(CPRect)frameRect frameName:(CPString)frameName groupName:(CPString)groupName
|
||||||
@@ -110,6 +111,7 @@ CPWebViewScrollNative = 2;
|
|||||||
_iframe.style.width = "100%";
|
_iframe.style.width = "100%";
|
||||||
_iframe.style.height = "100%";
|
_iframe.style.height = "100%";
|
||||||
_iframe.style.borderWidth = "0px";
|
_iframe.style.borderWidth = "0px";
|
||||||
|
_iframe.frameBorder = "0";
|
||||||
|
|
||||||
[self setDrawsBackground:YES];
|
[self setDrawsBackground:YES];
|
||||||
|
|
||||||
@@ -171,7 +173,32 @@ CPWebViewScrollNative = 2;
|
|||||||
[self _resizeWebFrame];
|
[self _resizeWebFrame];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)_resizeWebFrame
|
- (void)_attachScrollEventIfNecessary
|
||||||
|
{
|
||||||
|
if (_scrollMode !== CPWebViewScrollAppKit)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var win = null;
|
||||||
|
try { win = [self DOMWindow]; } catch (e) {}
|
||||||
|
|
||||||
|
if (win && win.addEventListener)
|
||||||
|
{
|
||||||
|
var scrollEventHandler = function(anEvent)
|
||||||
|
{
|
||||||
|
var frameBounds = [self bounds],
|
||||||
|
frameCenter = CGPointMake(CGRectGetMidX(frameBounds), CGRectGetMidY(frameBounds)),
|
||||||
|
windowOrigin = [self convertPoint:frameCenter toView:nil],
|
||||||
|
globalOrigin = [[self window] convertBaseToBridge:windowOrigin];
|
||||||
|
|
||||||
|
anEvent._overrideLocation = globalOrigin;
|
||||||
|
[[[self window] platformWindow] scrollEvent:anEvent];
|
||||||
|
};
|
||||||
|
|
||||||
|
win.addEventListener("DOMMouseScroll", scrollEventHandler, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_resizeWebFrame
|
||||||
{
|
{
|
||||||
if (_scrollMode === CPWebViewScrollAppKit)
|
if (_scrollMode === CPWebViewScrollAppKit)
|
||||||
{
|
{
|
||||||
@@ -181,13 +208,14 @@ CPWebViewScrollNative = 2;
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
[_frameView setFrameSize:[_scrollView contentSize]];
|
var visibleRect = [_frameView visibleRect];
|
||||||
|
[_frameView setFrameSize:CGSizeMake(CGRectGetMaxX(visibleRect), CGRectGetMaxY(visibleRect))];
|
||||||
|
|
||||||
// try to get the document size so we can correctly set the frame
|
// try to get the document size so we can correctly set the frame
|
||||||
var win = null;
|
var win = null;
|
||||||
try { win = [self DOMWindow]; } catch (e) {}
|
try { win = [self DOMWindow]; } catch (e) {}
|
||||||
|
|
||||||
if (win && win.document)
|
if (win && win.document && win.document.body)
|
||||||
{
|
{
|
||||||
var width = win.document.body.scrollWidth,
|
var width = win.document.body.scrollWidth,
|
||||||
height = win.document.body.scrollHeight;
|
height = win.document.body.scrollHeight;
|
||||||
@@ -203,6 +231,8 @@ CPWebViewScrollNative = 2;
|
|||||||
|
|
||||||
[_frameView setFrameSize:CGSizeMake(800, 1600)];
|
[_frameView setFrameSize:CGSizeMake(800, 1600)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[_frameView scrollRectToVisible:visibleRect];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,6 +247,9 @@ CPWebViewScrollNative = 2;
|
|||||||
|
|
||||||
- (void)_setScrollMode:(int)aScrollMode
|
- (void)_setScrollMode:(int)aScrollMode
|
||||||
{
|
{
|
||||||
|
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||||
|
_scrollMode = CPWebViewScrollNative;
|
||||||
|
else
|
||||||
_scrollMode = aScrollMode;
|
_scrollMode = aScrollMode;
|
||||||
|
|
||||||
_ignoreLoadStart = YES;
|
_ignoreLoadStart = YES;
|
||||||
@@ -256,6 +289,8 @@ CPWebViewScrollNative = 2;
|
|||||||
|
|
||||||
[self _setScrollMode:CPWebViewScrollAppKit];
|
[self _setScrollMode:CPWebViewScrollAppKit];
|
||||||
|
|
||||||
|
[_frameView setFrameSize:[_scrollView contentSize]];
|
||||||
|
|
||||||
[self _startedLoading];
|
[self _startedLoading];
|
||||||
|
|
||||||
_ignoreLoadStart = YES;
|
_ignoreLoadStart = YES;
|
||||||
@@ -293,10 +328,18 @@ CPWebViewScrollNative = 2;
|
|||||||
// clear the iframe
|
// clear the iframe
|
||||||
_iframe.src = "";
|
_iframe.src = "";
|
||||||
|
|
||||||
|
if (_loadHTMLStringTimer !== nil)
|
||||||
|
{
|
||||||
|
window.clearTimeout(_loadHTMLStringTimer);
|
||||||
|
_loadHTMLStringTimer = nil;
|
||||||
|
}
|
||||||
|
|
||||||
// need to give the browser a chance to reset iframe, otherwise we'll be document.write()-ing the previous document
|
// need to give the browser a chance to reset iframe, otherwise we'll be document.write()-ing the previous document
|
||||||
window.setTimeout(function() {
|
_loadHTMLStringTimer = window.setTimeout(function()
|
||||||
|
{
|
||||||
var win = [self DOMWindow];
|
var win = [self DOMWindow];
|
||||||
|
|
||||||
|
if (win)
|
||||||
win.document.write(_html);
|
win.document.write(_html);
|
||||||
|
|
||||||
window.setTimeout(_loadCallback, 1);
|
window.setTimeout(_loadCallback, 1);
|
||||||
@@ -315,6 +358,7 @@ CPWebViewScrollNative = 2;
|
|||||||
- (void)_finishedLoading
|
- (void)_finishedLoading
|
||||||
{
|
{
|
||||||
[self _resizeWebFrame];
|
[self _resizeWebFrame];
|
||||||
|
[self _attachScrollEventIfNecessary];
|
||||||
|
|
||||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPWebViewProgressFinishedNotification object:self];
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPWebViewProgressFinishedNotification object:self];
|
||||||
|
|
||||||
|
|||||||
+419
-92
@@ -26,14 +26,9 @@
|
|||||||
|
|
||||||
@import "CGGeometry.j"
|
@import "CGGeometry.j"
|
||||||
@import "CPAnimation.j"
|
@import "CPAnimation.j"
|
||||||
|
@import "CPPlatformWindow.j"
|
||||||
@import "CPResponder.j"
|
@import "CPResponder.j"
|
||||||
@import "CPScreen.j"
|
@import "CPScreen.j"
|
||||||
@import "CPPlatformWindow.j"
|
|
||||||
|
|
||||||
#include "../Platform/Platform.h"
|
|
||||||
#include "../Platform/DOM/CPDOMDisplayServer.h"
|
|
||||||
|
|
||||||
#include "../CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -175,6 +170,9 @@ CPWindowBelow = 2;
|
|||||||
CPWindowWillCloseNotification = @"CPWindowWillCloseNotification";
|
CPWindowWillCloseNotification = @"CPWindowWillCloseNotification";
|
||||||
CPWindowDidBecomeMainNotification = @"CPWindowDidBecomeMainNotification";
|
CPWindowDidBecomeMainNotification = @"CPWindowDidBecomeMainNotification";
|
||||||
CPWindowDidResignMainNotification = @"CPWindowDidResignMainNotification";
|
CPWindowDidResignMainNotification = @"CPWindowDidResignMainNotification";
|
||||||
|
CPWindowDidBecomeKeyNotification = @"CPWindowDidBecomeKeyNotification";
|
||||||
|
CPWindowDidResignKeyNotification = @"CPWindowDidResignKeyNotification";
|
||||||
|
CPWindowDidResizeNotification = @"CPWindowDidResizeNotification";
|
||||||
CPWindowDidMoveNotification = @"CPWindowDidMoveNotification";
|
CPWindowDidMoveNotification = @"CPWindowDidMoveNotification";
|
||||||
CPWindowWillBeginSheetNotification = @"CPWindowWillBeginSheetNotification";
|
CPWindowWillBeginSheetNotification = @"CPWindowWillBeginSheetNotification";
|
||||||
CPWindowDidEndSheetNotification = @"CPWindowDidEndSheetNotification";
|
CPWindowDidEndSheetNotification = @"CPWindowDidEndSheetNotification";
|
||||||
@@ -197,6 +195,8 @@ var SHADOW_MARGIN_LEFT = 20.0,
|
|||||||
var CPWindowSaveImage = nil,
|
var CPWindowSaveImage = nil,
|
||||||
CPWindowSavingImage = nil;
|
CPWindowSavingImage = nil;
|
||||||
|
|
||||||
|
var CPWindowResizeTime = 0.2;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@class CPWindow
|
@class CPWindow
|
||||||
@@ -317,6 +317,8 @@ var CPWindowSaveImage = nil,
|
|||||||
CPDictionary _sheetContext;
|
CPDictionary _sheetContext;
|
||||||
CPWindow _parentView;
|
CPWindow _parentView;
|
||||||
BOOL _isSheet;
|
BOOL _isSheet;
|
||||||
|
|
||||||
|
_CPWindowFrameAnimation _frameAnimation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -369,6 +371,15 @@ CPTexturedBackgroundWindowMask
|
|||||||
[self setPlatformWindow:[CPPlatformWindow primaryPlatformWindow]];
|
[self setPlatformWindow:[CPPlatformWindow primaryPlatformWindow]];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// give zero sized borderless bridge windows a default size if we're not in the browser so they show up in NativeHost.
|
||||||
|
if ((aStyleMask & CPBorderlessBridgeWindowMask) && aContentRect.size.width === 0 && aContentRect.size.height === 0)
|
||||||
|
{
|
||||||
|
var visibleFrame = [[[CPScreen alloc] init] visibleFrame];
|
||||||
|
_frame.size.height = MIN(768.0, visibleFrame.size.height);
|
||||||
|
_frame.size.width = MIN(1024.0, visibleFrame.size.width);
|
||||||
|
_frame.origin.x = (visibleFrame.size.width - _frame.size.width) / 2;
|
||||||
|
_frame.origin.y = (visibleFrame.size.height - _frame.size.height) / 2;
|
||||||
|
}
|
||||||
[self setPlatformWindow:[[CPPlatformWindow alloc] initWithContentRect:_frame]];
|
[self setPlatformWindow:[[CPPlatformWindow alloc] initWithContentRect:_frame]];
|
||||||
[self platformWindow]._only = self;
|
[self platformWindow]._only = self;
|
||||||
}
|
}
|
||||||
@@ -469,9 +480,6 @@ CPTexturedBackgroundWindowMask
|
|||||||
|
|
||||||
- (void)awakeFromCib
|
- (void)awakeFromCib
|
||||||
{
|
{
|
||||||
if (_initialFirstResponder)
|
|
||||||
[self makeFirstResponder:_initialFirstResponder];
|
|
||||||
|
|
||||||
_keyViewLoopIsDirty = ![self _hasKeyViewLoop];
|
_keyViewLoopIsDirty = ![self _hasKeyViewLoop];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -613,6 +621,13 @@ CPTexturedBackgroundWindowMask
|
|||||||
@param shouldDisplay whether the window should redraw its views
|
@param shouldDisplay whether the window should redraw its views
|
||||||
@param shouldAnimate whether the window resize should be animated
|
@param shouldAnimate whether the window resize should be animated
|
||||||
*/
|
*/
|
||||||
|
- (void)_setClippedFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
|
||||||
|
{
|
||||||
|
aFrame.size.width = MIN(MAX(aFrame.size.width, _minSize.width), _maxSize.width)
|
||||||
|
aFrame.size.height = MIN(MAX(aFrame.size.height, _minSize.height), _maxSize.height);
|
||||||
|
[self setFrame:aFrame display:shouldDisplay animate:shouldAnimate];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
|
- (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
|
||||||
{
|
{
|
||||||
aFrame = _CGRectMakeCopy(aFrame);
|
aFrame = _CGRectMakeCopy(aFrame);
|
||||||
@@ -643,9 +658,10 @@ CPTexturedBackgroundWindowMask
|
|||||||
|
|
||||||
if (shouldAnimate)
|
if (shouldAnimate)
|
||||||
{
|
{
|
||||||
var animation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
|
[_frameAnimation stopAnimation];
|
||||||
|
_frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
|
||||||
|
|
||||||
[animation startAnimation];
|
[_frameAnimation startAnimation];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -672,16 +688,16 @@ CPTexturedBackgroundWindowMask
|
|||||||
|
|
||||||
if (!_CGSizeEqualToSize(size, newSize))
|
if (!_CGSizeEqualToSize(size, newSize))
|
||||||
{
|
{
|
||||||
size.width = MIN(MAX(newSize.width, _minSize.width), _maxSize.width);
|
size.width = newSize.width;
|
||||||
size.height = MIN(MAX(newSize.height, _minSize.height), _maxSize.height);
|
size.height = newSize.height;
|
||||||
|
|
||||||
[_windowView setFrameSize:size];
|
[_windowView setFrameSize:size];
|
||||||
|
|
||||||
if (_hasShadow)
|
if (_hasShadow)
|
||||||
[_shadowView setFrameSize:_CGSizeMake(SHADOW_MARGIN_LEFT + size.width + SHADOW_MARGIN_RIGHT, SHADOW_MARGIN_BOTTOM + size.height + SHADOW_MARGIN_TOP + SHADOW_DISTANCE)];
|
[_shadowView setFrameSize:_CGSizeMake(SHADOW_MARGIN_LEFT + size.width + SHADOW_MARGIN_RIGHT, SHADOW_MARGIN_BOTTOM + size.height + SHADOW_MARGIN_TOP + SHADOW_DISTANCE)];
|
||||||
|
|
||||||
if (!_isAnimating && [_delegate respondsToSelector:@selector(windowDidResize:)])
|
if (!_isAnimating)
|
||||||
[_delegate windowDidResize:self];
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidResizeNotification object:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([self _sharesChromeWithPlatformWindow])
|
if ([self _sharesChromeWithPlatformWindow])
|
||||||
@@ -691,7 +707,7 @@ CPTexturedBackgroundWindowMask
|
|||||||
|
|
||||||
- (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay
|
- (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay
|
||||||
{
|
{
|
||||||
[super setFrame:aFrame display:shouldDisplay animate:NO];
|
[self _setClippedFrame:aFrame display:shouldDisplay animate:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -699,7 +715,7 @@ CPTexturedBackgroundWindowMask
|
|||||||
*/
|
*/
|
||||||
- (void)setFrame:(CGRect)aFrame
|
- (void)setFrame:(CGRect)aFrame
|
||||||
{
|
{
|
||||||
[self setFrame:aFrame display:YES animate:NO];
|
[self _setClippedFrame:aFrame display:YES animate:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -708,7 +724,7 @@ CPTexturedBackgroundWindowMask
|
|||||||
*/
|
*/
|
||||||
- (void)setFrameOrigin:(CGPoint)anOrigin
|
- (void)setFrameOrigin:(CGPoint)anOrigin
|
||||||
{
|
{
|
||||||
[self setFrame:_CGRectMake(anOrigin.x, anOrigin.y, _CGRectGetWidth(_frame), _CGRectGetHeight(_frame)) display:YES animate:NO];
|
[self _setClippedFrame:_CGRectMake(anOrigin.x, anOrigin.y, _CGRectGetWidth(_frame), _CGRectGetHeight(_frame)) display:YES animate:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -717,7 +733,7 @@ CPTexturedBackgroundWindowMask
|
|||||||
*/
|
*/
|
||||||
- (void)setFrameSize:(CGSize)aSize
|
- (void)setFrameSize:(CGSize)aSize
|
||||||
{
|
{
|
||||||
[self setFrame:_CGRectMake(_CGRectGetMinX(_frame), _CGRectGetMinY(_frame), aSize.width, aSize.height) display:YES animate:NO];
|
[self _setClippedFrame:_CGRectMake(_CGRectGetMinX(_frame), _CGRectGetMinY(_frame), aSize.width, aSize.height) display:YES animate:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -726,8 +742,19 @@ CPTexturedBackgroundWindowMask
|
|||||||
*/
|
*/
|
||||||
- (void)orderFront:(id)aSender
|
- (void)orderFront:(id)aSender
|
||||||
{
|
{
|
||||||
|
#if PLATFORM(DOM)
|
||||||
[_platformWindow orderFront:self];
|
[_platformWindow orderFront:self];
|
||||||
[_platformWindow order:CPWindowAbove window:self relativeTo:nil];
|
[_platformWindow order:CPWindowAbove window:self relativeTo:nil];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (_firstResponder === self || !_firstResponder)
|
||||||
|
[self makeFirstResponder:[self initialFirstResponder]];
|
||||||
|
|
||||||
|
if (!CPApp._keyWindow)
|
||||||
|
[self makeKeyWindow];
|
||||||
|
|
||||||
|
if (!CPApp._mainWindow)
|
||||||
|
[self makeMainWindow];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -746,20 +773,19 @@ CPTexturedBackgroundWindowMask
|
|||||||
*/
|
*/
|
||||||
- (void)orderOut:(id)aSender
|
- (void)orderOut:(id)aSender
|
||||||
{
|
{
|
||||||
|
#if PLATFORM(DOM)
|
||||||
if ([self _sharesChromeWithPlatformWindow])
|
if ([self _sharesChromeWithPlatformWindow])
|
||||||
[_platformWindow orderOut:self];
|
[_platformWindow orderOut:self];
|
||||||
|
#endif
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(windowWillClose:)])
|
if ([_delegate respondsToSelector:@selector(windowWillClose:)])
|
||||||
[_delegate windowWillClose:self];
|
[_delegate windowWillClose:self];
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
[_platformWindow order:CPWindowOut window:self relativeTo:nil];
|
[_platformWindow order:CPWindowOut window:self relativeTo:nil];
|
||||||
|
#endif
|
||||||
|
|
||||||
if ([CPApp keyWindow] == self)
|
[self _updateMainAndKeyWindows];
|
||||||
{
|
|
||||||
[self resignKeyWindow];
|
|
||||||
|
|
||||||
CPApp._keyWindow = nil;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -769,7 +795,9 @@ CPTexturedBackgroundWindowMask
|
|||||||
*/
|
*/
|
||||||
- (void)orderWindow:(CPWindowOrderingMode)aPlace relativeTo:(int)otherWindowNumber
|
- (void)orderWindow:(CPWindowOrderingMode)aPlace relativeTo:(int)otherWindowNumber
|
||||||
{
|
{
|
||||||
|
#if PLATFORM(DOM)
|
||||||
[_platformWindow order:aPlace window:self relativeTo:CPApp._windows[otherWindowNumber]];
|
[_platformWindow order:aPlace window:self relativeTo:CPApp._windows[otherWindowNumber]];
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -778,6 +806,11 @@ CPTexturedBackgroundWindowMask
|
|||||||
*/
|
*/
|
||||||
- (void)setLevel:(int)aLevel
|
- (void)setLevel:(int)aLevel
|
||||||
{
|
{
|
||||||
|
if (aLevel === _level)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_platformWindow moveWindow:self fromLevel:_level toLevel:aLevel];
|
||||||
|
|
||||||
_level = aLevel;
|
_level = aLevel;
|
||||||
|
|
||||||
if ([self _sharesChromeWithPlatformWindow])
|
if ([self _sharesChromeWithPlatformWindow])
|
||||||
@@ -867,6 +900,23 @@ CPTexturedBackgroundWindowMask
|
|||||||
return _contentView;
|
return _contentView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Applies an alpha value to the window.
|
||||||
|
@param aValue the alpha value to apply
|
||||||
|
*/
|
||||||
|
- (void)setAlphaValue:(float)aValue
|
||||||
|
{
|
||||||
|
[_windowView setAlphaValue:aValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the alpha value of the window.
|
||||||
|
*/
|
||||||
|
- (float)alphaValue
|
||||||
|
{
|
||||||
|
return [_windowView alphaValue];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the window's background color.
|
Sets the window's background color.
|
||||||
@param aColor the new color for the background
|
@param aColor the new color for the background
|
||||||
@@ -1058,13 +1108,31 @@ CPTexturedBackgroundWindowMask
|
|||||||
*/
|
*/
|
||||||
- (void)setDelegate:(id)aDelegate
|
- (void)setDelegate:(id)aDelegate
|
||||||
{
|
{
|
||||||
// FIXME: Unregister for notifications!
|
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||||
|
|
||||||
|
[defaultCenter removeObserver:_delegate name:CPWindowDidResignKeyNotification object:self];
|
||||||
|
[defaultCenter removeObserver:_delegate name:CPWindowDidBecomeKeyNotification object:self];
|
||||||
|
[defaultCenter removeObserver:_delegate name:CPWindowDidBecomeMainNotification object:self];
|
||||||
|
[defaultCenter removeObserver:_delegate name:CPWindowDidResignMainNotification object:self];
|
||||||
|
[defaultCenter removeObserver:_delegate name:CPWindowDidMoveNotification object:self];
|
||||||
|
[defaultCenter removeObserver:_delegate name:CPWindowDidResizeNotification object:self];
|
||||||
|
|
||||||
_delegate = aDelegate;
|
_delegate = aDelegate;
|
||||||
|
|
||||||
_delegateRespondsToWindowWillReturnUndoManagerSelector = [_delegate respondsToSelector:@selector(windowWillReturnUndoManager:)];
|
_delegateRespondsToWindowWillReturnUndoManagerSelector = [_delegate respondsToSelector:@selector(windowWillReturnUndoManager:)];
|
||||||
|
|
||||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
if ([_delegate respondsToSelector:@selector(windowDidResignKey:)])
|
||||||
|
[defaultCenter
|
||||||
|
addObserver:_delegate
|
||||||
|
selector:@selector(windowDidResignKey:)
|
||||||
|
name:CPWindowDidResignKeyNotification
|
||||||
|
object:self];
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(windowDidBecomeKey:)])
|
||||||
|
[defaultCenter
|
||||||
|
addObserver:_delegate
|
||||||
|
selector:@selector(windowDidBecomeKey:)
|
||||||
|
name:CPWindowDidBecomeKeyNotification
|
||||||
|
object:self];
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(windowDidBecomeMain:)])
|
if ([_delegate respondsToSelector:@selector(windowDidBecomeMain:)])
|
||||||
[defaultCenter
|
[defaultCenter
|
||||||
@@ -1086,6 +1154,13 @@ CPTexturedBackgroundWindowMask
|
|||||||
selector:@selector(windowDidMove:)
|
selector:@selector(windowDidMove:)
|
||||||
name:CPWindowDidMoveNotification
|
name:CPWindowDidMoveNotification
|
||||||
object:self];
|
object:self];
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(windowDidResize:)])
|
||||||
|
[defaultCenter
|
||||||
|
addObserver:_delegate
|
||||||
|
selector:@selector(windowDidResize:)
|
||||||
|
name:CPWindowDidResizeNotification
|
||||||
|
object:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -1126,6 +1201,16 @@ CPTexturedBackgroundWindowMask
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (id)initialFirstResponder
|
||||||
|
{
|
||||||
|
return _initialFirstResponder;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setInitialFirstResponder:(id)aResponder
|
||||||
|
{
|
||||||
|
_initialFirstResponder = aResponder;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Attempts to make the \c aResponder the first responder. Before trying
|
Attempts to make the \c aResponder the first responder. Before trying
|
||||||
to make it the first responder, the receiver will ask the current first responder
|
to make it the first responder, the receiver will ask the current first responder
|
||||||
@@ -1133,9 +1218,9 @@ CPTexturedBackgroundWindowMask
|
|||||||
\c aResponder accept first responder, then finally tell it to become first responder.
|
\c aResponder accept first responder, then finally tell it to become first responder.
|
||||||
@return \c YES if the attempt was successful. \c NO otherwise.
|
@return \c YES if the attempt was successful. \c NO otherwise.
|
||||||
*/
|
*/
|
||||||
- (void)makeFirstResponder:(CPResponder)aResponder
|
- (BOOL)makeFirstResponder:(CPResponder)aResponder
|
||||||
{
|
{
|
||||||
if (_firstResponder == aResponder)
|
if (_firstResponder === aResponder)
|
||||||
return YES;
|
return YES;
|
||||||
|
|
||||||
if(![_firstResponder resignFirstResponder])
|
if(![_firstResponder resignFirstResponder])
|
||||||
@@ -1274,10 +1359,21 @@ CPTexturedBackgroundWindowMask
|
|||||||
*/
|
*/
|
||||||
- (void)center
|
- (void)center
|
||||||
{
|
{
|
||||||
|
if (_isFullPlatformWindow)
|
||||||
|
return;
|
||||||
|
|
||||||
var size = [self frame].size,
|
var size = [self frame].size,
|
||||||
containerSize = [CPPlatform isBrowser] ? [_platformWindow contentBounds].size : [[self screen] visibleFrame].size;
|
containerSize = [CPPlatform isBrowser] ? [_platformWindow contentBounds].size : [[self screen] visibleFrame].size;
|
||||||
|
|
||||||
[self setFrameOrigin:CGPointMake((containerSize.width - size.width) / 2.0, (containerSize.height - size.height) / 2.0)];
|
var origin = CGPointMake((containerSize.width - size.width) / 2.0, (containerSize.height - size.height) / 2.0);
|
||||||
|
|
||||||
|
if (origin.x < 0.0)
|
||||||
|
origin.x = 0.0;
|
||||||
|
|
||||||
|
if (origin.y < 0.0)
|
||||||
|
origin.y = 0.0;
|
||||||
|
|
||||||
|
[self setFrameOrigin:origin];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -1291,48 +1387,91 @@ CPTexturedBackgroundWindowMask
|
|||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
case CPFlagsChanged: return [[self firstResponder] flagsChanged:anEvent];
|
||||||
|
|
||||||
case CPKeyUp: return [[self firstResponder] keyUp:anEvent];
|
case CPKeyUp: return [[self firstResponder] keyUp:anEvent];
|
||||||
case CPKeyDown: return [[self firstResponder] keyDown:anEvent];
|
|
||||||
|
case CPKeyDown: if ([anEvent charactersIgnoringModifiers] === CPTabCharacter)
|
||||||
|
{
|
||||||
|
if ([anEvent modifierFlags] & CPShiftKeyMask)
|
||||||
|
[self selectPreviousKeyView:self];
|
||||||
|
else
|
||||||
|
[self selectNextKeyView:self];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if ([anEvent charactersIgnoringModifiers] === CPBackTabCharacter)
|
||||||
|
return [self selectPreviousKeyView:self];
|
||||||
|
|
||||||
|
[[self firstResponder] keyDown:anEvent];
|
||||||
|
|
||||||
|
// Trigger the default button if needed
|
||||||
|
// FIXME: Is this only applicable in a sheet? See isse: #722.
|
||||||
|
if (![self disableKeyEquivalentForDefaultButton])
|
||||||
|
{
|
||||||
|
var defaultButton = [self defaultButton],
|
||||||
|
keyEquivalent = [defaultButton keyEquivalent],
|
||||||
|
modifierMask = [defaultButton keyEquivalentModifierMask];
|
||||||
|
|
||||||
|
if ([anEvent _triggersKeyEquivalent:keyEquivalent withModifierMask:modifierMask])
|
||||||
|
[[self defaultButton] performClick:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
case CPScrollWheel: return [[_windowView hitTest:point] scrollWheel:anEvent];
|
case CPScrollWheel: return [[_windowView hitTest:point] scrollWheel:anEvent];
|
||||||
|
|
||||||
case CPLeftMouseUp: if (!_leftMouseDownView)
|
case CPLeftMouseUp:
|
||||||
return [[_windowView hitTest:point] mouseUp:anEvent];
|
case CPRightMouseUp: var hitTestedView = _leftMouseDownView,
|
||||||
|
selector = type == CPRightMouseUp ? @selector(rightMouseUp:) : @selector(mouseUp:);
|
||||||
|
|
||||||
[_leftMouseDownView mouseUp:anEvent]
|
if (!hitTestedView)
|
||||||
|
hitTestedView = [_windowView hitTest:point];
|
||||||
|
|
||||||
|
[hitTestedView performSelector:selector withObject:anEvent];
|
||||||
|
|
||||||
_leftMouseDownView = nil;
|
_leftMouseDownView = nil;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case CPLeftMouseDown: _leftMouseDownView = [_windowView hitTest:point];
|
case CPLeftMouseDown:
|
||||||
|
case CPRightMouseDown: _leftMouseDownView = [_windowView hitTest:point];
|
||||||
|
|
||||||
if (_leftMouseDownView != _firstResponder && [_leftMouseDownView acceptsFirstResponder])
|
if (_leftMouseDownView != _firstResponder && [_leftMouseDownView acceptsFirstResponder])
|
||||||
[self makeFirstResponder:_leftMouseDownView];
|
[self makeFirstResponder:_leftMouseDownView];
|
||||||
|
|
||||||
[CPApp activateIgnoringOtherApps:YES];
|
[CPApp activateIgnoringOtherApps:YES];
|
||||||
|
|
||||||
var theWindow = [anEvent window];
|
var theWindow = [anEvent window],
|
||||||
|
selector = type == CPRightMouseDown ? @selector(rightMouseDown:) : @selector(mouseDown:);
|
||||||
|
|
||||||
if ([theWindow isKeyWindow] || [theWindow becomesKeyOnlyIfNeeded])
|
if ([theWindow isKeyWindow] || [theWindow becomesKeyOnlyIfNeeded] && ![_leftMouseDownView needsPanelToBecomeKey])
|
||||||
return [_leftMouseDownView mouseDown:anEvent];
|
return [_leftMouseDownView performSelector:selector withObject:anEvent];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// FIXME: delayed ordering?
|
// FIXME: delayed ordering?
|
||||||
[self makeKeyAndOrderFront:self];
|
[self makeKeyAndOrderFront:self];
|
||||||
|
|
||||||
if ([_leftMouseDownView acceptsFirstMouse:anEvent])
|
if ([_leftMouseDownView acceptsFirstMouse:anEvent])
|
||||||
return [_leftMouseDownView mouseDown:anEvent]
|
return [_leftMouseDownView performSelector:selector withObject:anEvent];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CPLeftMouseDragged: if (!_leftMouseDownView)
|
|
||||||
|
case CPLeftMouseDragged:
|
||||||
|
case CPRightMouseDragged: if (!_leftMouseDownView)
|
||||||
return [[_windowView hitTest:point] mouseDragged:anEvent];
|
return [[_windowView hitTest:point] mouseDragged:anEvent];
|
||||||
|
|
||||||
return [_leftMouseDownView mouseDragged:anEvent];
|
var selector;
|
||||||
|
if (type == CPRightMouseDragged)
|
||||||
|
{
|
||||||
|
selector = @selector(rightMouseDragged:)
|
||||||
|
if (![_leftMouseDownView respondsToSelector:selector])
|
||||||
|
selector = nil;
|
||||||
|
}
|
||||||
|
|
||||||
case CPRightMouseUp: return [_rightMouseDownView mouseUp:anEvent];
|
if (!selector)
|
||||||
case CPRightMouseDown: _rightMouseDownView = [_windowView hitTest:point];
|
selector = @selector(mouseDragged:)
|
||||||
return [_rightMouseDownView mouseDown:anEvent];
|
|
||||||
case CPRightMouseDragged: return [_rightMouseDownView mouseDragged:anEvent];
|
return [_leftMouseDownView performSelector:selector withObject:anEvent];
|
||||||
|
|
||||||
case CPMouseMoved: if (!_acceptsMouseMovedEvents)
|
case CPMouseMoved: if (!_acceptsMouseMovedEvents)
|
||||||
return;
|
return;
|
||||||
@@ -1403,8 +1542,14 @@ CPTexturedBackgroundWindowMask
|
|||||||
*/
|
*/
|
||||||
- (void)becomeKeyWindow
|
- (void)becomeKeyWindow
|
||||||
{
|
{
|
||||||
if (_firstResponder != self && [_firstResponder respondsToSelector:@selector(becomeKeyWindow)])
|
CPApp._keyWindow = self;
|
||||||
|
|
||||||
|
if (_firstResponder !== self && [_firstResponder respondsToSelector:@selector(becomeKeyWindow)])
|
||||||
[_firstResponder becomeKeyWindow];
|
[_firstResponder becomeKeyWindow];
|
||||||
|
|
||||||
|
[[CPNotificationCenter defaultCenter]
|
||||||
|
postNotificationName:CPWindowDidBecomeKeyNotification
|
||||||
|
object:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -1441,13 +1586,10 @@ CPTexturedBackgroundWindowMask
|
|||||||
*/
|
*/
|
||||||
- (void)makeKeyWindow
|
- (void)makeKeyWindow
|
||||||
{
|
{
|
||||||
if (![self canBecomeKeyWindow])
|
if ([CPApp keyWindow] === self || ![self canBecomeKeyWindow])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[CPApp._keyWindow resignKeyWindow];
|
[[CPApp keyWindow] resignKeyWindow];
|
||||||
|
|
||||||
CPApp._keyWindow = self;
|
|
||||||
|
|
||||||
[self becomeKeyWindow];
|
[self becomeKeyWindow];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1456,11 +1598,15 @@ CPTexturedBackgroundWindowMask
|
|||||||
*/
|
*/
|
||||||
- (void)resignKeyWindow
|
- (void)resignKeyWindow
|
||||||
{
|
{
|
||||||
if (_firstResponder != self && [_firstResponder respondsToSelector:@selector(resignKeyWindow)])
|
if (_firstResponder !== self && [_firstResponder respondsToSelector:@selector(resignKeyWindow)])
|
||||||
[_firstResponder resignKeyWindow];
|
[_firstResponder resignKeyWindow];
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(windowDidResignKey:)])
|
if (CPApp._keyWindow === self)
|
||||||
[_delegate windowDidResignKey:self];
|
CPApp._keyWindow = nil;
|
||||||
|
|
||||||
|
[[CPNotificationCenter defaultCenter]
|
||||||
|
postNotificationName:CPWindowDidResignKeyNotification
|
||||||
|
object:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -1489,12 +1635,12 @@ CPTexturedBackgroundWindowMask
|
|||||||
[_inclusiveRegisteredDraggedTypes unionSet:pasteboardTypes];
|
[_inclusiveRegisteredDraggedTypes unionSet:pasteboardTypes];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_noteUnregisteredDraggedTypes:(CPArray)pasteboardTypes
|
- (void)_noteUnregisteredDraggedTypes:(CPSet)pasteboardTypes
|
||||||
{
|
{
|
||||||
if (!pasteboardTypes)
|
if (!pasteboardTypes)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes]
|
[_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes];
|
||||||
|
|
||||||
if ([_inclusiveRegisteredDraggedTypes count] === 0)
|
if ([_inclusiveRegisteredDraggedTypes count] === 0)
|
||||||
_inclusiveRegisteredDraggedTypes = nil;
|
_inclusiveRegisteredDraggedTypes = nil;
|
||||||
@@ -1525,7 +1671,7 @@ CPTexturedBackgroundWindowMask
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
[self _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
|
[self _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
|
||||||
[_registeredDraggedTypes addObjectsFromArray:pasteboardTypes]
|
[_registeredDraggedTypes addObjectsFromArray:pasteboardTypes];
|
||||||
[self _noteRegisteredDraggedTypes:_registeredDraggedTypes];
|
[self _noteRegisteredDraggedTypes:_registeredDraggedTypes];
|
||||||
|
|
||||||
_registeredDraggedTypesArray = nil;
|
_registeredDraggedTypesArray = nil;
|
||||||
@@ -1538,7 +1684,7 @@ CPTexturedBackgroundWindowMask
|
|||||||
- (CPArray)registeredDraggedTypes
|
- (CPArray)registeredDraggedTypes
|
||||||
{
|
{
|
||||||
if (!_registeredDraggedTypesArray)
|
if (!_registeredDraggedTypesArray)
|
||||||
_registeredDraggedTypesArray = [_registeredDraggedTypes allObjects]
|
_registeredDraggedTypesArray = [_registeredDraggedTypes allObjects];
|
||||||
|
|
||||||
return _registeredDraggedTypesArray;
|
return _registeredDraggedTypesArray;
|
||||||
}
|
}
|
||||||
@@ -1649,6 +1795,8 @@ CPTexturedBackgroundWindowMask
|
|||||||
|
|
||||||
[[self platformWindow] miniaturize:sender];
|
[[self platformWindow] miniaturize:sender];
|
||||||
|
|
||||||
|
[self _updateMainAndKeyWindows];
|
||||||
|
|
||||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidMiniaturizeNotification object:self];
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidMiniaturizeNotification object:self];
|
||||||
|
|
||||||
_isMiniaturized = YES;
|
_isMiniaturized = YES;
|
||||||
@@ -1784,13 +1932,10 @@ CPTexturedBackgroundWindowMask
|
|||||||
*/
|
*/
|
||||||
- (void)makeMainWindow
|
- (void)makeMainWindow
|
||||||
{
|
{
|
||||||
if (![self canBecomeMainWindow])
|
if ([CPApp mainWindow] === self || ![self canBecomeMainWindow])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[CPApp._mainWindow resignMainWindow];
|
[[CPApp mainWindow] resignMainWindow];
|
||||||
|
|
||||||
CPApp._mainWindow = self;
|
|
||||||
|
|
||||||
[self becomeMainWindow];
|
[self becomeMainWindow];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1799,6 +1944,8 @@ CPTexturedBackgroundWindowMask
|
|||||||
*/
|
*/
|
||||||
- (void)becomeMainWindow
|
- (void)becomeMainWindow
|
||||||
{
|
{
|
||||||
|
CPApp._mainWindow = self;
|
||||||
|
|
||||||
[self _synchronizeMenuBarTitleWithWindowTitle];
|
[self _synchronizeMenuBarTitleWithWindowTitle];
|
||||||
[self _synchronizeSaveMenuWithDocumentSaving];
|
[self _synchronizeSaveMenuWithDocumentSaving];
|
||||||
|
|
||||||
@@ -1815,6 +1962,82 @@ CPTexturedBackgroundWindowMask
|
|||||||
[[CPNotificationCenter defaultCenter]
|
[[CPNotificationCenter defaultCenter]
|
||||||
postNotificationName:CPWindowDidResignMainNotification
|
postNotificationName:CPWindowDidResignMainNotification
|
||||||
object:self];
|
object:self];
|
||||||
|
|
||||||
|
if (CPApp._mainWindow === self)
|
||||||
|
CPApp._mainWindow = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_updateMainAndKeyWindows
|
||||||
|
{
|
||||||
|
var allWindows = [CPApp orderedWindows],
|
||||||
|
windowCount = [allWindows count];
|
||||||
|
|
||||||
|
if ([self isKeyWindow])
|
||||||
|
{
|
||||||
|
var keyWindow = [CPApp keyWindow];
|
||||||
|
[self resignKeyWindow];
|
||||||
|
|
||||||
|
if (keyWindow && keyWindow !== self && [keyWindow canBecomeKeyWindow])
|
||||||
|
[keyWindow makeKeyWindow];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var mainMenu = [CPApp mainMenu],
|
||||||
|
menuBarClass = objj_getClass("_CPMenuBarWindow"),
|
||||||
|
menuWindow;
|
||||||
|
|
||||||
|
for (var i = 0; i < windowCount; i++)
|
||||||
|
{
|
||||||
|
var currentWindow = allWindows[i];
|
||||||
|
|
||||||
|
if ([currentWindow isKindOfClass:menuBarClass])
|
||||||
|
menuWindow = currentWindow;
|
||||||
|
|
||||||
|
if (currentWindow === self || currentWindow === menuWindow)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ([currentWindow isVisible] && [currentWindow canBecomeKeyWindow])
|
||||||
|
{
|
||||||
|
[currentWindow makeKeyWindow];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (![CPApp keyWindow])
|
||||||
|
[menuWindow makeKeyWindow];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([self isMainWindow])
|
||||||
|
{
|
||||||
|
var mainWindow = [CPApp mainWindow];
|
||||||
|
[self resignMainWindow];
|
||||||
|
|
||||||
|
if (mainWindow && mainWindow !== self && [mainWindow canBecomeMainWindow])
|
||||||
|
[mainWindow makeMainWindow];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var mainMenu = [CPApp mainMenu],
|
||||||
|
menuBarClass = objj_getClass("_CPMenuBarWindow"),
|
||||||
|
menuWindow;
|
||||||
|
|
||||||
|
for (var i = 0; i < windowCount; i++)
|
||||||
|
{
|
||||||
|
var currentWindow = allWindows[i];
|
||||||
|
|
||||||
|
if ([currentWindow isKindOfClass:menuBarClass])
|
||||||
|
menuWindow = currentWindow;
|
||||||
|
|
||||||
|
if (currentWindow === self || currentWindow === menuWindow)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ([currentWindow isVisible] && [currentWindow canBecomeMainWindow])
|
||||||
|
{
|
||||||
|
[currentWindow makeMainWindow];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Managing Toolbars
|
// Managing Toolbars
|
||||||
@@ -1883,11 +2106,17 @@ CPTexturedBackgroundWindowMask
|
|||||||
|
|
||||||
- (void)_setFrame:(CGRect)aFrame delegate:(id)delegate duration:(int)duration curve:(CPAnimationCurve)curve
|
- (void)_setFrame:(CGRect)aFrame delegate:(id)delegate duration:(int)duration curve:(CPAnimationCurve)curve
|
||||||
{
|
{
|
||||||
var animation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
|
[_frameAnimation stopAnimation];
|
||||||
[animation setDelegate:delegate];
|
_frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
|
||||||
[animation setAnimationCurve:curve];
|
[_frameAnimation setDelegate:delegate];
|
||||||
[animation setDuration:duration];
|
[_frameAnimation setAnimationCurve:curve];
|
||||||
[animation startAnimation];
|
[_frameAnimation setDuration:duration];
|
||||||
|
[_frameAnimation startAnimation];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPTimeInterval)animationResizeTime:(CGRect)newWindowFrame
|
||||||
|
{
|
||||||
|
return CPWindowResizeTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
@@ -1901,7 +2130,7 @@ CPTexturedBackgroundWindowMask
|
|||||||
sheetFrame.origin.y = CGRectGetMinY(_frame) + CGRectGetMinY(contentRect);
|
sheetFrame.origin.y = CGRectGetMinY(_frame) + CGRectGetMinY(contentRect);
|
||||||
sheetFrame.origin.x = CGRectGetMinX(_frame) + FLOOR((CGRectGetWidth(_frame) - CGRectGetWidth(sheetFrame)) / 2.0);
|
sheetFrame.origin.x = CGRectGetMinX(_frame) + FLOOR((CGRectGetWidth(_frame) - CGRectGetWidth(sheetFrame)) / 2.0);
|
||||||
|
|
||||||
[attachedSheet setFrameOrigin:sheetFrame.origin];
|
[attachedSheet setFrame:sheetFrame display:YES animate:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
@@ -1935,10 +2164,10 @@ CPTexturedBackgroundWindowMask
|
|||||||
[CPApp runModalForWindow:aSheet];
|
[CPApp runModalForWindow:aSheet];
|
||||||
|
|
||||||
[aSheet orderFront:self];
|
[aSheet orderFront:self];
|
||||||
[aSheet setFrame:startFrame];
|
[aSheet setFrame:startFrame display:YES animate:NO];
|
||||||
_sheetContext["opened"] = YES;
|
_sheetContext["opened"] = YES;
|
||||||
|
|
||||||
[aSheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseOut];
|
[aSheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseOut];
|
||||||
|
|
||||||
// Should run the main loop here until _isAnimating = FALSE
|
// Should run the main loop here until _isAnimating = FALSE
|
||||||
[aSheet becomeKeyWindow];
|
[aSheet becomeKeyWindow];
|
||||||
@@ -1959,7 +2188,7 @@ CPTexturedBackgroundWindowMask
|
|||||||
[self _setUpMasksForView:sheetContent];
|
[self _setUpMasksForView:sheetContent];
|
||||||
|
|
||||||
_sheetContext["opened"] = NO;
|
_sheetContext["opened"] = NO;
|
||||||
[sheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseIn];
|
[sheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseIn];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
@@ -1988,18 +2217,21 @@ CPTexturedBackgroundWindowMask
|
|||||||
[self _restoreMasksForView:sheetContent];
|
[self _restoreMasksForView:sheetContent];
|
||||||
|
|
||||||
var delegate = _sheetContext["modalDelegate"],
|
var delegate = _sheetContext["modalDelegate"],
|
||||||
endSelector = _sheetContext["endSelector"];
|
endSelector = _sheetContext["endSelector"],
|
||||||
|
returnCode = _sheetContext["returnCode"],
|
||||||
if (delegate != nil && endSelector != nil)
|
contextInfo = _sheetContext["contextInfo"];
|
||||||
objj_msgSend(delegate, endSelector, sheet, _sheetContext["returnCode"], _sheetContext["contextInfo"]);
|
|
||||||
|
|
||||||
_sheetContext = nil;
|
_sheetContext = nil;
|
||||||
sheet._parentView = nil;
|
sheet._parentView = nil;
|
||||||
|
|
||||||
|
if (delegate != nil && endSelector != nil)
|
||||||
|
objj_msgSend(delegate, endSelector, sheet, returnCode, contextInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_setUpMasksForView:(CPView)aView
|
- (void)_setUpMasksForView:(CPView)aView
|
||||||
{
|
{
|
||||||
var views = [CPArray arrayWithArray:[aView subviews]];
|
var views = [aView subviews];
|
||||||
|
|
||||||
[views addObject:aView];
|
[views addObject:aView];
|
||||||
|
|
||||||
for (var i = 0, count = [views count]; i < count; i++)
|
for (var i = 0, count = [views count]; i < count; i++)
|
||||||
@@ -2014,7 +2246,8 @@ CPTexturedBackgroundWindowMask
|
|||||||
|
|
||||||
- (void)_restoreMasksForView:(CPView)aView
|
- (void)_restoreMasksForView:(CPView)aView
|
||||||
{
|
{
|
||||||
var views = [CPArray arrayWithArray:[aView subviews]];
|
var views = [aView subviews];
|
||||||
|
|
||||||
[views addObject:aView];
|
[views addObject:aView];
|
||||||
|
|
||||||
for (var i = 0, count = [views count]; i < count; i++)
|
for (var i = 0, count = [views count]; i < count; i++)
|
||||||
@@ -2065,7 +2298,7 @@ CPTexturedBackgroundWindowMask
|
|||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)performKeyEquivalent:(CPEvent)anEvent
|
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
// FIXME: should we be starting at the root, in other words _windowView?
|
// FIXME: should we be starting at the root, in other words _windowView?
|
||||||
// The evidence seems to point to no...
|
// The evidence seems to point to no...
|
||||||
@@ -2076,19 +2309,92 @@ CPTexturedBackgroundWindowMask
|
|||||||
{
|
{
|
||||||
// It's not clear why we do performKeyEquivalent again here...
|
// It's not clear why we do performKeyEquivalent again here...
|
||||||
// Perhaps to allow something to happen between sendEvent: and keyDown:?
|
// Perhaps to allow something to happen between sendEvent: and keyDown:?
|
||||||
if (![anEvent _couldBeKeyEquivalent] || ![self performKeyEquivalent:anEvent])
|
if ([anEvent _couldBeKeyEquivalent] && [self performKeyEquivalent:anEvent])
|
||||||
[self interpretKeyEvents:[anEvent]];
|
return;
|
||||||
|
|
||||||
|
// Apple's documentation is inconsistent with their behavior here. According to the docs
|
||||||
|
// an event going of the responder chain is passed to the input system as a last resort.
|
||||||
|
// However, the only methods I could get Cocoa to call automatically are
|
||||||
|
// moveUp: moveDown: moveLeft: moveRight: pageUp: pageDown: and complete:
|
||||||
|
[self _processKeyboardUIKey:anEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)insertNewline:(id)sender
|
/*
|
||||||
|
@ignore
|
||||||
|
Interprets the key event for action messages and sends the action message down the responder chain
|
||||||
|
Cocoa only sends moveDown:, moveUp:, moveLeft:, moveRight:, pageUp:, pageDown: and complete: messages.
|
||||||
|
We deviate from this by sending (the default) scrollPageUp: scrollPageDown: for pageUp and pageDown keys.
|
||||||
|
@param anEvent the event to handle.
|
||||||
|
@return YES if the key event was handled, NO if no responder handled the key event
|
||||||
|
*/
|
||||||
|
- (BOOL)_processKeyboardUIKey:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
if (_defaultButton && _defaultButtonEnabled)
|
var character = [anEvent charactersIgnoringModifiers],
|
||||||
[_defaultButton performClick:nil];
|
uiKeys = [CPLeftArrowFunctionKey, CPRightArrowFunctionKey, CPUpArrowFunctionKey, CPDownArrowFunctionKey, CPPageUpFunctionKey, CPPageDownFunctionKey, CPEscapeFunctionKey];
|
||||||
|
|
||||||
|
if (![uiKeys containsObject:character])
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
var selectors = [CPKeyBinding selectorsForKey:character modifierFlags:0];
|
||||||
|
|
||||||
|
if ([selectors count] <= 0)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
if (character !== CPEscapeFunctionKey)
|
||||||
|
{
|
||||||
|
var selector = [selectors objectAtIndex:0];
|
||||||
|
return [[self firstResponder] tryToPerform:selector with:self];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Cocoa sends complete: for the escape key (in stead of the default cancelOperation:)
|
||||||
|
// This is also the only action that is not sent directly to the first responder, but through doCommandBySelector.
|
||||||
|
// The difference is that doCommandBySelector: will also send the action to the window and application delegates.
|
||||||
|
[[self firstResponder] doCommandBySelector:@selector(complete:)];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)insertTab:(id)sender
|
/*
|
||||||
|
@ignore
|
||||||
|
Interprets the key event for action messages and sends the action message down the responder chain
|
||||||
|
Cocoa only sends moveDown:, moveUp:, moveLeft:, moveRight:, pageUp:, pageDown: and complete: messages.
|
||||||
|
We deviate from this by sending (the default) scrollPageUp: scrollPageDown: for pageUp and pageDown keys.
|
||||||
|
@param anEvent the event to handle.
|
||||||
|
@return YES if the key event was handled, NO if no responder handled the key event
|
||||||
|
*/
|
||||||
|
- (BOOL)_processKeyboardUIKey:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
[self selectNextKeyView:nil];
|
var character = [anEvent charactersIgnoringModifiers],
|
||||||
|
uiKeys = [
|
||||||
|
CPLeftArrowFunctionKey,
|
||||||
|
CPRightArrowFunctionKey,
|
||||||
|
CPUpArrowFunctionKey,
|
||||||
|
CPDownArrowFunctionKey,
|
||||||
|
CPPageUpFunctionKey,
|
||||||
|
CPPageDownFunctionKey,
|
||||||
|
CPEscapeFunctionKey
|
||||||
|
];
|
||||||
|
|
||||||
|
if (![uiKeys containsObject:character])
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
var selectors = [CPKeyBinding selectorsForKey:character modifierFlags:0];
|
||||||
|
|
||||||
|
if ([selectors count] <= 0)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
if (character !== CPEscapeFunctionKey)
|
||||||
|
{
|
||||||
|
var selector = [selectors objectAtIndex:0];
|
||||||
|
return [[self firstResponder] tryToPerform:selector with:self];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Cocoa sends complete: for the escape key (in stead of the default cancelOperation:)
|
||||||
|
// This is also the only action that is not sent directly to the first responder, but through doCommandBySelector.
|
||||||
|
// The difference is that doCommandBySelector: will also send the action to the window and application delegates.
|
||||||
|
[[self firstResponder] doCommandBySelector:@selector(complete:)];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_dirtyKeyViewLoop
|
- (void)_dirtyKeyViewLoop
|
||||||
@@ -2196,11 +2502,16 @@ CPTexturedBackgroundWindowMask
|
|||||||
|
|
||||||
- (void)setDefaultButton:(CPButton)aButton
|
- (void)setDefaultButton:(CPButton)aButton
|
||||||
{
|
{
|
||||||
[_defaultButton setDefaultButton:NO];
|
if (_defaultButton === aButton)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ([_defaultButton keyEquivalent] === CPCarriageReturnCharacter)
|
||||||
|
[_defaultButton setKeyEquivalent:nil];
|
||||||
|
|
||||||
_defaultButton = aButton;
|
_defaultButton = aButton;
|
||||||
|
|
||||||
[_defaultButton setDefaultButton:YES];
|
if ([_defaultButton keyEquivalent] !== CPCarriageReturnCharacter)
|
||||||
|
[_defaultButton setKeyEquivalent:CPCarriageReturnCharacter];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPButton)defaultButton
|
- (CPButton)defaultButton
|
||||||
@@ -2369,9 +2680,21 @@ var keyViewComparator = function(a, b, context)
|
|||||||
*/
|
*/
|
||||||
- (CPUndoManager)undoManager
|
- (CPUndoManager)undoManager
|
||||||
{
|
{
|
||||||
|
// If we've ever created an undo manager, return it.
|
||||||
|
if (_undoManager)
|
||||||
|
return _undoManager;
|
||||||
|
|
||||||
|
// If not, check to see if the document has one.
|
||||||
|
var documentUndoManager = [[_windowController document] undoManager];
|
||||||
|
|
||||||
|
if (documentUndoManager)
|
||||||
|
return documentUndoManager;
|
||||||
|
|
||||||
|
// If not, check to see if the delegate has one.
|
||||||
if (_delegateRespondsToWindowWillReturnUndoManagerSelector)
|
if (_delegateRespondsToWindowWillReturnUndoManagerSelector)
|
||||||
return [_delegate windowWillReturnUndoManager:self];
|
return [_delegate windowWillReturnUndoManager:self];
|
||||||
|
|
||||||
|
// If not, create one.
|
||||||
if (!_undoManager)
|
if (!_undoManager)
|
||||||
_undoManager = [[CPUndoManager alloc] init];
|
_undoManager = [[CPUndoManager alloc] init];
|
||||||
|
|
||||||
@@ -2449,7 +2772,7 @@ var interpolate = function(fromValue, toValue, progress)
|
|||||||
|
|
||||||
- (id)initWithWindow:(CPWindow)aWindow targetFrame:(CGRect)aTargetFrame
|
- (id)initWithWindow:(CPWindow)aWindow targetFrame:(CGRect)aTargetFrame
|
||||||
{
|
{
|
||||||
self = [super initWithDuration:0.2 animationCurve:CPAnimationLinear];
|
self = [super initWithDuration:[aWindow animationResizeTime:aTargetFrame] animationCurve:CPAnimationLinear];
|
||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
@@ -2478,8 +2801,12 @@ var interpolate = function(fromValue, toValue, progress)
|
|||||||
if (value == 1.0)
|
if (value == 1.0)
|
||||||
_window._isAnimating = NO;
|
_window._isAnimating = NO;
|
||||||
|
|
||||||
[_window setFrameOrigin:CGPointMake(interpolate(CGRectGetMinX(_startFrame), CGRectGetMinX(_targetFrame), value), interpolate(CGRectGetMinY(_startFrame), CGRectGetMinY(_targetFrame), value))];
|
var newFrame = CGRectMake(interpolate(CGRectGetMinX(_startFrame), CGRectGetMinX(_targetFrame), value),
|
||||||
[_window setFrameSize:CGSizeMake(interpolate(CGRectGetWidth(_startFrame), CGRectGetWidth(_targetFrame), value), interpolate(CGRectGetHeight(_startFrame), CGRectGetHeight(_targetFrame), value))];
|
interpolate(CGRectGetMinY(_startFrame), CGRectGetMinY(_targetFrame), value),
|
||||||
|
interpolate(CGRectGetWidth(_startFrame), CGRectGetWidth(_targetFrame), value),
|
||||||
|
interpolate(CGRectGetHeight(_startFrame), CGRectGetHeight(_targetFrame), value));
|
||||||
|
|
||||||
|
[_window setFrame:newFrame display:YES animate:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -71,9 +71,10 @@ var _CPToolbarViewBackgroundColor = nil;
|
|||||||
[self addSubview:_toolbarBackgroundView positioned:CPWindowBelow relativeTo:nil];
|
[self addSubview:_toolbarBackgroundView positioned:CPWindowBelow relativeTo:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
var frame = CGRectMakeZero();
|
var frame = CGRectMakeZero(),
|
||||||
|
toolbarOffset = [self toolbarOffset];
|
||||||
|
|
||||||
frame.origin = CGPointMakeCopy([self toolbarOffset]);
|
frame.origin = CGPointMake(toolbarOffset.width, toolbarOffset.height);
|
||||||
frame.size = [_toolbarView frame].size;
|
frame.size = [_toolbarView frame].size;
|
||||||
|
|
||||||
[_toolbarBackgroundView setFrame:frame];
|
[_toolbarBackgroundView setFrame:frame];
|
||||||
|
|||||||
@@ -43,21 +43,21 @@ var HUD_TITLEBAR_HEIGHT = 26.0;
|
|||||||
|
|
||||||
_CPHUDWindowViewBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
_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/CPWindowHUDBackground0.png"] size:CPSizeMake(7.0, 37.0)],
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground1.png"] size:CPSizeMake(1.0, 78.0)],
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground1.png"] size:CPSizeMake(1.0, 37.0)],
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground2.png"] size:CPSizeMake(6.0, 78.0)],
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground2.png"] size:CPSizeMake(7.0, 37.0)],
|
||||||
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground3.png"] size:CPSizeMake(6.0, 1.0)],
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground3.png"] size:CPSizeMake(7.0, 1.0)],
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground4.png"] size:CPSizeMake(5.0, 5.0)],
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground4.png"] size:CPSizeMake(2.0, 2.0)],
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground5.png"] size:CPSizeMake(6.0, 1.0)],
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground5.png"] size:CPSizeMake(7.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/CPWindowHUDBackground6.png"] size:CPSizeMake(7.0, 3.0)],
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground7.png"] size:CPSizeMake(6.0, 6.0)],
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground7.png"] size:CPSizeMake(1.0, 3.0)],
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground8.png"] size:CPSizeMake(6.0, 6.0)]
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground8.png"] size:CPSizeMake(7.0, 3.0)]
|
||||||
]]];
|
]]];
|
||||||
|
|
||||||
_CPHUDWindowViewCloseImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowClose.png"] size:CPSizeMake(20.0, 20.0)];
|
_CPHUDWindowViewCloseImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowClose.png"] size:CPSizeMake(18.0, 18.0)];
|
||||||
_CPHUDWindowViewCloseActiveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowCloseActive.png"] size:CPSizeMake(20.0, 20.0)];
|
_CPHUDWindowViewCloseActiveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowCloseActive.png"] size:CPSizeMake(18.0, 18.0)];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
+ (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||||
@@ -148,7 +148,7 @@ var HUD_TITLEBAR_HEIGHT = 26.0;
|
|||||||
{
|
{
|
||||||
var closeSize = [_CPHUDWindowViewCloseImage size];
|
var closeSize = [_CPHUDWindowViewCloseImage size];
|
||||||
|
|
||||||
_closeButton = [[CPButton alloc] initWithFrame:CGRectMake(4.0, 4.0, closeSize.width, closeSize.height)];
|
_closeButton = [[CPButton alloc] initWithFrame:CGRectMake(8.0, 5.0, closeSize.width, closeSize.height)];
|
||||||
|
|
||||||
[_closeButton setBordered:NO];
|
[_closeButton setBordered:NO];
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
@import "_CPWindowView.j"
|
@import "_CPWindowView.j"
|
||||||
|
|
||||||
|
|
||||||
var GRADIENT_HEIGHT = 41.0;
|
var GRADIENT_HEIGHT = 41.0;
|
||||||
|
|
||||||
var _CPTexturedWindowHeadGradientColor = nil,
|
var _CPTexturedWindowHeadGradientColor = nil,
|
||||||
|
|||||||
@@ -20,10 +20,8 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@import "CPView.j"
|
|
||||||
@import "CPImageView.j"
|
@import "CPImageView.j"
|
||||||
|
@import "CPView.j"
|
||||||
#include "../CoreGraphics/CGGeometry.h"
|
|
||||||
|
|
||||||
|
|
||||||
var _CPWindowViewResizeIndicatorImage = nil;
|
var _CPWindowViewResizeIndicatorImage = nil;
|
||||||
@@ -36,8 +34,10 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
|||||||
CGSize _resizeIndicatorOffset;
|
CGSize _resizeIndicatorOffset;
|
||||||
|
|
||||||
CPView _toolbarView;
|
CPView _toolbarView;
|
||||||
|
CGSize _toolbarOffset;
|
||||||
// BOOL _isAnimatingToolbar;
|
// BOOL _isAnimatingToolbar;
|
||||||
|
|
||||||
|
|
||||||
CGRect _resizeFrame;
|
CGRect _resizeFrame;
|
||||||
CGPoint _mouseDraggedPoint;
|
CGPoint _mouseDraggedPoint;
|
||||||
|
|
||||||
@@ -79,8 +79,8 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
|||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_styleMask = aStyleMask;
|
_styleMask = aStyleMask;
|
||||||
_resizeIndicatorOffset = CGSizeMake(0.0, 0.0);
|
_resizeIndicatorOffset = CGSizeMakeZero();
|
||||||
_toolbarOffset = CGSizeMake(0.0, 0.0);
|
_toolbarOffset = CGSizeMakeZero();
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -160,10 +160,15 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
|||||||
if (!visibleFrame)
|
if (!visibleFrame)
|
||||||
visibleFrame = [[CPPlatformWindow primaryPlatformWindow] visibleFrame];
|
visibleFrame = [[CPPlatformWindow primaryPlatformWindow] visibleFrame];
|
||||||
|
|
||||||
|
var minPointY = 0;
|
||||||
|
|
||||||
|
if([CPMenu menuBarVisible])
|
||||||
|
minPointY = [[CPApp mainMenu] menuBarHeight];
|
||||||
|
|
||||||
var restrictedPoint = CGPointMake(0, 0);
|
var restrictedPoint = CGPointMake(0, 0);
|
||||||
|
|
||||||
restrictedPoint.x = MIN(MAX(aPoint.x, -_frame.size.width + 4.0), CGRectGetMaxX(visibleFrame) - 4.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);
|
restrictedPoint.y = MIN(MAX(aPoint.y, minPointY), CGRectGetMaxY(visibleFrame) - 8.0);
|
||||||
|
|
||||||
return restrictedPoint;
|
return restrictedPoint;
|
||||||
}
|
}
|
||||||
@@ -222,7 +227,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPImage)showsResizeIndicator
|
- (BOOL)showsResizeIndicator
|
||||||
{
|
{
|
||||||
return _resizeIndicator !== nil;
|
return _resizeIndicator !== nil;
|
||||||
}
|
}
|
||||||
@@ -263,7 +268,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
|||||||
|
|
||||||
- (CGSize)toolbarOffset
|
- (CGSize)toolbarOffset
|
||||||
{
|
{
|
||||||
return CGSizeMakeZero();
|
return _toolbarOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPColor)toolbarLabelColor
|
- (CPColor)toolbarLabelColor
|
||||||
|
|||||||
@@ -27,8 +27,6 @@
|
|||||||
@import "CPWindow.j"
|
@import "CPWindow.j"
|
||||||
@import "CPDocument.j"
|
@import "CPDocument.j"
|
||||||
|
|
||||||
#include "Platform/Platform.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -133,7 +131,7 @@
|
|||||||
if (_window)
|
if (_window)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[[CPBundle bundleForClass:[_cibOwner class]] loadCibFile:[self windowCibPath] externalNameTable:[CPDictionary dictionaryWithObject:_cibOwner forKey:CPCibOwner]];
|
[[CPBundle mainBundle] loadCibFile:[self windowCibPath] externalNameTable:[CPDictionary dictionaryWithObject:_cibOwner forKey:CPCibOwner]];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -322,25 +320,6 @@
|
|||||||
return _documents;
|
return _documents;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setViewController:(CPViewController)aViewController
|
|
||||||
{
|
|
||||||
var containerView = [self viewControllerContainerView] || [[self window] contentView],
|
|
||||||
view = [_viewController view],
|
|
||||||
frame = view ? [view frame] : [containerView bounds];
|
|
||||||
|
|
||||||
[view removeFromSuperview];
|
|
||||||
|
|
||||||
_viewController = aViewController;
|
|
||||||
|
|
||||||
view = [_viewController view];
|
|
||||||
|
|
||||||
if (view)
|
|
||||||
{
|
|
||||||
[view setFrame:frame];
|
|
||||||
[containerView addSubview:view];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setViewControllerContainerView:(CPView)aView
|
- (void)setViewControllerContainerView:(CPView)aView
|
||||||
{
|
{
|
||||||
_viewControllerContainerView = aView;
|
_viewControllerContainerView = aView;
|
||||||
@@ -443,7 +422,7 @@
|
|||||||
if (_windowCibPath)
|
if (_windowCibPath)
|
||||||
return _windowCibPath;
|
return _windowCibPath;
|
||||||
|
|
||||||
return [[CPBundle bundleForClass:[_cibOwner class]] pathForResource:_windowCibName + @".cib"];
|
return [[CPBundle mainBundle] pathForResource:_windowCibName + @".cib"];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setting and Getting Window Attributes
|
// Setting and Getting Window Attributes
|
||||||
|
|||||||
+9
-4
@@ -60,7 +60,7 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey";
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_data = [CPURLConnection sendSynchronousRequest:[CPURLRequest requestWithURL:aURL] returningResponse:nil error:nil];
|
_data = [CPURLConnection sendSynchronousRequest:[CPURLRequest requestWithURL:aURL] returningResponse:nil];
|
||||||
_awakenCustomResources = YES;
|
_awakenCustomResources = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey";
|
|||||||
|
|
||||||
var topLevelObjects = [anExternalNameTable objectForKey:CPCibTopLevelObjects];
|
var topLevelObjects = [anExternalNameTable objectForKey:CPCibTopLevelObjects];
|
||||||
|
|
||||||
[objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects]
|
[objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects];
|
||||||
[objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects];
|
[objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects];
|
||||||
[objectData awakeWithOwner:owner topLevelObjects:topLevelObjects];
|
[objectData awakeWithOwner:owner topLevelObjects:topLevelObjects];
|
||||||
|
|
||||||
@@ -171,12 +171,17 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey";
|
|||||||
|
|
||||||
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)data
|
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)data
|
||||||
{
|
{
|
||||||
_data = [CPData dataWithString:data];
|
// FIXME: Why aren't we getting connection:didFailWithError:
|
||||||
|
if (!data)
|
||||||
|
return [self connection:aConnection didFailWithError:nil];
|
||||||
|
|
||||||
|
_data = [CPData dataWithRawString:data];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError
|
- (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError
|
||||||
{
|
{
|
||||||
alert("cib: connection failed.");
|
if ([_loadDelegate respondsToSelector:@selector(cibDidFailToLoad:)])
|
||||||
|
[_loadDelegate cibDidFailToLoad:self];
|
||||||
|
|
||||||
_loadDelegate = nil;
|
_loadDelegate = nil;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,16 +32,18 @@
|
|||||||
var selectorName = _label,
|
var selectorName = _label,
|
||||||
selectorNameLength = [selectorName length];
|
selectorNameLength = [selectorName length];
|
||||||
|
|
||||||
if (selectorNameLength && selectorName[selectorNameLength - 1] !== ':')
|
if (selectorNameLength && selectorName.charAt(selectorNameLength - 1) !== ':')
|
||||||
selectorName += ':';
|
selectorName += ':';
|
||||||
|
|
||||||
var selector = CPSelectorFromString(selectorName);
|
var selector = CPSelectorFromString(selectorName);
|
||||||
|
|
||||||
// Not having a selector is a fatal error.
|
// Not having a selector is a fatal error.
|
||||||
if (!selector)
|
if (!selector)
|
||||||
|
{
|
||||||
[CPException
|
[CPException
|
||||||
raise:CPInvalidArgumentException
|
raise:CPInvalidArgumentException
|
||||||
reason:@"-[" + [self className] + ' ' + _cmd + @"] selector " + selectorName + @" does not exist."];
|
reason:@"-[" + [self className] + ' ' + _cmd + @"] selector " + selectorName + @" does not exist."];
|
||||||
|
}
|
||||||
|
|
||||||
// If the destination doesn't respond to this selector, warn but don't die.
|
// If the destination doesn't respond to this selector, warn but don't die.
|
||||||
if (_destination && ![_destination respondsToSelector:selector])
|
if (_destination && ![_destination respondsToSelector:selector])
|
||||||
@@ -58,7 +60,7 @@
|
|||||||
else
|
else
|
||||||
[CPException
|
[CPException
|
||||||
raise:CPInvalidArgumentException
|
raise:CPInvalidArgumentException
|
||||||
reason:@"-[" + [self className] + ' ' + _cmd + @"] " + [_source description] + " does not respond to setAction:"];
|
reason:@"-[" + [self className] + ' ' + _cmd + @"] " + [_source description] + @" does not respond to setAction:"];
|
||||||
|
|
||||||
// Not being able to set the target is a fatal error.
|
// Not being able to set the target is a fatal error.
|
||||||
if ([_source respondsToSelector:@selector(setTarget:)])
|
if ([_source respondsToSelector:@selector(setTarget:)])
|
||||||
@@ -67,10 +69,14 @@
|
|||||||
else
|
else
|
||||||
[CPException
|
[CPException
|
||||||
raise:CPInvalidArgumentException
|
raise:CPInvalidArgumentException
|
||||||
reason:@"-[" + [self className] + ' ' + _cmd + @"] " + [_source description] + " does not respond to setTarget:"];
|
reason:@"-[" + [self className] + ' ' + _cmd + @"] " + [_source description] + @" does not respond to setTarget:"];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation _CPCibControlConnector : CPCibControlConnector { } @end
|
@implementation _CPCibControlConnector : CPCibControlConnector
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|||||||
+54
-29
@@ -27,8 +27,6 @@
|
|||||||
|
|
||||||
var CPCibOwner = @"CPCibOwner";
|
var CPCibOwner = @"CPCibOwner";
|
||||||
|
|
||||||
var LoadInfoForCib = {};
|
|
||||||
|
|
||||||
@implementation CPObject (CPCibLoading)
|
@implementation CPObject (CPCibLoading)
|
||||||
|
|
||||||
- (void)awakeFromCib
|
- (void)awakeFromCib
|
||||||
@@ -39,12 +37,12 @@ var LoadInfoForCib = {};
|
|||||||
|
|
||||||
@implementation CPBundle (CPCibLoading)
|
@implementation CPBundle (CPCibLoading)
|
||||||
|
|
||||||
+ (void)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable
|
+ (CPCib)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable
|
||||||
{
|
{
|
||||||
[[[CPCib alloc] initWithContentsOfURL:anAbsolutePath] instantiateCibWithExternalNameTable:aNameTable];
|
return [[[CPCib alloc] initWithContentsOfURL:anAbsolutePath] instantiateCibWithExternalNameTable:aNameTable];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)loadCibNamed:(CPString)aName owner:(id)anOwner
|
+ (CPCib)loadCibNamed:(CPString)aName owner:(id)anOwner
|
||||||
{
|
{
|
||||||
if (![aName hasSuffix:@".cib"])
|
if (![aName hasSuffix:@".cib"])
|
||||||
aName = [aName stringByAppendingString:@".cib"];
|
aName = [aName stringByAppendingString:@".cib"];
|
||||||
@@ -53,22 +51,24 @@ var LoadInfoForCib = {};
|
|||||||
var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle],
|
var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle],
|
||||||
path = [bundle pathForResource:aName];
|
path = [bundle pathForResource:aName];
|
||||||
|
|
||||||
[self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner]];
|
return [self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable
|
- (CPCib)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable
|
||||||
{
|
{
|
||||||
[[[CPCib alloc] initWithContentsOfURL:aFileName] instantiateCibWithExternalNameTable:aNameTable];
|
return [[[CPCib alloc] initWithContentsOfURL:aFileName] instantiateCibWithExternalNameTable:aNameTable];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable loadDelegate:aDelegate
|
+ (CPCib)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable loadDelegate:aDelegate
|
||||||
{
|
{
|
||||||
var cib = [[CPCib alloc] initWithContentsOfURL:anAbsolutePath loadDelegate:self];
|
return ([[CPCib alloc]
|
||||||
|
initWithContentsOfURL:anAbsolutePath
|
||||||
LoadInfoForCib[[cib UID]] = { loadDelegate:aDelegate, externalNameTable:aNameTable };
|
loadDelegate:[[_CPCibLoadDelegate alloc]
|
||||||
|
initWithLoadDelegate:aDelegate
|
||||||
|
externalNameTable:aNameTable]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)loadCibNamed:(CPString)aName owner:(id)anOwner loadDelegate:(id)aDelegate
|
+ (CPCib)loadCibNamed:(CPString)aName owner:(id)anOwner loadDelegate:(id)aDelegate
|
||||||
{
|
{
|
||||||
if (![aName hasSuffix:@".cib"])
|
if (![aName hasSuffix:@".cib"])
|
||||||
aName = [aName stringByAppendingString:@".cib"];
|
aName = [aName stringByAppendingString:@".cib"];
|
||||||
@@ -77,25 +77,50 @@ var LoadInfoForCib = {};
|
|||||||
var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle],
|
var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle],
|
||||||
path = [bundle pathForResource:aName];
|
path = [bundle pathForResource:aName];
|
||||||
|
|
||||||
[self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner] loadDelegate:aDelegate];
|
return [self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner] loadDelegate:aDelegate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable loadDelegate:(id)aDelegate
|
- (CPCib)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable loadDelegate:(id)aDelegate
|
||||||
{
|
{
|
||||||
var cib = [[CPCib alloc] initWithCibNamed:aFileName bundle:self loadDelegate:[self class]];
|
return ([[CPCib alloc]
|
||||||
|
initWithCibNamed:aFileName
|
||||||
LoadInfoForCib[[cib UID]] = { loadDelegate:aDelegate, externalNameTable:aNameTable };
|
bundle:self
|
||||||
}
|
loadDelegate:[[_CPCibLoadDelegate alloc]
|
||||||
|
initWithLoadDelegate:aDelegate
|
||||||
+ (void)cibDidFinishLoading:(CPCib)aCib
|
externalNameTable:aNameTable]]);
|
||||||
{
|
}
|
||||||
var loadInfo = LoadInfoForCib[[aCib UID]];
|
|
||||||
|
@end
|
||||||
delete LoadInfoForCib[[aCib UID]];
|
|
||||||
|
@implementation _CPCibLoadDelegate : CPObject
|
||||||
[aCib instantiateCibWithExternalNameTable:loadInfo.externalNameTable];
|
{
|
||||||
|
id _loadDelegate;
|
||||||
[loadInfo.loadDelegate cibDidFinishLoading:aCib];
|
CPDictionary _externalNameTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithLoadDelegate:(id)aLoadDelegate externalNameTable:(id)anExternalNameTable
|
||||||
|
{
|
||||||
|
self = [self init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_loadDelegate = aLoadDelegate;
|
||||||
|
_externalNameTable = anExternalNameTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)cibDidFinishLoading:(CPCib)aCib
|
||||||
|
{
|
||||||
|
[aCib instantiateCibWithExternalNameTable:_externalNameTable];
|
||||||
|
|
||||||
|
[_loadDelegate cibDidFinishLoading:aCib];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)cibDidFailToLoad:(CPCib)aCib
|
||||||
|
{
|
||||||
|
[_loadDelegate cibDidFailToLoad:aCib];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
|
|||||||
if ([aCoder respondsToSelector:@selector(bundle)] &&
|
if ([aCoder respondsToSelector:@selector(bundle)] &&
|
||||||
(![aCoder respondsToSelector:@selector(awakenCustomResources)] || [aCoder awakenCustomResources]))
|
(![aCoder respondsToSelector:@selector(awakenCustomResources)] || [aCoder awakenCustomResources]))
|
||||||
if (_className === @"CPImage")
|
if (_className === @"CPImage")
|
||||||
return [[CPImage alloc] initWithContentsOfFile:[[aCoder bundle] pathForResource:_resourceName] size:[_properties objectForKey:@"size"]];
|
return [[CPImage alloc] initWithContentsOfFile:[[aCoder bundle] pathForResource:_resourceName] size:_properties.valueForKey(@"size")];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -112,4 +112,14 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
|
|||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (unsigned)loadStatus
|
||||||
|
{
|
||||||
|
return CPImageLoadStatusCompleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)delegate
|
||||||
|
{
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -37,7 +37,13 @@
|
|||||||
|
|
||||||
- (void)setCustomClassName:(CPString)aClassName
|
- (void)setCustomClassName:(CPString)aClassName
|
||||||
{
|
{
|
||||||
|
if (_className === aClassName)
|
||||||
|
return;
|
||||||
|
|
||||||
_className = aClassName;
|
_className = aClassName;
|
||||||
|
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
[self setNeedsLayout];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -97,9 +103,7 @@ var _CPCibCustomViewClassNameKey = @"_CPCibCustomViewClassNameKey";
|
|||||||
[view setBounds:[self bounds]];
|
[view setBounds:[self bounds]];
|
||||||
|
|
||||||
// Since the object replacement logic hasn't had a chance to kick in yet, we need to do it manually:
|
// Since the object replacement logic hasn't had a chance to kick in yet, we need to do it manually:
|
||||||
|
var subviews = [self subviews],
|
||||||
// we need to copy subviews since each time we add a subview to a different view its removed from the original subviews array
|
|
||||||
var subviews = [[self subviews] copy],
|
|
||||||
index = 0,
|
index = 0,
|
||||||
count = subviews.length;
|
count = subviews.length;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
|
@import "CGGeometry.j"
|
||||||
|
@import "CPWindow.j"
|
||||||
|
|
||||||
|
|
||||||
var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey",
|
var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey",
|
||||||
_CPCibWindowTemplateMaxSizeKey = @"_CPCibWindowTemplateMaxSizeKey",
|
_CPCibWindowTemplateMaxSizeKey = @"_CPCibWindowTemplateMaxSizeKey",
|
||||||
|
|||||||
@@ -22,13 +22,10 @@
|
|||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
@import <AppKit/CABackingStore.j>
|
@import "CABackingStore.j"
|
||||||
|
|
||||||
@import <AppKit/CGContext.j>
|
@import "CGContext.j"
|
||||||
@import <AppKit/CGGeometry.j>
|
@import "CGGeometry.j"
|
||||||
|
|
||||||
#include "../CoreGraphics/CGGeometry.h"
|
|
||||||
#include "../CoreGraphics/CGAffineTransform.j"
|
|
||||||
|
|
||||||
|
|
||||||
#define DOM(aLayer) aLayer._DOMElement
|
#define DOM(aLayer) aLayer._DOMElement
|
||||||
@@ -777,8 +774,7 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
|
|||||||
@ignore
|
@ignore
|
||||||
*/
|
*/
|
||||||
+ (void)runLoopUpdateLayers
|
+ (void)runLoopUpdateLayers
|
||||||
{if (window.oops) {alert(window.latest); objj_debug_print_backtrace();}
|
{
|
||||||
window.loop = true;
|
|
||||||
for (UID in CALayerRegisteredRunLoopUpdates)
|
for (UID in CALayerRegisteredRunLoopUpdates)
|
||||||
{
|
{
|
||||||
var layer = CALayerRegisteredRunLoopUpdates[UID],
|
var layer = CALayerRegisteredRunLoopUpdates[UID],
|
||||||
|
|||||||
@@ -20,14 +20,11 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CGGeometry.h"
|
|
||||||
#include "CGAffineTransform.h"
|
|
||||||
|
|
||||||
#define _function(inline) function inline { return _##inline; }
|
|
||||||
|
|
||||||
@import "CGGeometry.j"
|
@import "CGGeometry.j"
|
||||||
|
|
||||||
|
|
||||||
|
#define _function(inline) function inline { return _##inline; }
|
||||||
|
|
||||||
_function(CGAffineTransformMake(a, b, c, d, tx, ty))
|
_function(CGAffineTransformMake(a, b, c, d, tx, ty))
|
||||||
_function(CGAffineTransformMakeIdentity())
|
_function(CGAffineTransformMakeIdentity())
|
||||||
_function(CGAffineTransformMakeCopy(anAffineTransform))
|
_function(CGAffineTransformMakeCopy(anAffineTransform))
|
||||||
|
|||||||
@@ -20,13 +20,12 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CGGeometry.h"
|
|
||||||
#include "CGAffineTransform.h"
|
|
||||||
|
|
||||||
@import "CGGeometry.j"
|
|
||||||
@import "CGAffineTransform.j"
|
@import "CGAffineTransform.j"
|
||||||
|
@import "CPCompatibility.j"
|
||||||
|
@import "CGGeometry.j"
|
||||||
@import "CGPath.j"
|
@import "CGPath.j"
|
||||||
|
|
||||||
|
|
||||||
kCGLineCapButt = 0;
|
kCGLineCapButt = 0;
|
||||||
kCGLineCapRound = 1;
|
kCGLineCapRound = 1;
|
||||||
kCGLineCapSquare = 2;
|
kCGLineCapSquare = 2;
|
||||||
|
|||||||
@@ -63,6 +63,7 @@
|
|||||||
#define _CGInsetMakeCopy(anInset) _CGInsetMake(anInset.top, anInset.right, anInset.bottom, anInset.left)
|
#define _CGInsetMakeCopy(anInset) _CGInsetMake(anInset.top, anInset.right, anInset.bottom, anInset.left)
|
||||||
#define _CGInsetMakeZero() _CGInsetMake(0, 0, 0, 0)
|
#define _CGInsetMakeZero() _CGInsetMake(0, 0, 0, 0)
|
||||||
#define _CGInsetIsEmpty(anInset) ((anInset).top === 0 && (anInset).right === 0 && (anInset).bottom === 0 && (anInset).left === 0)
|
#define _CGInsetIsEmpty(anInset) ((anInset).top === 0 && (anInset).right === 0 && (anInset).bottom === 0 && (anInset).left === 0)
|
||||||
|
#define _CGInsetEqualToInset(lhsInset, rhsInset) ((lhsInset).top === (rhsInset).top && (lhsInset).right === (rhsInset).right && (lhsInset).bottom === (rhsInset).bottom && (lhsInset).left === (rhsInset).left)
|
||||||
|
|
||||||
// DEPRECATED
|
// DEPRECATED
|
||||||
#define _CGPointCreateCopy(aPoint) _CGPointMake(aPoint.x, aPoint.y)
|
#define _CGPointCreateCopy(aPoint) _CGPointMake(aPoint.x, aPoint.y)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user