mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-09-11 05:07:13 +00:00
Compare commits
1634
Commits
0.7
...
localStorage
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4091acd0ec | ||
|
|
6a72e1b6ff | ||
|
|
b3141f1a62 | ||
|
|
aea8f1f0dc | ||
|
|
f8114b0760 | ||
|
|
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 | ||
|
|
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 | ||
|
|
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 | ||
|
|
1db2e0282a | ||
|
|
2351f73c76 | ||
|
|
20a38c3aac | ||
|
|
bca25d0f5f | ||
|
|
b26853e4d7 | ||
|
|
39049f82fc | ||
|
|
a30250f758 | ||
|
|
629737cda3 | ||
|
|
ec41411675 | ||
|
|
becdf2bfeb | ||
|
|
1e723945f8 | ||
|
|
dfb7599bb6 | ||
|
|
e1d3363ad9 | ||
|
|
c36c750c5d | ||
|
|
c7581c0847 | ||
|
|
936d65291f | ||
|
|
a64030ad93 | ||
|
|
01d60ad4e9 | ||
|
|
06b64c6a87 | ||
|
|
0eff4e2bc0 | ||
|
|
44d6139db2 | ||
|
|
506e3004b7 | ||
|
|
9ce4c7a468 | ||
|
|
2fc724e469 | ||
|
|
afb69a7f03 | ||
|
|
cd2dd9f12d | ||
|
|
29963f74d6 | ||
|
|
565a017ebd | ||
|
|
0b85847524 | ||
|
|
cfc46edfb8 | ||
|
|
f250373673 | ||
|
|
b0acc13da7 | ||
|
|
d705af8965 | ||
|
|
a401dfddff | ||
|
|
f579fd925e | ||
|
|
e6d86eaa9b | ||
|
|
348e45a5cd | ||
|
|
2120e9cf2a | ||
|
|
3002acc895 | ||
|
|
0b3c313280 | ||
|
|
982ab4b4fa | ||
|
|
a0ee2f384b | ||
|
|
56a739655f | ||
|
|
150ee44da0 | ||
|
|
78795e3167 | ||
|
|
b0dd3cd818 | ||
|
|
ef12ec54d7 | ||
|
|
495b774965 | ||
|
|
1381bb5c54 | ||
|
|
f1d4794dd1 | ||
|
|
d58473c270 | ||
|
|
7adf32f36e | ||
|
|
5c3beb4160 | ||
|
|
b82c307007 | ||
|
|
a7010e7598 | ||
|
|
f850cbf780 | ||
|
|
4581fe4f22 | ||
|
|
35df54ae99 | ||
|
|
f8a5f91687 | ||
|
|
4b71557584 | ||
|
|
feda903f2f | ||
|
|
150e264f0d | ||
|
|
b592f6ae92 | ||
|
|
37ba8fb57d | ||
|
|
72f80cdbed | ||
|
|
c070f20669 | ||
|
|
a4d5165a3d | ||
|
|
4fdddfb585 | ||
|
|
0575e96b60 | ||
|
|
d0a8749986 | ||
|
|
44fbf8afe2 | ||
|
|
1eb9202233 | ||
|
|
b7da92d225 | ||
|
|
e4f6d0db1f | ||
|
|
0a8bd9f687 | ||
|
|
f2608998f9 | ||
|
|
ffb08d32ce | ||
|
|
119e776ddc | ||
|
|
652930d5aa | ||
|
|
e3babe97e4 | ||
|
|
72d01865ae | ||
|
|
b9664681a3 | ||
|
|
fd5c545189 | ||
|
|
0639f4b00f | ||
|
|
ab49986238 | ||
|
|
a4fdc50d1d | ||
|
|
ed228b6183 | ||
|
|
e0e675531a | ||
|
|
44e0879224 | ||
|
|
1e6fa93ea2 | ||
|
|
2aaed6bffd | ||
|
|
2d367a8b47 | ||
|
|
52c18abc5e | ||
|
|
595c70ed56 | ||
|
|
9faec8decd | ||
|
|
90dc1f6cf8 | ||
|
|
ba01976151 | ||
|
|
4d7f5a8a09 | ||
|
|
2d01fa6f94 | ||
|
|
970f848b84 | ||
|
|
31feec0465 | ||
|
|
2466c14300 | ||
|
|
49927fcfb7 | ||
|
|
f612683dfb | ||
|
|
11e6ad2153 | ||
|
|
d041c69e0d | ||
|
|
b394052145 | ||
|
|
bce83e45b5 | ||
|
|
77bd8d3a76 | ||
|
|
118ece9f1c | ||
|
|
971956a6ba | ||
|
|
48cd362015 | ||
|
|
b12b1bf662 | ||
|
|
6829d502d7 | ||
|
|
aa8689a4f0 | ||
|
|
44cbcc60fa | ||
|
|
d4edb28837 | ||
|
|
3245f38788 | ||
|
|
392cca1b2a | ||
|
|
ad901ed4b0 | ||
|
|
8f1e56e398 | ||
|
|
b694437dba | ||
|
|
370efb35aa | ||
|
|
dc93f39b58 | ||
|
|
629c8669c2 | ||
|
|
558dbdc612 | ||
|
|
1944f51f97 | ||
|
|
312a48a3fe | ||
|
|
5fc67ff7de | ||
|
|
d584b4dccf | ||
|
|
9d50b33268 | ||
|
|
722166a9d2 | ||
|
|
ec83a0f779 | ||
|
|
e20311c25a | ||
|
|
c21fb3bb26 | ||
|
|
9dfdde674f | ||
|
|
f4b37fbf3b | ||
|
|
13c5736a0f | ||
|
|
47de360719 | ||
|
|
19e3d93f1a | ||
|
|
2d5aef6157 | ||
|
|
e94ddb4179 | ||
|
|
29785e21cd | ||
|
|
95612b256f | ||
|
|
a3a03d702c | ||
|
|
742df0df82 | ||
|
|
aaac5e429d | ||
|
|
c3ac3ddd3f | ||
|
|
61c0d33b4d | ||
|
|
67672ebb0c | ||
|
|
6132243968 | ||
|
|
88635ed440 | ||
|
|
3d42cba823 | ||
|
|
51a58f650e | ||
|
|
6c79a31b38 | ||
|
|
91ffb0ea0c | ||
|
|
77c74412dc | ||
|
|
008a320e6a | ||
|
|
f3e90f87b1 | ||
|
|
11b881273e | ||
|
|
229debc2b7 | ||
|
|
0c24a60bac | ||
|
|
2aa061a6af | ||
|
|
8f9d83495c | ||
|
|
cb18896137 | ||
|
|
b13eee1fc9 | ||
|
|
95c3401640 | ||
|
|
2f40cff3e2 | ||
|
|
848828222b | ||
|
|
d3e6819fd7 | ||
|
|
55bbfc9205 | ||
|
|
b6e9625729 | ||
|
|
fe91331dc4 | ||
|
|
cf946c62a8 | ||
|
|
420ce1799a | ||
|
|
72adaa51ee | ||
|
|
695f60aefc | ||
|
|
e00c2f3c05 | ||
|
|
7ae0f1fec9 | ||
|
|
6b3f05f517 | ||
|
|
93c90274b5 | ||
|
|
2d1d30a663 | ||
|
|
baa1318298 | ||
|
|
8fddc2370b | ||
|
|
ea8245a6b3 | ||
|
|
d508459480 | ||
|
|
6fc56226ba | ||
|
|
c98107b6b8 | ||
|
|
17d68eeb97 | ||
|
|
a457145312 | ||
|
|
0c13138a20 | ||
|
|
e8b1ff8846 | ||
|
|
eeae653c94 | ||
|
|
6d402bdc00 | ||
|
|
fddf3d70ff | ||
|
|
87e39bc707 | ||
|
|
7c4f01d81b | ||
|
|
96523aca07 | ||
|
|
1ceeec8b5b | ||
|
|
cba546880b | ||
|
|
2355cf4f6c | ||
|
|
2c0e717b23 | ||
|
|
8745843105 | ||
|
|
ef252a97c4 | ||
|
|
14ad8f6d6d | ||
|
|
bcd8c72ae4 | ||
|
|
499d2d93d5 | ||
|
|
84f131808d | ||
|
|
79fa65624d | ||
|
|
9ca96bc909 | ||
|
|
3dbddcf186 | ||
|
|
df8c648d70 | ||
|
|
ee7c71a184 | ||
|
|
de163e22d9 | ||
|
|
d9ef4342b6 | ||
|
|
e75ef74ea5 | ||
|
|
2e26db5bf5 | ||
|
|
fe1c45980d | ||
|
|
0423546451 | ||
|
|
8da4ea0823 | ||
|
|
c48d9a01c6 | ||
|
|
4ca0044bbd | ||
|
|
9f2ea190fc | ||
|
|
4248348308 | ||
|
|
eaf701beca | ||
|
|
a48a305cd8 | ||
|
|
cc334296bb | ||
|
|
bb2726fb9a | ||
|
|
95b9ea336b | ||
|
|
ba84e6d3e2 | ||
|
|
22c248454e | ||
|
|
42611f3a84 | ||
|
|
d7b778e8ac | ||
|
|
1be9d6816e | ||
|
|
d263c74d5d | ||
|
|
25634a66cb | ||
|
|
228e801c91 | ||
|
|
abc715facb | ||
|
|
a0a81be042 | ||
|
|
64948053df | ||
|
|
039de1b6e8 | ||
|
|
b050559532 | ||
|
|
064a062cd8 | ||
|
|
b2d994bd66 | ||
|
|
315e0eac0c | ||
|
|
06eac3e79b | ||
|
|
9e825ea62e | ||
|
|
d8249b6035 | ||
|
|
7b14f41cd8 | ||
|
|
4bb4d6cd62 | ||
|
|
82404265fb | ||
|
|
9ee71e762c | ||
|
|
d52aa1575e | ||
|
|
717c8520b4 | ||
|
|
76edc4f914 | ||
|
|
66b447de7b | ||
|
|
afaa816d5c | ||
|
|
13e88c6295 | ||
|
|
b6cf4ad0a4 | ||
|
|
b457119925 | ||
|
|
b5cdcec004 | ||
|
|
86d5ea6c64 | ||
|
|
424611e7c7 | ||
|
|
de920e959a | ||
|
|
9ab75eb662 | ||
|
|
4870ac86ef | ||
|
|
24c6f0ec9f | ||
|
|
250ceb69f4 | ||
|
|
0561f69c86 | ||
|
|
341eddb9f9 | ||
|
|
ee8fef4e85 | ||
|
|
e6d1753e74 | ||
|
|
891d2a28c1 | ||
|
|
0af70c04a0 | ||
|
|
efaff96168 | ||
|
|
6fc02623df | ||
|
|
a27f104a63 | ||
|
|
9838bbf084 | ||
|
|
6076185da7 | ||
|
|
810f82cc60 | ||
|
|
fce91c7ad3 | ||
|
|
e6ea4c267a | ||
|
|
95274f618c | ||
|
|
385bec7400 | ||
|
|
41cb21cd0f | ||
|
|
c7520593da | ||
|
|
666ac4acd1 | ||
|
|
ea15b247d3 | ||
|
|
ea252323d2 | ||
|
|
42775cb152 | ||
|
|
f925585475 | ||
|
|
aba7ea8bf1 | ||
|
|
29b0aa7cde | ||
|
|
375b490678 | ||
|
|
27c2285600 | ||
|
|
1d1f664e07 | ||
|
|
f2e95f7e63 | ||
|
|
3055522645 | ||
|
|
7347428e94 | ||
|
|
4a8a205ae2 | ||
|
|
090bf3c46d | ||
|
|
1691b6f07e | ||
|
|
22578c3650 | ||
|
|
57c7757c2e | ||
|
|
16deb3700d | ||
|
|
f5d05a7c93 | ||
|
|
40b5332c83 | ||
|
|
238da6b80f | ||
|
|
1c4f11c1d2 | ||
|
|
e57e7cbbc5 | ||
|
|
97cfb5c1f9 | ||
|
|
9d7ba990a8 | ||
|
|
cac6204a96 | ||
|
|
b7f41c104c | ||
|
|
1123e848bf | ||
|
|
e3fe4ff92f | ||
|
|
d6b338b160 | ||
|
|
ddada18069 | ||
|
|
b43b097d40 | ||
|
|
2cc723752e | ||
|
|
6b02a4105b | ||
|
|
3098bfe6db | ||
|
|
5e658354ab | ||
|
|
2f5e4d8335 | ||
|
|
a607d79c7d | ||
|
|
81c71beaa7 | ||
|
|
5bd30fc4e5 | ||
|
|
46d452be5e | ||
|
|
2338ca2fa2 | ||
|
|
2900163644 | ||
|
|
e90f0188c3 | ||
|
|
5fa457621b | ||
|
|
e125139777 | ||
|
|
bc6f168afa | ||
|
|
fc85ae16a5 | ||
|
|
d5f2654eae | ||
|
|
5e951c1e53 | ||
|
|
69cdc2ccd0 | ||
|
|
3474e8baf1 | ||
|
|
6e7e3ef35e | ||
|
|
8a2cd8c5c6 | ||
|
|
306c1a962a | ||
|
|
8441e62f49 | ||
|
|
9b948dcac7 | ||
|
|
1fb9c973fe | ||
|
|
048bcc1be7 | ||
|
|
1d8cebd5be | ||
|
|
0e55a5d7c4 | ||
|
|
c6b934a035 | ||
|
|
5b531b2005 | ||
|
|
570a2a56ff | ||
|
|
d79ed12b5c | ||
|
|
7864a9fa8e | ||
|
|
3aa7378699 | ||
|
|
1d76ac1b91 | ||
|
|
99697926d9 | ||
|
|
32d0c6ca17 | ||
|
|
2dac122c30 | ||
|
|
e9092007ee | ||
|
|
b94c82f4aa | ||
|
|
6a32314c0b | ||
|
|
eff3170df1 | ||
|
|
62d825d970 | ||
|
|
cb416e0277 | ||
|
|
5066a1d395 | ||
|
|
df3658bc96 | ||
|
|
3ac8ac40bc | ||
|
|
e5c5378ec0 | ||
|
|
ef41abec97 | ||
|
|
72d4675ec4 | ||
|
|
1cd8acb92c | ||
|
|
9856e6bfd7 | ||
|
|
be2ffe95c5 | ||
|
|
3f2d6f24d2 | ||
|
|
714cd402df | ||
|
|
ffd99e3ed7 | ||
|
|
64a8e4c5c0 | ||
|
|
bb0a1eadda | ||
|
|
a8ab16002e | ||
|
|
9dc0c3ab6d | ||
|
|
82df59e7dc | ||
|
|
47694c2d80 | ||
|
|
4993d16738 | ||
|
|
43c0db44ea | ||
|
|
ebbf3c4576 | ||
|
|
f109313d32 | ||
|
|
e305d30c1b | ||
|
|
317f1d356c | ||
|
|
25f3d99732 | ||
|
|
b0443fe5e3 | ||
|
|
3f5bb77230 | ||
|
|
1cf292279c | ||
|
|
2e350f6bc5 | ||
|
|
cfd91b7a61 | ||
|
|
1a8062fbbc | ||
|
|
32096ade9f | ||
|
|
b7493586e2 | ||
|
|
a02cda6376 | ||
|
|
2348a8ebd3 | ||
|
|
7728d8abfb | ||
|
|
b21b08f899 | ||
|
|
c752db905d | ||
|
|
7ca50e4d28 | ||
|
|
1862eacc27 | ||
|
|
0497888edf | ||
|
|
25d76c9510 | ||
|
|
46dbce0dbb | ||
|
|
98ef1bfd05 | ||
|
|
7205146e1b | ||
|
|
02907a599d | ||
|
|
d6ac69029b | ||
|
|
c8ed0f5436 | ||
|
|
20d14d2f81 | ||
|
|
668540d0ce | ||
|
|
ee46ab23ba | ||
|
|
dba418a93d | ||
|
|
186adee0f2 | ||
|
|
abd3abdfea | ||
|
|
7aa58fa98a | ||
|
|
a32368f89a | ||
|
|
4f1d9fe836 | ||
|
|
98df1859af | ||
|
|
1bdea9ff45 | ||
|
|
17273ecbfa | ||
|
|
fd62233960 | ||
|
|
5b0876b7ed | ||
|
|
96afa4b950 | ||
|
|
5e74290486 | ||
|
|
d00197b1f7 | ||
|
|
8b9f36043d | ||
|
|
041f8200df | ||
|
|
b77eef0cd3 | ||
|
|
774e958d49 | ||
|
|
f7c00df9a9 | ||
|
|
98e18340b7 | ||
|
|
58e06142b9 | ||
|
|
c895170597 | ||
|
|
a619bc15c2 | ||
|
|
369cacb3aa | ||
|
|
78fe93be68 | ||
|
|
1a7a07b51a | ||
|
|
2996404ad4 | ||
|
|
669dff7a9b | ||
|
|
3a7dee6cc2 | ||
|
|
7017000c81 | ||
|
|
379eb05144 | ||
|
|
8fc45cf345 | ||
|
|
dc85900780 | ||
|
|
0a28127667 | ||
|
|
879561f67b | ||
|
|
7f9bc98929 | ||
|
|
4c01bebd07 | ||
|
|
2fbe026215 | ||
|
|
efcc5d1054 | ||
|
|
2cf5b90183 | ||
|
|
75060a3385 | ||
|
|
b55ddcf4ce | ||
|
|
744e78b7ad | ||
|
|
f360ab9475 | ||
|
|
58ac49e0b0 | ||
|
|
d1c0237bf3 | ||
|
|
abc1c6f2db | ||
|
|
14ba9c95eb | ||
|
|
0b03025924 | ||
|
|
b369aa6aff | ||
|
|
f189ec6eb9 | ||
|
|
3b761ec55e | ||
|
|
1b4a5dc48b | ||
|
|
356d2e9ea7 | ||
|
|
d3bebfd064 | ||
|
|
da9221bf71 | ||
|
|
8990f6c387 | ||
|
|
cdaa363a82 | ||
|
|
e910fee03f | ||
|
|
7528c452c4 | ||
|
|
824cd6d5f1 | ||
|
|
3f7db4ca12 | ||
|
|
2ee3b93e0d | ||
|
|
bd69683dc2 | ||
|
|
1b8f263224 | ||
|
|
58aef6ef74 | ||
|
|
8a1c1b931f | ||
|
|
db77e826d4 | ||
|
|
35fa76064c | ||
|
|
d2df0919a5 | ||
|
|
b378a4d0fa | ||
|
|
e174edd0dc | ||
|
|
3060c3f100 | ||
|
|
14528d5a49 | ||
|
|
35c1221905 | ||
|
|
300f74bf4d | ||
|
|
e8dd56bda7 | ||
|
|
0c9f247a82 | ||
|
|
51e6f92fee | ||
|
|
d1d0d72e32 | ||
|
|
aef723e160 | ||
|
|
ab8add681e | ||
|
|
07da83715b | ||
|
|
7db40a6b0d | ||
|
|
55a8084b39 | ||
|
|
475cd6a21f | ||
|
|
4c3a43989b | ||
|
|
0d7ba4e872 | ||
|
|
a40714e14a | ||
|
|
c850c0cf45 | ||
|
|
ddc9334af3 | ||
|
|
654b0493bb | ||
|
|
64cbf98140 | ||
|
|
5fc8cd697e | ||
|
|
2423faa8c6 | ||
|
|
172c7330ab | ||
|
|
1a5bf1c8eb | ||
|
|
377f331b47 | ||
|
|
3e85bf0e8b | ||
|
|
3f496f1a10 | ||
|
|
b52da00d46 | ||
|
|
69fa064509 | ||
|
|
0c349a8d7f | ||
|
|
3b8664e6ff | ||
|
|
2bb6da5132 | ||
|
|
0876653ae3 | ||
|
|
4876c7142f | ||
|
|
856373adec | ||
|
|
fbf559043e | ||
|
|
bbda6e6e77 | ||
|
|
4cd7d35499 | ||
|
|
a8393eaa8a | ||
|
|
6a9804939e | ||
|
|
b50067e39e | ||
|
|
028be939f9 | ||
|
|
b5e84342ac | ||
|
|
5bc92b686b | ||
|
|
e8f1763615 | ||
|
|
41dc660140 | ||
|
|
a05ecd2759 | ||
|
|
f51222dff6 | ||
|
|
598411c072 | ||
|
|
241cc2ac06 | ||
|
|
38e2ca3589 | ||
|
|
5ccc638baf | ||
|
|
9e6ba1ea06 | ||
|
|
c0400d6362 | ||
|
|
e9fee72744 | ||
|
|
59bec06e6e | ||
|
|
64b81cfcdb | ||
|
|
865a2b513f | ||
|
|
2e37945b4f | ||
|
|
92594a7ef9 | ||
|
|
a34e23fa1c | ||
|
|
fa5352ad40 | ||
|
|
4d179b1db7 | ||
|
|
d2b1df88e8 | ||
|
|
756885fd53 | ||
|
|
0ef4e9bca5 | ||
|
|
4370604165 | ||
|
|
5ce96b45bb | ||
|
|
4f4a488762 | ||
|
|
d53207efd5 | ||
|
|
ba81b1356d | ||
|
|
ae7fbad2b9 | ||
|
|
e69d770583 | ||
|
|
8382bb1ae8 | ||
|
|
82cfc5f994 | ||
|
|
16be11325f | ||
|
|
5829c8b682 | ||
|
|
57ee7bcfce | ||
|
|
4824f22e3c | ||
|
|
88be473da4 | ||
|
|
3ff945663f | ||
|
|
9f989297df | ||
|
|
12d03a5128 | ||
|
|
369e02fb37 | ||
|
|
48f0aa0b78 | ||
|
|
3e8cb8f9c6 | ||
|
|
4865d6b20f | ||
|
|
745e24d2f5 | ||
|
|
d7b679dc78 | ||
|
|
9b99457871 | ||
|
|
6592328553 | ||
|
|
9c226ae574 | ||
|
|
215619e6e2 | ||
|
|
eee6fe0e67 | ||
|
|
8e3ac66a2d | ||
|
|
cc90f2e5f0 | ||
|
|
0356c6e622 | ||
|
|
308bbb2f8c | ||
|
|
d0599aef8f | ||
|
|
afba1909bb | ||
|
|
3761fb8037 | ||
|
|
adc2344454 | ||
|
|
a5a43de26e | ||
|
|
c281d01974 | ||
|
|
8660c72015 | ||
|
|
cb81eeed15 | ||
|
|
6ad5ec4d66 | ||
|
|
b2f35b61d3 | ||
|
|
ddbc1e0e94 | ||
|
|
4086d37dac | ||
|
|
b9208c2f59 | ||
|
|
92bce1a663 | ||
|
|
a5b468bbeb | ||
|
|
761e32a847 | ||
|
|
1f356053db | ||
|
|
9d64526f26 | ||
|
|
3c087f01b4 | ||
|
|
0ef7f53250 | ||
|
|
528ef4394a | ||
|
|
b12017cd51 | ||
|
|
714fc9d5bb | ||
|
|
d131127717 | ||
|
|
b8046c479f | ||
|
|
af062da99d | ||
|
|
21da2c6f56 | ||
|
|
7cc6e6af0a | ||
|
|
ab2cb38362 | ||
|
|
8c171e5a40 | ||
|
|
ac6c03f2c7 | ||
|
|
e97b78477b | ||
|
|
849dda0725 | ||
|
|
b8755c113f | ||
|
|
d57e7050db | ||
|
|
dd4db720ef | ||
|
|
202d59475b | ||
|
|
1fecae3dc0 | ||
|
|
998f52c4a4 | ||
|
|
bd07054a1b | ||
|
|
adde315e2d | ||
|
|
c97bb6cbdd | ||
|
|
f4171f9afa | ||
|
|
d165761740 | ||
|
|
ca1ea3721f | ||
|
|
7d158de356 | ||
|
|
71a99deada | ||
|
|
c7f81691bf | ||
|
|
05cdc2bab3 | ||
|
|
8beb71aa76 | ||
|
|
201fda96a5 | ||
|
|
4e94fa51fe | ||
|
|
f920202bec | ||
|
|
19f1657824 | ||
|
|
5d1db76be2 | ||
|
|
c6795fdfcf | ||
|
|
35a9305347 | ||
|
|
e36ab855e8 | ||
|
|
d516037286 | ||
|
|
b4abc5a99d | ||
|
|
9bb9db760e | ||
|
|
831ea11a6b | ||
|
|
bfcb94a844 | ||
|
|
1e3b79de17 | ||
|
|
fe21fc82c4 | ||
|
|
cb9d81aa7f | ||
|
|
8f1a02cb0f | ||
|
|
1f0e4b0eca | ||
|
|
e0f53b89ca | ||
|
|
8b25240d04 | ||
|
|
7e88b1abfd | ||
|
|
e38dfc4335 | ||
|
|
90fe0d64f5 | ||
|
|
eab4f4bf78 | ||
|
|
ece999662d | ||
|
|
8c049c3de4 | ||
|
|
6cab77e005 | ||
|
|
c74642b641 | ||
|
|
e7e804cae3 | ||
|
|
7ca3473b64 | ||
|
|
927b94244a | ||
|
|
a5c467fba5 | ||
|
|
fc74bba68c | ||
|
|
656c94a8cd | ||
|
|
896eaf7937 | ||
|
|
886b4ef118 | ||
|
|
c42fb68d8a | ||
|
|
3f27fca518 | ||
|
|
c7823a92f8 | ||
|
|
c61c892732 | ||
|
|
b0470ca2d7 | ||
|
|
7c305c45fc | ||
|
|
cfda93d1e3 | ||
|
|
b4c7af498b | ||
|
|
6ddb7851f6 | ||
|
|
7f60bdec4f | ||
|
|
8971c320bd | ||
|
|
a710dc974f | ||
|
|
e1b63b848f | ||
|
|
5409face8c | ||
|
|
c9e40cbfba | ||
|
|
35947697f2 | ||
|
|
3e1f09bb7a | ||
|
|
82ef2356a5 | ||
|
|
33f96dacd1 | ||
|
|
cc24cd9a73 | ||
|
|
0fff3bade6 | ||
|
|
b1c410d42c | ||
|
|
f4b4d38165 | ||
|
|
f46aa870a7 | ||
|
|
7d4c2840eb | ||
|
|
8fb0abd3d6 | ||
|
|
f6bd4ddd96 | ||
|
|
5f5efffe9d | ||
|
|
48f31743dd | ||
|
|
1224ca9493 | ||
|
|
45ec895df0 | ||
|
|
318d0456af | ||
|
|
5446e1f98f | ||
|
|
d4b9c4c5e1 | ||
|
|
5cb9f5f7c2 | ||
|
|
a7bd5e1bf0 | ||
|
|
bf21fbd000 | ||
|
|
377107d63a | ||
|
|
25d20df5f3 | ||
|
|
cfdb6b0df2 | ||
|
|
9955346958 | ||
|
|
a71822cee8 | ||
|
|
3523a9ff12 | ||
|
|
1f64cb6393 | ||
|
|
0235076fb6 | ||
|
|
c56e552d6e | ||
|
|
5a3f1c81a0 | ||
|
|
25c145e490 | ||
|
|
44dc4f6595 | ||
|
|
d3938f3031 | ||
|
|
cfa21b0c96 | ||
|
|
83bceaa867 | ||
|
|
f6a731ff91 | ||
|
|
354fddf6b2 | ||
|
|
aebbdbe0a3 | ||
|
|
15bff97388 |
@@ -1,3 +1,7 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
Frameworks
|
Frameworks
|
||||||
Build
|
Build
|
||||||
|
Demos
|
||||||
|
./Aristo
|
||||||
|
WebSite
|
||||||
|
.push-package
|
||||||
|
|||||||
-12
@@ -1,12 +0,0 @@
|
|||||||
[submodule "External/narwhal"]
|
|
||||||
path = External/narwhal
|
|
||||||
url = git://github.com/tlrobinson/narwhal.git
|
|
||||||
[submodule "External/jack"]
|
|
||||||
path = External/jack
|
|
||||||
url = git://github.com/tlrobinson/jack.git
|
|
||||||
[submodule "External/browserjs"]
|
|
||||||
path = External/browserjs
|
|
||||||
url = git://github.com/tlrobinson/browserjs.git
|
|
||||||
[submodule "External/ojunit"]
|
|
||||||
path = External/ojunit
|
|
||||||
url = git://github.com/280north/ojunit.git
|
|
||||||
@@ -25,12 +25,18 @@
|
|||||||
@import "CPAnimation.j"
|
@import "CPAnimation.j"
|
||||||
@import "CPApplication.j"
|
@import "CPApplication.j"
|
||||||
@import "CPBezierPath.j"
|
@import "CPBezierPath.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"
|
||||||
@import "CPCib.j"
|
@import "CPCib.j"
|
||||||
|
@import "CPCibConnector.j"
|
||||||
|
@import "CPCibControlConnector.j"
|
||||||
@import "CPCibLoading.j"
|
@import "CPCibLoading.j"
|
||||||
|
@import "CPCibOutletConnector.j"
|
||||||
@import "CPClipView.j"
|
@import "CPClipView.j"
|
||||||
|
@import "CPCollectionViewItem.j"
|
||||||
@import "CPCollectionView.j"
|
@import "CPCollectionView.j"
|
||||||
@import "CPColor.j"
|
@import "CPColor.j"
|
||||||
@import "CPColorPanel.j"
|
@import "CPColorPanel.j"
|
||||||
@@ -38,6 +44,7 @@
|
|||||||
@import "CPCompatibility.j"
|
@import "CPCompatibility.j"
|
||||||
@import "CPControl.j"
|
@import "CPControl.j"
|
||||||
@import "CPCookie.j"
|
@import "CPCookie.j"
|
||||||
|
@import "CPCursor.j"
|
||||||
@import "CPDocument.j"
|
@import "CPDocument.j"
|
||||||
@import "CPDocumentController.j"
|
@import "CPDocumentController.j"
|
||||||
@import "CPEvent.j"
|
@import "CPEvent.j"
|
||||||
@@ -50,12 +57,15 @@
|
|||||||
@import "CPImageView.j"
|
@import "CPImageView.j"
|
||||||
@import "CPMenu.j"
|
@import "CPMenu.j"
|
||||||
@import "CPMenuItem.j"
|
@import "CPMenuItem.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 "CPScrollView.j"
|
||||||
@import "CPScroller.j"
|
@import "CPScroller.j"
|
||||||
@import "CPSecureTextField.j"
|
@import "CPSecureTextField.j"
|
||||||
@@ -69,7 +79,10 @@
|
|||||||
@import "CPTextField.j"
|
@import "CPTextField.j"
|
||||||
@import "CPToolbar.j"
|
@import "CPToolbar.j"
|
||||||
@import "CPToolbarItem.j"
|
@import "CPToolbarItem.j"
|
||||||
|
@import "CPTreeNode.j"
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
@import "CPViewAnimation.j"
|
||||||
|
@import "CPViewController.j"
|
||||||
@import "CPWebView.j"
|
@import "CPWebView.j"
|
||||||
@import "CPWindow.j"
|
@import "CPWindow.j"
|
||||||
@import "CPWindowController.j"
|
@import "CPWindowController.j"
|
||||||
|
|||||||
@@ -0,0 +1,381 @@
|
|||||||
|
/*
|
||||||
|
* CPAccordionView.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Francisco Tolmasky.
|
||||||
|
* Copyright 2009, 280 North, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import <Foundation/CPArray.j>
|
||||||
|
@import <Foundation/CPObject.j>
|
||||||
|
@import <Foundation/CPKeyValueObserving.j>
|
||||||
|
@import <Foundation/CPIndexSet.j>
|
||||||
|
@import <Foundation/CPString.j>
|
||||||
|
|
||||||
|
@import <AppKit/CPView.j>
|
||||||
|
|
||||||
|
#import "CoreGraphics/CGGeometry.h"
|
||||||
|
|
||||||
|
|
||||||
|
@implementation CPAccordionViewItem : CPObject
|
||||||
|
{
|
||||||
|
CPString _identifier @accessors(property=identifier);
|
||||||
|
CPView _view @accessors(property=view);
|
||||||
|
CPString _label @accessors(property=label);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
return [self initWithIdentifier:@""];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithIdentifier:(CPString)anIdentifier
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
[self setIdentifier:anIdentifier];
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation CPAccordionView : CPView
|
||||||
|
{
|
||||||
|
CPInteger _dirtyItemIndex;
|
||||||
|
CPView _itemHeaderPrototype;
|
||||||
|
|
||||||
|
CPMutableArray _items;
|
||||||
|
CPMutableArray _itemViews;
|
||||||
|
CPIndexSet _expandedItemIndexes;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
|
{
|
||||||
|
self = [super initWithFrame:aFrame];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_items = [];
|
||||||
|
_itemViews = [];
|
||||||
|
_expandedItemIndexes = [CPIndexSet indexSet];
|
||||||
|
|
||||||
|
[self setItemHeaderPrototype:[[CPButton alloc] initWithFrame:_CGRectMake(0.0, 0.0, 100.0, 24.0)]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setItemHeaderPrototype:(CPView)aView
|
||||||
|
{
|
||||||
|
_itemHeaderPrototype = aView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPView)itemHeaderPrototype
|
||||||
|
{
|
||||||
|
return _itemHeaderPrototype;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPArray)items
|
||||||
|
{
|
||||||
|
return _items;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)addItem:(CPAccordionViewItem)anItem
|
||||||
|
{
|
||||||
|
[self insertItem:anItem atIndex:_items.length];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)insertItem:(CPAccordionViewItem)anItem atIndex:(CPInteger)anIndex
|
||||||
|
{
|
||||||
|
// FIXME: SHIFT ITEMS RIGHT
|
||||||
|
[_expandedItemIndexes addIndex:anIndex];
|
||||||
|
|
||||||
|
var itemView = [[_CPAccordionItemView alloc] initWithAccordionView:self];
|
||||||
|
|
||||||
|
[itemView setIndex:anIndex];
|
||||||
|
[itemView setLabel:[anItem label]];
|
||||||
|
[itemView setContentView:[anItem view]];
|
||||||
|
|
||||||
|
[self addSubview:itemView];
|
||||||
|
|
||||||
|
[_items insertObject:anItem atIndex:anIndex];
|
||||||
|
[_itemViews insertObject:itemView atIndex:anIndex];
|
||||||
|
|
||||||
|
[self _invalidateItemsStartingAtIndex:anIndex];
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeItem:(CPAccordionViewItem)anItem
|
||||||
|
{
|
||||||
|
[self removeItemAtIndex:[_items indexOfObjectIdenticalTo:anItem]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeItemAtIndex:(CPInteger)anIndex
|
||||||
|
{
|
||||||
|
// SHIFT ITEMS LEFT
|
||||||
|
[_expandedItemIndexes removeIndex:anIndex];
|
||||||
|
|
||||||
|
[_itemViews[anIndex] removeFromSuperview];
|
||||||
|
|
||||||
|
[_items removeObjectAtIndex:anIndex];
|
||||||
|
[_itemViews removeObjectAtIndex:anIndex];
|
||||||
|
|
||||||
|
[self _invalidateItemsStartingAtIndex:anIndex];
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeAllItems
|
||||||
|
{
|
||||||
|
var count = _items.length;
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
[self removeItemAtIndex:count];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)expandItemAtIndex:(CPInteger)anIndex
|
||||||
|
{
|
||||||
|
if (![_itemViews[anIndex] isCollapsed])
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_expandedItemIndexes addIndex:anIndex];
|
||||||
|
[_itemViews[anIndex] setCollapsed:NO];
|
||||||
|
|
||||||
|
[self _invalidateItemsStartingAtIndex:anIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)collapseItemAtIndex:(CPInteger)anIndex
|
||||||
|
{
|
||||||
|
if ([_itemViews[anIndex] isCollapsed])
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_expandedItemIndexes removeIndex:anIndex];
|
||||||
|
[_itemViews[anIndex] setCollapsed:YES];
|
||||||
|
|
||||||
|
[self _invalidateItemsStartingAtIndex:anIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)toggleItemAtIndex:(CPInteger)anIndex
|
||||||
|
{
|
||||||
|
var itemView = _itemViews[anIndex];
|
||||||
|
|
||||||
|
if ([itemView isCollapsed])
|
||||||
|
[self expandItemAtIndex:anIndex];
|
||||||
|
|
||||||
|
else
|
||||||
|
[self collapseItemAtIndex:anIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPIndexSet)expandedItemIndexes
|
||||||
|
{
|
||||||
|
return _expandedItemIndexes;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPIndexSet)collapsedItemIndexes
|
||||||
|
{
|
||||||
|
var indexSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, _items.length)];
|
||||||
|
|
||||||
|
[indexSet removeIndexes:_expandedIndexes];
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
if (_dirtyItemIndex === CPNotFound)
|
||||||
|
_dirtyItemIndex = anIndex;
|
||||||
|
|
||||||
|
_dirtyItemIndex = MIN(_dirtyItemIndex, anIndex);
|
||||||
|
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFrameSize:(CGSize)aSize
|
||||||
|
{
|
||||||
|
var width = _CGRectGetWidth([self frame]);
|
||||||
|
|
||||||
|
[super setFrameSize:aSize];
|
||||||
|
|
||||||
|
if (width !== _CGRectGetWidth([self frame]))
|
||||||
|
[self _invalidateItemsStartingAtIndex:0];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)layoutSubviews
|
||||||
|
{
|
||||||
|
if (_items.length <= 0)
|
||||||
|
return [self setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), 0.0)];
|
||||||
|
|
||||||
|
if (_dirtyItemIndex === CPNotFound)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_dirtyItemIndex = MIN(_dirtyItemIndex, _items.length - 1);
|
||||||
|
|
||||||
|
var index = _dirtyItemIndex,
|
||||||
|
count = _itemViews.length,
|
||||||
|
width = _CGRectGetWidth([self bounds]),
|
||||||
|
y = index > 0 ? CGRectGetMaxY([_itemViews[index - 1] frame]) : 0.0;
|
||||||
|
|
||||||
|
// Do this now (instead of after looping), so that if we are made dirty again in the middle we don't blow this value away.
|
||||||
|
_dirtyItemIndex = CPNotFound;
|
||||||
|
|
||||||
|
for (; index < count; ++index)
|
||||||
|
{
|
||||||
|
var itemView = _itemViews[index];
|
||||||
|
|
||||||
|
[itemView setFrameY:y width:width];
|
||||||
|
|
||||||
|
y = CGRectGetMaxY([itemView frame]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[self setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), y)];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPAccordionItemView : CPView
|
||||||
|
{
|
||||||
|
CPAccordionView _accordionView;
|
||||||
|
|
||||||
|
BOOL _isCollapsed @accessors(getter=isCollapsed, setter=setCollapsed:);
|
||||||
|
CPInteger _index @accessors(property=index);
|
||||||
|
CPView _headerView;
|
||||||
|
CPView _contentView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithAccordionView:(CPAccordionView)anAccordionView
|
||||||
|
{
|
||||||
|
self = [super initWithFrame:_CGRectMakeZero()];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_accordionView = anAccordionView;
|
||||||
|
_isCollapsed = NO;
|
||||||
|
|
||||||
|
var bounds = [self bounds];
|
||||||
|
|
||||||
|
_headerView = [CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:[_accordionView itemHeaderPrototype]]];
|
||||||
|
|
||||||
|
if ([_headerView respondsToSelector:@selector(setTarget:)] && [_headerView respondsToSelector:@selector(setAction:)])
|
||||||
|
{
|
||||||
|
[_headerView setTarget:self];
|
||||||
|
[_headerView setAction:@selector(toggle:)];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self addSubview:_headerView];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)toggle:(id)aSender
|
||||||
|
{
|
||||||
|
[_accordionView toggleItemAtIndex:[self index]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setLabel:(CPString)aLabel
|
||||||
|
{
|
||||||
|
if ([_headerView respondsToSelector:@selector(setTitle:)])
|
||||||
|
[_headerView setTitle:aLabel];
|
||||||
|
|
||||||
|
else if ([_headerView respondsToSelector:@selector(setLabel:)])
|
||||||
|
[_headerView setLabel:aLabel];
|
||||||
|
|
||||||
|
else if ([_headerView respondsToSelector:@selector(setStringValue:)])
|
||||||
|
[_headerView setStringValue:aLabel];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setEnabled:(BOOL)isEnabled
|
||||||
|
{
|
||||||
|
if ([_headerView respondsToSelector:@selector(setEnabled:)])
|
||||||
|
[_headerView setEnabled:isEnabled];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setContentView:(CPView)aView
|
||||||
|
{
|
||||||
|
if (_contentView === aView)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_contentView removeObserver:self forKeyPath:@"frame"];
|
||||||
|
|
||||||
|
[_contentView removeFromSuperview];
|
||||||
|
|
||||||
|
_contentView = aView;
|
||||||
|
|
||||||
|
[_contentView addObserver:self forKeyPath:@"frame" options:CPKeyValueObservingOptionOld | CPKeyValueObservingOptionNew context:NULL];
|
||||||
|
|
||||||
|
[self addSubview:_contentView];
|
||||||
|
|
||||||
|
[_accordionView _invalidateItemsStartingAtIndex:[self index]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFrameY:(float)aY width:(float)aWidth
|
||||||
|
{
|
||||||
|
var headerHeight = _CGRectGetHeight([_headerView frame]);
|
||||||
|
|
||||||
|
// Size to fit or something?
|
||||||
|
[_headerView setFrameSize:_CGSizeMake(aWidth, headerHeight)];
|
||||||
|
[_contentView setFrameOrigin:_CGPointMake(0.0, headerHeight)];
|
||||||
|
|
||||||
|
if ([self isCollapsed])
|
||||||
|
[self setFrame:_CGRectMake(0.0, aY, aWidth, headerHeight)];
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var contentHeight = _CGRectGetHeight([_contentView frame]);
|
||||||
|
|
||||||
|
[_contentView setFrameSize:_CGSizeMake(aWidth, contentHeight)];
|
||||||
|
[self setFrame:_CGRectMake(0.0, aY, aWidth, contentHeight + headerHeight)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)resizeSubviewsWithOldSize:(CGSize)aSize
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)observeValueForKeyPath:(CPString)aKeyPath
|
||||||
|
ofObject:(id)anObject
|
||||||
|
change:(CPDictionary)aChange
|
||||||
|
context:(id)aContext
|
||||||
|
{
|
||||||
|
if (aKeyPath === "frame" && !CGRectEqualToRect([aChange objectForKey:CPKeyValueChangeOldKey], [aChange objectForKey:CPKeyValueChangeNewKey]))
|
||||||
|
[_accordionView _invalidateItemsStartingAtIndex:[self index]];
|
||||||
|
/*
|
||||||
|
else if (aKeyPath === "itemHeaderPrototype")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
+34
-26
@@ -62,12 +62,12 @@ var CPAlertWarningImage,
|
|||||||
CPAlert is an alert panel that can be displayed modally to present the
|
CPAlert is an alert panel that can be displayed modally to present the
|
||||||
user with a message and one or more options.
|
user with a message and one or more options.
|
||||||
|
|
||||||
It can be used to display an information message (<pre>CPInformationalAlertStyle</pre>),
|
It can be used to display an information message \c CPInformationalAlertStyle,
|
||||||
a warning message (<pre>CPWarningAlertStyle</pre> - which is the default), or a critical
|
a warning message \c CPWarningAlertStyle (the default), or a critical
|
||||||
alert (<pre>CPCriticalAlertStyle</pre>). In each case the user can be presented with one
|
alert \c CPCriticalAlertStyle. In each case the user can be presented with one
|
||||||
or more options by adding buttons using the <pre>addButtonWithTitle:</pre> method.
|
or more options by adding buttons using the \c -addButtonWithTitle: method.
|
||||||
|
|
||||||
The panel is displayed modally by calling <pre>runModal</pre> and once the user has
|
The panel is displayed modally by calling \c -runModal and once the user has
|
||||||
dismissed the panel, a message will be sent to the panel's delegate (if set), informing
|
dismissed the panel, a message will be sent to the panel's delegate (if set), informing
|
||||||
it which button was clicked (see delegate methods).
|
it which button was clicked (see delegate methods).
|
||||||
|
|
||||||
@@ -112,25 +112,16 @@ var CPAlertWarningImage,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Initializes a <pre>CPAlert</pre> panel with the default alert style (<pre>CPWarningAlertStyle</pre>).
|
Initializes a \c CPAlert panel with the default alert style \c CPWarningAlertStyle.
|
||||||
*/
|
*/
|
||||||
- (id)init
|
- (id)init
|
||||||
{
|
{
|
||||||
self = [super init];
|
if (self = [super init])
|
||||||
|
|
||||||
if (self)
|
|
||||||
{
|
{
|
||||||
_buttonCount = 0;
|
_buttonCount = 0;
|
||||||
_buttons = [CPArray array];
|
_buttons = [CPArray array];
|
||||||
_alertStyle = CPWarningAlertStyle;
|
_alertStyle = CPWarningAlertStyle;
|
||||||
|
|
||||||
_messageLabel = [[CPTextField alloc] initWithFrame:CGRectMake(57.0, 10.0, 220.0, 80.0)];
|
|
||||||
[_messageLabel setFont:[CPFont systemFontOfSize:12.0]];
|
|
||||||
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
|
|
||||||
[_messageLabel setAlignment:CPJustifiedTextAlignment];
|
|
||||||
|
|
||||||
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMake(15.0, 12.0, 32.0, 32.0)];
|
|
||||||
|
|
||||||
[self setWindowStyle:nil];
|
[self setWindowStyle:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,11 +136,11 @@ var CPAlertWarningImage,
|
|||||||
{
|
{
|
||||||
_windowStyle = styleMask;
|
_windowStyle = styleMask;
|
||||||
|
|
||||||
_alertPanel = [[CPPanel alloc] initWithContentRect:CGRectMake(0.0, 0.0, 300.0, 130.0) styleMask:styleMask ? styleMask | CPTitledWindowMask : CPTitledWindowMask];
|
_alertPanel = [[CPPanel alloc] initWithContentRect:CGRectMake(0.0, 0.0, 400.0, 110.0) styleMask:styleMask ? styleMask | CPTitledWindowMask : CPTitledWindowMask];
|
||||||
[_alertPanel setFloatingPanel:YES];
|
[_alertPanel setFloatingPanel:YES];
|
||||||
[_alertPanel center];
|
[_alertPanel center];
|
||||||
|
|
||||||
[_messageLabel setTextColor:(styleMask == CPHUDBackgroundWindowMask) ? [CPColor whiteColor] : [CPColor blackColor]];
|
[_messageLabel setTextColor:(styleMask & CPHUDBackgroundWindowMask) ? [CPColor whiteColor] : [CPColor blackColor]];
|
||||||
|
|
||||||
var count = [_buttons count];
|
var count = [_buttons count];
|
||||||
for(var i=0; i < count; i++)
|
for(var i=0; i < count; i++)
|
||||||
@@ -157,11 +148,25 @@ var CPAlertWarningImage,
|
|||||||
var button = _buttons[i];
|
var button = _buttons[i];
|
||||||
|
|
||||||
[button setFrameSize:CGSizeMake([button frame].size.width, (styleMask == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)];
|
[button setFrameSize:CGSizeMake([button frame].size.width, (styleMask == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)];
|
||||||
[button setBezelStyle:(styleMask == CPHUDBackgroundWindowMask) ? CPHUDBezelStyle : CPRoundedBezelStyle];
|
|
||||||
|
[button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]];
|
||||||
|
|
||||||
[[_alertPanel contentView] addSubview:button];
|
[[_alertPanel contentView] addSubview:button];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_messageLabel)
|
||||||
|
{
|
||||||
|
var bounds = [[_alertPanel contentView] bounds];
|
||||||
|
|
||||||
|
_messageLabel = [[CPTextField alloc] initWithFrame:CGRectMake(57.0, 10.0, CGRectGetWidth(bounds) - 73.0, 62.0)];
|
||||||
|
[_messageLabel setFont:[CPFont boldSystemFontOfSize:13.0]];
|
||||||
|
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
|
||||||
|
[_messageLabel setAlignment:CPJustifiedTextAlignment];
|
||||||
|
[_messageLabel setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||||
|
|
||||||
|
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMake(15.0, 12.0, 32.0, 32.0)];
|
||||||
|
}
|
||||||
|
|
||||||
[[_alertPanel contentView] addSubview:_messageLabel];
|
[[_alertPanel contentView] addSubview:_messageLabel];
|
||||||
[[_alertPanel contentView] addSubview:_alertImageView];
|
[[_alertPanel contentView] addSubview:_alertImageView];
|
||||||
}
|
}
|
||||||
@@ -244,21 +249,24 @@ var CPAlertWarningImage,
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
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 <pre>CPAlert</pre> 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.
|
||||||
|
|
||||||
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 button = [[CPButton alloc] initWithFrame:CGRectMake(200.0 - (_buttonCount * 90.0), 98.0, 80.0, (_windowStyle == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)];
|
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 setTitle:title];
|
[button setTitle:title];
|
||||||
[button setTarget:self];
|
[button setTarget:self];
|
||||||
[button setTag:_buttonCount];
|
[button setTag:_buttonCount];
|
||||||
[button setAction:@selector(_notifyDelegate:)];
|
[button setAction:@selector(_notifyDelegate:)];
|
||||||
|
|
||||||
[button setBezelStyle:(_windowStyle == CPHUDBackgroundWindowMask) ? CPHUDBezelStyle : CPRoundRectBezelStyle];
|
[button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]];
|
||||||
|
[button setAutoresizingMask:CPViewMinXMargin | CPViewMinYMargin];
|
||||||
|
|
||||||
[[_alertPanel contentView] addSubview:button];
|
[[_alertPanel contentView] addSubview:button];
|
||||||
|
|
||||||
if (_buttonCount == 0)
|
if (_buttonCount == 0)
|
||||||
@@ -269,7 +277,7 @@ var CPAlertWarningImage,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Displays the <pre>CPAlert</pre> panel as a modal dialog. The user will not be
|
Displays the \c CPAlert panel as a modal dialog. The user will not be
|
||||||
able to interact with any other controls until s/he has dismissed the alert
|
able to interact with any other controls until s/he has dismissed the alert
|
||||||
by clicking on one of the buttons.
|
by clicking on one of the buttons.
|
||||||
*/
|
*/
|
||||||
@@ -298,11 +306,11 @@ var CPAlertWarningImage,
|
|||||||
/* @ignore */
|
/* @ignore */
|
||||||
- (void)_notifyDelegate:(id)button
|
- (void)_notifyDelegate:(id)button
|
||||||
{
|
{
|
||||||
if (_delegate && [_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
|
|
||||||
[_delegate alertDidEnd:self returnCode:[button tag]];
|
|
||||||
|
|
||||||
[CPApp abortModal];
|
[CPApp abortModal];
|
||||||
[_alertPanel close];
|
[_alertPanel close];
|
||||||
|
|
||||||
|
if (_delegate && [_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
|
||||||
|
[_delegate alertDidEnd:self returnCode:[button tag]];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+50
-15
@@ -57,10 +57,10 @@ ACTUAL_FRAME_RATE = 0;
|
|||||||
@par Delegate Methods
|
@par Delegate Methods
|
||||||
|
|
||||||
@delegate -(BOOL)animationShouldStart:(CPAnimation)animation;
|
@delegate -(BOOL)animationShouldStart:(CPAnimation)animation;
|
||||||
Called at the beginning of <code>startAnimation</code>.
|
Called at the beginning of \c -startAnimation.
|
||||||
@param animation the animation that will start
|
@param animation the animation that will start
|
||||||
@return <code>YES</code> allows the animation to start.
|
@return \c YES allows the animation to start.
|
||||||
<code>NO</code> stops the animation.
|
\c NO stops the animation.
|
||||||
|
|
||||||
@delegate -(void)animationDidEnd:(CPAnimation)animation;
|
@delegate -(void)animationDidEnd:(CPAnimation)animation;
|
||||||
Called when an animation has completed.
|
Called when an animation has completed.
|
||||||
@@ -72,7 +72,7 @@ ACTUAL_FRAME_RATE = 0;
|
|||||||
|
|
||||||
@delegate - (float)animation:(CPAnimation)animation valueForProgress:(float)progress;
|
@delegate - (float)animation:(CPAnimation)animation valueForProgress:(float)progress;
|
||||||
The value from this method will be returned when CPAnimation's
|
The value from this method will be returned when CPAnimation's
|
||||||
<code>currentValue</code> method is called.
|
\c currentValue method is called.
|
||||||
@param animation the animation to obtain the curve value for
|
@param animation the animation to obtain the curve value for
|
||||||
@param progress the current animation progress
|
@param progress the current animation progress
|
||||||
@return the curve value
|
@return the curve value
|
||||||
@@ -106,8 +106,9 @@ ACTUAL_FRAME_RATE = 0;
|
|||||||
{
|
{
|
||||||
_progress = 0.0;
|
_progress = 0.0;
|
||||||
_duration = MAX(0.0, aDuration);
|
_duration = MAX(0.0, aDuration);
|
||||||
_animationCurve = anAnimationCurve;
|
|
||||||
_frameRate = 60.0;
|
_frameRate = 60.0;
|
||||||
|
|
||||||
|
[self setAnimationCurve:anAnimationCurve];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -120,7 +121,7 @@ ACTUAL_FRAME_RATE = 0;
|
|||||||
*/
|
*/
|
||||||
- (void)setAnimationCurve:(CPAnimationCurve)anAnimationCurve
|
- (void)setAnimationCurve:(CPAnimationCurve)anAnimationCurve
|
||||||
{
|
{
|
||||||
switch (_animationCurve)
|
switch (anAnimationCurve)
|
||||||
{
|
{
|
||||||
case CPAnimationEaseInOut: timingFunctionName = kCAMediaTimingFunctionEaseInEaseOut;
|
case CPAnimationEaseInOut: timingFunctionName = kCAMediaTimingFunctionEaseInEaseOut;
|
||||||
break;
|
break;
|
||||||
@@ -154,7 +155,7 @@ ACTUAL_FRAME_RATE = 0;
|
|||||||
/*!
|
/*!
|
||||||
Sets the animation's length.
|
Sets the animation's length.
|
||||||
@param aDuration the new animation length
|
@param aDuration the new animation length
|
||||||
@throws CPInvalidArgumentException if <code>aDuration</code> is negative
|
@throws CPInvalidArgumentException if \c aDuration is negative
|
||||||
*/
|
*/
|
||||||
- (void)setDuration:(CPTimeInterval)aDuration
|
- (void)setDuration:(CPTimeInterval)aDuration
|
||||||
{
|
{
|
||||||
@@ -175,7 +176,7 @@ ACTUAL_FRAME_RATE = 0;
|
|||||||
/*!
|
/*!
|
||||||
Sets the animation frame rate. This is not a guaranteed frame rate. 0 means to go as fast as possible.
|
Sets the animation frame rate. This is not a guaranteed frame rate. 0 means to go as fast as possible.
|
||||||
@param frameRate the new desired frame rate
|
@param frameRate the new desired frame rate
|
||||||
@throws CPInvalidArgumentException if <code>frameRate</code> is negative
|
@throws CPInvalidArgumentException if \c frameRate is negative
|
||||||
*/
|
*/
|
||||||
- (void)setFrameRate:(float)frameRate
|
- (void)setFrameRate:(float)frameRate
|
||||||
{
|
{
|
||||||
@@ -211,14 +212,14 @@ ACTUAL_FRAME_RATE = 0;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Starts the animation. The method calls <code>animationShouldStart:</code>
|
Starts the animation. The method calls \c -animationShouldStart:
|
||||||
on the delegate (if it implements it) to see if the animation
|
on the delegate (if it implements it) to see if the animation
|
||||||
should begin.
|
should begin.
|
||||||
*/
|
*/
|
||||||
- (void)startAnimation
|
- (void)startAnimation
|
||||||
{
|
{
|
||||||
// If we're already animating, or our delegate stops us, animate.
|
// If we're already animating, or our delegate stops us, animate.
|
||||||
if (_timer || _delegate && [_delegate respondsToSelector:@selector(animationShouldStart)] && ![_delegate animationShouldStart:self])
|
if (_timer || _delegate && [_delegate respondsToSelector:@selector(animationShouldStart:)] && ![_delegate animationShouldStart:self])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_progress === 1.0)
|
if (_progress === 1.0)
|
||||||
@@ -270,7 +271,7 @@ ACTUAL_FRAME_RATE = 0;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the animation
|
Returns \c YES if the animation
|
||||||
is running.
|
is running.
|
||||||
*/
|
*/
|
||||||
- (BOOL)isAnimating
|
- (BOOL)isAnimating
|
||||||
@@ -300,13 +301,47 @@ ACTUAL_FRAME_RATE = 0;
|
|||||||
*/
|
*/
|
||||||
- (float)currentValue
|
- (float)currentValue
|
||||||
{
|
{
|
||||||
|
var t = [self currentProgress];
|
||||||
|
|
||||||
if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)])
|
if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)])
|
||||||
return [_delegate animation:self valueForProgress:_progress];
|
return [_delegate animation:self valueForProgress:t];
|
||||||
|
|
||||||
if (_animationCurve == CPAnimationLinear)
|
var c1 = [],
|
||||||
return _progress;
|
c2 = [];
|
||||||
|
|
||||||
alert("IMPLEMENT ANIMATION CURVES!!!");
|
[_timingFunction getControlPointAtIndex:1 values:c1];
|
||||||
|
[_timingFunction getControlPointAtIndex:2 values:c2];
|
||||||
|
|
||||||
|
return CubicBezierAtTime(t,c1[0],c1[1],c2[0],c2[1],_duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
// currently used function to determine time
|
||||||
|
// 1:1 conversion to js from webkit source files
|
||||||
|
// UnitBezier.h, WebCore_animation_AnimationBase.cpp
|
||||||
|
var CubicBezierAtTime = function CubicBezierAtTime(t,p1x,p1y,p2x,p2y,duration)
|
||||||
|
{
|
||||||
|
var ax=0,bx=0,cx=0,ay=0,by=0,cy=0;
|
||||||
|
// `ax t^3 + bx t^2 + cx t' expanded using Horner's rule.
|
||||||
|
function sampleCurveX(t) {return ((ax*t+bx)*t+cx)*t;};
|
||||||
|
function sampleCurveY(t) {return ((ay*t+by)*t+cy)*t;};
|
||||||
|
function sampleCurveDerivativeX(t) {return (3.0*ax*t+2.0*bx)*t+cx;};
|
||||||
|
// The epsilon value to pass given that the animation is going to run over |duration| seconds. The longer the animation, the more precision is needed in the timing function result to avoid ugly discontinuities.
|
||||||
|
function solveEpsilon(duration) {return 1.0/(200.0*duration);};
|
||||||
|
function solve(x,epsilon) {return sampleCurveY(solveCurveX(x,epsilon));};
|
||||||
|
// Given an x value, find a parametric value it came from.
|
||||||
|
function solveCurveX(x,epsilon) {var t0,t1,t2,x2,d2,i;
|
||||||
|
function fabs(n) {if(n>=0) {return n;}else {return 0-n;}};
|
||||||
|
// First try a few iterations of Newton's method -- normally very fast.
|
||||||
|
for(t2=x, i=0; i<8; i++) {x2=sampleCurveX(t2)-x; if(fabs(x2)<epsilon) {return t2;} d2=sampleCurveDerivativeX(t2); if(fabs(d2)<1e-6) {break;} t2=t2-x2/d2;}
|
||||||
|
// Fall back to the bisection method for reliability.
|
||||||
|
t0=0.0; t1=1.0; t2=x; if(t2<t0) {return t0;} if(t2>t1) {return t1;}
|
||||||
|
while(t0<t1) {x2=sampleCurveX(t2); if(fabs(x2-x)<epsilon) {return t2;} if(x>x2) {t0=t2;}else {t1=t2;} t2=(t1-t0)*.5+t0;}
|
||||||
|
return t2; // Failure.
|
||||||
|
};
|
||||||
|
// Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1).
|
||||||
|
cx=3.0*p1x; bx=3.0*(p2x-p1x)-cx; ax=1.0-cx-bx; cy=3.0*p1y; by=3.0*(p2y-p1y)-cy; ay=1.0-cy-by;
|
||||||
|
// Convert from input time to parametric value in curve, then from that to output time.
|
||||||
|
return solve(t, solveEpsilon(duration));
|
||||||
|
};
|
||||||
|
|||||||
+451
-100
@@ -28,6 +28,10 @@
|
|||||||
@import "CPResponder.j"
|
@import "CPResponder.j"
|
||||||
@import "CPDocumentController.j"
|
@import "CPDocumentController.j"
|
||||||
@import "CPThemeBlend.j"
|
@import "CPThemeBlend.j"
|
||||||
|
@import "CPCibLoading.j"
|
||||||
|
@import "CPPlatform.j"
|
||||||
|
|
||||||
|
#include "Platform/Platform.h"
|
||||||
|
|
||||||
var CPMainCibFile = @"CPMainCibFile",
|
var CPMainCibFile = @"CPMainCibFile",
|
||||||
CPMainCibFileHumanFriendly = @"Main cib file base name";
|
CPMainCibFileHumanFriendly = @"Main cib file base name";
|
||||||
@@ -36,6 +40,15 @@ CPApp = nil;
|
|||||||
|
|
||||||
CPApplicationWillFinishLaunchingNotification = @"CPApplicationWillFinishLaunchingNotification";
|
CPApplicationWillFinishLaunchingNotification = @"CPApplicationWillFinishLaunchingNotification";
|
||||||
CPApplicationDidFinishLaunchingNotification = @"CPApplicationDidFinishLaunchingNotification";
|
CPApplicationDidFinishLaunchingNotification = @"CPApplicationDidFinishLaunchingNotification";
|
||||||
|
CPApplicationWillTerminateNotification = @"CPApplicationWillTerminateNotification";
|
||||||
|
CPApplicationWillBecomeActiveNotification = @"CPApplicationWillBecomeActiveNotification";
|
||||||
|
CPApplicationDidBecomeActiveNotification = @"CPApplicationDidBecomeActiveNotification";
|
||||||
|
CPApplicationWillResignActiveNotification = @"CPApplicationWillResignActiveNotification";
|
||||||
|
CPApplicationDidResignActiveNotification = @"CPApplicationDidResignActiveNotification";
|
||||||
|
|
||||||
|
CPTerminateNow = YES;
|
||||||
|
CPTerminateCancel = NO;
|
||||||
|
CPTerminateLater = -1; // not currently supported
|
||||||
|
|
||||||
CPRunStoppedResponse = -1000;
|
CPRunStoppedResponse = -1000;
|
||||||
CPRunAbortedResponse = -1001;
|
CPRunAbortedResponse = -1001;
|
||||||
@@ -48,7 +61,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
CPApplication is THE way to start up the Cappucino framework for your application to use.
|
CPApplication is THE way to start up the Cappucino framework for your application to use.
|
||||||
Every GUI application has exactly one instance of CPApplication (or of a custom subclass of
|
Every GUI application has exactly one instance of CPApplication (or of a custom subclass of
|
||||||
CPApplication). Your program's main() function can create that instance by calling the
|
CPApplication). Your program's main() function can create that instance by calling the
|
||||||
<code>CPApplicationMain</code> function. A simple example looks like this:
|
\c CPApplicationMain function. A simple example looks like this:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
function main(args, namedArgs)
|
function main(args, namedArgs)
|
||||||
@@ -75,6 +88,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;
|
||||||
@@ -83,10 +98,16 @@ CPRunContinuesResponse = -1002;
|
|||||||
|
|
||||||
//
|
//
|
||||||
id _delegate;
|
id _delegate;
|
||||||
|
BOOL _finishedLaunching;
|
||||||
|
BOOL _isActive;
|
||||||
|
|
||||||
CPDictionary _namedArgs;
|
CPDictionary _namedArgs;
|
||||||
CPArray _args;
|
CPArray _args;
|
||||||
CPString _fullArgsString;
|
CPString _fullArgsString;
|
||||||
|
|
||||||
|
CPImage _applicationIconImage;
|
||||||
|
|
||||||
|
CPPanel _aboutPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -104,7 +125,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Initializes the Document based application with basic menu functions.
|
Initializes the Document based application with basic menu functions.
|
||||||
Functions are <code>New, Open, Undo, Redo, Save, Cut, Copy, Paste</code>.
|
Functions are \c New, \c Open, \c Undo, \c Redo, \c Save, \c Cut, \c Copy, \c Paste.
|
||||||
@return the initialized application
|
@return the initialized application
|
||||||
*/
|
*/
|
||||||
- (id)init
|
- (id)init
|
||||||
@@ -126,14 +147,14 @@ CPRunContinuesResponse = -1002;
|
|||||||
[_mainMenu setAutoenablesItems:NO];
|
[_mainMenu setAutoenablesItems:NO];
|
||||||
|
|
||||||
var bundle = [CPBundle bundleForClass:[CPApplication class]],
|
var bundle = [CPBundle bundleForClass:[CPApplication class]],
|
||||||
newMenuItem = [[CPMenuItem alloc] initWithTitle:@"New" action:@selector(newDocument:) keyEquivalent:@"N"];
|
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 setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/New.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||||
[newMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/NewHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
[newMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/NewHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||||
|
|
||||||
[_mainMenu addItem:newMenuItem];
|
[_mainMenu addItem:newMenuItem];
|
||||||
|
|
||||||
var openMenuItem = [[CPMenuItem alloc] initWithTitle:@"Open" action:@selector(openDocument:) keyEquivalent:@"O"];
|
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 setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Open.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||||
[openMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/OpenHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
[openMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/OpenHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||||
@@ -146,7 +167,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
[saveMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Save.png"] size:CGSizeMake(16.0, 16.0)]];
|
[saveMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Save.png"] size:CGSizeMake(16.0, 16.0)]];
|
||||||
[saveMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/SaveHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
|
[saveMenuItem 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" action:@selector(saveDocument:) keyEquivalent:@"s"]];
|
||||||
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save As" action:@selector(saveDocumentAs:) keyEquivalent:nil]];
|
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save As" action:@selector(saveDocumentAs:) keyEquivalent:nil]];
|
||||||
|
|
||||||
[saveMenuItem setSubmenu:saveMenu];
|
[saveMenuItem setSubmenu:saveMenu];
|
||||||
@@ -165,9 +186,9 @@ CPRunContinuesResponse = -1002;
|
|||||||
[editMenu addItem:undoMenuItem];
|
[editMenu addItem:undoMenuItem];
|
||||||
[editMenu addItem:redoMenuItem];
|
[editMenu addItem:redoMenuItem];
|
||||||
|
|
||||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"X"]],
|
[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:@"Copy" action:@selector(copy:) keyEquivalent:@"c"]],
|
||||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"V"]];
|
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"v"]];
|
||||||
|
|
||||||
[editMenuItem setSubmenu:editMenu];
|
[editMenuItem setSubmenu:editMenu];
|
||||||
[editMenuItem setHidden:YES];
|
[editMenuItem setHidden:YES];
|
||||||
@@ -193,36 +214,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];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -234,13 +264,21 @@ CPRunContinuesResponse = -1002;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
This method is called by <code>run</code> before the event loop begins.
|
This method is called by \c -run before the event loop begins.
|
||||||
When it successfully completes, it posts the notification
|
When it successfully completes, it posts the notification
|
||||||
CPApplicationDidFinishLaunchingNotification. If you override
|
CPApplicationDidFinishLaunchingNotification. If you override
|
||||||
<code>finishLaunching</code>, the subclass method should invoke the superclass method.
|
\c -finishLaunching, the subclass method should invoke the superclass method.
|
||||||
*/
|
*/
|
||||||
- (void)finishLaunching
|
- (void)finishLaunching
|
||||||
{
|
{
|
||||||
|
// At this point we clear the window.status to eliminate Safari's "Cancelled" error message
|
||||||
|
// The message shouldn't be displayed, because only an XHR is cancelled, but it is a usability issue.
|
||||||
|
// We do it here so that applications can change it in willFinish or didFinishLaunching
|
||||||
|
window.status = " ";
|
||||||
|
|
||||||
|
// We also want to set the default cursor on the body, so that buttons and things don't have an iBeam
|
||||||
|
[[CPCursor arrowCursor] set];
|
||||||
|
|
||||||
var bundle = [CPBundle mainBundle],
|
var bundle = [CPBundle mainBundle],
|
||||||
types = [bundle objectForInfoDictionaryKey:@"CPBundleDocumentTypes"];
|
types = [bundle objectForInfoDictionaryKey:@"CPBundleDocumentTypes"];
|
||||||
|
|
||||||
@@ -266,18 +304,172 @@ CPRunContinuesResponse = -1002;
|
|||||||
postNotificationName:CPApplicationWillFinishLaunchingNotification
|
postNotificationName:CPApplicationWillFinishLaunchingNotification
|
||||||
object:self];
|
object:self];
|
||||||
|
|
||||||
if (_documentController)
|
var needsUntitled = !!_documentController,
|
||||||
|
URLStrings = window.cpOpeningURLStrings && window.cpOpeningURLStrings(),
|
||||||
|
index = 0,
|
||||||
|
count = [URLStrings count];
|
||||||
|
|
||||||
|
for (; index < count; ++index)
|
||||||
|
needsUntitled = ![self _openURL:[CPURL URLWithString:URLStrings[index]]] || needsUntitled;
|
||||||
|
|
||||||
|
if (needsUntitled && [_delegate respondsToSelector:@selector(applicationShouldOpenUntitledFile:)])
|
||||||
|
needsUntitled = [_delegate applicationShouldOpenUntitledFile:self];
|
||||||
|
|
||||||
|
if (needsUntitled)
|
||||||
[_documentController newDocument:self];
|
[_documentController newDocument:self];
|
||||||
|
|
||||||
|
[_documentController _updateRecentDocumentsMenu];
|
||||||
|
|
||||||
[defaultCenter
|
[defaultCenter
|
||||||
postNotificationName:CPApplicationDidFinishLaunchingNotification
|
postNotificationName:CPApplicationDidFinishLaunchingNotification
|
||||||
object:self];
|
object:self];
|
||||||
|
|
||||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||||
|
|
||||||
|
_finishedLaunching = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)terminate:(id)aSender
|
||||||
|
{
|
||||||
|
[[CPNotificationCenter defaultCenter]
|
||||||
|
postNotificationName:CPApplicationWillTerminateNotification
|
||||||
|
object:self];
|
||||||
|
|
||||||
|
if (![CPPlatform isBrowser])
|
||||||
|
{
|
||||||
|
[[CPDocumentController sharedDocumentController] closeAllDocumentsWithDelegate:self
|
||||||
|
didCloseAllSelector:@selector(_documentController:didCloseAll:context:)
|
||||||
|
contextInfo:nil];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[[[self keyWindow] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setApplicationIconImage:(CPImage)anImage
|
||||||
|
{
|
||||||
|
_applicationIconImage = anImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPImage)applicationIconImage
|
||||||
|
{
|
||||||
|
if (_applicationIconImage)
|
||||||
|
return _applicationIconImage;
|
||||||
|
|
||||||
|
var imagePath = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPApplicationIcon"];
|
||||||
|
if (imagePath)
|
||||||
|
_applicationIconImage = [[CPImage alloc] initWithContentsOfFile:imagePath];
|
||||||
|
|
||||||
|
return _applicationIconImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)orderFrontStandardAboutPanel:(id)sender
|
||||||
|
{
|
||||||
|
[self orderFrontStandardAboutPanelWithOptions:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)orderFrontStandardAboutPanelWithOptions:(CPDictionary)options
|
||||||
|
{
|
||||||
|
if (!_aboutPanel)
|
||||||
|
{
|
||||||
|
var mainInfo = [[CPBundle mainBundle] infoDictionary],
|
||||||
|
applicationTitle = [options objectForKey:"ApplicationName"] || [mainInfo objectForKey:@"CPBundleName"],
|
||||||
|
applicationIcon = [options objectForKey:@"ApplicationIcon"] || [self applicationIconImage],
|
||||||
|
version = [options objectForKey:@"Version"] || [mainInfo objectForKey:@"CPBundleVersion"],
|
||||||
|
applicationVersion = [options objectForKey:@"ApplicationVersion"] || [mainInfo objectForKey:@"CPBundleShortVersionString"],
|
||||||
|
copyright = [options objectForKey:@"Copyright"] || [mainInfo objectForKey:@"CPHumanReadableCopyright"];
|
||||||
|
|
||||||
|
var aboutPanelController = [[CPWindowController alloc] initWithWindowCibName:@"AboutPanel"],
|
||||||
|
aboutPanel = [aboutPanelController window],
|
||||||
|
contentView = [aboutPanel contentView],
|
||||||
|
imageView = [contentView viewWithTag:1],
|
||||||
|
applicationLabel = [contentView viewWithTag:2],
|
||||||
|
versionLabel = [contentView viewWithTag:3],
|
||||||
|
copyrightLabel = [contentView viewWithTag:4],
|
||||||
|
standardPath = [[CPBundle bundleForClass:[self class]] pathForResource:@"standardApplicationIcon.png"];
|
||||||
|
|
||||||
|
// FIXME move this into the CIB eventually
|
||||||
|
[applicationLabel setFont:[CPFont boldSystemFontOfSize:14.0]];
|
||||||
|
[applicationLabel setAlignment:CPCenterTextAlignment];
|
||||||
|
[versionLabel setAlignment:CPCenterTextAlignment];
|
||||||
|
[copyrightLabel setAlignment:CPCenterTextAlignment];
|
||||||
|
|
||||||
|
[imageView setImage:applicationIcon || [[CPImage alloc] initWithContentsOfFile:standardPath
|
||||||
|
size:CGSizeMake(256, 256)]];
|
||||||
|
|
||||||
|
[applicationLabel setStringValue:applicationTitle || ""];
|
||||||
|
|
||||||
|
if (applicationVersion && version)
|
||||||
|
[versionLabel setStringValue:@"Version " + applicationVersion + " (" + version + ")"];
|
||||||
|
else if (applicationVersion || version)
|
||||||
|
[versionLabel setStringValue:@"Version " + (applicationVersion || version)];
|
||||||
|
else
|
||||||
|
[versionLabel setStringValue:@""];
|
||||||
|
|
||||||
|
[copyrightLabel setStringValue:copyright || ""];
|
||||||
|
[aboutPanel center];
|
||||||
|
|
||||||
|
_aboutPanel = aboutPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
[_aboutPanel orderFront:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)_documentController:(NSDocumentController *)docController didCloseAll:(BOOL)didCloseAll context:(Object)info
|
||||||
|
{
|
||||||
|
// callback method for terminate:
|
||||||
|
if (didCloseAll)
|
||||||
|
{
|
||||||
|
if ([_delegate respondsToSelector:@selector(applicationShouldTerminate:)])
|
||||||
|
[self replyToApplicationShouldTerminate:[_delegate applicationShouldTerminate:self]];
|
||||||
|
else
|
||||||
|
[self replyToApplicationShouldTerminate:YES];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)replyToApplicationShouldTerminate:(BOOL)terminate
|
||||||
|
{
|
||||||
|
if (terminate == CPTerminateNow)
|
||||||
|
{
|
||||||
|
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillTerminateNotification object:self];
|
||||||
|
[CPPlatform terminateApplication];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)activateIgnoringOtherApps:(BOOL)shouldIgnoreOtherApps
|
||||||
|
{
|
||||||
|
[self _willBecomeActive];
|
||||||
|
|
||||||
|
[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
|
||||||
|
{
|
||||||
|
[CPPlatform hideOtherApplications:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Calls <code>finishLaunching</code> method which results in starting
|
Calls \c -finishLaunching method which results in starting
|
||||||
the main event loop.
|
the main event loop.
|
||||||
*/
|
*/
|
||||||
- (void)run
|
- (void)run
|
||||||
@@ -287,7 +479,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
|
|
||||||
// Managing the Event Loop
|
// Managing the Event Loop
|
||||||
/*!
|
/*!
|
||||||
Starts a modal event loop for <code>aWindow</code>
|
Starts a modal event loop for \c aWindow
|
||||||
@param aWindow the window to start the event loop for
|
@param aWindow the window to start the event loop for
|
||||||
*/
|
*/
|
||||||
- (void)runModalForWindow:(CPWindow)aWindow
|
- (void)runModalForWindow:(CPWindow)aWindow
|
||||||
@@ -296,8 +488,8 @@ CPRunContinuesResponse = -1002;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Stops the event loop started by <code>runModalForWindow:</code> and
|
Stops the event loop started by \c -runModalForWindow: and
|
||||||
sets the code that <code>runModalForWindow:</code> will return.
|
sets the code that \c -runModalForWindow: will return.
|
||||||
@param aCode the return code for the modal event
|
@param aCode the return code for the modal event
|
||||||
*/
|
*/
|
||||||
- (void)stopModalWithCode:(int)aCode
|
- (void)stopModalWithCode:(int)aCode
|
||||||
@@ -338,7 +530,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Aborts the event loop started by <code>runModalForWindow:</code>
|
Aborts the event loop started by \c -runModalForWindow:
|
||||||
*/
|
*/
|
||||||
- (void)abortModal
|
- (void)abortModal
|
||||||
{
|
{
|
||||||
@@ -346,7 +538,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets up a modal session with <code>theWindow</code>.
|
Sets up a modal session with \c theWindow.
|
||||||
@param aWindow the window to set up the modal session for
|
@param aWindow the window to set up the modal session for
|
||||||
*/
|
*/
|
||||||
- (CPModalSession)beginModalSessionForWindow:(CPWindow)aWindow
|
- (CPModalSession)beginModalSessionForWindow:(CPWindow)aWindow
|
||||||
@@ -375,7 +567,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the window for the current modal session. If there is no
|
Returns the window for the current modal session. If there is no
|
||||||
modal session, it returns <code>nil</code>.
|
modal session, it returns \c nil.
|
||||||
*/
|
*/
|
||||||
- (CPWindow)modalWindow
|
- (CPWindow)modalWindow
|
||||||
{
|
{
|
||||||
@@ -388,10 +580,8 @@ CPRunContinuesResponse = -1002;
|
|||||||
/* @ignore */
|
/* @ignore */
|
||||||
- (BOOL)_handleKeyEquivalent:(CPEvent)anEvent
|
- (BOOL)_handleKeyEquivalent:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
if ([_mainMenu performKeyEquivalent:anEvent])
|
return [[self keyWindow] performKeyEquivalent:anEvent] ||
|
||||||
return YES;
|
[_mainMenu performKeyEquivalent:anEvent];
|
||||||
|
|
||||||
return NO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -400,12 +590,29 @@ CPRunContinuesResponse = -1002;
|
|||||||
*/
|
*/
|
||||||
- (void)sendEvent:(CPEvent)anEvent
|
- (void)sendEvent:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
|
_currentEvent = anEvent;
|
||||||
|
|
||||||
|
var willPropagate = [[[anEvent window] platformWindow] _willPropagateCurrentDOMEvent];
|
||||||
|
|
||||||
|
// temporarily pretend we won't propagate the event. we'll restore the saved value later
|
||||||
|
// we do this outside the if so that changes user code might make in _handleKeyEquiv. are preserved
|
||||||
|
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:NO];
|
||||||
|
|
||||||
// Check if this is a candidate for key equivalent...
|
// Check if this is a candidate for key equivalent...
|
||||||
if ([anEvent type] == CPKeyDown &&
|
if ([anEvent _couldBeKeyEquivalent] && [self _handleKeyEquivalent:anEvent])
|
||||||
[anEvent modifierFlags] & (CPCommandKeyMask | CPControlKeyMask) &&
|
{
|
||||||
[[anEvent characters] length] > 0 &&
|
var characters = [anEvent characters],
|
||||||
[self _handleKeyEquivalent:anEvent])
|
modifierFlags = [anEvent modifierFlags];
|
||||||
|
|
||||||
|
// Unconditionally propagate on these keys to solve browser copy paste bugs
|
||||||
|
if ((characters == "c" || characters == "x" || characters == "v") && (modifierFlags & CPPlatformActionKeyMask))
|
||||||
|
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we make it this far, then restore the original willPropagate value
|
||||||
|
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:willPropagate];
|
||||||
|
|
||||||
if (_eventListeners.length)
|
if (_eventListeners.length)
|
||||||
{
|
{
|
||||||
@@ -443,7 +650,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the CPWindow object corresponding to <code>aWindowNumber</code>.
|
Returns the CPWindow object corresponding to \c aWindowNumber.
|
||||||
*/
|
*/
|
||||||
- (CPWindow)windowWithWindowNumber:(int)aWindowNumber
|
- (CPWindow)windowWithWindowNumber:(int)aWindowNumber
|
||||||
{
|
{
|
||||||
@@ -458,6 +665,19 @@ 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
|
||||||
|
{
|
||||||
|
return CPWindowObjectList();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)hide:(id)aSender
|
||||||
|
{
|
||||||
|
[CPPlatform hide:self];
|
||||||
|
}
|
||||||
|
|
||||||
// Accessing the Main Menu
|
// Accessing the Main Menu
|
||||||
/*!
|
/*!
|
||||||
Returns the application's main menu
|
Returns the application's main menu
|
||||||
@@ -473,17 +693,23 @@ CPRunContinuesResponse = -1002;
|
|||||||
*/
|
*/
|
||||||
- (void)setMainMenu:(CPMenu)aMenu
|
- (void)setMainMenu:(CPMenu)aMenu
|
||||||
{
|
{
|
||||||
_mainMenu = aMenu;
|
if ([aMenu _menuName] === "CPMainMenu")
|
||||||
|
{
|
||||||
|
if (_mainMenu === aMenu)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_mainMenu = aMenu;
|
||||||
|
|
||||||
|
if ([CPPlatform supportsNativeMainMenu])
|
||||||
|
window.cpSetMainMenu(_mainMenu);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[aMenu _setMenuName:@"CPMainMenu"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)orderFrontStandardAboutPanel:(id)aSender
|
- (void)orderFrontColorPanel:(id)aSender
|
||||||
{
|
{
|
||||||
[self orderFrontStandardAboutPanelWithOptions:nil];
|
[[CPColorPanel sharedColorPanel] orderFront:self];
|
||||||
}
|
|
||||||
|
|
||||||
- (void)orderFrontStandardAboutPanelWithOptions:(CPDictionary)aDictionary
|
|
||||||
{
|
|
||||||
// FIXME: Implement.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Posting Actions
|
// Posting Actions
|
||||||
@@ -494,7 +720,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
@param anAction the action to perform.
|
@param anAction the action to perform.
|
||||||
@param anObject the argument for the action
|
@param anObject the argument for the action
|
||||||
method
|
method
|
||||||
@return <code>YES</code> if the action was performed
|
@return \c YES if the action was performed
|
||||||
*/
|
*/
|
||||||
- (BOOL)tryToPerform:(SEL)anAction with:(id)anObject
|
- (BOOL)tryToPerform:(SEL)anAction with:(id)anObject
|
||||||
{
|
{
|
||||||
@@ -519,7 +745,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
@param anAction the action to send
|
@param anAction the action to send
|
||||||
@param aTarget the target for the action
|
@param aTarget the target for the action
|
||||||
@param aSender the action sender
|
@param aSender the action sender
|
||||||
@return <code>YES</code>
|
@return \c YES
|
||||||
*/
|
*/
|
||||||
- (BOOL)sendAction:(SEL)anAction to:(id)aTarget from:(id)aSender
|
- (BOOL)sendAction:(SEL)anAction to:(id)aTarget from:(id)aSender
|
||||||
{
|
{
|
||||||
@@ -535,12 +761,12 @@ CPRunContinuesResponse = -1002;
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Finds a target for the specified action. If the
|
Finds a target for the specified action. If the
|
||||||
action is <code>nil</code>, returns <code>nil</code>.
|
action is \c nil, returns \c nil.
|
||||||
If the target is not <code>nil</code>, <code>aTarget</code> is
|
If the target is not \c nil, \c aTarget is
|
||||||
returned. Otherwise, it calls <code>targetForAction:</code>
|
returned. Otherwise, it calls \c -targetForAction:
|
||||||
to search for a target.
|
to search for a target.
|
||||||
@param anAction the action to find a target for
|
@param anAction the action to find a target for
|
||||||
@param aTarget if not <code>nil</code>, this will be returned
|
@param aTarget if not \c nil, this will be returned
|
||||||
@aSender not used
|
@aSender not used
|
||||||
@return a target for the action
|
@return a target for the action
|
||||||
*/
|
*/
|
||||||
@@ -568,7 +794,7 @@ CPRunContinuesResponse = -1002;
|
|||||||
</ol>
|
</ol>
|
||||||
@param aWindow the window to search for a target
|
@param aWindow the window to search for a target
|
||||||
@param anAction the action to find a responder to
|
@param anAction the action to find a responder to
|
||||||
@return the object that responds to the action, or <code>nil</code>
|
@return the object that responds to the action, or \c nil
|
||||||
if no matching target was found
|
if no matching target was found
|
||||||
@ignore
|
@ignore
|
||||||
*/
|
*/
|
||||||
@@ -602,8 +828,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;
|
||||||
@@ -614,13 +839,13 @@ 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>
|
||||||
</ol>
|
</ol>
|
||||||
@param anAction the action to handle
|
@param anAction the action to handle
|
||||||
@return a target that can respond, or <code>nil</code>
|
@return a target that can respond, or \c nil
|
||||||
if no match could be found
|
if no match could be found
|
||||||
*/
|
*/
|
||||||
- (id)targetForAction:(SEL)anAction
|
- (id)targetForAction:(SEL)anAction
|
||||||
@@ -653,8 +878,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
|
||||||
@@ -662,6 +885,11 @@ CPRunContinuesResponse = -1002;
|
|||||||
_eventListeners.push(_CPEventListenerMake(aMask, function (anEvent) { objj_msgSend(aTarget, aSelector, anEvent); }));
|
_eventListeners.push(_CPEventListenerMake(aMask, function (anEvent) { objj_msgSend(aTarget, aSelector, anEvent); }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CPEvent)currentEvent
|
||||||
|
{
|
||||||
|
return _currentEvent;
|
||||||
|
}
|
||||||
|
|
||||||
// Managing Sheets
|
// Managing Sheets
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -674,12 +902,43 @@ CPRunContinuesResponse = -1002;
|
|||||||
*/
|
*/
|
||||||
- (void)beginSheet:(CPWindow)aSheet modalForWindow:(CPWindow)aWindow modalDelegate:(id)aModalDelegate didEndSelector:(SEL)aDidEndSelector contextInfo:(id)aContextInfo
|
- (void)beginSheet:(CPWindow)aSheet modalForWindow:(CPWindow)aWindow modalDelegate:(id)aModalDelegate didEndSelector:(SEL)aDidEndSelector contextInfo:(id)aContextInfo
|
||||||
{
|
{
|
||||||
|
var styleMask = [aSheet styleMask];
|
||||||
|
if (!(styleMask & CPDocModalWindowMask))
|
||||||
|
{
|
||||||
|
[CPException raise:CPInternalInconsistencyException reason:@"Currently only CPDocModalWindowMask style mask is supported for attached sheets"];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[aWindow orderFront:self];
|
||||||
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo];
|
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)endSheet:(CPWindow)sheet returnCode:(int)returnCode
|
||||||
|
{
|
||||||
|
var count = [_windows count];
|
||||||
|
|
||||||
|
while (--count >= 0)
|
||||||
|
{
|
||||||
|
var aWindow = [_windows objectAtIndex:count];
|
||||||
|
var context = aWindow._sheetContext;
|
||||||
|
|
||||||
|
if (context != nil && context["sheet"] === sheet)
|
||||||
|
{
|
||||||
|
context["returnCode"] = returnCode;
|
||||||
|
[aWindow _detachSheetWindow];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)endSheet:(CPWindow)sheet
|
||||||
|
{
|
||||||
|
[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;
|
||||||
@@ -712,12 +971,18 @@ CPRunContinuesResponse = -1002;
|
|||||||
- (void)_reloadArguments
|
- (void)_reloadArguments
|
||||||
{
|
{
|
||||||
_fullArgsString = window.location.hash;
|
_fullArgsString = window.location.hash;
|
||||||
var args = _fullArgsString.replace("#", "").split("/").slice(0);
|
|
||||||
|
|
||||||
for(var i=0, count = args.length; i<count; i++)
|
if (_fullArgsString.length)
|
||||||
args[i] = decodeURIComponent(args[i]);
|
{
|
||||||
|
var args = _fullArgsString.substring(1).split("/");
|
||||||
|
|
||||||
_args = args;
|
for (var i = 0, count = args.length; i < count; i++)
|
||||||
|
args[i] = decodeURIComponent(args[i]);
|
||||||
|
|
||||||
|
_args = args;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_args = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPDictionary)namedArguments
|
- (CPDictionary)namedArguments
|
||||||
@@ -725,6 +990,87 @@ CPRunContinuesResponse = -1002;
|
|||||||
return _namedArgs;
|
return _namedArgs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)_openURL:(CPURL)aURL
|
||||||
|
{
|
||||||
|
if (_delegate && [_delegate respondsToSelector:@selector(application:openFile:)])
|
||||||
|
{
|
||||||
|
CPLog.warn("application:openFile: is deprecated, use application:openURL: instead.");
|
||||||
|
return [_delegate application:self openFile:[aURL absoluteString]];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_delegate && [_delegate respondsToSelector:@selector(application:openURL:)])
|
||||||
|
return [_delegate application:self openURL:aURL];
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
if (self._activeMenu)
|
||||||
|
[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
|
||||||
|
{
|
||||||
|
// FIXME: don't hardcode
|
||||||
|
return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo");
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var _CPModalSessionMake = function(aWindow, aStopCode)
|
var _CPModalSessionMake = function(aWindow, aStopCode)
|
||||||
@@ -750,13 +1096,20 @@ var _CPRunModalLoop = function(anEvent)
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Starts the GUI and Cappuccino frameworks. This function should be
|
Starts the GUI and Cappuccino frameworks. This function should be
|
||||||
called from the <code>main()</code> function of your program.
|
called from the \c main() function of your program.
|
||||||
@class CPApplication
|
@class CPApplication
|
||||||
@return void
|
@return void
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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];
|
||||||
|
|
||||||
@@ -765,25 +1118,8 @@ function CPApplicationMain(args, namedArgs)
|
|||||||
|
|
||||||
[principalClass sharedApplication];
|
[principalClass sharedApplication];
|
||||||
|
|
||||||
//FIXME?
|
if ([args containsObject:"debug"])
|
||||||
if (!args && !namedArgs)
|
CPLogRegister(CPLogPopup);
|
||||||
{
|
|
||||||
var args = [CPApp arguments],
|
|
||||||
searchParams = window.location.search.substring(1).split("&");
|
|
||||||
namedArgs = [CPDictionary dictionary];
|
|
||||||
|
|
||||||
if([args containsObject:"debug"])
|
|
||||||
CPLogRegister(CPLogPopup);
|
|
||||||
|
|
||||||
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;
|
||||||
@@ -797,9 +1133,9 @@ var _CPAppBootstrapperActions = nil;
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)actions
|
+ (CPArray)actions
|
||||||
{
|
{
|
||||||
return [@selector(loadDefaultTheme), @selector(loadMainCibFile)];
|
return [@selector(bootstrapPlatform), @selector(loadDefaultTheme), @selector(loadMainCibFile)];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)performActions
|
+ (void)performActions
|
||||||
@@ -818,18 +1154,23 @@ var _CPAppBootstrapperActions = nil;
|
|||||||
[CPApp run];
|
[CPApp run];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (BOOL)bootstrapPlatform
|
||||||
|
{
|
||||||
|
return [CPPlatform bootstrap];
|
||||||
|
}
|
||||||
|
|
||||||
+ (BOOL)loadDefaultTheme
|
+ (BOOL)loadDefaultTheme
|
||||||
{
|
{
|
||||||
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:[[CPBundle bundleForClass:[CPApplication class]] pathForResource:@"Aristo.blend"]];
|
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:[[CPBundle bundleForClass:[CPApplication class]] pathForResource:[CPApplication defaultThemeName] + ".blend"]];
|
||||||
|
|
||||||
[blend loadWithDelegate:self];
|
[blend loadWithDelegate:self];
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)blendDidFinishLoading:(CPBundle)aBundle
|
+ (void)blendDidFinishLoading:(CPThemeBlend)aThemeBlend
|
||||||
{
|
{
|
||||||
[CPTheme setDefaultTheme:[CPTheme themeNamed:@"Aristo"]];
|
[CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]];
|
||||||
|
|
||||||
[self performActions];
|
[self performActions];
|
||||||
}
|
}
|
||||||
@@ -841,7 +1182,7 @@ var _CPAppBootstrapperActions = nil;
|
|||||||
|
|
||||||
if (mainCibFile)
|
if (mainCibFile)
|
||||||
{
|
{
|
||||||
[CPBundle loadCibFile:[mainBundle pathForResource:mainCibFile]
|
[mainBundle loadCibFile:mainCibFile
|
||||||
externalNameTable:[CPDictionary dictionaryWithObject:CPApp forKey:CPCibOwner]
|
externalNameTable:[CPDictionary dictionaryWithObject:CPApp forKey:CPCibOwner]
|
||||||
loadDelegate:self];
|
loadDelegate:self];
|
||||||
|
|
||||||
@@ -856,4 +1197,14 @@ var _CPAppBootstrapperActions = nil;
|
|||||||
[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
|
||||||
|
{
|
||||||
|
_CPAppBootstrapperActions = nil;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+86
-9
@@ -50,52 +50,76 @@ var DefaultLineWidth = 1.0;
|
|||||||
float _lineWidth;
|
float _lineWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Create a new CPBezierPath object.
|
||||||
|
*/
|
||||||
+ (CPBezierPath)bezierPath
|
+ (CPBezierPath)bezierPath
|
||||||
{
|
{
|
||||||
return [[[self class] alloc] init];
|
return [[self alloc] init];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Create a new CPBezierPath object initialized with an oval path drawn within a rectangular path.
|
||||||
|
*/
|
||||||
+ (CPBezierPath)bezierPathWithOvalInRect:(CGRect)rect
|
+ (CPBezierPath)bezierPathWithOvalInRect:(CGRect)rect
|
||||||
{
|
{
|
||||||
var path = [[self class] bezierPath];
|
var path = [self bezierPath];
|
||||||
|
|
||||||
[path appendBezierPathWithOvalInRect:rect];
|
[path appendBezierPathWithOvalInRect:rect];
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Create a new CPBezierPath object initialized with a rectangular path.
|
||||||
|
*/
|
||||||
+ (CPBezierPath)bezierPathWithRect:(CGRect)rect
|
+ (CPBezierPath)bezierPathWithRect:(CGRect)rect
|
||||||
{
|
{
|
||||||
var path = [[self class] bezierPath];
|
var path = [self bezierPath];
|
||||||
|
|
||||||
[path appendBezierPathWithRect:rect];
|
[path appendBezierPathWithRect:rect];
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Get default line width.
|
||||||
|
*/
|
||||||
+ (float)defaultLineWidth
|
+ (float)defaultLineWidth
|
||||||
{
|
{
|
||||||
return DefaultLineWidth;
|
return DefaultLineWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set default line width.
|
||||||
|
*/
|
||||||
+ (void)setDefaultLineWidth:(float)width
|
+ (void)setDefaultLineWidth:(float)width
|
||||||
{
|
{
|
||||||
DefaultLineWidth = width;
|
DefaultLineWidth = width;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)fillRect:(CGRect)rect
|
/*!
|
||||||
|
Fill rectangular path with current fill color.
|
||||||
|
*/
|
||||||
|
+ (void)fillRect:(CGRect)aRect
|
||||||
{
|
{
|
||||||
[[[self class] bezierPathWithRect:rect] fill];
|
[[self bezierPathWithRect:aRect] fill];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)strokeRect:(CGRect)rect
|
/*!
|
||||||
|
Using the current stroke color and default drawing attributes, strokes a counterclockwise path beginning at the rectangle's origin.
|
||||||
|
*/
|
||||||
|
+ (void)strokeRect:(CGRect)aRect
|
||||||
{
|
{
|
||||||
[[[self class] bezierPathWithRect:rect] stroke];
|
[[self bezierPathWithRect:aRect] stroke];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Using the current stroke color and default drawing attributes, strokes a line between two points.
|
||||||
|
*/
|
||||||
+ (void)strokeLineFromPoint:(CGPoint)point1 toPoint:(CGPoint)point2
|
+ (void)strokeLineFromPoint:(CGPoint)point1 toPoint:(CGPoint)point2
|
||||||
{
|
{
|
||||||
var path = [[self class] bezierPath];
|
var path = [self bezierPath];
|
||||||
|
|
||||||
[path moveToPoint:point1];
|
[path moveToPoint:point1];
|
||||||
[path lineToPoint:point2];
|
[path lineToPoint:point2];
|
||||||
@@ -103,6 +127,9 @@ var DefaultLineWidth = 1.0;
|
|||||||
[path stroke];
|
[path stroke];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Create a new CPBezierPath object using the default line width.
|
||||||
|
*/
|
||||||
- (id)init
|
- (id)init
|
||||||
{
|
{
|
||||||
if (self = [super init])
|
if (self = [super init])
|
||||||
@@ -114,26 +141,41 @@ var DefaultLineWidth = 1.0;
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Moves the current point to another location.
|
||||||
|
*/
|
||||||
- (void)moveToPoint:(CGPoint)point
|
- (void)moveToPoint:(CGPoint)point
|
||||||
{
|
{
|
||||||
CGPathMoveToPoint(_path, nil, point.x, point.y);
|
CGPathMoveToPoint(_path, nil, point.x, point.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Append a straight line to the path.
|
||||||
|
*/
|
||||||
- (void)lineToPoint:(CGPoint)point
|
- (void)lineToPoint:(CGPoint)point
|
||||||
{
|
{
|
||||||
CGPathAddLineToPoint(_path, nil, point.x, point.y);
|
CGPathAddLineToPoint(_path, nil, point.x, point.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Add a cubic Bezier curve to the path.
|
||||||
|
*/
|
||||||
- (void)curveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2
|
- (void)curveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2
|
||||||
{
|
{
|
||||||
CGPathAddCurveToPoint(_path, nil, controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, endPoint.x, endPoint.y);
|
CGPathAddCurveToPoint(_path, nil, controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, endPoint.x, endPoint.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Create a line segment between the first and last points in the subpath, closing it.
|
||||||
|
*/
|
||||||
- (void)closePath
|
- (void)closePath
|
||||||
{
|
{
|
||||||
CGPathCloseSubpath(_path);
|
CGPathCloseSubpath(_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Draw a line along the path with the current stroke color and default drawing attributes.
|
||||||
|
*/
|
||||||
- (void)stroke
|
- (void)stroke
|
||||||
{
|
{
|
||||||
var ctx = [[CPGraphicsContext currentContext] graphicsPort];
|
var ctx = [[CPGraphicsContext currentContext] graphicsPort];
|
||||||
@@ -145,6 +187,9 @@ var DefaultLineWidth = 1.0;
|
|||||||
CGContextStrokePath(ctx);
|
CGContextStrokePath(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Fill the path with the current fill color.
|
||||||
|
*/
|
||||||
- (void)fill
|
- (void)fill
|
||||||
{
|
{
|
||||||
var ctx = [[CPGraphicsContext currentContext] graphicsPort];
|
var ctx = [[CPGraphicsContext currentContext] graphicsPort];
|
||||||
@@ -156,56 +201,88 @@ var DefaultLineWidth = 1.0;
|
|||||||
CGContextFillPath(ctx);
|
CGContextFillPath(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Get the line width.
|
||||||
|
*/
|
||||||
- (float)lineWidth
|
- (float)lineWidth
|
||||||
{
|
{
|
||||||
return _lineWidth;
|
return _lineWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Set the line width.
|
||||||
|
*/
|
||||||
- (void)setLineWidth:(float)lineWidth
|
- (void)setLineWidth:(float)lineWidth
|
||||||
{
|
{
|
||||||
_lineWidth = lineWidth;
|
_lineWidth = lineWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Get the total number of elements.
|
||||||
|
*/
|
||||||
- (unsigned)elementCount
|
- (unsigned)elementCount
|
||||||
{
|
{
|
||||||
return _path.count;
|
return _path.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Check if receiver is empty, returns appropriate Boolean value.
|
||||||
|
*/
|
||||||
- (BOOL)isEmpty
|
- (BOOL)isEmpty
|
||||||
{
|
{
|
||||||
return CGPathIsEmpty(_path);
|
return CGPathIsEmpty(_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Get the current point.
|
||||||
|
*/
|
||||||
- (CGPoint)currentPoint
|
- (CGPoint)currentPoint
|
||||||
{
|
{
|
||||||
return CGPathGetCurrentPoint(_path);
|
return CGPathGetCurrentPoint(_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Append a series of line segments.
|
||||||
|
*/
|
||||||
- (void)appendBezierPathWithPoints:(CPArray)points count:(unsigned)count
|
- (void)appendBezierPathWithPoints:(CPArray)points count:(unsigned)count
|
||||||
{
|
{
|
||||||
CGPathAddLines(_path, nil, points, count);
|
CGPathAddLines(_path, nil, points, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Append a rectangular path.
|
||||||
|
*/
|
||||||
- (void)appendBezierPathWithRect:(CGRect)rect
|
- (void)appendBezierPathWithRect:(CGRect)rect
|
||||||
{
|
{
|
||||||
CGPathAddRect(_path, nil, rect);
|
CGPathAddRect(_path, nil, rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Append an oval path; oval is drawn within the rectangular path.
|
||||||
|
*/
|
||||||
- (void)appendBezierPathWithOvalInRect:(CGRect)rect
|
- (void)appendBezierPathWithOvalInRect:(CGRect)rect
|
||||||
{
|
{
|
||||||
CGPathAddPath(_path, nil, CGPathWithEllipseInRect(rect));
|
CGPathAddPath(_path, nil, CGPathWithEllipseInRect(rect));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Append a rounded rectangular path.
|
||||||
|
*/
|
||||||
- (void)appendBezierPathWithRoundedRect:(CGRect)rect xRadius:(float)xRadius yRadius:(float)yRadius
|
- (void)appendBezierPathWithRoundedRect:(CGRect)rect xRadius:(float)xRadius yRadius:(float)yRadius
|
||||||
{
|
{
|
||||||
CGPathAddPath(_path, nil, CGPathWithRoundedRectangleInRect(rect, xRadius, yRadius, YES, YES, YES, YES));
|
CGPathAddPath(_path, nil, CGPathWithRoundedRectangleInRect(rect, xRadius, yRadius, YES, YES, YES, YES));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Append the contents of a CPBezierPath object.
|
||||||
|
*/
|
||||||
- (void)appendBezierPath:(NSBezierPath *)other
|
- (void)appendBezierPath:(NSBezierPath *)other
|
||||||
{
|
{
|
||||||
CGPathAddPath(_path, nil, other._path);
|
CGPathAddPath(_path, nil, other._path);
|
||||||
}
|
}
|
||||||
|
/*!
|
||||||
|
Remove all path elements; clears path.
|
||||||
|
*/
|
||||||
- (void)removeAllPoints
|
- (void)removeAllPoints
|
||||||
{
|
{
|
||||||
_path = CGPathCreateMutable();
|
_path = CGPathCreateMutable();
|
||||||
|
|||||||
+244
@@ -0,0 +1,244 @@
|
|||||||
|
/*
|
||||||
|
* CPBox.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Ross Boucher.
|
||||||
|
* Copyright 2009, 280 North, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import "CPView.j"
|
||||||
|
|
||||||
|
// CPBorderType
|
||||||
|
CPNoBorder = 0;
|
||||||
|
CPLineBorder = 1;
|
||||||
|
CPBezelBorder = 2;
|
||||||
|
CPGrooveBorder = 3;
|
||||||
|
|
||||||
|
@implementation CPBox : CPView
|
||||||
|
{
|
||||||
|
CPBorderType _borderType;
|
||||||
|
|
||||||
|
CPColor _borderColor;
|
||||||
|
CPColor _fillColor;
|
||||||
|
|
||||||
|
float _cornerRadius;
|
||||||
|
float _borderWidth;
|
||||||
|
|
||||||
|
CPSize _contentMargin;
|
||||||
|
CPView _contentView;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)boxEnclosingView:(CPView)aView
|
||||||
|
{
|
||||||
|
var box = [[self alloc] initWithFrame:CGRectMakeZero()],
|
||||||
|
enclosingView = [aView superview];
|
||||||
|
|
||||||
|
[box setFrameFromContentFrame:[aView frame]];
|
||||||
|
|
||||||
|
[enclosingView replaceSubview:aView with:box];
|
||||||
|
|
||||||
|
[box setContentView:aView];
|
||||||
|
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithFrame:(CPRect)frameRect
|
||||||
|
{
|
||||||
|
self = [super initWithFrame:frameRect];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_fillColor = [CPColor clearColor];
|
||||||
|
_borderColor = [CPColor blackColor];
|
||||||
|
|
||||||
|
_borderWidth = 1.0;
|
||||||
|
_contentMargin = CGSizeMake(0.0, 0.0);
|
||||||
|
|
||||||
|
_contentView = [[CPView alloc] initWithFrame:[self bounds]];
|
||||||
|
|
||||||
|
[self addSubview:_contentView];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configuring Boxes
|
||||||
|
|
||||||
|
- (CPRect)borderRect
|
||||||
|
{
|
||||||
|
return [self bounds];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPBorderType)borderType
|
||||||
|
{
|
||||||
|
return _borderType;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setBorderType:(CPBorderType)value
|
||||||
|
{
|
||||||
|
_borderType = value;
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPColor)borderColor
|
||||||
|
{
|
||||||
|
return _borderColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setBorderColor:(CPColor)color
|
||||||
|
{
|
||||||
|
if ([color isEqual:_borderColor])
|
||||||
|
return;
|
||||||
|
|
||||||
|
_borderColor = color;
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (float)borderWidth
|
||||||
|
{
|
||||||
|
return _borderWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setBorderWidth:(float)width
|
||||||
|
{
|
||||||
|
if (width === _borderWidth)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_borderWidth = width;
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (float)cornerRadius
|
||||||
|
{
|
||||||
|
return _cornerRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setCornerRadius:(float)radius
|
||||||
|
{
|
||||||
|
if (radius === _cornerRadius)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_cornerRadius = radius;
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPColor)fillColor
|
||||||
|
{
|
||||||
|
return _fillColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFillColor:(CPColor)color
|
||||||
|
{
|
||||||
|
if ([color isEqual:_fillColor])
|
||||||
|
return;
|
||||||
|
|
||||||
|
_fillColor = color;
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPView)contentView
|
||||||
|
{
|
||||||
|
return _contentView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setContentView:(CPView)aView
|
||||||
|
{
|
||||||
|
if (aView === _contentView)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[aView setFrame:CGRectInset([self bounds], _contentMargin.width + _borderWidth, _contentMargin.height + _borderWidth)];
|
||||||
|
[self replaceSubview:_contentView with:aView];
|
||||||
|
|
||||||
|
_contentView = aView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPSize)contentViewMargins
|
||||||
|
{
|
||||||
|
return _contentMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setContentViewMargins:(CPSize)size
|
||||||
|
{
|
||||||
|
if(size.width < 0 || size.height < 0)
|
||||||
|
[CPException raise:CPGenericException reason:@"Margins must be positive"];
|
||||||
|
|
||||||
|
_contentMargin = CGSizeMakeCopy(size);
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFrameFromContentFrame:(CPRect)aRect
|
||||||
|
{
|
||||||
|
[self setFrame:CGRectInset(aRect, -(_contentMargin.width + _borderWidth), -(_contentMargin.height + _borderWidth))];
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sizeToFit
|
||||||
|
{
|
||||||
|
var contentFrame = [_contentView frame];
|
||||||
|
|
||||||
|
[self setFrameSize:CGSizeMake(contentFrame.size.width + _contentMargin.width * 2,
|
||||||
|
contentFrame.size.height + _contentMargin.height * 2)];
|
||||||
|
|
||||||
|
[_contentView setFrameOrigin:CGPointMake(_contentMargin.width, _contentMargin.height)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drawRect:(CPRect)rect
|
||||||
|
{
|
||||||
|
var bounds = [self bounds],
|
||||||
|
aContext = [[CPGraphicsContext currentContext] graphicsPort],
|
||||||
|
border2 = _borderWidth/2,
|
||||||
|
|
||||||
|
strokeRect = CGRectMake(bounds.origin.x + border2,
|
||||||
|
bounds.origin.y + border2,
|
||||||
|
bounds.size.width - _borderWidth,
|
||||||
|
bounds.size.height - _borderWidth),
|
||||||
|
|
||||||
|
fillRect = CGRectMake(bounds.origin.x + border2,
|
||||||
|
bounds.origin.y + border2,
|
||||||
|
bounds.size.width - _borderWidth,
|
||||||
|
bounds.size.height - _borderWidth);
|
||||||
|
|
||||||
|
CGContextSetFillColor(aContext, [self fillColor]);
|
||||||
|
CGContextSetStrokeColor(aContext, [self borderColor]);
|
||||||
|
CGContextSetLineWidth(aContext, _borderWidth);
|
||||||
|
|
||||||
|
switch(_borderType)
|
||||||
|
{
|
||||||
|
case CPLineBorder: CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES);
|
||||||
|
CGContextStrokeRoundedRectangleInRect(aContext, strokeRect, _cornerRadius, YES, YES, YES, YES);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CPBezelBorder: CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES);
|
||||||
|
CGContextSetStrokeColor(aContext, [CPColor colorWithWhite:190.0/255.0 alpha:1.0]);
|
||||||
|
CGContextBeginPath(aContext);
|
||||||
|
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;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,896 @@
|
|||||||
|
/*
|
||||||
|
* 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 "CPControl.j"
|
||||||
|
@import "CPImage.j"
|
||||||
|
@import "CPTableView.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:[self class]]
|
||||||
|
pathForResource:"browser-leaf.png"]
|
||||||
|
size:CGSizeMake(9,9)];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPImage)highlightedBranchImage
|
||||||
|
{
|
||||||
|
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[self 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:CPThemeStateSelected];
|
||||||
|
[_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;
|
||||||
|
|
||||||
|
// unloads all later columns.
|
||||||
|
var indexPlusOne = columnIndex + 1;
|
||||||
|
|
||||||
|
[[_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 setNextResponder:table];
|
||||||
|
|
||||||
|
[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)];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)_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];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
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 setNextResponder:[self tableViewInColumn:[self lastColumn]]];
|
||||||
|
|
||||||
|
[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
|
||||||
|
|
||||||
|
@implementation _CPBrowserResizeControl : CPView
|
||||||
|
{
|
||||||
|
CGPoint _mouseDownX;
|
||||||
|
CPBrowser _browser;
|
||||||
|
unsigned _index;
|
||||||
|
unsigned _width;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var _CPBrowserResizeControlBackgroundImage = nil;
|
||||||
|
|
||||||
|
@implementation _CPBrowserScrollView : CPScrollView
|
||||||
|
{
|
||||||
|
_CPBrowserResizeControl _resizeControl;
|
||||||
|
CPBrowser _browser @accessors;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (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;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)initWithFrame:(CGRect)aFrame
|
||||||
|
{
|
||||||
|
if (self = [super initWithFrame:aFrame])
|
||||||
|
{
|
||||||
|
_resizeControl = [[_CPBrowserResizeControl alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
[_resizeControl setBackgroundColor:[CPColor colorWithPatternImage:[[self class] backgroundImage]]];
|
||||||
|
[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
|
||||||
|
|
||||||
|
@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:)])
|
||||||
|
[_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];
|
||||||
|
|
||||||
|
var isHighlighted = [self themeState] & CPThemeStateSelected;
|
||||||
|
[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
|
||||||
+12
-36
@@ -24,32 +24,11 @@
|
|||||||
@import "CGGeometry.j"
|
@import "CGGeometry.j"
|
||||||
|
|
||||||
@import "CPControl.j"
|
@import "CPControl.j"
|
||||||
|
@import "CPStringDrawing.j"
|
||||||
|
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
#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 */
|
||||||
|
|
||||||
CPRoundedBezelStyle = 1;
|
CPRoundedBezelStyle = 1;
|
||||||
@@ -145,7 +124,7 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
|
|
||||||
+ (id)themeAttributes
|
+ (id)themeAttributes
|
||||||
{
|
{
|
||||||
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMakeZero(), nil]
|
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]]
|
||||||
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
|
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +151,7 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
|
|
||||||
// Setting the state
|
// Setting the state
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the button has a 'mixed' state in addition to on and off.
|
Returns \c YES if the button has a 'mixed' state in addition to on and off.
|
||||||
*/
|
*/
|
||||||
- (BOOL)allowsMixedState
|
- (BOOL)allowsMixedState
|
||||||
{
|
{
|
||||||
@@ -192,8 +171,8 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
|
|
||||||
_allowsMixedState = aFlag;
|
_allowsMixedState = aFlag;
|
||||||
|
|
||||||
if (!_allowsMixedState)
|
if (!_allowsMixedState && [self state] === CPMixedState)
|
||||||
[self unsetThemeState:CPButtonStateMixed];
|
[self setState:CPOnState];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setObjectValue:(id)anObjectValue
|
- (void)setObjectValue:(id)anObjectValue
|
||||||
@@ -248,9 +227,9 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the button's state to <code>aState</code>.
|
Sets the button's state to \c aState.
|
||||||
@param aState Possible states are any of the CPButton globals:
|
@param aState Possible states are any of the CPButton globals:
|
||||||
<code>CPOffState, CPOnState, CPMixedState</code>
|
\c CPOffState, \c CPOnState, \c CPMixedState
|
||||||
*/
|
*/
|
||||||
- (void)setState:(CPInteger)aState
|
- (void)setState:(CPInteger)aState
|
||||||
{
|
{
|
||||||
@@ -368,7 +347,7 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
|
|
||||||
- (void)setButtonType:(CPButtonType)aButtonType
|
- (void)setButtonType:(CPButtonType)aButtonType
|
||||||
{
|
{
|
||||||
switch (buttonType)
|
switch (aButtonType)
|
||||||
{
|
{
|
||||||
case CPMomentaryLightButton: [self setHighlightsBy:CPChangeBackgroundCellMask];
|
case CPMomentaryLightButton: [self setHighlightsBy:CPChangeBackgroundCellMask];
|
||||||
[self setShowsStateBy:CPNoCellMask];
|
[self setShowsStateBy:CPNoCellMask];
|
||||||
@@ -390,7 +369,7 @@ CPButtonStateMixed = CPThemeState("mixed");
|
|||||||
[self setShowsStateBy:CPChangeBackgroundCellMask];
|
[self setShowsStateBy:CPChangeBackgroundCellMask];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPToggleButton: [self setHighlightsBy:CPPushInCellMask | NSContentsCellMask];
|
case CPToggleButton: [self setHighlightsBy:CPPushInCellMask | CPContentsCellMask];
|
||||||
[self setShowsStateBy:CPContentsCellMask];
|
[self setShowsStateBy:CPContentsCellMask];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -460,7 +439,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();
|
||||||
@@ -523,8 +502,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,8 +510,7 @@ 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"
|
||||||
positioned:CPWindowAbove
|
positioned:CPWindowAbove
|
||||||
@@ -602,7 +578,7 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
|||||||
@implementation CPButton (CPCoding)
|
@implementation CPButton (CPCoding)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Initializes the button by unarchiving data from <code>aCoder</code>.
|
Initializes the button by unarchiving data from \c aCoder.
|
||||||
@param aCoder the coder containing the archived CPButton.
|
@param aCoder the coder containing the archived CPButton.
|
||||||
*/
|
*/
|
||||||
- (id)initWithCoder:(CPCoder)aCoder
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
|||||||
+211
-23
@@ -4,8 +4,33 @@
|
|||||||
#include "CoreGraphics/CGGeometry.h"
|
#include "CoreGraphics/CGGeometry.h"
|
||||||
|
|
||||||
|
|
||||||
@implementation CPButtonBar : CPControl
|
@implementation CPButtonBar : CPView
|
||||||
{
|
{
|
||||||
|
BOOL _hasResizeControl;
|
||||||
|
BOOL _resizeControlIsLeftAligned;
|
||||||
|
CPArray _buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)plusButton
|
||||||
|
{
|
||||||
|
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
|
||||||
|
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:self] pathForResource:@"plus_button.png"] size:CGSizeMake(11, 12)];
|
||||||
|
|
||||||
|
[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:self] pathForResource:@"minus_button.png"] size:CGSizeMake(11, 4)];
|
||||||
|
|
||||||
|
[button setImage:image];
|
||||||
|
[button setImagePosition:CPImageOnly];
|
||||||
|
|
||||||
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPString)themeClass
|
+ (CPString)themeClass
|
||||||
@@ -15,47 +40,210 @@
|
|||||||
|
|
||||||
+ (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]]
|
||||||
forKeys:[@"bezel-color"]];
|
forKeys:[@"resize-control-inset", @"resize-control-size", @"resize-control-color", @"bezel-color", @"button-bezel-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++)
|
||||||
|
{
|
||||||
|
var button = _buttons[i];
|
||||||
|
|
||||||
|
var normalColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateNormal],
|
||||||
|
highlightedColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateHighlighted],
|
||||||
|
disabledColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateDisabled];
|
||||||
|
|
||||||
|
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal|CPThemeStateBordered];
|
||||||
|
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted|CPThemeStateBordered];
|
||||||
|
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled|CPThemeStateBordered];
|
||||||
|
|
||||||
|
// 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];
|
||||||
|
|
||||||
|
[button 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 buttonsNotHidden = [CPArray arrayWithArray:_buttons],
|
||||||
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
|
count = [buttonsNotHidden count];
|
||||||
}
|
|
||||||
|
|
||||||
- (void)addSubview:(CPView)aSubview
|
while (count--)
|
||||||
{
|
if ([buttonsNotHidden[count] isHidden])
|
||||||
[super addSubview:aSubview];
|
[buttonsNotHidden removeObject:buttonsNotHidden[count]];
|
||||||
|
|
||||||
[aSubview setAutoresizingMask:CPViewMinXMargin];
|
var currentButtonOffset = _resizeControlIsLeftAligned ? CGRectGetMaxX([self bounds]) + 1 : -1,
|
||||||
|
height = CGRectGetHeight([self bounds]) - 1;
|
||||||
|
|
||||||
|
for (var i = 0, count = [buttonsNotHidden count]; i < count; i++)
|
||||||
|
{
|
||||||
|
var button = buttonsNotHidden[i],
|
||||||
|
width = CGRectGetWidth([button frame]);
|
||||||
|
|
||||||
|
if (_resizeControlIsLeftAligned)
|
||||||
|
{
|
||||||
|
[button setFrame:CGRectMake(currentButtonOffset - width, 1, width, height)];
|
||||||
|
currentButtonOffset -= width - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[button setFrame:CGRectMake(currentButtonOffset, 1, width, height)];
|
||||||
|
currentButtonOffset += width - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
[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"]];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@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
|
||||||
|
|
||||||
|
|||||||
+16
-8
@@ -38,8 +38,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the document view to be <code>aView</code>.
|
Sets the document view to be \c aView.
|
||||||
@param aView the new document view. It's frame origin will be changed to <code>(0,0)</code> after calling this method.
|
@param aView the new document view. It's frame origin will be changed to \c (0,0) after calling this method.
|
||||||
*/
|
*/
|
||||||
- (void)setDocumentView:(CPView)aView
|
- (void)setDocumentView:(CPView)aView
|
||||||
{
|
{
|
||||||
@@ -95,7 +95,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns a new point that may be adjusted from <code>aPoint</code>
|
Returns a new point that may be adjusted from \c aPoint
|
||||||
to make sure it lies within the document view.
|
to make sure it lies within the document view.
|
||||||
@param aPoint
|
@param aPoint
|
||||||
@return the adjusted point
|
@return the adjusted point
|
||||||
@@ -120,15 +120,19 @@
|
|||||||
|
|
||||||
[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];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Scrolls the clip view to the specified point. The method
|
Scrolls the clip view to the specified point. The method
|
||||||
sets its bounds origin to <code>aPoint</code>.
|
sets its bounds origin to \c aPoint.
|
||||||
*/
|
*/
|
||||||
- (void)scrollToPoint:(CGPoint)aPoint
|
- (void)scrollToPoint:(CGPoint)aPoint
|
||||||
{
|
{
|
||||||
@@ -173,9 +177,13 @@
|
|||||||
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];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+191
-134
@@ -26,7 +26,8 @@
|
|||||||
@import <Foundation/CPKeyedArchiver.j>
|
@import <Foundation/CPKeyedArchiver.j>
|
||||||
@import <Foundation/CPKeyedUnarchiver.j>
|
@import <Foundation/CPKeyedUnarchiver.j>
|
||||||
|
|
||||||
@import <AppKit/CPView.j>
|
@import "CPView.j"
|
||||||
|
@import "CPCollectionViewItem.j"
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -61,6 +62,7 @@
|
|||||||
@param indices the indices to obtain drag types
|
@param indices the indices to obtain drag types
|
||||||
@return an array of drag types (CPString)
|
@return an array of drag types (CPString)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@implementation CPCollectionView : CPView
|
@implementation CPCollectionView : CPView
|
||||||
{
|
{
|
||||||
CPArray _content;
|
CPArray _content;
|
||||||
@@ -77,6 +79,8 @@
|
|||||||
CGSize _minItemSize;
|
CGSize _minItemSize;
|
||||||
CGSize _maxItemSize;
|
CGSize _maxItemSize;
|
||||||
|
|
||||||
|
CPArray _backgroundColors;
|
||||||
|
|
||||||
float _tileWidth;
|
float _tileWidth;
|
||||||
|
|
||||||
BOOL _isSelectable;
|
BOOL _isSelectable;
|
||||||
@@ -93,6 +97,8 @@
|
|||||||
unsigned _numberOfColumns;
|
unsigned _numberOfColumns;
|
||||||
|
|
||||||
id _delegate;
|
id _delegate;
|
||||||
|
|
||||||
|
CPEvent _mouseDownEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
@@ -110,6 +116,8 @@
|
|||||||
_minItemSize = CGSizeMakeZero();
|
_minItemSize = CGSizeMakeZero();
|
||||||
_maxItemSize = CGSizeMakeZero();
|
_maxItemSize = CGSizeMakeZero();
|
||||||
|
|
||||||
|
[self setBackgroundColors:nil];
|
||||||
|
|
||||||
_verticalMargin = 5.0;
|
_verticalMargin = 5.0;
|
||||||
_tileWidth = -1.0;
|
_tileWidth = -1.0;
|
||||||
|
|
||||||
@@ -122,13 +130,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the item prototype to <code>anItem</code>
|
Sets the item prototype to \c anItem
|
||||||
@param anItem the new item prototype
|
@param anItem the new item prototype
|
||||||
*/
|
*/
|
||||||
- (void)setItemPrototype:(CPCollectionViewItem)anItem
|
- (void)setItemPrototype:(CPCollectionViewItem)anItem
|
||||||
{
|
{
|
||||||
_itemData = [CPKeyedArchiver archivedDataWithRootObject:anItem];
|
_cachedItems = [];
|
||||||
_itemForDragging = anItem//[CPKeyedUnarchiver unarchiveObjectWithData:_itemData];
|
_itemData = nil;
|
||||||
|
_itemForDragging = nil;
|
||||||
_itemPrototype = anItem;
|
_itemPrototype = anItem;
|
||||||
|
|
||||||
[self reloadContent];
|
[self reloadContent];
|
||||||
@@ -143,7 +152,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns a collection view item for <code>anObject</code>.
|
Returns a collection view item for \c anObject.
|
||||||
@param anObject the object to be represented.
|
@param anObject the object to be represented.
|
||||||
*/
|
*/
|
||||||
- (CPCollectionViewItem)newItemForRepresentedObject:(id)anObject
|
- (CPCollectionViewItem)newItemForRepresentedObject:(id)anObject
|
||||||
@@ -152,8 +161,15 @@
|
|||||||
|
|
||||||
if (_cachedItems.length)
|
if (_cachedItems.length)
|
||||||
item = _cachedItems.pop();
|
item = _cachedItems.pop();
|
||||||
|
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if (!_itemData)
|
||||||
|
if (_itemPrototype)
|
||||||
|
_itemData = [CPKeyedArchiver archivedDataWithRootObject:_itemPrototype];
|
||||||
|
|
||||||
item = [CPKeyedUnarchiver unarchiveObjectWithData:_itemData];
|
item = [CPKeyedUnarchiver unarchiveObjectWithData:_itemData];
|
||||||
|
}
|
||||||
|
|
||||||
[item setRepresentedObject:anObject];
|
[item setRepresentedObject:anObject];
|
||||||
[[item view] setFrameSize:_itemSize];
|
[[item view] setFrameSize:_itemSize];
|
||||||
@@ -163,7 +179,7 @@
|
|||||||
|
|
||||||
// Working with the Responder Chain
|
// Working with the Responder Chain
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> by default.
|
Returns \c YES by default.
|
||||||
*/
|
*/
|
||||||
- (BOOL)acceptsFirstResponder
|
- (BOOL)acceptsFirstResponder
|
||||||
{
|
{
|
||||||
@@ -175,13 +191,13 @@
|
|||||||
*/
|
*/
|
||||||
- (BOOL)isFirstResponder
|
- (BOOL)isFirstResponder
|
||||||
{
|
{
|
||||||
return [[self window] firstResponder] == self;
|
return [[self window] firstResponder] === self;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setting the Content
|
// Setting the Content
|
||||||
/*!
|
/*!
|
||||||
Sets the content of the collection view to the content in <code>anArray</code>.
|
Sets the content of the collection view to the content in \c anArray.
|
||||||
This array can be of any type, and each element will be passed to the <code>setRepresentedObject:</code> method.
|
This array can be of any type, and each element will be passed to the \c -setRepresentedObject: method.
|
||||||
It's the responsibility of your custom collection view item to interpret the object.
|
It's the responsibility of your custom collection view item to interpret the object.
|
||||||
@param anArray the content array
|
@param anArray the content array
|
||||||
*/
|
*/
|
||||||
@@ -214,7 +230,7 @@
|
|||||||
// Setting the Selection Mode
|
// Setting the Selection Mode
|
||||||
/*!
|
/*!
|
||||||
Sets whether the user is allowed to select items
|
Sets whether the user is allowed to select items
|
||||||
@param isSelectable <code>YES</code> allows the user to select items.
|
@param isSelectable \c YES allows the user to select items.
|
||||||
*/
|
*/
|
||||||
- (void)setSelectable:(BOOL)isSelectable
|
- (void)setSelectable:(BOOL)isSelectable
|
||||||
{
|
{
|
||||||
@@ -233,17 +249,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the collection view is
|
Returns \c YES if the collection view is
|
||||||
selected, and <code>NO</code> otherwise.
|
selectable, and \c NO otherwise.
|
||||||
*/
|
*/
|
||||||
- (BOOL)isSelected
|
- (BOOL)isSelectable
|
||||||
{
|
{
|
||||||
return _isSelected;
|
return _isSelectable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether the user may have no items selected. If YES, mouse clicks not on any item will empty the current selection. The first item will also start off as selected.
|
Sets whether the user may have no items selected. If YES, mouse clicks not on any item will empty the current selection. The first item will also start off as selected.
|
||||||
@param shouldAllowMultipleSelection <code>YES</code> allows the user to select multiple items
|
@param shouldAllowMultipleSelection \c YES allows the user to select multiple items
|
||||||
*/
|
*/
|
||||||
- (void)setAllowsEmptySelection:(BOOL)shouldAllowEmptySelection
|
- (void)setAllowsEmptySelection:(BOOL)shouldAllowEmptySelection
|
||||||
{
|
{
|
||||||
@@ -251,7 +267,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the user can select no items, <code>NO</code> otherwise.
|
Returns \c YES if the user can select no items, \c NO otherwise.
|
||||||
*/
|
*/
|
||||||
- (BOOL)allowsEmptySelection
|
- (BOOL)allowsEmptySelection
|
||||||
{
|
{
|
||||||
@@ -260,7 +276,7 @@
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether the user can select multiple items.
|
Sets whether the user can select multiple items.
|
||||||
@param shouldAllowMultipleSelection <code>YES</code> allows the user to select multiple items
|
@param shouldAllowMultipleSelection \c YES allows the user to select multiple items
|
||||||
*/
|
*/
|
||||||
- (void)setAllowsMultipleSelection:(BOOL)shouldAllowMultipleSelection
|
- (void)setAllowsMultipleSelection:(BOOL)shouldAllowMultipleSelection
|
||||||
{
|
{
|
||||||
@@ -268,7 +284,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the user can select multiple items, <code>NO</code> otherwise.
|
Returns \c YES if the user can select multiple items, \c NO otherwise.
|
||||||
*/
|
*/
|
||||||
- (BOOL)allowsMultipleSelection
|
- (BOOL)allowsMultipleSelection
|
||||||
{
|
{
|
||||||
@@ -305,7 +321,7 @@
|
|||||||
*/
|
*/
|
||||||
- (CPIndexSet)selectionIndexes
|
- (CPIndexSet)selectionIndexes
|
||||||
{
|
{
|
||||||
return _selectionIndexes;
|
return [_selectionIndexes copy];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
@@ -317,12 +333,14 @@
|
|||||||
while (count--)
|
while (count--)
|
||||||
{
|
{
|
||||||
[[_items[count] view] removeFromSuperview];
|
[[_items[count] view] removeFromSuperview];
|
||||||
|
[_items[count] setSelected:NO];
|
||||||
|
|
||||||
_cachedItems.push(_items[count]);
|
_cachedItems.push(_items[count]);
|
||||||
}
|
}
|
||||||
|
|
||||||
_items = [];
|
_items = [];
|
||||||
|
|
||||||
if (!_itemData || !_content)
|
if (!_itemPrototype || !_content)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var index = 0;
|
var index = 0;
|
||||||
@@ -336,6 +354,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];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -520,6 +542,30 @@
|
|||||||
return _maxItemSize;
|
return _maxItemSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setBackgroundColors:(CPArray)backgroundColors
|
||||||
|
{
|
||||||
|
if (_backgroundColors === backgroundColors)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_backgroundColors = backgroundColors;
|
||||||
|
|
||||||
|
if (!_backgroundColors)
|
||||||
|
_backgroundColors = [CPColor whiteColor];
|
||||||
|
|
||||||
|
if ([_backgroundColors count] === 1)
|
||||||
|
[self setBackgroundColor:_backgroundColors[0]];
|
||||||
|
|
||||||
|
else
|
||||||
|
[self setBackgroundColor:nil];
|
||||||
|
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPArray)backgroundColors
|
||||||
|
{
|
||||||
|
return _backgroundColors;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)mouseUp:(CPEvent)anEvent
|
- (void)mouseUp:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
if ([_selectionIndexes count] && [anEvent clickCount] == 2 && [_delegate respondsToSelector:@selector(collectionView:didDoubleClickOnItemAtIndex:)])
|
if ([_selectionIndexes count] && [anEvent clickCount] == 2 && [_delegate respondsToSelector:@selector(collectionView:didDoubleClickOnItemAtIndex:)])
|
||||||
@@ -528,6 +574,8 @@
|
|||||||
|
|
||||||
- (void)mouseDown:(CPEvent)anEvent
|
- (void)mouseDown:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
|
_mouseDownEvent = anEvent;
|
||||||
|
|
||||||
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||||
row = FLOOR(location.y / (_itemSize.height + _verticalMargin)),
|
row = FLOOR(location.y / (_itemSize.height + _verticalMargin)),
|
||||||
column = FLOOR(location.x / (_itemSize.width + _horizontalMargin)),
|
column = FLOOR(location.x / (_itemSize.width + _horizontalMargin)),
|
||||||
@@ -535,6 +583,7 @@
|
|||||||
|
|
||||||
if (index >= 0 && index < _items.length)
|
if (index >= 0 && index < _items.length)
|
||||||
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
||||||
|
|
||||||
else if (_allowsEmptySelection)
|
else if (_allowsEmptySelection)
|
||||||
[self setSelectionIndexes:[CPIndexSet indexSet]];
|
[self setSelectionIndexes:[CPIndexSet indexSet]];
|
||||||
}
|
}
|
||||||
@@ -548,6 +597,10 @@
|
|||||||
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];
|
||||||
|
|
||||||
@@ -555,18 +608,20 @@
|
|||||||
|
|
||||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||||
|
|
||||||
[_itemForDragging setRepresentedObject:_content[[_selectionIndexes firstIndex]]];
|
if (!_itemForDragging)
|
||||||
|
_itemForDragging = [self newItemForRepresentedObject:_content[[_selectionIndexes firstIndex]]];
|
||||||
|
else
|
||||||
|
[_itemForDragging setRepresentedObject:_content[[_selectionIndexes firstIndex]]];
|
||||||
|
|
||||||
var view = [_itemForDragging view],
|
var view = [_itemForDragging view];
|
||||||
frame = [view frame];
|
|
||||||
|
|
||||||
[view setFrameSize:_itemSize];
|
[view setFrameSize:_itemSize];
|
||||||
[view setAlphaValue:0.7];
|
[view setAlphaValue:0.7];
|
||||||
|
|
||||||
[self dragView:view
|
[self dragView:view
|
||||||
at:[[_items[[_selectionIndexes firstIndex]] view] frame].origin
|
at:[[_items[[_selectionIndexes firstIndex]] view] frame].origin
|
||||||
offset:CGPointMakeZero()
|
offset:CGSizeMakeZero()
|
||||||
event:anEvent
|
event:_mouseDownEvent
|
||||||
pasteboard:nil
|
pasteboard:nil
|
||||||
source:self
|
source:self
|
||||||
slideBack:YES];
|
slideBack:YES];
|
||||||
@@ -625,100 +680,131 @@
|
|||||||
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 rectForItemAtIndex:indexArray[index]]);
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/*!
|
@implementation CPCollectionView (KeyboardInteraction)
|
||||||
Represents an object inside a CPCollectionView.
|
|
||||||
*/
|
- (void)_scrollToSelection
|
||||||
@implementation CPCollectionViewItem : CPObject
|
|
||||||
{
|
{
|
||||||
id _representedObject;
|
var frame = [self frameForItemsAtIndexes:[self selectionIndexes]];
|
||||||
|
|
||||||
CPView _view;
|
if (!CGRectIsNull(frame))
|
||||||
|
[self scrollRectToVisible:frame];
|
||||||
BOOL _isSelected;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setting the Represented Object
|
- (void)moveLeft:(id)sender
|
||||||
/*!
|
|
||||||
Sets the object to be represented by this item.
|
|
||||||
@param anObject the object to be represented
|
|
||||||
*/
|
|
||||||
- (void)setRepresentedObject:(id)anObject
|
|
||||||
{
|
{
|
||||||
if (_representedObject == anObject)
|
var index = [[self selectionIndexes] firstIndex];
|
||||||
return;
|
if (index === CPNotFound)
|
||||||
|
index = [[self items] count];
|
||||||
|
|
||||||
_representedObject = anObject;
|
index = MAX(index - 1, 0);
|
||||||
|
|
||||||
// FIXME: This should be set up by bindings
|
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
||||||
[_view setRepresentedObject:anObject];
|
[self _scrollToSelection];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
- (void)moveRight:(id)sender
|
||||||
Returns the object represented by this view item
|
|
||||||
*/
|
|
||||||
- (id)representedObject
|
|
||||||
{
|
{
|
||||||
return _representedObject;
|
var index = MIN([[self selectionIndexes] firstIndex] + 1, [[self items] count]-1);
|
||||||
|
|
||||||
|
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
||||||
|
[self _scrollToSelection];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modifying the View
|
- (void)moveDown:(id)sender
|
||||||
/*!
|
|
||||||
Sets the view that is used represent this object.
|
|
||||||
@param aView the view used to represent this object
|
|
||||||
*/
|
|
||||||
- (void)setView:(CPView)aView
|
|
||||||
{
|
{
|
||||||
_view = aView;
|
var index = MIN([[self selectionIndexes] firstIndex] + [self numberOfColumns], [[self items] count]-1);
|
||||||
|
|
||||||
|
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
||||||
|
[self _scrollToSelection];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
- (void)moveUp:(id)sender
|
||||||
Returns the view that represents this object.
|
|
||||||
*/
|
|
||||||
- (CPView)view
|
|
||||||
{
|
{
|
||||||
return _view;
|
var index = [[self selectionIndexes] firstIndex];
|
||||||
|
if (index == CPNotFound)
|
||||||
|
index = [[self items] count];
|
||||||
|
|
||||||
|
index = MAX(0, index - [self numberOfColumns]);
|
||||||
|
|
||||||
|
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
||||||
|
[self _scrollToSelection];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modifying the Selection
|
- (void)deleteBackward:(id)sender
|
||||||
/*!
|
|
||||||
Sets whether this view item should be selected.
|
|
||||||
@param shouldBeSelected <code>YES</code> makes the item selected. <code>NO</code> deselects it.
|
|
||||||
*/
|
|
||||||
- (void)setSelected:(BOOL)shouldBeSelected
|
|
||||||
{
|
{
|
||||||
if (_isSelected == shouldBeSelected)
|
if ([[self delegate] respondsToSelector:@selector(collectionView:shouldDeleteItemsAtIndexes:)])
|
||||||
return;
|
{
|
||||||
|
[[self delegate] collectionView:self shouldDeleteItemsAtIndexes:[self selectionIndexes]];
|
||||||
|
|
||||||
_isSelected = shouldBeSelected;
|
var index = [[self selectionIndexes] firstIndex];
|
||||||
|
if (index > [[self content] count]-1)
|
||||||
|
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:[[self content] count]-1]];
|
||||||
|
|
||||||
// FIXME: This should be set up by bindings
|
[self _scrollToSelection];
|
||||||
[_view setSelected:_isSelected];
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
- (void)keyDown:(CPEvent)anEvent
|
||||||
Returns <code>YES</code> if the item is currently selected. <code>NO</code> if the item is not selected.
|
|
||||||
*/
|
|
||||||
- (BOOL)isSelected
|
|
||||||
{
|
{
|
||||||
return _isSelected;
|
[self interpretKeyEvents:[anEvent]];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parent Collection View
|
@end
|
||||||
/*!
|
|
||||||
Returns the collection view of which this item is a part.
|
@implementation CPCollectionView (Deprecated)
|
||||||
*/
|
|
||||||
- (CPCollectionView)collectionView
|
- (CGRect)rectForItemAtIndex:(int)anIndex
|
||||||
{
|
{
|
||||||
return [_view superview];
|
_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",
|
||||||
|
CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey",
|
||||||
|
CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey";
|
||||||
|
|
||||||
|
|
||||||
@implementation CPCollectionView (CPCoding)
|
@implementation CPCollectionView (CPCoding)
|
||||||
@@ -735,13 +821,21 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
|||||||
_cachedItems = [];
|
_cachedItems = [];
|
||||||
|
|
||||||
_itemSize = CGSizeMakeZero();
|
_itemSize = CGSizeMakeZero();
|
||||||
_minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey];
|
|
||||||
_maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey];
|
|
||||||
|
|
||||||
_verticalMargin = [aCoder decodeSizeForKey:CPCollectionViewVerticalMarginKey];
|
_minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey] || CGSizeMakeZero();
|
||||||
|
_maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey] || CGSizeMakeZero();
|
||||||
|
|
||||||
|
_verticalMargin = [aCoder decodeFloatForKey:CPCollectionViewVerticalMarginKey];
|
||||||
|
|
||||||
|
_isSelectable = [aCoder decodeBoolForKey:CPCollectionViewSelectableKey];
|
||||||
|
|
||||||
|
[self setBackgroundColors:[aCoder decodeObjectForKey:CPCollectionViewBackgroundColorsKey]];
|
||||||
|
|
||||||
_tileWidth = -1.0;
|
_tileWidth = -1.0;
|
||||||
|
|
||||||
_selectionIndexes = [CPIndexSet indexSet];
|
_selectionIndexes = [CPIndexSet indexSet];
|
||||||
|
|
||||||
|
_allowsEmptySelection = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -751,54 +845,17 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
|||||||
{
|
{
|
||||||
[super encodeWithCoder:aCoder];
|
[super encodeWithCoder:aCoder];
|
||||||
|
|
||||||
[aCoder encodeSize:_minItemSize forKey:CPCollectionViewMinItemSizeKey];
|
if (!CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()))
|
||||||
[aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey];
|
[aCoder encodeSize:_minItemSize forKey:CPCollectionViewMinItemSizeKey];
|
||||||
|
|
||||||
[aCoder encodeSize:_verticalMargin forKey:CPCollectionViewVerticalMarginKey];
|
if (!CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
|
||||||
}
|
[aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey];
|
||||||
|
|
||||||
@end
|
[aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey];
|
||||||
|
|
||||||
var CPCollectionViewItemViewKey = @"CPCollectionViewItemViewKey";
|
[aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey];
|
||||||
|
|
||||||
@implementation CPCollectionViewItem (CPCoding)
|
[aCoder encodeObject:_backgroundColors forKey:CPCollectionViewBackgroundColorsKey];
|
||||||
|
|
||||||
/*
|
|
||||||
FIXME Not yet implemented
|
|
||||||
*/
|
|
||||||
- (id)copy
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
var CPCollectionViewItemViewKey = @"CPCollectionViewItemViewKey";
|
|
||||||
|
|
||||||
@implementation CPCollectionViewItem (CPCoding)
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Initializes the view item by unarchiving data from a coder.
|
|
||||||
@param aCoder the coder from which the data will be unarchived
|
|
||||||
@return the initialized collection view item
|
|
||||||
*/
|
|
||||||
- (id)initWithCoder:(CPCoder)aCoder
|
|
||||||
{
|
|
||||||
self = [super init];
|
|
||||||
|
|
||||||
if (self)
|
|
||||||
_view = [aCoder decodeObjectForKey:CPCollectionViewItemViewKey];
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Archives the colletion view item to the provided coder.
|
|
||||||
@param aCoder the coder to which the view item should be archived
|
|
||||||
*/
|
|
||||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
|
||||||
{
|
|
||||||
[aCoder encodeObject:_view forKey:CPCollectionViewItemViewKey];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* CPCollectionViewItem.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Francisco Tolmasky.
|
||||||
|
* Copyright 2009, 280 North, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import "CPViewController.j"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Represents an object inside a CPCollectionView.
|
||||||
|
*/
|
||||||
|
@implementation CPCollectionViewItem : CPViewController
|
||||||
|
{
|
||||||
|
BOOL _isSelected;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setting the Represented Object
|
||||||
|
/*!
|
||||||
|
Sets the object to be represented by this item.
|
||||||
|
@param anObject the object to be represented
|
||||||
|
*/
|
||||||
|
- (void)setRepresentedObject:(id)anObject
|
||||||
|
{
|
||||||
|
[super setRepresentedObject:anObject];
|
||||||
|
|
||||||
|
var view = [self view];
|
||||||
|
|
||||||
|
if ([view respondsToSelector:@selector(setRepresentedObject:)])
|
||||||
|
[view setRepresentedObject:[self representedObject]];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modifying the Selection
|
||||||
|
/*!
|
||||||
|
Sets whether this view item should be selected.
|
||||||
|
@param shouldBeSelected \c YES makes the item selected. \c NO deselects it.
|
||||||
|
*/
|
||||||
|
- (void)setSelected:(BOOL)shouldBeSelected
|
||||||
|
{
|
||||||
|
shouldBeSelected = !!shouldBeSelected;
|
||||||
|
|
||||||
|
if (_isSelected === shouldBeSelected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_isSelected = shouldBeSelected;
|
||||||
|
|
||||||
|
var view = [self view];
|
||||||
|
|
||||||
|
if ([view respondsToSelector:@selector(setSelected:)])
|
||||||
|
[view setSelected:[self isSelected]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns \c YES if the item is currently selected. \c NO if the item is not selected.
|
||||||
|
*/
|
||||||
|
- (BOOL)isSelected
|
||||||
|
{
|
||||||
|
return _isSelected;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parent Collection View
|
||||||
|
/*!
|
||||||
|
Returns the collection view of which this item is a part.
|
||||||
|
*/
|
||||||
|
- (CPCollectionView)collectionView
|
||||||
|
{
|
||||||
|
return [_view superview];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
+96
-60
@@ -46,6 +46,11 @@ var cachedBlackColor,
|
|||||||
cachedLightGrayColor,
|
cachedLightGrayColor,
|
||||||
cachedDarkGrayColor,
|
cachedDarkGrayColor,
|
||||||
cachedWhiteColor,
|
cachedWhiteColor,
|
||||||
|
cachedBrownColor,
|
||||||
|
cachedCyanColor,
|
||||||
|
cachedMagentaColor,
|
||||||
|
cachedOrangeColor,
|
||||||
|
cachedPurpleColor,
|
||||||
cachedShadowColor,
|
cachedShadowColor,
|
||||||
cachedClearColor;
|
cachedClearColor;
|
||||||
|
|
||||||
@@ -53,13 +58,13 @@ var cachedBlackColor,
|
|||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@code CPColor
|
@code CPColor
|
||||||
|
|
||||||
<code>CPColor</code> 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 <code>set:</code> method
|
<p>The class does not have a \c -set: method
|
||||||
like NextStep based frameworks to change the color of
|
like NextStep based frameworks to change the color of
|
||||||
the current context. To change the color of the current
|
the current context. To change the color of the current
|
||||||
context, use CGContextSetFillColor().
|
context, use CGContextSetFillColor().
|
||||||
@@ -112,7 +117,7 @@ var cachedBlackColor,
|
|||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Creates a new color object with <code>white</code> for the RGB components.
|
Creates a new color object with \c white for the RGB components.
|
||||||
For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent.
|
For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent.
|
||||||
|
|
||||||
@param white a float between 0.0 and 1.0
|
@param white a float between 0.0 and 1.0
|
||||||
@@ -128,7 +133,7 @@ var cachedBlackColor,
|
|||||||
/*!
|
/*!
|
||||||
@deprecated in favor of colorWithWhite:apha:
|
@deprecated in favor of colorWithWhite:apha:
|
||||||
|
|
||||||
Creates a new color object with <code>white</code> for the RGB components.
|
Creates a new color object with \c white for the RGB components.
|
||||||
For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent.
|
For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent.
|
||||||
|
|
||||||
@param white a float between 0.0 and 1.0
|
@param white a float between 0.0 and 1.0
|
||||||
@@ -291,6 +296,61 @@ var cachedBlackColor,
|
|||||||
return cachedYellowColor;
|
return cachedYellowColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns a brown color object (RGBA=[0.6, 0.4, 0.2, 1.0])
|
||||||
|
*/
|
||||||
|
+ (CPColor)brownColor
|
||||||
|
{
|
||||||
|
if (!cachedBrownColor)
|
||||||
|
cachedBrownColor = [[CPColor alloc] _initWithRGBA:[0.6, 0.4, 0.2, 1.0]];
|
||||||
|
|
||||||
|
return cachedBrownColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns a cyan color object (RGBA=[0.0, 1.0, 1.0, 1.0])
|
||||||
|
*/
|
||||||
|
+ (CPColor)cyanColor
|
||||||
|
{
|
||||||
|
if (!cachedCyanColor)
|
||||||
|
cachedCyanColor = [[CPColor alloc] _initWithRGBA:[0.0, 1.0, 1.0, 1.0]];
|
||||||
|
|
||||||
|
return cachedCyanColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns a magenta color object (RGBA=[1.0, 0.0, 1.0, 1.0])
|
||||||
|
*/
|
||||||
|
+ (CPColor)magentaColor
|
||||||
|
{
|
||||||
|
if (!cachedMagentaColor)
|
||||||
|
cachedMagentaColor = [[CPColor alloc] _initWithRGBA:[1.0, 0.0, 1.0, 1.0]];
|
||||||
|
|
||||||
|
return cachedMagentaColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns a orange color object (RGBA=[1.0, 0.5, 0.0, 1.0])
|
||||||
|
*/
|
||||||
|
+ (CPColor)orangeColor
|
||||||
|
{
|
||||||
|
if (!cachedOrangeColor)
|
||||||
|
cachedOrangeColor = [[CPColor alloc] _initWithRGBA:[1.0, 0.5, 0.0, 1.0]];
|
||||||
|
|
||||||
|
return cachedOrangeColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns a purple color object (RGBA=[0.5, 0.0, 0.5, 1.0])
|
||||||
|
*/
|
||||||
|
+ (CPColor)purpleColor
|
||||||
|
{
|
||||||
|
if (!cachedPurpleColor)
|
||||||
|
cachedPurpleColor = [[CPColor alloc] _initWithRGBA:[0.5, 0.0, 0.5, 1.0]];
|
||||||
|
|
||||||
|
return cachedPurpleColor;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns a shadow looking color (RGBA=[0.0, 0.0, 0.0, 0.33])
|
Returns a shadow looking color (RGBA=[0.0, 0.0, 0.0, 0.33])
|
||||||
*/
|
*/
|
||||||
@@ -315,8 +375,18 @@ var cachedBlackColor,
|
|||||||
return cachedClearColor;
|
return cachedClearColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (CPColor)alternateSelectedControlColor
|
||||||
|
{
|
||||||
|
return [[CPColor alloc] _initWithRGBA:[0.22, 0.46, 0.84, 1.0]];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPColor)secondarySelectedControlColor
|
||||||
|
{
|
||||||
|
return [[CPColor alloc] _initWithRGBA:[0.83, 0.83, 0.83, 1.0]];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Creates a color using a tile pattern with <code>anImage</code>
|
Creates a color using a tile pattern with \c anImage
|
||||||
@param the image to tile
|
@param the image to tile
|
||||||
@return a tiled image color object
|
@return a tiled image color object
|
||||||
*/
|
*/
|
||||||
@@ -368,50 +438,15 @@ var cachedBlackColor,
|
|||||||
{
|
{
|
||||||
_components = components;
|
_components = components;
|
||||||
|
|
||||||
if (!CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0 && window.Base64 && window.CRC32)
|
var hasAlpha = CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0;
|
||||||
{
|
|
||||||
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);
|
_cssString = (hasAlpha ? "rgba(" : "rgb(") +
|
||||||
bytes[g_off] = Math.round(_components[1]*255);
|
parseInt(_components[0] * 255.0) + ", " +
|
||||||
bytes[b_off] = Math.round(_components[2]*255);
|
parseInt(_components[1] * 255.0) + ", " +
|
||||||
bytes[a_off] = Math.round(_components[3]*255);
|
parseInt(_components[2] * 255.0) +
|
||||||
|
(hasAlpha ? (", " + _components[3]) : "") + ")";
|
||||||
// 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;
|
|
||||||
|
|
||||||
_cssString = (hasAlpha ? "rgba(" : "rgb(") +
|
|
||||||
parseInt(_components[0] * 255.0) + ", " +
|
|
||||||
parseInt(_components[1] * 255.0) + ", " +
|
|
||||||
parseInt(_components[2] * 255.0) +
|
|
||||||
(hasAlpha ? (", " + _components[3]) : "") + ")";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,6 +459,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;
|
||||||
@@ -623,6 +659,15 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@implementation CPColor (Debugging)
|
||||||
|
|
||||||
|
+ (CPColor)randomColor
|
||||||
|
{
|
||||||
|
return [CPColor colorWithRed:RAND() green:RAND() blue:RAND() alpha:1.0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
var CPColorComponentsKey = @"CPColorComponentsKey",
|
var CPColorComponentsKey = @"CPColorComponentsKey",
|
||||||
CPColorPatternImageKey = @"CPColorPatternImageKey";
|
CPColorPatternImageKey = @"CPColorPatternImageKey";
|
||||||
|
|
||||||
@@ -656,8 +701,11 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
|
|||||||
|
|
||||||
var hexCharacters = "0123456789ABCDEF";
|
var hexCharacters = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
// HACK: prevent these from becoming globals. workaround for obj-j "function foo(){}" behavior
|
||||||
|
var hexToRGB, rgbToHex, byteToHex;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Used for the CPColor <code>colorWithHexString:</code> implementation
|
Used for the CPColor \c +colorWithHexString: implementation
|
||||||
@ignore
|
@ignore
|
||||||
@class CPColor
|
@class CPColor
|
||||||
@return an array of rgb components
|
@return an array of rgb components
|
||||||
@@ -682,18 +730,6 @@ function hexToRGB(hex)
|
|||||||
return [red, green, blue, 1.0];
|
return [red, green, blue, 1.0];
|
||||||
}
|
}
|
||||||
|
|
||||||
function integerToBytes(integer, length) {
|
|
||||||
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) {
|
function rgbToHex(r,g,b) {
|
||||||
return byteToHex(r) + byteToHex(g) + byteToHex(b);
|
return byteToHex(r) + byteToHex(g) + byteToHex(b);
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-12
@@ -58,7 +58,7 @@ CPColorPickerViewHeight = 370;
|
|||||||
|
|
||||||
CPColorPanel provides a reusable panel that can be used
|
CPColorPanel provides a reusable panel that can be used
|
||||||
displayed on screen to prompt the user for a color selection. To
|
displayed on screen to prompt the user for a color selection. To
|
||||||
obtain the panel, call the <code>sharedColorPanel</code> method.
|
obtain the panel, call the \c +sharedColorPanel method.
|
||||||
*/
|
*/
|
||||||
@implementation CPColorPanel : CPPanel
|
@implementation CPColorPanel : CPPanel
|
||||||
{
|
{
|
||||||
@@ -111,7 +111,7 @@ CPColorPickerViewHeight = 370;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
To obtain the color panel, use <code>sharedColorPanel</code>.
|
To obtain the color panel, use \c +sharedColorPanel.
|
||||||
@ignore
|
@ignore
|
||||||
*/
|
*/
|
||||||
- (id)init
|
- (id)init
|
||||||
@@ -137,7 +137,7 @@ CPColorPickerViewHeight = 370;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the color of the panel, and updates the picker. Also posts a <code>CPColorPanelDidChangeNotification</code>.
|
Sets the color of the panel, and updates the picker. Also posts a \c CPColorPanelDidChangeNotification.
|
||||||
*/
|
*/
|
||||||
- (void)setColor:(CPColor)aColor
|
- (void)setColor:(CPColor)aColor
|
||||||
{
|
{
|
||||||
@@ -491,7 +491,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
|||||||
var future = new Date();
|
var future = new Date();
|
||||||
future.setYear(2019);
|
future.setYear(2019);
|
||||||
|
|
||||||
[_swatchCookie setValue: CPJSObjectCreateJSON(result) expires:future domain: nil];
|
[_swatchCookie setValue: JSON.stringify(result) expires:future domain: nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setColorPanel:(CPColorPanel)panel
|
- (void)setColorPanel:(CPColorPanel)panel
|
||||||
@@ -518,9 +518,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];
|
||||||
@@ -563,7 +564,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 +576,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,8 +613,8 @@ 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];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isOpaque
|
- (BOOL)isOpaque
|
||||||
@@ -625,7 +626,7 @@ 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);
|
||||||
|
|
||||||
@@ -650,7 +651,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
|
||||||
|
|||||||
@@ -23,11 +23,13 @@
|
|||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
@import "CPColorPanel.j"
|
@import "CPColorPanel.j"
|
||||||
|
|
||||||
|
#include "Platform/Platform.h"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@class CPColorPicker
|
@class CPColorPicker
|
||||||
|
|
||||||
CPColorPicker is an abstract superclass for all color picker subclasses. If you want a particular color picker, use CPColorPanel's <code>setPickerMode:</code> method. The simplest way to implement your own color picker is to create a subclass of CPColorPicker.
|
CPColorPicker is an abstract superclass for all color picker subclasses. If you want a particular color picker, use CPColorPanel's \c +setPickerMode: method. The simplest way to implement your own color picker is to create a subclass of CPColorPicker.
|
||||||
*/
|
*/
|
||||||
@implementation CPColorPicker : CPObject
|
@implementation CPColorPicker : CPObject
|
||||||
{
|
{
|
||||||
@@ -60,7 +62,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
FIXME Not implemented.
|
FIXME Not implemented.
|
||||||
@return <code>nil</code>
|
@return \c nil
|
||||||
@ignore
|
@ignore
|
||||||
*/
|
*/
|
||||||
- (CPImage)provideNewButtonImage
|
- (CPImage)provideNewButtonImage
|
||||||
@@ -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];
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
|||||||
|
|
||||||
CPColorWell is a CPControl for selecting and displaying a single color value. An example of a CPColorWell object (or simply color well) is found in CPColorPanel, which uses a color well to display the current color selection.</p>
|
CPColorWell is a CPControl for selecting and displaying a single color value. An example of a CPColorWell object (or simply color well) is found in CPColorPanel, which uses a color well to display the current color selection.</p>
|
||||||
|
|
||||||
<p>An application can have one or more active CPColorWells. You can activate multiple CPColorWells by invoking the <code>activate:</code> method with <code>NO</code> as its argument. When a mouse-down event occurs on an CPColorWell's border, it becomes the only active color well. When a color well becomes active, it brings up the color panel also.
|
<p>An application can have one or more active CPColorWells. You can activate multiple CPColorWells by invoking the \c -activate: method with \c NO as its argument. When a mouse-down event occurs on an CPColorWell's border, it becomes the only active color well. When a color well becomes active, it brings up the color panel also.
|
||||||
*/
|
*/
|
||||||
@implementation CPColorWell : CPControl
|
@implementation CPColorWell : CPControl
|
||||||
{
|
{
|
||||||
@@ -127,7 +127,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Changes the color of the well to that of <code>aSender</code>.
|
Changes the color of the well to that of \c aSender.
|
||||||
@param aSender the object from which to retrieve the color
|
@param aSender the object from which to retrieve the color
|
||||||
*/
|
*/
|
||||||
- (void)takeColorFrom:(id)aSender
|
- (void)takeColorFrom:(id)aSender
|
||||||
@@ -138,7 +138,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
|||||||
// Activating and Deactivating Color Wells
|
// Activating and Deactivating Color Wells
|
||||||
/*!
|
/*!
|
||||||
Activates the color well, displays the color panel, and makes the panel's current color the same as its own.
|
Activates the color well, displays the color panel, and makes the panel's current color the same as its own.
|
||||||
If exclusive is <code>YES</code>, deactivates any other CPColorWells. <code>NO</code>, keeps them active.
|
If exclusive is \c YES, deactivates any other CPColorWells. \c NO, keeps them active.
|
||||||
@param shouldBeExclusive whether other color wells should be deactivated.
|
@param shouldBeExclusive whether other color wells should be deactivated.
|
||||||
*/
|
*/
|
||||||
- (void)activate:(BOOL)shouldBeExclusive
|
- (void)activate:(BOOL)shouldBeExclusive
|
||||||
@@ -179,7 +179,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the color well is active.
|
Returns \c YES if the color well is active.
|
||||||
*/
|
*/
|
||||||
- (BOOL)isActive
|
- (BOOL)isActive
|
||||||
{
|
{
|
||||||
@@ -262,7 +262,7 @@ var CPColorWellColorKey = "CPColorWellColorKey",
|
|||||||
@implementation CPColorWell (CPCoding)
|
@implementation CPColorWell (CPCoding)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Initializes the color well by unarchiving data from <code>aCoder</code>.
|
Initializes the color well by unarchiving data from \c aCoder.
|
||||||
@param aCoder the coder containing the archived CPColorWell.
|
@param aCoder the coder containing the archived CPColorWell.
|
||||||
*/
|
*/
|
||||||
- (id)initWithCoder:(CPCoder)aCoder
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
|||||||
+55
-24
@@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@import "CPEvent.j"
|
@import "CPEvent.j"
|
||||||
|
@import "CPPlatform.j"
|
||||||
|
|
||||||
// Browser Engines
|
// Browser Engines
|
||||||
CPUnknownBrowserEngine = 0;
|
CPUnknownBrowserEngine = 0;
|
||||||
@@ -30,22 +31,28 @@ CPKHTMLBrowserEngine = 3;
|
|||||||
CPOperaBrowserEngine = 4;
|
CPOperaBrowserEngine = 4;
|
||||||
CPWebKitBrowserEngine = 5;
|
CPWebKitBrowserEngine = 5;
|
||||||
|
|
||||||
|
// Operating Systems
|
||||||
|
CPMacOperatingSystem = 0;
|
||||||
|
CPWindowsOperatingSystem = 1;
|
||||||
|
CPOtherOperatingSystem = 2;
|
||||||
|
|
||||||
// Features
|
// Features
|
||||||
CPCSSRGBAFeature = 1 << 5;
|
CPCSSRGBAFeature = 1 << 5;
|
||||||
|
|
||||||
CPHTMLCanvasFeature = 1 << 6;
|
CPHTMLCanvasFeature = 1 << 6;
|
||||||
CPHTMLContentEditableFeature = 1 << 7;
|
CPHTMLContentEditableFeature = 1 << 7;
|
||||||
|
CPHTMLDragAndDropFeature = 1 << 8;
|
||||||
|
|
||||||
CPJavascriptInnerTextFeature = 1 << 8;
|
CPJavascriptInnerTextFeature = 1 << 9;
|
||||||
CPJavascriptTextContentFeature = 1 << 9;
|
CPJavascriptTextContentFeature = 1 << 10;
|
||||||
CPJavascriptClipboardEventsFeature = 1 << 10;
|
CPJavascriptClipboardEventsFeature = 1 << 11;
|
||||||
CPJavascriptClipboardAccessFeature = 1 << 11;
|
CPJavascriptClipboardAccessFeature = 1 << 12;
|
||||||
CPJavaScriptCanvasDrawFeature = 1 << 12;
|
CPJavaScriptCanvasDrawFeature = 1 << 13;
|
||||||
CPJavaScriptCanvasTransformFeature = 1 << 13;
|
CPJavaScriptCanvasTransformFeature = 1 << 14;
|
||||||
|
|
||||||
CPVMLFeature = 1 << 14;
|
CPVMLFeature = 1 << 15;
|
||||||
|
|
||||||
CPJavascriptRemedialKeySupport = 1 << 15;
|
CPJavascriptRemedialKeySupport = 1 << 16;
|
||||||
CPJavaScriptShadowFeature = 1 << 20;
|
CPJavaScriptShadowFeature = 1 << 20;
|
||||||
|
|
||||||
CPJavaScriptNegativeMouseWheelValues = 1 << 22;
|
CPJavaScriptNegativeMouseWheelValues = 1 << 22;
|
||||||
@@ -55,7 +62,7 @@ CPOpacityRequiresFilterFeature = 1 << 24;
|
|||||||
|
|
||||||
//Internet explorer does not allow dynamically changing the type of an input element
|
//Internet explorer does not allow dynamically changing the type of an input element
|
||||||
CPInputTypeCanBeChangedFeature = 1 << 25;
|
CPInputTypeCanBeChangedFeature = 1 << 25;
|
||||||
|
CPHTML5DragAndDropSourceYOffBy1 = 1 << 26;
|
||||||
|
|
||||||
|
|
||||||
var USER_AGENT = "",
|
var USER_AGENT = "",
|
||||||
@@ -66,7 +73,7 @@ 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
|
||||||
@@ -100,16 +107,31 @@ 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 |= CPJavascriptClipboardEventsFeature;
|
PLATFORM_FEATURES |= CPJavascriptClipboardEventsFeature;
|
||||||
PLATFORM_FEATURES |= CPJavascriptClipboardAccessFeature;
|
PLATFORM_FEATURES |= CPJavascriptClipboardAccessFeature;
|
||||||
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
|
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
|
||||||
|
|
||||||
var versionStart = USER_AGENT.indexOf("AppleWebKit/") + "AppleWebKit/".length,
|
var versionStart = USER_AGENT.indexOf("AppleWebKit/") + "AppleWebKit/".length,
|
||||||
versionEnd = USER_AGENT.indexOf(" ", versionStart),
|
versionEnd = USER_AGENT.indexOf(" ", versionStart),
|
||||||
version = parseFloat(USER_AGENT.substring(versionStart, versionEnd), 10);
|
versionString = USER_AGENT.substring(versionStart, versionEnd),
|
||||||
|
versionDivision = versionString.indexOf('.'),
|
||||||
|
majorVersion = parseInt(versionString.substring(0, versionDivision)),
|
||||||
|
minorVersion = parseInt(versionString.substr(versionDivision + 1));
|
||||||
|
|
||||||
if(USER_AGENT.indexOf("Plainview") == -1 && version >= 525.14 || USER_AGENT.indexOf("Chrome") != -1)
|
if((USER_AGENT.indexOf("Safari") !== CPNotFound && (majorVersion > 525 || (majorVersion === 525 && minorVersion > 14))) || USER_AGENT.indexOf("Chrome") !== CPNotFound)
|
||||||
PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport;
|
PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport;
|
||||||
|
|
||||||
|
// FIXME this is a terrible hack to get around this bug:
|
||||||
|
// https://bugs.webkit.org/show_bug.cgi?id=21548
|
||||||
|
if (![CPPlatform isBrowser])
|
||||||
|
PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport;
|
||||||
|
|
||||||
|
if (majorVersion < 532 || (majorVersion === 532 && minorVersion < 6))
|
||||||
|
PLATFORM_FEATURES |= CPHTML5DragAndDropSourceYOffBy1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// KHTML
|
// KHTML
|
||||||
@@ -119,22 +141,19 @@ else if (USER_AGENT.indexOf("KHTML") != -1) // Must follow WebKit check.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Gecko
|
// Gecko
|
||||||
else if (USER_AGENT.indexOf("Gecko") != -1) // Must follow KHTML check.
|
else if (USER_AGENT.indexOf("Gecko") !== -1) // Must follow KHTML check.
|
||||||
{
|
{
|
||||||
PLATFORM_ENGINE = CPGeckoBrowserEngine;
|
PLATFORM_ENGINE = CPGeckoBrowserEngine;
|
||||||
|
|
||||||
PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature;
|
PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature;
|
||||||
|
|
||||||
var index = USER_AGENT.indexOf("Firefox"),
|
var index = USER_AGENT.indexOf("Firefox"),
|
||||||
version = (index == -1) ? 2.0 : parseFloat(USER_AGENT.substring(index + "Firefox".length + 1));
|
version = (index === -1) ? 2.0 : parseFloat(USER_AGENT.substring(index + "Firefox".length + 1));
|
||||||
|
|
||||||
if (version >= 3.0)
|
if (version >= 3.0)
|
||||||
PLATFORM_FEATURES |= CPCSSRGBAFeature;
|
PLATFORM_FEATURES |= CPCSSRGBAFeature;
|
||||||
|
|
||||||
var geckoIndex = USER_AGENT.indexOf("Gecko"),
|
if (version < 3.0)
|
||||||
geckoVersion = (geckoIndex === -1) ? 0.0 : parseFloat(USER_AGENT.substring(geckoIndex + "Gecko".length + 1, USER_AGENT.indexOf(' ', geckoIndex)));
|
|
||||||
|
|
||||||
if (version < 20061028)
|
|
||||||
PLATFORM_FEATURES |= CPJavaScriptMouseWheelValues_8_15;
|
PLATFORM_FEATURES |= CPJavaScriptMouseWheelValues_8_15;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,25 +189,37 @@ function CPFeatureIsCompatible(aFeature)
|
|||||||
|
|
||||||
function CPBrowserIsEngine(anEngine)
|
function CPBrowserIsEngine(anEngine)
|
||||||
{
|
{
|
||||||
return PLATFORM_ENGINE == anEngine;
|
return PLATFORM_ENGINE === anEngine;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (USER_AGENT.indexOf("Mac") != -1)
|
function CPBrowserIsOperatingSystem(anOperatingSystem)
|
||||||
{
|
{
|
||||||
|
return OPERATING_SYSTEM === anOperatingSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPERATING_SYSTEM = CPOtherOperatingSystem;
|
||||||
|
|
||||||
|
if (USER_AGENT.indexOf("Mac") !== -1)
|
||||||
|
{
|
||||||
|
OPERATING_SYSTEM = CPMacOperatingSystem;
|
||||||
|
|
||||||
CPPlatformActionKeyMask = CPCommandKeyMask;
|
CPPlatformActionKeyMask = CPCommandKeyMask;
|
||||||
|
|
||||||
CPUndoKeyEquivalent = @"Z";
|
CPUndoKeyEquivalent = @"z";
|
||||||
CPRedoKeyEquivalent = @"Z";
|
CPRedoKeyEquivalent = @"Z";
|
||||||
|
|
||||||
CPUndoKeyEquivalentModifierMask = CPCommandKeyMask;
|
CPUndoKeyEquivalentModifierMask = CPCommandKeyMask;
|
||||||
CPRedoKeyEquivalentModifierMask = CPCommandKeyMask | CPShiftKeyMask;
|
CPRedoKeyEquivalentModifierMask = CPCommandKeyMask;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (USER_AGENT.indexOf("Windows") !== -1)
|
||||||
|
OPERATING_SYSTEM = CPWindowsOperatingSystem;
|
||||||
|
|
||||||
CPPlatformActionKeyMask = CPControlKeyMask;
|
CPPlatformActionKeyMask = CPControlKeyMask;
|
||||||
|
|
||||||
CPUndoKeyEquivalent = @"Z";
|
CPUndoKeyEquivalent = @"z";
|
||||||
CPRedoKeyEquivalent = @"Y";
|
CPRedoKeyEquivalent = @"y";
|
||||||
|
|
||||||
CPUndoKeyEquivalentModifierMask = CPControlKeyMask;
|
CPUndoKeyEquivalentModifierMask = CPControlKeyMask;
|
||||||
CPRedoKeyEquivalentModifierMask = CPControlKeyMask;
|
CPRedoKeyEquivalentModifierMask = CPControlKeyMask;
|
||||||
|
|||||||
+61
-109
@@ -27,47 +27,42 @@
|
|||||||
#include "CoreGraphics/CGGeometry.h"
|
#include "CoreGraphics/CGGeometry.h"
|
||||||
#include "Platform/Platform.h"
|
#include "Platform/Platform.h"
|
||||||
|
|
||||||
/*
|
CPLeftTextAlignment = 0;
|
||||||
@global
|
CPRightTextAlignment = 1;
|
||||||
@group CPTextAlignment
|
CPCenterTextAlignment = 2;
|
||||||
*/
|
CPJustifiedTextAlignment = 3;
|
||||||
CPLeftTextAlignment = 0;
|
CPNaturalTextAlignment = 4;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPTextAlignment
|
|
||||||
*/
|
|
||||||
CPRightTextAlignment = 1;
|
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPTextAlignment
|
|
||||||
*/
|
|
||||||
CPCenterTextAlignment = 2;
|
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPTextAlignment
|
|
||||||
*/
|
|
||||||
CPJustifiedTextAlignment = 3;
|
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPTextAlignment
|
|
||||||
*/
|
|
||||||
CPNaturalTextAlignment = 4;
|
|
||||||
|
|
||||||
/*
|
CPRegularControlSize = 0;
|
||||||
@global
|
CPSmallControlSize = 1;
|
||||||
@group CPControlSize
|
CPMiniControlSize = 2;
|
||||||
*/
|
|
||||||
CPRegularControlSize = 0;
|
CPLineBreakByWordWrapping = 0;
|
||||||
/*
|
CPLineBreakByCharWrapping = 1;
|
||||||
@global
|
CPLineBreakByClipping = 2;
|
||||||
@group CPControlSize
|
CPLineBreakByTruncatingHead = 3;
|
||||||
*/
|
CPLineBreakByTruncatingTail = 4;
|
||||||
CPSmallControlSize = 1;
|
CPLineBreakByTruncatingMiddle = 5;
|
||||||
/*
|
|
||||||
@global
|
CPTopVerticalTextAlignment = 1,
|
||||||
@group CPControlSize
|
CPCenterVerticalTextAlignment = 2,
|
||||||
*/
|
CPBottomVerticalTextAlignment = 3;
|
||||||
CPMiniControlSize = 2;
|
|
||||||
|
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";
|
||||||
@@ -94,6 +89,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
id _target;
|
id _target;
|
||||||
SEL _action;
|
SEL _action;
|
||||||
int _sendActionOn;
|
int _sendActionOn;
|
||||||
|
BOOL _sendsActionOnEndEditing @accessors(property=sendsActionOnEndEditing);
|
||||||
|
|
||||||
// Mouse Tracking Support
|
// Mouse Tracking Support
|
||||||
BOOL _continuousTracking;
|
BOOL _continuousTracking;
|
||||||
@@ -101,9 +97,6 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
unsigned _trackingMouseDownFlags;
|
unsigned _trackingMouseDownFlags;
|
||||||
CGPoint _previousTrackingLocation;
|
CGPoint _previousTrackingLocation;
|
||||||
|
|
||||||
JSObject _ephemeralSubviewsForNames;
|
|
||||||
CPSet _ephereralSubviews;
|
|
||||||
|
|
||||||
CPString _toolTip;
|
CPString _toolTip;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +107,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,
|
||||||
@@ -181,7 +174,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Causes <code>anAction</code> to be sent to <code>anObject</code>.
|
Causes \c anAction to be sent to \c anObject.
|
||||||
@param anAction the action to send
|
@param anAction the action to send
|
||||||
@param anObject the object to which the action will be sent
|
@param anObject the object to which the action will be sent
|
||||||
*/
|
*/
|
||||||
@@ -296,11 +289,26 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
_previousTrackingLocation = currentLocation;
|
_previousTrackingLocation = currentLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setState:(int)state
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int)nextState
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)performClick:(id)sender
|
- (void)performClick:(id)sender
|
||||||
{
|
{
|
||||||
[self highlight:YES];
|
[self highlight:YES];
|
||||||
[self setState:[self nextState]];
|
[self setState:[self nextState]];
|
||||||
[self sendAction:[self action] to:[self target]];
|
[self sendAction:[self action] to:[self target]];
|
||||||
|
|
||||||
|
[CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)unhighlightButtonTimerDidFinish:(id)sender
|
||||||
|
{
|
||||||
[self highlight:NO];
|
[self highlight:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,10 +513,12 @@ var CPControlBlackColor = [CPColor blackColor];
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define BRIDGE(UPPERCASE, LOWERCASE, ATTRIBUTENAME) \
|
#define BRIDGE(UPPERCASE, LOWERCASE, ATTRIBUTENAME) \
|
||||||
|
/*! Sets the value for ATTRIBUTENAME */\
|
||||||
- (void)set##UPPERCASE:(id)aValue\
|
- (void)set##UPPERCASE:(id)aValue\
|
||||||
{\
|
{\
|
||||||
[self setValue:aValue forThemeAttribute:ATTRIBUTENAME];\
|
[self setValue:aValue forThemeAttribute:ATTRIBUTENAME];\
|
||||||
}\
|
}\
|
||||||
|
/*! Returns the current value for ATTRIBUTENAME */\
|
||||||
- (id)LOWERCASE\
|
- (id)LOWERCASE\
|
||||||
{\
|
{\
|
||||||
return [self valueForThemeAttribute:ATTRIBUTENAME];\
|
return [self valueForThemeAttribute:ATTRIBUTENAME];\
|
||||||
@@ -555,54 +565,6 @@ BRIDGE(ImageScaling, imageScaling, "image-scaling")
|
|||||||
return [self hasThemeState:CPThemeStateHighlighted];
|
return [self hasThemeState:CPThemeStateHighlighted];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPView)createEphemeralSubviewNamed:(CPString)aViewName
|
|
||||||
{
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
|
|
||||||
{
|
|
||||||
return _CGRectMakeZero();
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPView)layoutEphemeralSubviewNamed:(CPString)aViewName
|
|
||||||
positioned:(CPWindowOrderingMode)anOrderingMode
|
|
||||||
relativeToEphemeralSubviewNamed:(CPString)relativeToViewName
|
|
||||||
{
|
|
||||||
if (!_ephemeralSubviewsForNames)
|
|
||||||
{
|
|
||||||
_ephemeralSubviewsForNames = {};
|
|
||||||
_ephemeralSubviews = [CPSet set];
|
|
||||||
}
|
|
||||||
|
|
||||||
var frame = [self rectForEphemeralSubviewNamed:aViewName];
|
|
||||||
|
|
||||||
if (frame && !_CGRectIsEmpty(frame))
|
|
||||||
{
|
|
||||||
if (!_ephemeralSubviewsForNames[aViewName])
|
|
||||||
{
|
|
||||||
_ephemeralSubviewsForNames[aViewName] = [self createEphemeralSubviewNamed:aViewName];
|
|
||||||
|
|
||||||
[_ephemeralSubviews addObject:_ephemeralSubviewsForNames[aViewName]];
|
|
||||||
|
|
||||||
if (_ephemeralSubviewsForNames[aViewName])
|
|
||||||
[self addSubview:_ephemeralSubviewsForNames[aViewName] positioned:anOrderingMode relativeTo:_ephemeralSubviewsForNames[relativeToViewName]];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_ephemeralSubviewsForNames[aViewName])
|
|
||||||
[_ephemeralSubviewsForNames[aViewName] setFrame:frame];
|
|
||||||
}
|
|
||||||
else if (_ephemeralSubviewsForNames[aViewName])
|
|
||||||
{
|
|
||||||
[_ephemeralSubviewsForNames[aViewName] removeFromSuperview];
|
|
||||||
|
|
||||||
[_ephemeralSubviews removeObject:_ephemeralSubviewsForNames[aViewName]];
|
|
||||||
delete _ephemeralSubviewsForNames[aViewName];
|
|
||||||
}
|
|
||||||
|
|
||||||
return _ephemeralSubviewsForNames[aViewName];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPControlValueKey = "CPControlValueKey",
|
var CPControlValueKey = "CPControlValueKey",
|
||||||
@@ -611,7 +573,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";
|
||||||
|
|
||||||
@@ -634,6 +598,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;
|
||||||
@@ -645,23 +610,10 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
|
|||||||
*/
|
*/
|
||||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
{
|
{
|
||||||
var count = [_subviews count],
|
|
||||||
ephemeral
|
|
||||||
subviews = nil;
|
|
||||||
|
|
||||||
if (count > 0 && [_ephemeralSubviews count] > 0)
|
|
||||||
{
|
|
||||||
subviews = [_subviews.slice(0) copy];
|
|
||||||
|
|
||||||
while (count--)
|
|
||||||
if ([_ephemeralSubviews containsObject:_subviews[count]])
|
|
||||||
_subviews.splice(count, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
[super encodeWithCoder:aCoder];
|
[super encodeWithCoder:aCoder];
|
||||||
|
|
||||||
if (subviews)
|
if (_sendsActionOnEndEditing)
|
||||||
_subviews = subviews;
|
[aCoder encodeBool:_sendsActionOnEndEditing forKey:CPControlSendsActionOnEndEditingKey];
|
||||||
|
|
||||||
if (_value !== nil)
|
if (_value !== nil)
|
||||||
[aCoder encodeObject:_value forKey:CPControlValueKey];
|
[aCoder encodeObject:_value forKey:CPControlValueKey];
|
||||||
|
|||||||
+1
-1
@@ -38,7 +38,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Initializes a cookie with a given name <code>aName</code>.
|
Initializes a cookie with a given name \c aName.
|
||||||
@param the name for the cookie
|
@param the name for the cookie
|
||||||
*/
|
*/
|
||||||
- (id)initWithName:(CPString)aName
|
- (id)initWithName:(CPString)aName
|
||||||
|
|||||||
Executable
+272
@@ -0,0 +1,272 @@
|
|||||||
|
/*
|
||||||
|
Testing browsers:
|
||||||
|
WebKit r50235 (Safari 4.0.3+)
|
||||||
|
FireFox 3.5
|
||||||
|
Opera 10.0.0
|
||||||
|
|
||||||
|
Implemented class methods:
|
||||||
|
Webkit : All
|
||||||
|
IE : All
|
||||||
|
FireFox Win : All
|
||||||
|
FireFox Mac : All except closedHandCursor disappearingItemCursor // Firefox mac does not support url cursors
|
||||||
|
Opera : All except resizeLeftRightCursor resizeUpDownCursor operationNotAllowedCursor dragCopyCursor dragLinkCursor contextualMenuCursor openHandCursor closedHandCursor disappearingItemCursor // Opera does not support url cursors so these won't work with images
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Platform/Platform.h"
|
||||||
|
|
||||||
|
var currentCursor = nil,
|
||||||
|
cursorStack = [],
|
||||||
|
cursors = {},
|
||||||
|
cursorURLFormat = nil;
|
||||||
|
|
||||||
|
@implementation CPCursor : CPObject
|
||||||
|
{
|
||||||
|
CPString _cssString;
|
||||||
|
BOOL _isSetOnMouseEntered @accessors(readwrite, getter=isSetOnMouseEntered, setter=setOnMouseEntered:);
|
||||||
|
BOOL _isSetOnMouseExited @accessors(readwrite, getter=isSetOnMouseExited, setter=setOnMouseExited:);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)currentCursor
|
||||||
|
{
|
||||||
|
return currentCursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithCSSString:(CPString)aString
|
||||||
|
{
|
||||||
|
if (self = [super init])
|
||||||
|
_cssString = aString;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)cursorWithCSSString:(CPString)cssString
|
||||||
|
{
|
||||||
|
var cursor = cursors[cssString];
|
||||||
|
|
||||||
|
if (typeof cursor == 'undefined')
|
||||||
|
{
|
||||||
|
cursor = [[CPCursor alloc] initWithCSSString:cssString];
|
||||||
|
cursors[cssString] = cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)cursorWithImageNamed:(CPString)imageName
|
||||||
|
{
|
||||||
|
if (!cursorURLFormat)
|
||||||
|
{
|
||||||
|
cursorURLFormat = @"url(" + [[CPBundle bundleForClass:self] resourcePath] + @"/CPCursor/%@.cur)";
|
||||||
|
|
||||||
|
if (CPBrowserIsEngine(CPGeckoBrowserEngine))
|
||||||
|
cursorURLFormat += ", default";
|
||||||
|
}
|
||||||
|
|
||||||
|
var url = [CPString stringWithFormat:cursorURLFormat, imageName];
|
||||||
|
|
||||||
|
return [[CPCursor alloc] initWithCSSString:url];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)_cssString
|
||||||
|
{
|
||||||
|
return _cssString;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)arrowCursor
|
||||||
|
{
|
||||||
|
return [CPCursor cursorWithCSSString:@"default"]; // WebKit | FF | opera | IE
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)crosshairCursor
|
||||||
|
{
|
||||||
|
return [CPCursor cursorWithCSSString:@"crosshair"]; // WebKit | FF | opera | IE
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)IBeamCursor
|
||||||
|
{
|
||||||
|
return [CPCursor cursorWithCSSString:@"text"]; // WebKit | FF | opera | IE
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)pointingHandCursor
|
||||||
|
{
|
||||||
|
return [CPCursor cursorWithCSSString:@"pointer"]; // WebKit | FF | opera | IE
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)resizeDownCursor
|
||||||
|
{
|
||||||
|
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||||
|
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||||
|
|
||||||
|
return [CPCursor cursorWithCSSString:"s-resize"]; // WebKit | FF | opera
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)resizeUpCursor
|
||||||
|
{
|
||||||
|
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||||
|
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||||
|
|
||||||
|
return [CPCursor cursorWithCSSString:@"n-resize"]; // WebKit | FF | opera
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)resizeLeftCursor
|
||||||
|
{
|
||||||
|
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||||
|
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||||
|
|
||||||
|
return [CPCursor cursorWithCSSString:@"w-resize"]; // WebKit | FF | opera
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)resizeRightCursor
|
||||||
|
{
|
||||||
|
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||||
|
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||||
|
|
||||||
|
return [CPCursor cursorWithCSSString:@"e-resize"]; // WebKit | FF | opera
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)resizeLeftRightCursor
|
||||||
|
{
|
||||||
|
return [CPCursor cursorWithCSSString:@"col-resize"]; // WebKit | FF | IE
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)resizeUpDownCursor
|
||||||
|
{
|
||||||
|
return [CPCursor cursorWithCSSString:@"row-resize"]; // WebKit | FF | IE
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)operationNotAllowedCursor
|
||||||
|
{
|
||||||
|
return [CPCursor cursorWithCSSString:@"not-allowed"]; // WebKit | FF | IE
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)dragCopyCursor
|
||||||
|
{
|
||||||
|
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||||
|
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||||
|
|
||||||
|
return [CPCursor cursorWithCSSString:@"copy"]; // WebKit | FF
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)dragLinkCursor
|
||||||
|
{
|
||||||
|
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||||
|
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||||
|
|
||||||
|
return [CPCursor cursorWithCSSString:@"alias"]; // WebKit | FF
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)contextualMenuCursor
|
||||||
|
{
|
||||||
|
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||||
|
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||||
|
|
||||||
|
return [CPCursor cursorWithCSSString:@"context-menu"]; // WebKit | FF Mac . Not impl FF Win.
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)openHandCursor
|
||||||
|
{
|
||||||
|
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
|
||||||
|
return [CPCursor cursorWithCSSString:@"-webkit-grab"];
|
||||||
|
else if (CPBrowserIsEngine(CPGeckoBrowserEngine) || CPBrowserIsEngine(CPOperaBrowserEngine))
|
||||||
|
return [CPCursor cursorWithCSSString:@"move"];
|
||||||
|
|
||||||
|
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit only. move in FFMac|Opera
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)closedHandCursor
|
||||||
|
{
|
||||||
|
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
|
||||||
|
return [CPCursor cursorWithCSSString:@"-webkit-grabbing"];
|
||||||
|
|
||||||
|
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit only
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPCursor)disappearingItemCursor
|
||||||
|
{
|
||||||
|
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // None
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)hide
|
||||||
|
{
|
||||||
|
[self _setCursorCSS:"none"]; // Not supported in IE
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)unhide
|
||||||
|
{
|
||||||
|
[self _setCursorCSS:[currentCursor _cssString]]
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)setHiddenUntilMouseMoves:(BOOL)flag
|
||||||
|
{
|
||||||
|
if (flag)
|
||||||
|
[CPCursor hide];
|
||||||
|
else
|
||||||
|
[CPCursor unhide];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithImage:(CPImage)image hotSpot:(CPPoint)hotSpot
|
||||||
|
{
|
||||||
|
return [self initWithCSSString:"url(" + [image filename] + ")"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseEntered:(CPEvent)event
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseExited:(CPEvent)event
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)set
|
||||||
|
{
|
||||||
|
currentCursor = self;
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
[[self class] _setCursorCSS:_cssString];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)_setCursorCSS:(CPString)aString
|
||||||
|
{
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
var platformWindows = [[CPPlatformWindow visiblePlatformWindows] allObjects];
|
||||||
|
for (var i = 0, count = [platformWindows count]; i < count; i++)
|
||||||
|
platformWindows[i]._DOMBodyElement.style.cursor = aString;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)push
|
||||||
|
{
|
||||||
|
currentCursor = cursorStack.push(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)pop
|
||||||
|
{
|
||||||
|
[CPCursor pop];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)pop
|
||||||
|
{
|
||||||
|
if (cursorStack.length > 1)
|
||||||
|
{
|
||||||
|
cursorStack.pop();
|
||||||
|
currentCursor = cursorStack[cursorStack.length - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)coder
|
||||||
|
{
|
||||||
|
if (self = [super init])
|
||||||
|
_cssString = [coder decodeObjectForKey:@"CPCursorNameKey"];
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(CPCoder)coder
|
||||||
|
{
|
||||||
|
[coder encodeObject:_cssString forKey:@"CPCursorNameKey"];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
+259
-47
@@ -24,6 +24,8 @@
|
|||||||
@import <Foundation/CPArray.j>
|
@import <Foundation/CPArray.j>
|
||||||
|
|
||||||
@import "CPResponder.j"
|
@import "CPResponder.j"
|
||||||
|
@import "CPSavePanel.j"
|
||||||
|
@import "CPViewController.j"
|
||||||
@import "CPWindowController.j"
|
@import "CPWindowController.j"
|
||||||
|
|
||||||
|
|
||||||
@@ -91,18 +93,24 @@ var CPDocumentUntitledCount = 0;
|
|||||||
*/
|
*/
|
||||||
@implementation CPDocument : CPResponder
|
@implementation CPDocument : CPResponder
|
||||||
{
|
{
|
||||||
CPURL _fileURL;
|
CPWindow _window; // For outlet purposes.
|
||||||
CPString _fileType;
|
CPView _view; // For outlet purposes
|
||||||
CPArray _windowControllers;
|
CPDictionary _viewControllersForWindowControllers;
|
||||||
unsigned _untitledDocumentIndex;
|
|
||||||
|
|
||||||
BOOL _hasUndoManager;
|
CPURL _fileURL;
|
||||||
CPUndoManager _undoManager;
|
CPString _fileType;
|
||||||
|
CPArray _windowControllers;
|
||||||
|
unsigned _untitledDocumentIndex;
|
||||||
|
|
||||||
int _changeCount;
|
BOOL _hasUndoManager;
|
||||||
|
CPUndoManager _undoManager;
|
||||||
|
|
||||||
CPURLConnection _readConnection;
|
int _changeCount;
|
||||||
CPURLRequest _writeRequest;
|
|
||||||
|
CPURLConnection _readConnection;
|
||||||
|
CPURLRequest _writeRequest;
|
||||||
|
|
||||||
|
CPAlert _canCloseAlert;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -116,6 +124,7 @@ var CPDocumentUntitledCount = 0;
|
|||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_windowControllers = [];
|
_windowControllers = [];
|
||||||
|
_viewControllersForWindowControllers = [CPDictionary dictionary];
|
||||||
|
|
||||||
_hasUndoManager = YES;
|
_hasUndoManager = YES;
|
||||||
_changeCount = 0;
|
_changeCount = 0;
|
||||||
@@ -159,10 +168,10 @@ var CPDocumentUntitledCount = 0;
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
[self readFromURL:anAbsoluteURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo];
|
|
||||||
|
|
||||||
[self setFileURL:anAbsoluteURL];
|
[self setFileURL:anAbsoluteURL];
|
||||||
[self setFileType:aType];
|
[self setFileType:aType];
|
||||||
|
|
||||||
|
[self readFromURL:anAbsoluteURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -174,8 +183,8 @@ var CPDocumentUntitledCount = 0;
|
|||||||
@param absoluteContentsURL the location of the document's contents
|
@param absoluteContentsURL the location of the document's contents
|
||||||
@param aType the type of the contents
|
@param aType the type of the contents
|
||||||
@param aDelegate this object will receive a callback after the document's contents are loaded
|
@param aDelegate this object will receive a callback after the document's contents are loaded
|
||||||
@param aDidReadSelector the message selector that will be sent to <code>aDelegate</code>
|
@param aDidReadSelector the message selector that will be sent to \c aDelegate
|
||||||
@param aContextInfo passed as the argument to the message sent to the <code>aDelegate</code>
|
@param aContextInfo passed as the argument to the message sent to the \c aDelegate
|
||||||
@return the initialized document
|
@return the initialized document
|
||||||
*/
|
*/
|
||||||
- (id)initForURL:(CPURL)anAbsoluteURL withContentsOfURL:(CPURL)absoluteContentsURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo
|
- (id)initForURL:(CPURL)anAbsoluteURL withContentsOfURL:(CPURL)absoluteContentsURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo
|
||||||
@@ -184,10 +193,10 @@ var CPDocumentUntitledCount = 0;
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
[self readFromURL:absoluteContentsURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo];
|
|
||||||
|
|
||||||
[self setFileURL:anAbsoluteURL];
|
[self setFileURL:anAbsoluteURL];
|
||||||
[self setFileType:aType];
|
[self setFileType:aType];
|
||||||
|
|
||||||
|
[self readFromURL:absoluteContentsURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -201,10 +210,10 @@ var CPDocumentUntitledCount = 0;
|
|||||||
@throws CPUnsupportedMethodException if this method hasn't been overriden by the subclass
|
@throws CPUnsupportedMethodException if this method hasn't been overriden by the subclass
|
||||||
@return the document data
|
@return the document data
|
||||||
*/
|
*/
|
||||||
- (CPData)dataOfType:(CPString)aType error:({CPError})anError
|
- (CPData)dataOfType:(CPString)aType
|
||||||
{
|
{
|
||||||
[CPException raise:CPUnsupportedMethodException
|
[CPException raise:CPUnsupportedMethodException
|
||||||
reason:"dataOfType:error: must be overridden by the document subclass."];
|
reason:"dataOfType: must be overridden by the document subclass."];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -222,15 +231,73 @@ var CPDocumentUntitledCount = 0;
|
|||||||
reason:"readFromData:ofType: must be overridden by the document subclass."];
|
reason:"readFromData:ofType: must be overridden by the document subclass."];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)viewControllerWillLoadCib:(CPViewController)aViewController
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewControllerDidLoadCib:(CPViewController)aViewController
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPWindowController)firstEligibleExistingWindowController
|
||||||
|
{
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
// Creating and managing window controllers
|
// Creating and managing window controllers
|
||||||
/*!
|
/*!
|
||||||
Creates the window controller for this document.
|
Creates the window controller for this document.
|
||||||
*/
|
*/
|
||||||
- (void)makeWindowControllers
|
- (void)makeWindowControllers
|
||||||
{
|
{
|
||||||
var controller = [[CPWindowController alloc] initWithWindowCibName:nil];
|
[self makeViewAndWindowControllers];
|
||||||
|
}
|
||||||
|
|
||||||
[self addWindowController:controller];
|
- (void)makeViewAndWindowControllers
|
||||||
|
{
|
||||||
|
var viewCibName = [self viewCibName],
|
||||||
|
viewController = nil,
|
||||||
|
windowController = nil;
|
||||||
|
|
||||||
|
// Create our view controller if we have a cib for it.
|
||||||
|
if ([viewCibName length])
|
||||||
|
viewController = [[CPViewController alloc] initWithCibName:viewCibName bundle:nil owner:self];
|
||||||
|
|
||||||
|
// If we have a view controller, check if we have a free window for it.
|
||||||
|
if (viewController)
|
||||||
|
windowController = [self firstEligibleExistingWindowController];
|
||||||
|
|
||||||
|
// If not, create one.
|
||||||
|
if (!windowController)
|
||||||
|
{
|
||||||
|
var windowCibName = [self windowCibName];
|
||||||
|
|
||||||
|
// From a cib if we have one.
|
||||||
|
if ([windowCibName length])
|
||||||
|
windowController = [[CPWindowController alloc] initWithWindowCibName:windowCibName owner:self];
|
||||||
|
|
||||||
|
// If not you get a standard window capable of displaying multiple documents and view
|
||||||
|
else if (viewController)
|
||||||
|
{
|
||||||
|
var view = [viewController view],
|
||||||
|
viewFrame = [view frame];
|
||||||
|
|
||||||
|
viewFrame.origin = CGPointMake(50, 50);
|
||||||
|
|
||||||
|
var theWindow = [[CPWindow alloc] initWithContentRect:viewFrame styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask];
|
||||||
|
|
||||||
|
windowController = [[CPWindowController alloc] initWithWindow:theWindow];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (windowController && viewController)
|
||||||
|
[windowController setSupportsMultipleDocuments:YES];
|
||||||
|
|
||||||
|
if (windowController)
|
||||||
|
[self addWindowController:windowController];
|
||||||
|
|
||||||
|
if (viewController)
|
||||||
|
[self addViewController:viewController forWindowController:windowController];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -250,11 +317,51 @@ var CPDocumentUntitledCount = 0;
|
|||||||
{
|
{
|
||||||
[_windowControllers addObject:aWindowController];
|
[_windowControllers addObject:aWindowController];
|
||||||
|
|
||||||
if ([aWindowController document] != self)
|
if ([aWindowController document] !== self)
|
||||||
{
|
|
||||||
[aWindowController setNextResponder:self];
|
|
||||||
[aWindowController setDocument:self];
|
[aWindowController setDocument:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Remove a controller to the document's list of controllers. This should
|
||||||
|
be called after closing the controller's window.
|
||||||
|
@param aWindowController the controller to remove
|
||||||
|
*/
|
||||||
|
- (void)removeWindowController:(CPWindowController)aWindowController
|
||||||
|
{
|
||||||
|
if (aWindowController)
|
||||||
|
[_windowControllers removeObject:aWindowController];
|
||||||
|
|
||||||
|
if ([aWindowController document] === self)
|
||||||
|
[aWindowController setDocument:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPView)view
|
||||||
|
{
|
||||||
|
return _view;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPArray)viewControllers
|
||||||
|
{
|
||||||
|
return [_viewControllersForWindowControllers allValues];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)addViewController:(CPViewController)aViewController forWindowController:(CPWindowController)aWindowController
|
||||||
|
{
|
||||||
|
// FIXME: exception if we don't own the window controller?
|
||||||
|
[_viewControllersForWindowControllers setObject:aViewController forKey:[aWindowController UID]];
|
||||||
|
|
||||||
|
if ([aWindowController document] === self)
|
||||||
|
[aWindowController setViewController:aViewController];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeViewController:(CPViewController)aViewController
|
||||||
|
{
|
||||||
|
[_viewControllersForWindowControllers removeObject:aViewController];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPViewController)viewControllerForWindowController:(CPWindowController)aWindowController
|
||||||
|
{
|
||||||
|
return [_viewControllersForWindowControllers objectForKey:[aWindowController UID]];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Managing Document Windows
|
// Managing Document Windows
|
||||||
@@ -263,6 +370,7 @@ var CPDocumentUntitledCount = 0;
|
|||||||
*/
|
*/
|
||||||
- (void)showWindows
|
- (void)showWindows
|
||||||
{
|
{
|
||||||
|
[_windowControllers makeObjectsPerformSelector:@selector(setDocument:) withObject:self];
|
||||||
[_windowControllers makeObjectsPerformSelector:@selector(showWindow:) withObject:self];
|
[_windowControllers makeObjectsPerformSelector:@selector(showWindow:) withObject:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,6 +391,11 @@ var CPDocumentUntitledCount = 0;
|
|||||||
return @"Untitled " + _untitledDocumentIndex;
|
return @"Untitled " + _untitledDocumentIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CPString)viewCibName
|
||||||
|
{
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the document's Cib name
|
Returns the document's Cib name
|
||||||
*/
|
*/
|
||||||
@@ -292,18 +405,18 @@ var CPDocumentUntitledCount = 0;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Called after <code>aWindowController<code> loads the document's Nib file.
|
Called after \c aWindowController loads the document's Nib file.
|
||||||
@param aWindowController the controller that loaded the Nib file
|
@param aWindowController the controller that loaded the Nib file
|
||||||
*/
|
*/
|
||||||
- (void)windowControllerDidLoadNib:(CPWindowController)aWindowController
|
- (void)windowControllerDidLoadCib:(CPWindowController)aWindowController
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Called before <code>aWindowController</code> will load the document's Nib file.
|
Called before \c aWindowController will load the document's Nib file.
|
||||||
@param aWindowController the controller that will load the Nib file
|
@param aWindowController the controller that will load the Nib file
|
||||||
*/
|
*/
|
||||||
- (void)windowControllerWillLoadNib:(CPWindowController)aWindowController
|
- (void)windowControllerWillLoadCib:(CPWindowController)aWindowController
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,7 +453,7 @@ var CPDocumentUntitledCount = 0;
|
|||||||
*/
|
*/
|
||||||
- (void)setFileURL:(CPURL)aFileURL
|
- (void)setFileURL:(CPURL)aFileURL
|
||||||
{
|
{
|
||||||
if (_fileURL == aFileURL)
|
if (_fileURL === aFileURL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_fileURL = aFileURL;
|
_fileURL = aFileURL;
|
||||||
@@ -360,20 +473,38 @@ var CPDocumentUntitledCount = 0;
|
|||||||
*/
|
*/
|
||||||
- (void)saveToURL:(CPURL)anAbsoluteURL ofType:(CPString)aTypeName forSaveOperation:(CPSaveOperationType)aSaveOperation delegate:(id)aDelegate didSaveSelector:(SEL)aDidSaveSelector contextInfo:(id)aContextInfo
|
- (void)saveToURL:(CPURL)anAbsoluteURL ofType:(CPString)aTypeName forSaveOperation:(CPSaveOperationType)aSaveOperation delegate:(id)aDelegate didSaveSelector:(SEL)aDidSaveSelector contextInfo:(id)aContextInfo
|
||||||
{
|
{
|
||||||
var data = [self dataOfType:[self fileType] error:nil],
|
if (anAbsoluteURL.isLocalStorageURL())
|
||||||
oldChangeCount = _changeCount;
|
[[CPDocumentController sharedDocumentController] _addLocalDocumentURL:anAbsoluteURL];
|
||||||
|
|
||||||
|
var data = nil;
|
||||||
|
|
||||||
|
if ([self respondsToSelector:@selector(dataOfType:error:)])
|
||||||
|
{
|
||||||
|
CPLog.warn("[" + CPStringFromClass([self class]) + " " + CPStringFromSelector(@selector(dataOfType:error:)) + "] is deprecated, please implement " + CPStringFromSelector(@selector(dataOfType:)) + " instead and simply throw exceptions when necessary.");
|
||||||
|
|
||||||
|
data = [self dataOfType:[self fileType] error:nil];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
data = [self dataOfType:[self fileType]];
|
||||||
|
|
||||||
|
var oldChangeCount = _changeCount;
|
||||||
|
|
||||||
_writeRequest = [CPURLRequest requestWithURL:anAbsoluteURL];
|
_writeRequest = [CPURLRequest requestWithURL:anAbsoluteURL];
|
||||||
|
|
||||||
[_writeRequest setHTTPMethod:@"POST"];
|
// FIXME: THIS IS WRONG! We need a way to decide
|
||||||
[_writeRequest setHTTPBody:[data string]];
|
if ([CPPlatform isBrowser])
|
||||||
|
[_writeRequest setHTTPMethod:@"POST"];
|
||||||
|
else
|
||||||
|
[_writeRequest setHTTPMethod:@"PUT"];
|
||||||
|
|
||||||
|
[_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.
|
||||||
@@ -432,6 +563,7 @@ var CPDocumentUntitledCount = 0;
|
|||||||
_writeRequest = nil;
|
_writeRequest = nil;
|
||||||
|
|
||||||
objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo);
|
objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo);
|
||||||
|
[self _sendDocumentSavedNotification:NO];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -448,7 +580,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);
|
||||||
}
|
}
|
||||||
@@ -460,6 +592,7 @@ var CPDocumentUntitledCount = 0;
|
|||||||
_writeRequest = nil;
|
_writeRequest = nil;
|
||||||
|
|
||||||
objj_msgSend(session.delegate, session.didSaveSelector, self, YES, session.contextInfo);
|
objj_msgSend(session.delegate, session.didSaveSelector, self, YES, session.contextInfo);
|
||||||
|
[self _sendDocumentSavedNotification:YES];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,6 +620,7 @@ var CPDocumentUntitledCount = 0;
|
|||||||
alert("There was an error saving the document.");
|
alert("There was an error saving the document.");
|
||||||
|
|
||||||
objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo);
|
objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo);
|
||||||
|
[self _sendDocumentSavedNotification:NO];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -502,7 +636,7 @@ var CPDocumentUntitledCount = 0;
|
|||||||
|
|
||||||
// Managing Document Status
|
// Managing Document Status
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if there are any unsaved changes.
|
Returns \c YES if there are any unsaved changes.
|
||||||
*/
|
*/
|
||||||
- (BOOL)isDocumentEdited
|
- (BOOL)isDocumentEdited
|
||||||
{
|
{
|
||||||
@@ -548,7 +682,7 @@ var CPDocumentUntitledCount = 0;
|
|||||||
|
|
||||||
// Working with Undo Manager
|
// Working with Undo Manager
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the document has a
|
Returns \c YES if the document has a
|
||||||
CPUndoManager.
|
CPUndoManager.
|
||||||
*/
|
*/
|
||||||
- (BOOL)hasUndoManager
|
- (BOOL)hasUndoManager
|
||||||
@@ -558,7 +692,7 @@ var CPDocumentUntitledCount = 0;
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether the document should have a CPUndoManager.
|
Sets whether the document should have a CPUndoManager.
|
||||||
@param aFlag <code>YES</code> makes the document have an undo manager
|
@param aFlag \c YES makes the document have an undo manager
|
||||||
*/
|
*/
|
||||||
- (void)setHasUndoManager:(BOOL)aFlag
|
- (void)setHasUndoManager:(BOOL)aFlag
|
||||||
{
|
{
|
||||||
@@ -642,7 +776,7 @@ var CPDocumentUntitledCount = 0;
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the document's undo manager. If the document
|
Returns the document's undo manager. If the document
|
||||||
should have one, but the manager is <code>nil</code>, it
|
should have one, but the manager is \c nil, it
|
||||||
will be created and then returned.
|
will be created and then returned.
|
||||||
@return the document's undo manager
|
@return the document's undo manager
|
||||||
*/
|
*/
|
||||||
@@ -666,11 +800,16 @@ var CPDocumentUntitledCount = 0;
|
|||||||
// Handling User Actions
|
// Handling User Actions
|
||||||
/*!
|
/*!
|
||||||
Saves the document. If the document does not
|
Saves the document. If the document does not
|
||||||
have a file path to save to (<code>fileURL</code>)
|
have a file path to save to (\c fileURL)
|
||||||
then <code>saveDocumentAs:</code> will be called.
|
then \c -saveDocumentAs: will be called.
|
||||||
@param aSender the object requesting the save
|
@param aSender the object requesting the save
|
||||||
*/
|
*/
|
||||||
- (void)saveDocument:(id)aSender
|
- (void)saveDocument:(id)aSender
|
||||||
|
{
|
||||||
|
[self saveDocumentWithDelegate:nil didSaveSelector:nil contextInfo:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)saveDocumentWithDelegate:(id)delegate didSaveSelector:(SEL)didSaveSelector contextInfo:(Object)contextInfo
|
||||||
{
|
{
|
||||||
if (_fileURL)
|
if (_fileURL)
|
||||||
{
|
{
|
||||||
@@ -678,10 +817,10 @@ var CPDocumentUntitledCount = 0;
|
|||||||
postNotificationName:CPDocumentWillSaveNotification
|
postNotificationName:CPDocumentWillSaveNotification
|
||||||
object:self];
|
object:self];
|
||||||
|
|
||||||
[self saveToURL:_fileURL ofType:[self fileType] forSaveOperation:CPSaveOperation delegate:self didSaveSelector:@selector(document:didSave:contextInfo:) contextInfo:NULL];
|
[self saveToURL:_fileURL ofType:[self fileType] forSaveOperation:CPSaveOperation delegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
[self saveDocumentAs:self];
|
[self _saveDocumentAsWithDelegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -690,22 +829,30 @@ var CPDocumentUntitledCount = 0;
|
|||||||
*/
|
*/
|
||||||
- (void)saveDocumentAs:(id)aSender
|
- (void)saveDocumentAs:(id)aSender
|
||||||
{
|
{
|
||||||
_documentName = window.prompt("Document Name:");
|
[self _saveDocumentAsWithDelegate:nil didSaveSelector:nil contextInfo:nil];
|
||||||
|
}
|
||||||
|
|
||||||
if (!_documentName)
|
- (void)_saveDocumentAsWithDelegate:(id)delegate didSaveSelector:(SEL)didSaveSelector contextInfo:(Object)contextInfo
|
||||||
|
{
|
||||||
|
var savePanel = [CPSavePanel savePanel],
|
||||||
|
response = [savePanel runModal];
|
||||||
|
|
||||||
|
if (!response)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var saveURL = [savePanel URL];
|
||||||
|
|
||||||
[[CPNotificationCenter defaultCenter]
|
[[CPNotificationCenter defaultCenter]
|
||||||
postNotificationName:CPDocumentWillSaveNotification
|
postNotificationName:CPDocumentWillSaveNotification
|
||||||
object:self];
|
object:self];
|
||||||
|
|
||||||
[self saveToURL:[self proposedFileURL] ofType:[self fileType] forSaveOperation:CPSaveAsOperation delegate:self didSaveSelector:@selector(document:didSave:contextInfo:) contextInfo:NULL];
|
[self saveToURL:saveURL ofType:[self fileType] forSaveOperation:CPSaveAsOperation delegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ignore
|
@ignore
|
||||||
*/
|
*/
|
||||||
- (void)document:(id)aDocument didSave:(BOOL)didSave contextInfo:(id)aContextInfo
|
- (void)_sendDocumentSavedNotification:(BOOL)didSave
|
||||||
{
|
{
|
||||||
if (didSave)
|
if (didSave)
|
||||||
[[CPNotificationCenter defaultCenter]
|
[[CPNotificationCenter defaultCenter]
|
||||||
@@ -719,6 +866,71 @@ var CPDocumentUntitledCount = 0;
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@implementation CPDocument (ClosingDocuments)
|
||||||
|
|
||||||
|
- (void)close
|
||||||
|
{
|
||||||
|
[_windowControllers makeObjectsPerformSelector:@selector(removeDocumentAndCloseIfNecessary:) withObject:self];
|
||||||
|
[[CPDocumentController sharedDocumentController] removeDocument:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)shouldCloseWindowController:(CPWindowController)controller delegate:(id)delegate shouldCloseSelector:(SEL)selector contextInfo:(Object)info
|
||||||
|
{
|
||||||
|
if ([controller shouldCloseDocument] || ([_windowControllers count] < 2 && [_windowControllers indexOfObject:controller] !== CPNotFound))
|
||||||
|
[self canCloseDocumentWithDelegate:self shouldCloseSelector:@selector(_document:shouldClose:context:) contextInfo:{delegate:delegate, selector:selector, context:info}];
|
||||||
|
|
||||||
|
else if ([delegate respondsToSelector:selector])
|
||||||
|
objj_msgSend(delegate, selector, self, YES, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_document:(CPDocument)aDocument shouldClose:(BOOL)shouldClose context:(Object)context
|
||||||
|
{
|
||||||
|
if (aDocument === self && shouldClose)
|
||||||
|
[self close];
|
||||||
|
|
||||||
|
objj_msgSend(context.delegate, context.selector, aDocument, shouldClose, context.context);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)canCloseDocumentWithDelegate:(id)aDelegate shouldCloseSelector:(SEL)aSelector contextInfo:(Object)context
|
||||||
|
{
|
||||||
|
if (![self isDocumentEdited])
|
||||||
|
return [aDelegate respondsToSelector:aSelector] && objj_msgSend(aDelegate, aSelector, self, YES, context);
|
||||||
|
|
||||||
|
_canCloseAlert = [[CPAlert alloc] init];
|
||||||
|
|
||||||
|
[_canCloseAlert setDelegate:self];
|
||||||
|
[_canCloseAlert setAlertStyle:CPWarningAlertStyle];
|
||||||
|
[_canCloseAlert setTitle:@"Unsaved Document"];
|
||||||
|
[_canCloseAlert setMessageText:@"Do you want to save the changes you've made to the document \"" + ([self displayName] || [self fileName]) + "\"?"];
|
||||||
|
|
||||||
|
[_canCloseAlert addButtonWithTitle:@"Save"];
|
||||||
|
[_canCloseAlert addButtonWithTitle:@"Cancel"];
|
||||||
|
[_canCloseAlert addButtonWithTitle:@"Don't Save"];
|
||||||
|
|
||||||
|
_canCloseAlert._context = {delegate:aDelegate, selector:aSelector, context:context};
|
||||||
|
|
||||||
|
[_canCloseAlert runModal];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)alertDidEnd:(CPAlert)alert returnCode:(int)returnCode
|
||||||
|
{
|
||||||
|
if (alert !== _canCloseAlert)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var delegate = alert._context.delegate,
|
||||||
|
selector = alert._context.selector,
|
||||||
|
context = alert._context.context;
|
||||||
|
|
||||||
|
if (returnCode === 0)
|
||||||
|
[self saveDocumentWithDelegate:delegate didSaveSelector:selector contextInfo:context];
|
||||||
|
else
|
||||||
|
objj_msgSend(delegate, selector, self, returnCode === 2, context);
|
||||||
|
|
||||||
|
_canCloseAlert = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
var _CPReadSessionMake = function(aType, aDelegate, aDidReadSelector, aContextInfo)
|
var _CPReadSessionMake = function(aType, aDelegate, aDidReadSelector, aContextInfo)
|
||||||
{
|
{
|
||||||
return { fileType:aType, delegate:aDelegate, didReadSelector:aDidReadSelector, contextInfo:aContextInfo };
|
return { fileType:aType, delegate:aDelegate, didReadSelector:aDidReadSelector, contextInfo:aContextInfo };
|
||||||
|
|||||||
+217
-15
@@ -24,6 +24,7 @@
|
|||||||
@import <Foundation/CPBundle.j>
|
@import <Foundation/CPBundle.j>
|
||||||
|
|
||||||
@import "CPDocument.j"
|
@import "CPDocument.j"
|
||||||
|
@import "CPOpenPanel.j";
|
||||||
|
|
||||||
|
|
||||||
var CPSharedDocumentController = nil;
|
var CPSharedDocumentController = nil;
|
||||||
@@ -37,6 +38,7 @@ var CPSharedDocumentController = nil;
|
|||||||
{
|
{
|
||||||
CPArray _documents;
|
CPArray _documents;
|
||||||
CPArray _documentTypes;
|
CPArray _documentTypes;
|
||||||
|
CPArray _localDocumentURLs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -61,11 +63,27 @@ var CPSharedDocumentController = nil;
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_documents = [[CPArray alloc] init];
|
|
||||||
|
|
||||||
if (!CPSharedDocumentController)
|
if (!CPSharedDocumentController)
|
||||||
CPSharedDocumentController = self;
|
CPSharedDocumentController = self;
|
||||||
|
|
||||||
|
_localDocumentURLs = [CPSet set];
|
||||||
|
|
||||||
|
if (window.localStorage)
|
||||||
|
{
|
||||||
|
var localDocumentURLs = localStorage.getItem(CPDocumentControllerLocalDocumentURLsKey);
|
||||||
|
|
||||||
|
if (localDocumentURLs)
|
||||||
|
{
|
||||||
|
localDocumentURLs = JSON.parse(localDocumentURLs);
|
||||||
|
|
||||||
|
var count = [localDocumentURLs count];
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
[_localDocumentURLs addObject:new CFURL(localDocumentURLs[count])];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_documents = [];
|
||||||
_documentTypes = [[[CPBundle mainBundle] infoDictionary] objectForKey:@"CPBundleDocumentTypes"];
|
_documentTypes = [[[CPBundle mainBundle] infoDictionary] objectForKey:@"CPBundleDocumentTypes"];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
@@ -78,7 +96,7 @@ var CPSharedDocumentController = nil;
|
|||||||
method searches documents already open. It does not
|
method searches documents already open. It does not
|
||||||
open the document at the URL if it is not already open.
|
open the document at the URL if it is not already open.
|
||||||
@param aURL the url of the document
|
@param aURL the url of the document
|
||||||
@return the document, or <code>nil</code> if such a document is not open
|
@return the document, or \c nil if such a document is not open
|
||||||
*/
|
*/
|
||||||
- (CPDocument)documentForURL:(CPURL)aURL
|
- (CPDocument)documentForURL:(CPURL)aURL
|
||||||
{
|
{
|
||||||
@@ -144,6 +162,11 @@ var CPSharedDocumentController = nil;
|
|||||||
var type = [self typeForContentsOfURL:anAbsoluteURL error:anError];
|
var type = [self typeForContentsOfURL:anAbsoluteURL error:anError];
|
||||||
|
|
||||||
result = [self makeDocumentWithContentsOfURL:anAbsoluteURL ofType:type delegate:self didReadSelector:@selector(document:didRead:contextInfo:) contextInfo:[CPDictionary dictionaryWithObject:shouldDisplay forKey:@"shouldDisplay"]];
|
result = [self makeDocumentWithContentsOfURL:anAbsoluteURL ofType:type delegate:self didReadSelector:@selector(document:didRead:contextInfo:) contextInfo:[CPDictionary dictionaryWithObject:shouldDisplay forKey:@"shouldDisplay"]];
|
||||||
|
|
||||||
|
[self addDocument:result];
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
[self noteNewRecentDocument:result];
|
||||||
}
|
}
|
||||||
else if (shouldDisplay)
|
else if (shouldDisplay)
|
||||||
[result showWindows];
|
[result showWindows];
|
||||||
@@ -157,7 +180,7 @@ var CPSharedDocumentController = nil;
|
|||||||
@param anAbsoluteURL the document URL
|
@param anAbsoluteURL the document URL
|
||||||
@param absoluteContentsURL the location of the document's contents
|
@param absoluteContentsURL the location of the document's contents
|
||||||
@param anError not used
|
@param anError not used
|
||||||
@return the loaded document or <code>nil</code> if there was an error
|
@return the loaded document or \c nil if there was an error
|
||||||
*/
|
*/
|
||||||
- (CPDocument)reopenDocumentForURL:(CPURL)anAbsoluteURL withContentsOfURL:(CPURL)absoluteContentsURL error:(CPError)anError
|
- (CPDocument)reopenDocumentForURL:(CPURL)anAbsoluteURL withContentsOfURL:(CPURL)absoluteContentsURL error:(CPError)anError
|
||||||
{
|
{
|
||||||
@@ -187,7 +210,7 @@ var CPSharedDocumentController = nil;
|
|||||||
@param aDelegate receives a callback after the load has completed
|
@param aDelegate receives a callback after the load has completed
|
||||||
@param aSelector the selector to invoke for the callback
|
@param aSelector the selector to invoke for the callback
|
||||||
@param aContextInfo an object passed as an argument for the callback
|
@param aContextInfo an object passed as an argument for the callback
|
||||||
@return a new document or <code>nil</code> if there was an error
|
@return a new document or \c nil if there was an error
|
||||||
*/
|
*/
|
||||||
- (CPDocument)makeDocumentForURL:(CPURL)anAbsoluteURL withContentsOfURL:(CPURL)absoluteContentsURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aSelector contextInfo:(id)aContextInfo
|
- (CPDocument)makeDocumentForURL:(CPURL)anAbsoluteURL withContentsOfURL:(CPURL)absoluteContentsURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aSelector contextInfo:(id)aContextInfo
|
||||||
{
|
{
|
||||||
@@ -203,7 +226,6 @@ var CPSharedDocumentController = nil;
|
|||||||
if (!didRead)
|
if (!didRead)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[self addDocument:aDocument];
|
|
||||||
[aDocument makeWindowControllers];
|
[aDocument makeWindowControllers];
|
||||||
|
|
||||||
if ([aContextInfo objectForKey:@"shouldDisplay"])
|
if ([aContextInfo objectForKey:@"shouldDisplay"])
|
||||||
@@ -214,11 +236,25 @@ var CPSharedDocumentController = nil;
|
|||||||
Opens a new document in the application.
|
Opens a new document in the application.
|
||||||
@param aSender the requesting object
|
@param aSender the requesting object
|
||||||
*/
|
*/
|
||||||
- (CFAction)newDocument:(id)aSender
|
- (@action)newDocument:(id)aSender
|
||||||
{
|
{
|
||||||
[self openUntitledDocumentOfType:[[_documentTypes objectAtIndex:0] objectForKey:@"CPBundleTypeName"] display:YES];
|
[self openUntitledDocumentOfType:[[_documentTypes objectAtIndex:0] objectForKey:@"CPBundleTypeName"] display:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-(void)openDocument:(id)aSender
|
||||||
|
{
|
||||||
|
var openPanel = [CPOpenPanel openPanel];
|
||||||
|
|
||||||
|
[openPanel runModal];
|
||||||
|
|
||||||
|
var URLs = [openPanel URLs],
|
||||||
|
index = 0,
|
||||||
|
count = [URLs count];
|
||||||
|
|
||||||
|
for (; index < count; ++index)
|
||||||
|
[self openDocumentWithContentsOfURL:[CPURL URLWithString:URLs[index]] display:YES error:nil];
|
||||||
|
}
|
||||||
|
|
||||||
// Managing Documents
|
// Managing Documents
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -231,7 +267,7 @@ var CPSharedDocumentController = nil;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Adds <code>aDocument</code> under the control of the receiver.
|
Adds \c aDocument under the control of the receiver.
|
||||||
@param aDocument the document to add
|
@param aDocument the document to add
|
||||||
*/
|
*/
|
||||||
- (void)addDocument:(CPDocument)aDocument
|
- (void)addDocument:(CPDocument)aDocument
|
||||||
@@ -240,7 +276,7 @@ var CPSharedDocumentController = nil;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Removes <code>aDocument</code> from the control of the receiver.
|
Removes \c aDocument from the control of the receiver.
|
||||||
@param aDocument the document to remove
|
@param aDocument the document to remove
|
||||||
*/
|
*/
|
||||||
- (void)removeDocument:(CPDocument)aDocument
|
- (void)removeDocument:(CPDocument)aDocument
|
||||||
@@ -258,7 +294,8 @@ var CPSharedDocumentController = nil;
|
|||||||
var index = 0,
|
var index = 0,
|
||||||
count = _documentTypes.length,
|
count = _documentTypes.length,
|
||||||
|
|
||||||
extension = [[anAbsoluteURL pathExtension] lowercaseString];
|
extension = [[anAbsoluteURL pathExtension] lowercaseString],
|
||||||
|
starType = nil;
|
||||||
|
|
||||||
for (; index < count; ++index)
|
for (; index < count; ++index)
|
||||||
{
|
{
|
||||||
@@ -268,12 +305,17 @@ var CPSharedDocumentController = nil;
|
|||||||
extensionCount = extensions.length;
|
extensionCount = extensions.length;
|
||||||
|
|
||||||
for (; extensionIndex < extensionCount; ++extensionIndex)
|
for (; extensionIndex < extensionCount; ++extensionIndex)
|
||||||
if ([extensions[extensionIndex] lowercaseString] == extension)
|
{
|
||||||
|
var thisExtension = [extensions[extensionIndex] lowercaseString];
|
||||||
|
if (thisExtension === extension)
|
||||||
return [documentType objectForKey:@"CPBundleTypeName"];
|
return [documentType objectForKey:@"CPBundleTypeName"];
|
||||||
|
|
||||||
|
if (thisExtension === "****")
|
||||||
|
starType = [documentType objectForKey:@"CPBundleTypeName"];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME?
|
return starType || [self defaultType];
|
||||||
return [self defaultType];//nil;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Managing Document Types
|
// Managing Document Types
|
||||||
@@ -296,9 +338,9 @@ var CPSharedDocumentController = nil;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the CPDocument subclass associated with <code>aType</code>.
|
Returns the CPDocument subclass associated with \c aType.
|
||||||
@param aType the type of document
|
@param aType the type of document
|
||||||
@return a Cappuccino Class object, or <code>nil</code> if no match was found
|
@return a Cappuccino Class object, or \c nil if no match was found
|
||||||
*/
|
*/
|
||||||
- (Class)documentClassForType:(CPString)aType
|
- (Class)documentClassForType:(CPString)aType
|
||||||
{
|
{
|
||||||
@@ -308,3 +350,163 @@ var CPSharedDocumentController = nil;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@implementation CPDocumentController (Closing)
|
||||||
|
|
||||||
|
- (void)closeAllDocumentsWithDelegate:(id)aDelegate didCloseAllSelector:(SEL)didCloseSelector contextInfo:(Object)info
|
||||||
|
{
|
||||||
|
var context = {
|
||||||
|
delegate: aDelegate,
|
||||||
|
selector: didCloseSelector,
|
||||||
|
context: info
|
||||||
|
};
|
||||||
|
|
||||||
|
[self _closeDocumentsStartingWith:nil shouldClose:YES context:context];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursive callback method. Start it by passing in a document of nil.
|
||||||
|
- (void)_closeDocumentsStartingWith:(CPDocument)aDocument shouldClose:(BOOL)shouldClose context:(Object)context
|
||||||
|
{
|
||||||
|
if (shouldClose)
|
||||||
|
{
|
||||||
|
[aDocument close];
|
||||||
|
|
||||||
|
if ([[self documents] count] > 0)
|
||||||
|
{
|
||||||
|
[[[self documents] lastObject] canCloseDocumentWithDelegate:self
|
||||||
|
shouldCloseSelector:@selector(_closeDocumentsStartingWith:shouldClose:context:)
|
||||||
|
contextInfo:context];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([context.delegate respondsToSelector:context.selector])
|
||||||
|
objj_msgSend(context.delegate, context.selector, self, [[self documents] count] === 0, context.context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation CPDocumentController (Recents)
|
||||||
|
|
||||||
|
- (CPArray)recentDocumentURLs
|
||||||
|
{
|
||||||
|
// FIXME move this to CP land
|
||||||
|
if (typeof window["cpRecentDocumentURLs"] === 'function')
|
||||||
|
return window.cpRecentDocumentURLs();
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)clearRecentDocuments:(id)sender
|
||||||
|
{
|
||||||
|
if (typeof window["cpClearRecentDocuments"] === 'function')
|
||||||
|
window.cpClearRecentDocuments();
|
||||||
|
|
||||||
|
[self _updateRecentDocumentsMenu];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)noteNewRecentDocument:(CPDocument)aDocument
|
||||||
|
{
|
||||||
|
[self noteNewRecentDocumentURL:[[aDocument fileURL] absoluteString]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)noteNewRecentDocumentURL:(CPString)aURL
|
||||||
|
{
|
||||||
|
if (typeof window["cpNoteNewRecentDocumentPath"] === 'function')
|
||||||
|
window.cpNoteNewRecentDocumentPath(aURL);
|
||||||
|
|
||||||
|
[self _updateRecentDocumentsMenu];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_removeAllRecentDocumentsFromMenu:(CPMenu)aMenu
|
||||||
|
{
|
||||||
|
var items = [aMenu itemArray],
|
||||||
|
count = [items count];
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
{
|
||||||
|
var item = items[count];
|
||||||
|
|
||||||
|
if ([item action] === @selector(_openRecentDocument:))
|
||||||
|
[aMenu removeItemAtIndex:count];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_updateRecentDocumentsMenu
|
||||||
|
{
|
||||||
|
var menu = [[CPApp mainMenu] _menuWithName:@"_CPRecentDocumentsMenu"],
|
||||||
|
recentDocuments = [self recentDocumentURLs],
|
||||||
|
menuItems = [menu itemArray],
|
||||||
|
documentCount = [recentDocuments count],
|
||||||
|
menuItemCount = [menuItems count];
|
||||||
|
|
||||||
|
[self _removeAllRecentDocumentsFromMenu:menu];
|
||||||
|
|
||||||
|
if (menuItemCount)
|
||||||
|
{
|
||||||
|
if (!documentCount)
|
||||||
|
{
|
||||||
|
if ([menuItems[0] isSeparatorItem])
|
||||||
|
[menu removeItemAtIndex:0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (![menuItems[0] isSeparatorItem])
|
||||||
|
[menu insertItem:[CPMenuItem separatorItem] atIndex:0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (documentCount--)
|
||||||
|
{
|
||||||
|
var path = recentDocuments[documentCount],
|
||||||
|
item = [[CPMenuItem alloc] initWithTitle:[path lastPathComponent] action:@selector(_openRecentDocument:) keyEquivalent:nil];
|
||||||
|
|
||||||
|
[item setTag:path];
|
||||||
|
[menu insertItem:item atIndex:0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_openRecentDocument:(id)sender
|
||||||
|
{
|
||||||
|
[self openDocumentWithContentsOfURL:[sender tag] display:YES error:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var CPDocumentControllerLocalDocumentURLsKey = @"Cappuccino.CPDocumentController.documentURLs";
|
||||||
|
|
||||||
|
@implementation CPDocumentController (LocalStorage)
|
||||||
|
|
||||||
|
- (void)_addLocalDocumentURL:(CPURL)aURL
|
||||||
|
{
|
||||||
|
if (!window.localStorage)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_localDocumentURLs addObject:aURL];
|
||||||
|
|
||||||
|
var stringURLs = [],
|
||||||
|
URL = nil,
|
||||||
|
URLEnumerator = [_localDocumentURLs objectEnumerator];
|
||||||
|
|
||||||
|
while (URL = [URLEnumerator nextObject])
|
||||||
|
stringURLs.push(URL + "");
|
||||||
|
|
||||||
|
localStorage.setItem(CPDocumentControllerLocalDocumentURLsKey, JSON.stringify(stringURLs));
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_removeLocalDocumentURL:(CPURL)aURL
|
||||||
|
{
|
||||||
|
if (!window.localStorage)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_localDocumentURLs removeObject:aURL];
|
||||||
|
|
||||||
|
localStorage.setItem(CPDocumentControllerLocalDocumentURLsKey, JSON.stringify([self allObjects]));
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPSet)localDocumentURLs
|
||||||
|
{
|
||||||
|
return [_localDocumentURLs copy];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|||||||
+251
-143
@@ -26,73 +26,28 @@
|
|||||||
@import <AppKit/CPImageView.j>
|
@import <AppKit/CPImageView.j>
|
||||||
|
|
||||||
#import "CoreGraphics/CGGeometry.h"
|
#import "CoreGraphics/CGGeometry.h"
|
||||||
|
#import "Platform/Platform.h"
|
||||||
|
|
||||||
|
|
||||||
|
CPDragOperationNone = 0,
|
||||||
|
CPDragOperationCopy = 1 << 1,
|
||||||
|
CPDragOperationLink = 1 << 1,
|
||||||
|
CPDragOperationGeneric = 1 << 2,
|
||||||
|
CPDragOperationPrivate = 1 << 3,
|
||||||
|
CPDragOperationMove = 1 << 4,
|
||||||
|
CPDragOperationDelete = 1 << 5,
|
||||||
|
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 CPSharedDragServer = nil;
|
var CPDragServerPreviousEvent = nil,
|
||||||
|
CPDragServerAutoscrollInterval = nil;
|
||||||
var CPDragServerView = nil,
|
/*
|
||||||
CPDragServerSource = nil,
|
|
||||||
CPDragServerWindow = nil,
|
|
||||||
CPDragServerOffset = nil,
|
|
||||||
CPDragServerLocation = nil,
|
|
||||||
CPDragServerPasteboard = nil,
|
|
||||||
CPDragServerDestination = nil,
|
|
||||||
CPDragServerDraggingInfo = nil,
|
|
||||||
CPDragServerPreviousEvent = nil,
|
|
||||||
CPDragServerAutoscrollInterval = nil;
|
|
||||||
|
|
||||||
var CPDragServerIsDraggingImage = NO,
|
|
||||||
|
|
||||||
CPDragServerShouldSendDraggedViewMovedTo = NO,
|
|
||||||
CPDragServerShouldSendDraggedImageMovedTo = NO,
|
|
||||||
|
|
||||||
CPDragServerShouldSendDraggedViewEndedAtOperation = NO,
|
|
||||||
CPDragServerShouldSendDraggedImageEndedAtOperation = NO;
|
|
||||||
|
|
||||||
var CPDragServerAutoscroll = function()
|
var CPDragServerAutoscroll = function()
|
||||||
{
|
{
|
||||||
[CPDragServerSource autoscroll:CPDragServerPreviousEvent];
|
[CPDragServerSource autoscroll:CPDragServerPreviousEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
var CPDragServerStartDragging = function(anEvent)
|
|
||||||
{
|
|
||||||
CPDragServerUpdateDragging(anEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
var CPDragServerUpdateDragging = function(anEvent)
|
|
||||||
{
|
|
||||||
// If this is a mouse up, then complete the drag.
|
|
||||||
if([anEvent type] == CPLeftMouseUp)
|
|
||||||
{
|
|
||||||
if (CPDragServerAutoscrollInterval !== nil)
|
|
||||||
clearInterval(CPDragServerAutoscrollInterval);
|
|
||||||
|
|
||||||
CPDragServerAutoscrollInterval = nil;
|
|
||||||
|
|
||||||
CPDragServerLocation = [DRAGGING_WINDOW(CPDragServerDestination) convertBridgeToBase:[[anEvent window] convertBaseToBridge:[anEvent locationInWindow]]];
|
|
||||||
|
|
||||||
[CPDragServerView removeFromSuperview];
|
|
||||||
[CPSharedDragServer._dragWindow orderOut:nil];
|
|
||||||
|
|
||||||
if (CPDragServerDestination &&
|
|
||||||
(![CPDragServerDestination respondsToSelector:@selector(prepareForDragOperation:)] || [CPDragServerDestination prepareForDragOperation:CPDragServerDraggingInfo]) &&
|
|
||||||
(![CPDragServerDestination respondsToSelector:@selector(performDragOperation:)] || [CPDragServerDestination performDragOperation:CPDragServerDraggingInfo]) &&
|
|
||||||
[CPDragServerDestination respondsToSelector:@selector(concludeDragOperation:)])
|
|
||||||
[CPDragServerDestination concludeDragOperation:CPDragServerDraggingInfo];
|
|
||||||
|
|
||||||
if (CPDragServerShouldSendDraggedImageEndedAtOperation)
|
|
||||||
[CPDragServerSource draggedImage:[CPDragServerView image] endedAt:CPDragServerLocation operation:NO];
|
|
||||||
else if (CPDragServerShouldSendDraggedViewEndedAtOperation)
|
|
||||||
[CPDragServerSource draggedView:CPDragServerView endedAt:CPDragServerLocation operation:NO];
|
|
||||||
|
|
||||||
CPDragServerIsDraggingImage = NO;
|
|
||||||
CPDragServerDestination = nil;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CPDragServerAutoscrollInterval === nil)
|
if (CPDragServerAutoscrollInterval === nil)
|
||||||
{
|
{
|
||||||
if ([CPDragServerSource respondsToSelector:@selector(autoscroll:)])
|
if ([CPDragServerSource respondsToSelector:@selector(autoscroll:)])
|
||||||
@@ -101,43 +56,16 @@ var CPDragServerUpdateDragging = function(anEvent)
|
|||||||
|
|
||||||
CPDragServerPreviousEvent = anEvent;
|
CPDragServerPreviousEvent = anEvent;
|
||||||
|
|
||||||
// If we're not a mouse up, then we're going to want to grab the next event.
|
if (CPDragServerAutoscrollInterval !== nil)
|
||||||
[CPApp setCallback:CPDragServerUpdateDragging
|
clearInterval(CPDragServerAutoscrollInterval);
|
||||||
forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask
|
|
||||||
untilDate:nil inMode:0 dequeue:NO];
|
|
||||||
|
|
||||||
var location = [anEvent locationInWindow],
|
CPDragServerAutoscrollInterval = nil;
|
||||||
operation =
|
*/
|
||||||
bridgeLocation = [[anEvent window] convertBaseToBridge:location];
|
|
||||||
|
|
||||||
// We have to convert base to bridge since the drag event comes from the source window, not the drag window.
|
var CPSharedDragServer = nil;
|
||||||
var draggingDestination = [[CPDOMWindowBridge sharedDOMWindowBridge] _dragHitTest:bridgeLocation pasteboard:CPDragServerPasteboard];
|
|
||||||
|
|
||||||
CPDragServerLocation = [DRAGGING_WINDOW(draggingDestination) convertBridgeToBase:bridgeLocation];
|
var CPDragServerSource = nil;
|
||||||
|
var CPDragServerDraggingInfo = nil;
|
||||||
if(draggingDestination != CPDragServerDestination)
|
|
||||||
{
|
|
||||||
if (CPDragServerDestination && [CPDragServerDestination respondsToSelector:@selector(draggingExited:)])
|
|
||||||
[CPDragServerDestination draggingExited:CPDragServerDraggingInfo];
|
|
||||||
|
|
||||||
CPDragServerDestination = draggingDestination;
|
|
||||||
|
|
||||||
if (CPDragServerDestination && [CPDragServerDestination respondsToSelector:@selector(draggingEntered:)])
|
|
||||||
[CPDragServerDestination draggingEntered:CPDragServerDraggingInfo];
|
|
||||||
}
|
|
||||||
else if (CPDragServerDestination && [CPDragServerDestination respondsToSelector:@selector(draggingUpdated:)])
|
|
||||||
[CPDragServerDestination draggingUpdated:CPDragServerDraggingInfo];
|
|
||||||
|
|
||||||
location.x -= CPDragServerOffset.x;
|
|
||||||
location.y -= CPDragServerOffset.y;
|
|
||||||
|
|
||||||
[CPDragServerView setFrameOrigin:location];
|
|
||||||
|
|
||||||
if (CPDragServerShouldSendDraggedImageMovedTo)
|
|
||||||
[CPDragServerSource draggedImage:[CPDragServerView image] movedTo:location];
|
|
||||||
else if (CPDragServerShouldSendDraggedViewMovedTo)
|
|
||||||
[CPDragServerSource draggedView:CPDragServerView movedTo:location];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
CPDraggingInfo is a container of information about a specific dragging session.
|
CPDraggingInfo is a container of information about a specific dragging session.
|
||||||
@@ -147,24 +75,36 @@ var CPDragServerUpdateDragging = function(anEvent)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CPPasteboard)draggingPasteboard
|
||||||
|
{
|
||||||
|
if ([CPPlatform supportsDragAndDrop])
|
||||||
|
return [_CPDOMDataTransferPasteboard DOMDataTransferPasteboard];
|
||||||
|
|
||||||
|
return [[CPDragServer sharedDragServer] draggingPasteboard];
|
||||||
|
}
|
||||||
|
|
||||||
- (id)draggingSource
|
- (id)draggingSource
|
||||||
{
|
{
|
||||||
return CPDragServerSource;
|
return [[CPDragServer sharedDragServer] draggingSource];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
- (unsigned)draggingSourceOperationMask
|
||||||
|
*/
|
||||||
|
|
||||||
- (CPPoint)draggingLocation
|
- (CPPoint)draggingLocation
|
||||||
{
|
{
|
||||||
return CPDragServerLocation;
|
return [[CPDragServer sharedDragServer] draggingLocation];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPPasteboard)draggingPasteboard
|
- (CPWindow)draggingDestinationWindow
|
||||||
{
|
{
|
||||||
return CPDragServerPasteboard;
|
return DRAGGING_WINDOW([[CPDragServer sharedDragServer] draggingDestination]);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPImage)draggedImage
|
- (CPImage)draggedImage
|
||||||
{
|
{
|
||||||
return [CPDragServerView image];
|
return [[self draggedView] image];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGPoint)draggedImageLocation
|
- (CGPoint)draggedImageLocation
|
||||||
@@ -172,22 +112,48 @@ var CPDragServerUpdateDragging = function(anEvent)
|
|||||||
return [self draggedViewLocation];
|
return [self draggedViewLocation];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGPoint)draggedViewLocation
|
|
||||||
{
|
|
||||||
return [DRAGGING_WINDOW(CPDragServerDestination) convertBridgeToBase:[CPDragServerView frame].origin];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPView)draggedView
|
- (CPView)draggedView
|
||||||
{
|
{
|
||||||
return CPDragServerView;
|
return [[CPDragServer sharedDragServer] draggedView];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGPoint)draggedViewLocation
|
||||||
|
{
|
||||||
|
var dragServer = [CPDragServer sharedDragServer];
|
||||||
|
|
||||||
|
return [DRAGGING_WINDOW([dragServer draggingDestination]) convertPlatformWindowToBase:[[dragServer draggedView] frame].origin];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||||
|
CPDraggingSource_draggedImage_endedAt_operation_ = 1 << 1,
|
||||||
|
CPDraggingSource_draggedView_movedTo_ = 1 << 2,
|
||||||
|
CPDraggingSource_draggedView_endedAt_operation_ = 1 << 3;
|
||||||
|
|
||||||
@implementation CPDragServer : CPObject
|
@implementation CPDragServer : CPObject
|
||||||
{
|
{
|
||||||
CPWindow _dragWindow;
|
BOOL _isDragging @accessors(readonly, getter=isDragging);
|
||||||
CPImageView _imageView;
|
|
||||||
|
CPWindow _draggedWindow @accessors(readonly, getter=draggedWindow);
|
||||||
|
CPView _draggedView @accessors(readonly, getter=draggedView);
|
||||||
|
CPImageView _imageView;
|
||||||
|
|
||||||
|
BOOL _isDraggingImage;
|
||||||
|
|
||||||
|
CGSize _draggingOffset @accessors(readonly, getter=draggingOffset);
|
||||||
|
|
||||||
|
CPPasteboard _draggingPasteboard @accessors(readonly, getter=draggingPasteboard);
|
||||||
|
|
||||||
|
id _draggingSource @accessors(readonly, getter=draggingSource);
|
||||||
|
unsigned _implementedDraggingSourceMethods;
|
||||||
|
|
||||||
|
CGPoint _draggingLocation;
|
||||||
|
id _draggingDestination;
|
||||||
|
|
||||||
|
CGPoint _startDragLocation;
|
||||||
|
BOOL _shouldSlideBack;
|
||||||
|
unsigned _dragOperation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -196,7 +162,7 @@ var CPDragServerUpdateDragging = function(anEvent)
|
|||||||
*/
|
*/
|
||||||
+ (void)initialize
|
+ (void)initialize
|
||||||
{
|
{
|
||||||
if (self != [CPDragServer class])
|
if (self !== [CPDragServer class])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CPDragServerDraggingInfo = [[CPDraggingInfo alloc] init];
|
CPDragServerDraggingInfo = [[CPDraggingInfo alloc] init];
|
||||||
@@ -219,13 +185,105 @@ var CPDragServerUpdateDragging = function(anEvent)
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_dragWindow = [[CPWindow alloc] initWithContentRect:CPRectMakeZero() styleMask:CPBorderlessWindowMask];
|
_draggedWindow = [[CPWindow alloc] initWithContentRect:_CGRectMakeZero() styleMask:CPBorderlessWindowMask];
|
||||||
[_dragWindow setLevel:CPDraggingWindowLevel];
|
|
||||||
|
[_draggedWindow setLevel:CPDraggingWindowLevel];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (id)draggingDestination
|
||||||
|
{
|
||||||
|
return _draggingDestination;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGPoint)draggingLocation
|
||||||
|
{
|
||||||
|
return _draggingLocation
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)draggingStartedInPlatformWindow:(CPPlatformWindow)aPlatformWindow globalLocation:(CGPoint)aLocation
|
||||||
|
{
|
||||||
|
if (_isDraggingImage)
|
||||||
|
{
|
||||||
|
if ([_draggingSource respondsToSelector:@selector(draggedImage:beganAt:)])
|
||||||
|
[_draggingSource draggedImage:[_draggedView image] beganAt:aLocation];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ([_draggingSource respondsToSelector:@selector(draggedView:beganAt:)])
|
||||||
|
[_draggingSource draggedView:_draggedView beganAt:aLocation];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (![CPPlatform supportsDragAndDrop])
|
||||||
|
[_draggedWindow orderFront:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)draggingSourceUpdatedWithGlobalLocation:(CGPoint)aGlobalLocation
|
||||||
|
{
|
||||||
|
if (![CPPlatform supportsDragAndDrop])
|
||||||
|
[_draggedWindow setFrameOrigin:_CGPointMake(aGlobalLocation.x - _draggingOffset.width, aGlobalLocation.y - _draggingOffset.height)];
|
||||||
|
|
||||||
|
if (_implementedDraggingSourceMethods & CPDraggingSource_draggedImage_movedTo_)
|
||||||
|
[_draggingSource draggedImage:[_draggedView image] movedTo:aGlobalLocation];
|
||||||
|
|
||||||
|
else if (_implementedDraggingSourceMethods & CPDraggingSource_draggedView_movedTo_)
|
||||||
|
[_draggingSource draggedView:_draggedView movedTo:aGlobalLocation];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPDragOperation)draggingUpdatedInPlatformWindow:(CPPlatformWindow)aPlatformWindow location:(CGPoint)aLocation
|
||||||
|
{
|
||||||
|
var dragOperation = CPDragOperationCopy;
|
||||||
|
// 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]];
|
||||||
|
|
||||||
|
if (draggingDestination)
|
||||||
|
_draggingLocation = [DRAGGING_WINDOW(draggingDestination) convertPlatformWindowToBase:aLocation];
|
||||||
|
|
||||||
|
if(draggingDestination !== _draggingDestination)
|
||||||
|
{
|
||||||
|
if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingExited:)])
|
||||||
|
[_draggingDestination draggingExited:CPDragServerDraggingInfo];
|
||||||
|
|
||||||
|
_draggingDestination = draggingDestination;
|
||||||
|
|
||||||
|
if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingEntered:)])
|
||||||
|
dragOperation = [_draggingDestination draggingEntered:CPDragServerDraggingInfo];
|
||||||
|
}
|
||||||
|
else if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingUpdated:)])
|
||||||
|
dragOperation = [_draggingDestination draggingUpdated:CPDragServerDraggingInfo];
|
||||||
|
|
||||||
|
if (!_draggingDestination)
|
||||||
|
dragOperation = CPDragOperationNone;
|
||||||
|
|
||||||
|
return dragOperation;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)draggingEndedInPlatformWindow:(CPPlatformWindow)aPlatformWindow globalLocation:(CGPoint)aLocation operation:(CPDragOperation)anOperation
|
||||||
|
{
|
||||||
|
[_draggedView removeFromSuperview];
|
||||||
|
|
||||||
|
if (![CPPlatform supportsDragAndDrop])
|
||||||
|
[_draggedWindow orderOut:self];
|
||||||
|
|
||||||
|
if (_implementedDraggingSourceMethods & CPDraggingSource_draggedImage_endedAt_operation_)
|
||||||
|
[_draggingSource draggedImage:[_draggedView image] endedAt:aLocation operation:anOperation];
|
||||||
|
else if (_implementedDraggingSourceMethods & CPDraggingSource_draggedView_endedAt_operation_)
|
||||||
|
[_draggingSource draggedView:_draggedView endedAt:aLocation operation:anOperation];
|
||||||
|
|
||||||
|
_isDragging = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)performDragOperationInPlatformWindow:(CPPlatformWindow)aPlatformWindow
|
||||||
|
{
|
||||||
|
if (_draggingDestination &&
|
||||||
|
(![_draggingDestination respondsToSelector:@selector(prepareForDragOperation:)] || [_draggingDestination prepareForDragOperation:CPDragServerDraggingInfo]) &&
|
||||||
|
(![_draggingDestination respondsToSelector:@selector(performDragOperation:)] || [_draggingDestination performDragOperation:CPDragServerDraggingInfo]) &&
|
||||||
|
[_draggingDestination respondsToSelector:@selector(concludeDragOperation:)])
|
||||||
|
[_draggingDestination concludeDragOperation:CPDragServerDraggingInfo];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Initiates a drag session.
|
Initiates a drag session.
|
||||||
@param aView the view being dragged
|
@param aView the view being dragged
|
||||||
@@ -235,50 +293,72 @@ var CPDragServerUpdateDragging = function(anEvent)
|
|||||||
@param anEvent
|
@param anEvent
|
||||||
@param aPasteboard the pasteboard that contains the drag data
|
@param aPasteboard the pasteboard that contains the drag data
|
||||||
@param aSourceObject the object where the drag started
|
@param aSourceObject the object where the drag started
|
||||||
@param slideBack if <code>YES</code>, <code>aView</code> slides back to
|
@param slideBack if \c YES, \c aView slides back to
|
||||||
its origin on a failed drop
|
its origin on a failed drop
|
||||||
*/
|
*/
|
||||||
- (void)dragView:(CPView)aView fromWindow:(CPWindow)aWindow at:(CGPoint)viewLocation offset:(CGSize)mouseOffset event:(CPEvent)anEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack
|
- (void)dragView:(CPView)aView fromWindow:(CPWindow)aWindow at:(CGPoint)viewLocation offset:(CGSize)mouseOffset event:(CPEvent)mouseDownEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack
|
||||||
{
|
{
|
||||||
var eventLocation = [anEvent locationInWindow];
|
_isDragging = YES;
|
||||||
|
|
||||||
CPDragServerView = aView;
|
_draggedView = aView;
|
||||||
CPDragServerSource = aSourceObject;
|
_draggingPasteboard = aPasteboard || [CPPasteboard pasteboardWithName:CPDragPboard];
|
||||||
CPDragServerWindow = aWindow;
|
_draggingSource = aSourceObject;
|
||||||
CPDragServerOffset = CPPointMake(eventLocation.x - viewLocation.x, eventLocation.y - viewLocation.y);
|
_draggingDestination = nil;
|
||||||
CPDragServerPasteboard = [CPPasteboard pasteboardWithName:CPDragPboard];//aPasteboard;
|
_shouldSlideBack = slideBack;
|
||||||
|
|
||||||
[_dragWindow setFrameSize:CGSizeMakeCopy([[CPDOMWindowBridge sharedDOMWindowBridge] frame].size)];
|
// The offset is based on the distance from where we want the view to be initially from where the mouse is initially
|
||||||
[_dragWindow orderFront:self];
|
// Hence the use of mouseDownEvent's location and view's location in global coordinates.
|
||||||
|
var mouseDownWindow = [mouseDownEvent window],
|
||||||
|
mouseDownEventLocation = [mouseDownEvent locationInWindow];
|
||||||
|
|
||||||
[aView setFrameOrigin:viewLocation];
|
if (mouseDownEventLocation)
|
||||||
[[_dragWindow contentView] addSubview:aView];
|
|
||||||
|
|
||||||
if (CPDragServerIsDraggingImage)
|
|
||||||
{
|
{
|
||||||
if ([CPDragServerSource respondsToSelector:@selector(draggedImage:beganAt:)])
|
if (mouseDownWindow)
|
||||||
[CPDragServerSource draggedImage:[aView image] beganAt:viewLocation];
|
mouseDownEventLocation = [mouseDownWindow convertBaseToGlobal:mouseDownEventLocation];
|
||||||
|
|
||||||
CPDragServerShouldSendDraggedImageMovedTo = [CPDragServerSource respondsToSelector:@selector(draggedImage:movedTo:)];
|
_draggingOffset = _CGSizeMake(mouseDownEventLocation.x - viewLocation.x, mouseDownEventLocation.y - viewLocation.y);
|
||||||
CPDragServerShouldSendDraggedImageEndedAtOperation = [CPDragServerSource respondsToSelector:@selector(draggedImage:endAt:operation:)];
|
}
|
||||||
|
else
|
||||||
|
_draggingOffset = _CGSizeMakeZero();
|
||||||
|
|
||||||
CPDragServerShouldSendDraggedViewMovedTo = NO;
|
if ([CPPlatform isBrowser])
|
||||||
CPDragServerShouldSendDraggedViewEndedAtOperation = NO;
|
[_draggedWindow setPlatformWindow:[aWindow platformWindow]];
|
||||||
|
|
||||||
|
[aView setFrameOrigin:_CGPointMakeZero()];
|
||||||
|
|
||||||
|
var mouseLocation = [CPEvent mouseLocation];
|
||||||
|
|
||||||
|
// Place it where the mouse pointer is.
|
||||||
|
_startDragLocation = _CGPointMake(mouseLocation.x - _draggingOffset.width, mouseLocation.y - _draggingOffset.height);
|
||||||
|
[_draggedWindow setFrameOrigin:_startDragLocation];
|
||||||
|
[_draggedWindow setFrameSize:[aView frame].size];
|
||||||
|
|
||||||
|
[[_draggedWindow contentView] addSubview:aView];
|
||||||
|
|
||||||
|
_implementedDraggingSourceMethods = 0;
|
||||||
|
|
||||||
|
if (_draggedView === _imageView)
|
||||||
|
{
|
||||||
|
if ([_draggingSource respondsToSelector:@selector(draggedImage:movedTo:)])
|
||||||
|
_implementedDraggingSourceMethods |= CPDraggingSource_draggedImage_movedTo_;
|
||||||
|
|
||||||
|
if ([_draggingSource respondsToSelector:@selector(draggedImage:endedAt:operation:)])
|
||||||
|
_implementedDraggingSourceMethods |= CPDraggingSource_draggedImage_endedAt_operation_;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ([CPDragServerSource respondsToSelector:@selector(draggedView:beganAt:)])
|
if ([_draggingSource respondsToSelector:@selector(draggedView:movedTo:)])
|
||||||
[CPDragServerSource draggedView:aView beganAt:viewLocation];
|
_implementedDraggingSourceMethods |= CPDraggingSource_draggedView_movedTo_;
|
||||||
|
|
||||||
CPDragServerShouldSendDraggedViewMovedTo = [CPDragServerSource respondsToSelector:@selector(draggedView:movedTo:)];
|
if ([_draggingSource respondsToSelector:@selector(draggedView:endedAt:operation:)])
|
||||||
CPDragServerShouldSendDraggedViewEndedAtOperation = [CPDragServerSource respondsToSelector:@selector(draggedView:endedAt:operation:)];
|
_implementedDraggingSourceMethods |= CPDraggingSource_draggedView_endedAt_operation_;
|
||||||
|
|
||||||
|
|
||||||
CPDragServerShouldSendDraggedImageMovedTo = NO;
|
|
||||||
CPDragServerShouldSendDraggedImageEndedAtOperation = NO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CPDragServerStartDragging(anEvent);
|
if (![CPPlatform supportsDragAndDrop])
|
||||||
|
{
|
||||||
|
[self draggingStartedInPlatformWindow:[aWindow platformWindow] globalLocation:mouseLocation];
|
||||||
|
[self trackDragging:mouseDownEvent];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -290,22 +370,50 @@ var CPDragServerUpdateDragging = function(anEvent)
|
|||||||
@param anEvent
|
@param anEvent
|
||||||
@param aPasteboard the pasteboard where the drag data is located
|
@param aPasteboard the pasteboard where the drag data is located
|
||||||
@param aSourceObject the object where the drag started
|
@param aSourceObject the object where the drag started
|
||||||
@param slideBack if <code>YES</code>, <code>aView</code> slides back to
|
@param slideBack if \c YES, \c aView slides back to
|
||||||
its origin on a failed drop
|
its origin on a failed drop
|
||||||
*/
|
*/
|
||||||
- (void)dragImage:(CPImage)anImage fromWindow:(CPWindow)aWindow at:(CGPoint)imageLocation offset:(CGSize)mouseOffset event:(CPEvent)anEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack
|
- (void)dragImage:(CPImage)anImage fromWindow:(CPWindow)aWindow at:(CGPoint)imageLocation offset:(CGSize)mouseOffset event:(CPEvent)anEvent pasteboard:(CPPasteboard)aPasteboard source:(id)aSourceObject slideBack:(BOOL)slideBack
|
||||||
{
|
{
|
||||||
CPDragServerIsDraggingImage = YES;
|
_isDraggingImage = YES;
|
||||||
|
|
||||||
|
var imageSize = [anImage size];
|
||||||
|
|
||||||
if (!_imageView)
|
if (!_imageView)
|
||||||
_imageView = [[CPImageView alloc] initWithFrame:CPRectMakeZero()];
|
_imageView = [[CPImageView alloc] initWithFrame:_CGRectMake(0.0, 0.0, imageSize.width, imageSize.height)];
|
||||||
|
|
||||||
[_imageView setImage:anImage];
|
[_imageView setImage:anImage];
|
||||||
[_imageView setFrameSize:CGSizeMakeCopy([anImage size])];
|
|
||||||
|
|
||||||
[self dragView:_imageView fromWindow:aWindow at:imageLocation offset:mouseOffset event:anEvent pasteboard:aPasteboard source:aSourceObject slideBack:slideBack];
|
[self dragView:_imageView fromWindow:aWindow at:imageLocation offset:mouseOffset event:anEvent pasteboard:aPasteboard source:aSourceObject slideBack:slideBack];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)trackDragging:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
var type = [anEvent type],
|
||||||
|
platformWindow = [_draggedWindow platformWindow],
|
||||||
|
platformWindowLocation = [[anEvent window] convertBaseToPlatformWindow:[anEvent locationInWindow]];
|
||||||
|
|
||||||
|
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 draggingEndedInPlatformWindow:platformWindow globalLocation:platformWindowLocation operation:_dragOperation];
|
||||||
|
|
||||||
|
// Stop tracking events.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self draggingSourceUpdatedWithGlobalLocation: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.
|
||||||
|
[CPApp setTarget:self selector:@selector(trackDragging:)
|
||||||
|
forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask
|
||||||
|
untilDate:nil inMode:0 dequeue:NO];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation CPWindow (CPDraggingAdditions)
|
@implementation CPWindow (CPDraggingAdditions)
|
||||||
@@ -318,12 +426,12 @@ var CPDragServerUpdateDragging = function(anEvent)
|
|||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
// We don't need to do this because the only place this gets called
|
// We don't need to do this because the only place this gets called
|
||||||
// -_dragHitTest: in CPDOMWindowBridge does this already. Perhaps to
|
// -_dragHitTest: in CPPlatformWindow does this already. Perhaps to
|
||||||
// be safe?
|
// be safe?
|
||||||
// if (![self containsPoint:aPoint])
|
// if (![self containsPoint:aPoint])
|
||||||
// return nil;
|
// return nil;
|
||||||
|
|
||||||
var adjustedPoint = _CGPointMake(aPoint.x - _CGRectGetMinX(_frame), aPoint.y - _CGRectGetMinY(_frame)),
|
var adjustedPoint = [self convertPlatformWindowToBase:aPoint],
|
||||||
hitView = [_windowView hitTest:adjustedPoint];
|
hitView = [_windowView hitTest:adjustedPoint];
|
||||||
|
|
||||||
while (hitView && ![aPasteboard availableTypeFromArray:[hitView registeredDraggedTypes]])
|
while (hitView && ![aPasteboard availableTypeFromArray:[hitView registeredDraggedTypes]])
|
||||||
|
|||||||
+71
-97
@@ -25,110 +25,26 @@
|
|||||||
#include "CoreGraphics/CGGeometry.h"
|
#include "CoreGraphics/CGGeometry.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPLeftMouseDown = 1;
|
CPLeftMouseDown = 1;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPLeftMouseUp = 2;
|
CPLeftMouseUp = 2;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPRightMouseDown = 3;
|
CPRightMouseDown = 3;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPRightMouseUp = 4;
|
CPRightMouseUp = 4;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPMouseMoved = 5;
|
CPMouseMoved = 5;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPLeftMouseDragged = 6;
|
CPLeftMouseDragged = 6;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPRightMouseDragged = 7;
|
CPRightMouseDragged = 7;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPMouseEntered = 8;
|
CPMouseEntered = 8;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPMouseExited = 9;
|
CPMouseExited = 9;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPKeyDown = 10;
|
CPKeyDown = 10;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPKeyUp = 11;
|
CPKeyUp = 11;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPFlagsChanged = 12;
|
CPFlagsChanged = 12;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPAppKitDefined = 13;
|
CPAppKitDefined = 13;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPSystemDefined = 14;
|
CPSystemDefined = 14;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPApplicationDefined = 15;
|
CPApplicationDefined = 15;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPPeriodic = 16;
|
CPPeriodic = 16;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPCursorUpdate = 17;
|
CPCursorUpdate = 17;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPScrollWheel = 22;
|
CPScrollWheel = 22;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPOtherMouseDown = 25;
|
CPOtherMouseDown = 25;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPOtherMouseUp = 26;
|
CPOtherMouseUp = 26;
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPEventType
|
|
||||||
*/
|
|
||||||
CPOtherMouseDragged = 27;
|
CPOtherMouseDragged = 27;
|
||||||
|
|
||||||
// iPhone Event Types
|
// iPhone Event Types
|
||||||
@@ -206,6 +122,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
unsigned _clickCount;
|
unsigned _clickCount;
|
||||||
float _pressure;
|
float _pressure;
|
||||||
CPWindow _window;
|
CPWindow _window;
|
||||||
|
Number _windowNumber;
|
||||||
CPString _characters;
|
CPString _characters;
|
||||||
CPString _charactersIgnoringModifiers
|
CPString _charactersIgnoringModifiers
|
||||||
BOOL _isARepeat;
|
BOOL _isARepeat;
|
||||||
@@ -220,16 +137,16 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
/*!
|
/*!
|
||||||
Creates a new keyboard event.
|
Creates a new keyboard event.
|
||||||
@param anEventType the event type. Must be one of CPKeyDown, CPKeyUp or CPFlagsChanged
|
@param anEventType the event type. Must be one of CPKeyDown, CPKeyUp or CPFlagsChanged
|
||||||
@param aPoint the location of the cursor in the window specified by <code>aWindowNumber</code>
|
@param aPoint the location of the cursor in the window specified by \c aWindowNumber
|
||||||
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
|
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
|
||||||
@param aTimestamp the time the event occurred
|
@param aTimestamp the time the event occurred
|
||||||
@param aWindowNumber the number of the CPWindow where the event occurred
|
@param aWindowNumber the number of the CPWindow where the event occurred
|
||||||
@param aGraphicsContext the graphics context where the event occurred
|
@param aGraphicsContext the graphics context where the event occurred
|
||||||
@param characters the characters associated with the event
|
@param characters the characters associated with the event
|
||||||
@param unmodCharacters the string of keys pressed without the presence of any modifiers other than Shift
|
@param unmodCharacters the string of keys pressed without the presence of any modifiers other than Shift
|
||||||
@param repeatKey <code>YES</code> if this is caused by the system repeat as opposed to the user pressing the key again
|
@param repeatKey \c YES if this is caused by the system repeat as opposed to the user pressing the key again
|
||||||
@param code a number associated with the keyboard key of this event
|
@param code a number associated with the keyboard key of this event
|
||||||
@throws CPInternalInconsistencyException if <code>anEventType</code> is not a CPKeyDown,
|
@throws CPInternalInconsistencyException if \c anEventType is not a CPKeyDown,
|
||||||
CPKeyUp or CPFlagsChanged
|
CPKeyUp or CPFlagsChanged
|
||||||
@return the keyboard event
|
@return the keyboard event
|
||||||
*/
|
*/
|
||||||
@@ -245,7 +162,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
/*!
|
/*!
|
||||||
Creates a new mouse event
|
Creates a new mouse event
|
||||||
@param anEventType the event type
|
@param anEventType the event type
|
||||||
@param aPoint the location of the cursor in the window specified by <code>aWindowNumber</code>
|
@param aPoint the location of the cursor in the window specified by \c aWindowNumber
|
||||||
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
|
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
|
||||||
@param aTimestamp the time the event occurred
|
@param aTimestamp the time the event occurred
|
||||||
@param aWindowNumber the number of the CPWindow where the event occurred
|
@param aWindowNumber the number of the CPWindow where the event occurred
|
||||||
@@ -267,7 +184,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
/*!
|
/*!
|
||||||
Creates a new custom event
|
Creates a new custom event
|
||||||
@param anEventType the event type. Must be one of CPAppKitDefined, CPSystemDefined, CPApplicationDefined or CPPeriodic
|
@param anEventType the event type. Must be one of CPAppKitDefined, CPSystemDefined, CPApplicationDefined or CPPeriodic
|
||||||
@param aLocation the location of the cursor in the window specified by <code>aWindowNumber</code>
|
@param aLocation the location of the cursor in the window specified by \c aWindowNumber
|
||||||
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
|
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
|
||||||
@param aTimestamp the time the event occurred
|
@param aTimestamp the time the event occurred
|
||||||
@param aWindowNumber the number of the CPWindow where the event occurred
|
@param aWindowNumber the number of the CPWindow where the event occurred
|
||||||
@@ -327,7 +244,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
_charactersIgnoringModifiers = unmodCharacters;
|
_charactersIgnoringModifiers = unmodCharacters;
|
||||||
_isARepeat = isARepeat;
|
_isARepeat = isARepeat;
|
||||||
_keyCode = code;
|
_keyCode = code;
|
||||||
_window = [CPApp windowWithWindowNumber:aWindowNumber];
|
_windowNumber = aWindowNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -357,15 +274,26 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the location of the mouse (for mouse events).
|
Returns the location of the mouse (for mouse events).
|
||||||
If this is not a mouse event, it returns <code>nil</code>.
|
If this is not a mouse event, it returns \c nil.
|
||||||
If <code>window</code> returns <code>nil</code>, then
|
If \c window returns \c nil, then
|
||||||
the mouse coordinates will be based on the screen coordinates.
|
the mouse coordinates will be based on the screen coordinates.
|
||||||
Otherwise, the coordinates are relative to the window's coordinates.
|
Otherwise, the coordinates are relative to the window's coordinates.
|
||||||
@return the location of the mouse, or <code>nil</code> for non-mouse events.
|
@return the location of the mouse, or \c nil for non-mouse events.
|
||||||
*/
|
*/
|
||||||
- (CGPoint)locationInWindow
|
- (CGPoint)locationInWindow
|
||||||
{
|
{
|
||||||
return _location;
|
return _CGPointMakeCopy(_location);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGPoint)globalLocation
|
||||||
|
{
|
||||||
|
var theWindow = [self window],
|
||||||
|
location = [self locationInWindow];
|
||||||
|
|
||||||
|
if (theWindow)
|
||||||
|
return [theWindow convertBaseToGlobal:location];
|
||||||
|
|
||||||
|
return location;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -397,6 +325,9 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
*/
|
*/
|
||||||
- (CPWindow)window
|
- (CPWindow)window
|
||||||
{
|
{
|
||||||
|
if (!_window)
|
||||||
|
_window = [CPApp windowWithWindowNumber:_windowNumber];
|
||||||
|
|
||||||
return _window;
|
return _window;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,7 +345,10 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
*/
|
*/
|
||||||
- (int)buttonNumber
|
- (int)buttonNumber
|
||||||
{
|
{
|
||||||
return _buttonNumber;
|
if (_type === CPRightMouseDown || _type === CPRightMouseUp || _type === CPRightMouseDragged)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -444,7 +378,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the keyboard event was caused by the key being held down.
|
Returns \c YES if the keyboard event was caused by the key being held down.
|
||||||
@throws CPInternalInconsistencyException if this method is called on a non-key event
|
@throws CPInternalInconsistencyException if this method is called on a non-key event
|
||||||
*/
|
*/
|
||||||
- (BOOL)isARepeat
|
- (BOOL)isARepeat
|
||||||
@@ -461,6 +395,18 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
return _keyCode;
|
return _keyCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (CGPoint)mouseLocation
|
||||||
|
{
|
||||||
|
// FIXME: this is incorrect, we shouldn't depend on the current event.
|
||||||
|
var event = [CPApp currentEvent],
|
||||||
|
eventWindow = [event window];
|
||||||
|
|
||||||
|
if (eventWindow)
|
||||||
|
return [eventWindow convertBaseToGlobal:[event locationInWindow]];
|
||||||
|
|
||||||
|
return [event locationInWindow];
|
||||||
|
}
|
||||||
|
|
||||||
- (float)pressure
|
- (float)pressure
|
||||||
{
|
{
|
||||||
return _pressure;
|
return _pressure;
|
||||||
@@ -499,8 +445,16 @@ var _CPEventPeriodicEventPeriod = 0,
|
|||||||
return _deltaZ;
|
return _deltaZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)_couldBeKeyEquivalent
|
||||||
|
{
|
||||||
|
// FIXME: More cases? Space?
|
||||||
|
return _type === CPKeyDown &&
|
||||||
|
_modifierFlags & (CPCommandKeyMask | CPControlKeyMask) &&
|
||||||
|
[_characters length] > 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Generates periodic events every <code>aPeriod</code> seconds.
|
Generates periodic events every \c aPeriod seconds.
|
||||||
@param aDelay the number of seconds before the first event
|
@param aDelay the number of seconds before the first event
|
||||||
@param aPeriod the length of time in seconds between successive events
|
@param aPeriod the length of time in seconds between successive events
|
||||||
*/
|
*/
|
||||||
@@ -532,3 +486,23 @@ function _CPEventFirePeriodEvent()
|
|||||||
[CPApp sendEvent:[CPEvent otherEventWithType:CPPeriodic location:_CGPointMakeZero() modifierFlags:0 timestamp:0 windowNumber:0 context:nil subtype:0 data1:0 data2:0]];
|
[CPApp sendEvent:[CPEvent otherEventWithType:CPPeriodic location:_CGPointMakeZero() modifierFlags:0 timestamp:0 windowNumber:0 context:nil subtype:0 data1:0 data2:0]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var CPEventClass = [CPEvent class];
|
||||||
|
|
||||||
|
function _CPEventFromNativeMouseEvent(aNativeEvent, anEventType, aPoint, modifierFlags, aTimestamp, aWindowNumber, aGraphicsContext, anEventNumber, aClickCount, aPressure)
|
||||||
|
{
|
||||||
|
aNativeEvent.isa = CPEventClass;
|
||||||
|
|
||||||
|
aNativeEvent._type = anEventType;
|
||||||
|
aNativeEvent._location = aPoint;
|
||||||
|
aNativeEvent._modifierFlags = modifierFlags;
|
||||||
|
aNativeEvent._timestamp = aTimestamp;
|
||||||
|
aNativeEvent._windowNumber = aWindowNumber;
|
||||||
|
aNativeEvent._window = nil;
|
||||||
|
aNativeEvent._context = aGraphicsContext;
|
||||||
|
aNativeEvent._eventNumber = anEventNumber;
|
||||||
|
aNativeEvent._clickCount = aClickCount;
|
||||||
|
aNativeEvent._pressure = aPressure;
|
||||||
|
|
||||||
|
return aNativeEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+29
-6
@@ -30,17 +30,17 @@
|
|||||||
*/
|
*/
|
||||||
@implementation CPFlashMovie : CPObject
|
@implementation CPFlashMovie : CPObject
|
||||||
{
|
{
|
||||||
CPString _fileName;
|
CPString _filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Creates a new Flash movie with the swf at <code>aFileName</code>.
|
Creates a new Flash movie with the swf at \c aFileName.
|
||||||
@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 +48,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
|
||||||
+128
-36
@@ -20,10 +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 "CPDOMWindowBridge.j"
|
|
||||||
@import "CPFlashMovie.j"
|
@import "CPFlashMovie.j"
|
||||||
@import "CPView.j"
|
@import "CPView.j"
|
||||||
|
|
||||||
|
#include "Platform/Platform.h"
|
||||||
|
|
||||||
|
var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
*/
|
*/
|
||||||
@@ -31,9 +34,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,35 +49,32 @@
|
|||||||
|
|
||||||
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";
|
||||||
|
|
||||||
_DOMObjectElement.appendChild(_DOMParamElement);
|
_DOMInnerObjectElement = document.createElement(@"object");
|
||||||
|
_DOMInnerObjectElement.width = @"100%";
|
||||||
|
_DOMInnerObjectElement.height = @"100%";
|
||||||
|
|
||||||
var param = document.createElement("param");
|
_DOMObjectElement.appendChild(_DOMParamElement);
|
||||||
|
_DOMObjectElement.appendChild(_DOMInnerObjectElement);
|
||||||
|
|
||||||
param.name = "wmode";
|
_DOMElement.appendChild(_DOMObjectElement);
|
||||||
param.value = "transparent";
|
}
|
||||||
|
else
|
||||||
_DOMObjectElement.appendChild(param);
|
[self _rebuildIEObjects];
|
||||||
|
#endif
|
||||||
_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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -82,11 +86,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,19 +102,103 @@
|
|||||||
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
|
||||||
{
|
{
|
||||||
[[CPDOMWindowBridge sharedDOMWindowBridge] _propagateCurrentDOMEvent:YES];
|
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseDown:(CPEvent)anEvent
|
- (void)mouseDown:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
[[CPDOMWindowBridge sharedDOMWindowBridge] _propagateCurrentDOMEvent:YES];
|
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseUp:(CPEvent)anEvent
|
- (void)mouseUp:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
[[CPDOMWindowBridge sharedDOMWindowBridge] _propagateCurrentDOMEvent:YES];
|
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+17
-4
@@ -20,10 +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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var _CPFonts = {};
|
var _CPFonts = {},
|
||||||
_CPFontSystemFontFace = @"Arial";
|
_CPFontSystemFontFace = @"Arial, sans-serif",
|
||||||
|
_CPWrapRegExp = new RegExp("\\s*,\\s*", "g");
|
||||||
|
|
||||||
#define _CPCachedFont(aName, aSize, isBold) _CPFonts[(isBold ? @"bold " : @"") + ROUND(aSize) + @"px '" + aName + @"'"]
|
|
||||||
|
#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
|
||||||
@@ -95,7 +98,7 @@ var _CPFonts = {};
|
|||||||
_size = aSize;
|
_size = aSize;
|
||||||
_isBold = isBold;
|
_isBold = isBold;
|
||||||
|
|
||||||
_cssString = (_isBold ? @"bold " : @"") + ROUND(aSize) + @"px '" + aName + @"'";
|
_cssString = _CPCreateCSSString(_name, _size, _isBold);
|
||||||
|
|
||||||
_CPFonts[_cssString] = self;
|
_CPFonts[_cssString] = self;
|
||||||
}
|
}
|
||||||
@@ -127,6 +130,16 @@ 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]];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPFontNameKey = @"CPFontNameKey",
|
var CPFontNameKey = @"CPFontNameKey",
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
+30
-30
@@ -62,11 +62,11 @@ function CPPointMake(x, y)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Makes a CGRect with an origin and size equal to <code>aRect</code> less the <code>dX/dY</code> insets specified.
|
Makes a CGRect with an origin and size equal to \c aRect less the \c dX/dY insets specified.
|
||||||
@param dX the size of the inset in the x-axis
|
@param dX the size of the inset in the x-axis
|
||||||
@param dY the size of the inset in the y-axis
|
@param dY the size of the inset in the y-axis
|
||||||
@group CGRect
|
@group CGRect
|
||||||
@return CGRect a rectangle like <code>aRect</code> with an inset
|
@return CGRect a rectangle like \c aRect with an inset
|
||||||
*/
|
*/
|
||||||
function CPRectInset(aRect, dX, dY)
|
function CPRectInset(aRect, dX, dY)
|
||||||
{
|
{
|
||||||
@@ -132,7 +132,7 @@ function CPRectMake(x, y, width, height)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Creates a new rectangle with its origin offset by <code>dX</code> and <code>dY</code>.
|
Creates a new rectangle with its origin offset by \c dX and \c dY.
|
||||||
@group CGRect
|
@group CGRect
|
||||||
@param aRect the rectangle to copy the origin and size from
|
@param aRect the rectangle to copy the origin and size from
|
||||||
@param dX the amount added to the x-size of the new rectangle
|
@param dX the amount added to the x-size of the new rectangle
|
||||||
@@ -171,7 +171,7 @@ function CPRectStandardize(aRect)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the smallest rectangle that can contain the two argument <code>CGRect</code>s.
|
Returns the smallest rectangle that can contain the two argument \c CGRects.
|
||||||
@group CGRect
|
@group CGRect
|
||||||
@param lhsRect the first CGRect to use for the union calculation
|
@param lhsRect the first CGRect to use for the union calculation
|
||||||
@param rhsRect the second CGRect to use for the union calculation
|
@param rhsRect the second CGRect to use for the union calculation
|
||||||
@@ -211,12 +211,12 @@ function CPSizeMake(width, height)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the CGRect, <code>aRect</code>, contains
|
Returns \c YES if the CGRect, \c aRect, contains
|
||||||
the CGPoint, <code>aPoint</code>.
|
the CGPoint, \c aPoint.
|
||||||
@param aRect the rectangle to test with
|
@param aRect the rectangle to test with
|
||||||
@param aPoint the point to test with
|
@param aPoint the point to test with
|
||||||
@group CGRect
|
@group CGRect
|
||||||
@return BOOL <code>YES</code> if the rectangle contains the point, <code>NO</code> otherwise.
|
@return BOOL \c YES if the rectangle contains the point, \c NO otherwise.
|
||||||
*/
|
*/
|
||||||
function CPRectContainsPoint(aRect, aPoint)
|
function CPRectContainsPoint(aRect, aPoint)
|
||||||
{
|
{
|
||||||
@@ -227,25 +227,25 @@ function CPRectContainsPoint(aRect, aPoint)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns a <code>BOOL</code> indicating whether CGRect <code>possibleOuter</code>
|
Returns a \c BOOL indicating whether CGRect \c possibleOuter
|
||||||
contains CGRect <code>possibleInner</code>.
|
contains CGRect \c possibleInner.
|
||||||
@group CGRect
|
@group CGRect
|
||||||
@param possibleOuter the CGRect to test if <code>possibleInner</code> is inside of
|
@param possibleOuter the CGRect to test if \c possibleInner is inside of
|
||||||
@param possibleInner the CGRect to test if it fits inside <code>possibleOuter</code>.
|
@param possibleInner the CGRect to test if it fits inside \c possibleOuter.
|
||||||
@return BOOL <code>YES</code> if <code>possibleInner</code> fits inside <code>possibleOuter</code>.
|
@return BOOL \c YES if \c possibleInner fits inside \c possibleOuter.
|
||||||
*/
|
*/
|
||||||
function CPRectContainsRect(lhsRect, rhsRect)
|
function CPRectContainsRect(possibleOuter, possibleInner)
|
||||||
{
|
{
|
||||||
return CPRectEqualToRect(CPUnionRect(lhsRect, rhsRect), rhsRect);
|
return CGRectContainsRect(possibleOuter, possibleInner);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Tests whether the two CGPoints are equal to each other by comparing their
|
Tests whether the two CGPoints are equal to each other by comparing their
|
||||||
<code>x</code> and <code>y</code> members.
|
\c x and \c y members.
|
||||||
@group @CGPoint
|
@group @CGPoint
|
||||||
@param lhsPoint the first CGPoint to check
|
@param lhsPoint the first CGPoint to check
|
||||||
@param rhsPoint the second CGPoint to check
|
@param rhsPoint the second CGPoint to check
|
||||||
@return BOOL <code>YES</code> if the two points have the same x's, and the same y's.
|
@return BOOL \c YES if the two points have the same x's, and the same y's.
|
||||||
*/
|
*/
|
||||||
function CPPointEqualToPoint(lhsPoint, rhsPoint)
|
function CPPointEqualToPoint(lhsPoint, rhsPoint)
|
||||||
{
|
{
|
||||||
@@ -257,7 +257,7 @@ function CPPointEqualToPoint(lhsPoint, rhsPoint)
|
|||||||
@group CGRect
|
@group CGRect
|
||||||
@param lhsRect the first CGRect to compare
|
@param lhsRect the first CGRect to compare
|
||||||
@param rhsRect the second CGRect to compare
|
@param rhsRect the second CGRect to compare
|
||||||
@return BOOL <code>YES</code> if the two rectangles have the same origin and size. <code>NO</code>, otherwise.
|
@return BOOL \c YES if the two rectangles have the same origin and size. \c NO, otherwise.
|
||||||
*/
|
*/
|
||||||
function CPRectEqualToRect(lhsRect, rhsRect)
|
function CPRectEqualToRect(lhsRect, rhsRect)
|
||||||
{
|
{
|
||||||
@@ -346,11 +346,11 @@ function CPRectGetWidth(aRect)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the two rectangles intersect
|
Returns \c YES if the two rectangles intersect
|
||||||
@group CGRect
|
@group CGRect
|
||||||
@param lhsRect the first CGRect
|
@param lhsRect the first CGRect
|
||||||
@param rhsRect the second CGRect
|
@param rhsRect the second CGRect
|
||||||
@return BOOL <code>YES</code> if the two rectangles have any common spaces, and <code>NO</code>, otherwise.
|
@return BOOL \c YES if the two rectangles have any common spaces, and \c NO, otherwise.
|
||||||
*/
|
*/
|
||||||
function CPRectIntersectsRect(lhsRect, rhsRect)
|
function CPRectIntersectsRect(lhsRect, rhsRect)
|
||||||
{
|
{
|
||||||
@@ -358,11 +358,11 @@ function CPRectIntersectsRect(lhsRect, rhsRect)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the CGRect has no area.
|
Returns \c YES if the CGRect has no area.
|
||||||
The test is performed by checking if the width and height are both zero.
|
The test is performed by checking if the width and height are both zero.
|
||||||
@group CGRect
|
@group CGRect
|
||||||
@param aRect the CGRect to test
|
@param aRect the CGRect to test
|
||||||
@return BOOL <code>YES</code> if the CGRect has no area, and <code>NO</code>, otherwise.
|
@return BOOL \c YES if the CGRect has no area, and \c NO, otherwise.
|
||||||
*/
|
*/
|
||||||
function CPRectIsEmpty(aRect)
|
function CPRectIsEmpty(aRect)
|
||||||
{
|
{
|
||||||
@@ -370,10 +370,10 @@ function CPRectIsEmpty(aRect)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the CGRect has no area.
|
Returns \c YES if the CGRect has no area.
|
||||||
The test is performed by checking if the width and height are both zero.
|
The test is performed by checking if the width and height are both zero.
|
||||||
@group CGRect
|
@group CGRect
|
||||||
@return BOOL <code>YES</code> if the CGRect has no area, and <code>NO</code>, otherwise.
|
@return BOOL \c YES if the CGRect has no area, and \c NO, otherwise.
|
||||||
*/
|
*/
|
||||||
function CPRectIsNull(aRect)
|
function CPRectIsNull(aRect)
|
||||||
{
|
{
|
||||||
@@ -381,11 +381,11 @@ function CPRectIsNull(aRect)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the two CGSizes are identical.
|
Returns \c YES if the two CGSizes are identical.
|
||||||
@group CGSize
|
@group CGSize
|
||||||
@param lhsSize the first CGSize to compare
|
@param lhsSize the first CGSize to compare
|
||||||
@param rhsSize the second CGSize to compare
|
@param rhsSize the second CGSize to compare
|
||||||
@return BOOL <code>YES</code> if the two sizes are identical. <code>NO</code>, otherwise.
|
@return BOOL \c YES if the two sizes are identical. \c NO, otherwise.
|
||||||
*/
|
*/
|
||||||
function CPSizeEqualToSize(lhsSize, rhsSize)
|
function CPSizeEqualToSize(lhsSize, rhsSize)
|
||||||
{
|
{
|
||||||
@@ -454,7 +454,7 @@ function CPSizeFromString(aString)
|
|||||||
/*!
|
/*!
|
||||||
Returns a CGRect created from a string.
|
Returns a CGRect created from a string.
|
||||||
@group CGRect
|
@group CGRect
|
||||||
@param aString a string in the form generated by <code>CPStringFromRect</code>
|
@param aString a string in the form generated by \c CPStringFromRect
|
||||||
@return CGRect the rectangle created from the string
|
@return CGRect the rectangle created from the string
|
||||||
*/
|
*/
|
||||||
function CPRectFromString(aString)
|
function CPRectFromString(aString)
|
||||||
@@ -477,7 +477,7 @@ function CPPointFromEvent(anEvent)
|
|||||||
/*!
|
/*!
|
||||||
Returns a zero sized CGSize.
|
Returns a zero sized CGSize.
|
||||||
@group CGSize
|
@group CGSize
|
||||||
@return CGSize a size object with zeros for <code>width</code> and <code>height</code>
|
@return CGSize a size object with zeros for \c width and \c height
|
||||||
*/
|
*/
|
||||||
function CPSizeMakeZero()
|
function CPSizeMakeZero()
|
||||||
{
|
{
|
||||||
@@ -485,7 +485,7 @@ function CPSizeMakeZero()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns a rectangle at origin <code>(0,0)</code> and size of <code>(0,0)</code>.
|
Returns a rectangle at origin \c (0,0) and size of \c (0,0).
|
||||||
@group CGRect
|
@group CGRect
|
||||||
@return CGRect a zeroed out CGRect
|
@return CGRect a zeroed out CGRect
|
||||||
*/
|
*/
|
||||||
@@ -495,9 +495,9 @@ function CPRectMakeZero()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns a point located at <code>(0, 0)</code>.
|
Returns a point located at \c (0, 0).
|
||||||
@group CGPoint
|
@group CGPoint
|
||||||
@return CGPoint a point located at <code>(0, 0)</code>
|
@return CGPoint a point located at \c (0, 0)
|
||||||
*/
|
*/
|
||||||
function CPPointMakeZero()
|
function CPPointMakeZero()
|
||||||
{
|
{
|
||||||
|
|||||||
+72
-14
@@ -28,6 +28,9 @@
|
|||||||
|
|
||||||
@import "CPGeometry.j"
|
@import "CPGeometry.j"
|
||||||
|
|
||||||
|
#include "Platform/Platform.h"
|
||||||
|
|
||||||
|
|
||||||
CPImageLoadStatusInitialized = 0;
|
CPImageLoadStatusInitialized = 0;
|
||||||
CPImageLoadStatusLoading = 1;
|
CPImageLoadStatusLoading = 1;
|
||||||
CPImageLoadStatusCompleted = 2;
|
CPImageLoadStatusCompleted = 2;
|
||||||
@@ -38,6 +41,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,15 +62,11 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
|||||||
return [[CPImage alloc] initWithContentsOfFile:[aBundle pathForResource:aFilename]];
|
return [[CPImage alloc] initWithContentsOfFile:[aBundle pathForResource:aFilename]];
|
||||||
}
|
}
|
||||||
|
|
||||||
@implementation CPBundle (CPImageAdditions)
|
function CPAppKitImage(aFilename, aSize)
|
||||||
|
|
||||||
- (CPString)pathForResource:(CPString)aFilename
|
|
||||||
{
|
{
|
||||||
return [self resourcePath] + '/' + aFilename;
|
return CPImageInBundle(aFilename, aSize, [CPBundle bundleForClass:[CPView class]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@class CPImage
|
@class CPImage
|
||||||
@@ -83,6 +92,7 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
|||||||
{
|
{
|
||||||
CGSize _size;
|
CGSize _size;
|
||||||
CPString _filename;
|
CPString _filename;
|
||||||
|
CPString _name;
|
||||||
|
|
||||||
id _delegate;
|
id _delegate;
|
||||||
unsigned _loadStatus;
|
unsigned _loadStatus;
|
||||||
@@ -90,15 +100,20 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
|||||||
Image _image;
|
Image _image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
return [self initByReferencingFile:@"" size:CGSizeMake(-1, -1)];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Initializes the image, by associating it with a filename. The image
|
Initializes the image, by associating it with a filename. The image
|
||||||
denoted in <code>aFilename</code> is not actually loaded. It will
|
denoted in \c aFilename is not actually loaded. It will
|
||||||
be loaded once needed.
|
be loaded once needed.
|
||||||
@param aFilename the file containing the image
|
@param aFilename the file containing the image
|
||||||
@param aSize the image's size
|
@param aSize the image's size
|
||||||
@return the initialized image
|
@return the initialized image
|
||||||
*/
|
*/
|
||||||
- (CPImage)initByReferencingFile:(CPString)aFilename size:(CGSize)aSize
|
- (id)initByReferencingFile:(CPString)aFilename size:(CGSize)aSize
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
|
|
||||||
@@ -118,7 +133,7 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
|||||||
@param aSize the size of the image
|
@param aSize the size of the image
|
||||||
@return the initialized image.
|
@return the initialized image.
|
||||||
*/
|
*/
|
||||||
- (CPImage)initWithContentsOfFile:(CPString)aFilename size:(CGSize)aSize
|
- (id)initWithContentsOfFile:(CPString)aFilename size:(CGSize)aSize
|
||||||
{
|
{
|
||||||
self = [self initByReferencingFile:aFilename size:aSize];
|
self = [self initByReferencingFile:aFilename size:aSize];
|
||||||
|
|
||||||
@@ -134,9 +149,9 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
|||||||
@param aFilename the file name of the image
|
@param aFilename the file name of the image
|
||||||
@return the initialized image
|
@return the initialized image
|
||||||
*/
|
*/
|
||||||
- (CPImage)initWithContentsOfFile:(CPString)aFilename
|
- (id)initWithContentsOfFile:(CPString)aFilename
|
||||||
{
|
{
|
||||||
self = [self initByReferencingFile:aFilename size: CGSizeMake(-1, -1)];
|
self = [self initByReferencingFile:aFilename size:CGSizeMake(-1, -1)];
|
||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
[self load];
|
[self load];
|
||||||
@@ -169,6 +184,45 @@ 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.isa)
|
||||||
|
{
|
||||||
|
imageOrSize = CPAppKitImage("CPImage/" + aName + ".png", imageOrSize);
|
||||||
|
|
||||||
|
[imageOrSize setName:aName];
|
||||||
|
|
||||||
|
AppKitImageForNames[aName] = imageOrSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return imageOrSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setName:(CPString)aName
|
||||||
|
{
|
||||||
|
if (_name === aName)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (imagesForNames[aName] === self)
|
||||||
|
imagesForNames[aName] = nil;
|
||||||
|
|
||||||
|
_name = aName;
|
||||||
|
|
||||||
|
imagesForNames[aName] = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)name
|
||||||
|
{
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the receiver's delegate.
|
Sets the receiver's delegate.
|
||||||
@param the delegate
|
@param the delegate
|
||||||
@@ -187,9 +241,9 @@ function CPImageInBundle(aFilename, aSize, aBundle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the image data has already been loaded.
|
Returns the load status, which will be CPImageLoadStatusCompleted if the image data has already been loaded.
|
||||||
*/
|
*/
|
||||||
- (BOOL)loadStatus
|
- (unsigned)loadStatus
|
||||||
{
|
{
|
||||||
return _loadStatus;
|
return _loadStatus;
|
||||||
}
|
}
|
||||||
@@ -207,6 +261,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;
|
||||||
@@ -250,7 +305,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
|
||||||
|
|||||||
+66
-17
@@ -31,24 +31,10 @@
|
|||||||
|
|
||||||
#include "CoreGraphics/CGGeometry.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;
|
||||||
|
|
||||||
|
|
||||||
var CPImageViewShadowBackgroundColor = nil;
|
var CPImageViewShadowBackgroundColor = nil;
|
||||||
|
|
||||||
var LEFT_SHADOW_INSET = 3.0,
|
var LEFT_SHADOW_INSET = 3.0,
|
||||||
@@ -71,6 +57,8 @@ var LEFT_SHADOW_INSET = 3.0,
|
|||||||
BOOL _hasShadow;
|
BOOL _hasShadow;
|
||||||
CPView _shadowView;
|
CPView _shadowView;
|
||||||
|
|
||||||
|
BOOL _isEditable;
|
||||||
|
|
||||||
CGRect _imageRect;
|
CGRect _imageRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +74,12 @@ var LEFT_SHADOW_INSET = 3.0,
|
|||||||
_DOMImageElement.style.left = "0px";
|
_DOMImageElement.style.left = "0px";
|
||||||
_DOMImageElement.style.top = "0px";
|
_DOMImageElement.style.top = "0px";
|
||||||
|
|
||||||
|
if ([CPPlatform supportsDragAndDrop])
|
||||||
|
{
|
||||||
|
_DOMImageElement.setAttribute("draggable", "true");
|
||||||
|
_DOMImageElement.style["-khtml-user-drag"] = "element";
|
||||||
|
}
|
||||||
|
|
||||||
CPDOMDisplayServerAppendChild(_DOMElement, _DOMImageElement);
|
CPDOMDisplayServerAppendChild(_DOMElement, _DOMImageElement);
|
||||||
|
|
||||||
_DOMImageElement.style.visibility = "hidden";
|
_DOMImageElement.style.visibility = "hidden";
|
||||||
@@ -159,8 +153,8 @@ var LEFT_SHADOW_INSET = 3.0,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the image view draws with
|
Returns \c YES if the image view draws with
|
||||||
a drop shadow. The default is <code>NO</code>.
|
a drop shadow. The default is \c NO.
|
||||||
*/
|
*/
|
||||||
- (BOOL)hasShadow
|
- (BOOL)hasShadow
|
||||||
{
|
{
|
||||||
@@ -217,6 +211,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.
|
||||||
*/
|
*/
|
||||||
@@ -339,11 +338,50 @@ var LEFT_SHADOW_INSET = 3.0,
|
|||||||
[[self nextResponder] mouseDown:anEvent];
|
[[self nextResponder] mouseDown:anEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setEditable:(BOOL)shouldBeEditable
|
||||||
|
{
|
||||||
|
if (_isEditable === shouldBeEditable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_isEditable = shouldBeEditable;
|
||||||
|
|
||||||
|
if (_isEditable)
|
||||||
|
[self registerForDraggedTypes:[CPImagesPboardType]];
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var draggedTypes = [self registeredDraggedTypes];
|
||||||
|
|
||||||
|
[self unregisterDraggedTypes];
|
||||||
|
|
||||||
|
[draggedTypes removeObjectIdenticalTo:CPImagesPboardType];
|
||||||
|
|
||||||
|
[self registerForDraggedTypes:draggedTypes];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEditable
|
||||||
|
{
|
||||||
|
return _isEditable;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)performDragOperation:(CPDraggingInfo)aSender
|
||||||
|
{
|
||||||
|
var images = [CPKeyedUnarchiver unarchiveObjectWithData:[[aSender draggingPasteboard] dataForType:CPImagesPboardType]];
|
||||||
|
|
||||||
|
if ([images count])
|
||||||
|
{
|
||||||
|
[self setImage:images[0]];
|
||||||
|
[self sendAction:[self action] to:[self target]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPImageViewImageKey = @"CPImageViewImageKey",
|
var CPImageViewImageKey = @"CPImageViewImageKey",
|
||||||
CPImageViewImageScalingKey = @"CPImageViewImageScalingKey",
|
CPImageViewImageScalingKey = @"CPImageViewImageScalingKey",
|
||||||
CPImageViewHasShadowKey = @"CPImageViewHasShadowKey";
|
CPImageViewHasShadowKey = @"CPImageViewHasShadowKey",
|
||||||
|
CPImageViewIsEditableKey = @"CPImageViewIsEditableKey";
|
||||||
|
|
||||||
@implementation CPImageView (CPCoding)
|
@implementation CPImageView (CPCoding)
|
||||||
|
|
||||||
@@ -360,6 +398,11 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
|
|||||||
_DOMImageElement.style.left = "0px";
|
_DOMImageElement.style.left = "0px";
|
||||||
_DOMImageElement.style.top = "0px";
|
_DOMImageElement.style.top = "0px";
|
||||||
_DOMImageElement.style.visibility = "hidden";
|
_DOMImageElement.style.visibility = "hidden";
|
||||||
|
if ([CPPlatform supportsDragAndDrop])
|
||||||
|
{
|
||||||
|
_DOMImageElement.setAttribute("draggable", "true");
|
||||||
|
_DOMImageElement.style["-khtml-user-drag"] = "element";
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
self = [super initWithCoder:aCoder];
|
self = [super initWithCoder:aCoder];
|
||||||
@@ -372,6 +415,9 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
|
|||||||
|
|
||||||
[self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]];
|
[self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]];
|
||||||
|
|
||||||
|
if ([aCoder decodeBoolForKey:CPImageViewIsEditableKey] || NO)
|
||||||
|
[self setEditable:YES];
|
||||||
|
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
}
|
}
|
||||||
@@ -402,6 +448,9 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
|
|||||||
_subviews = actualSubviews;
|
_subviews = actualSubviews;
|
||||||
|
|
||||||
[aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey];
|
[aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey];
|
||||||
|
|
||||||
|
if (_isEditable)
|
||||||
|
[aCoder encodeBool:_isEditable forKey:CPImageViewIsEditableKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
-1937
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,556 @@
|
|||||||
|
|
||||||
|
#include "../CoreGraphics/CGGeometry.h"
|
||||||
|
#include "../Platform/Platform.h"
|
||||||
|
|
||||||
|
@import "_CPMenuWindow.j"
|
||||||
|
|
||||||
|
|
||||||
|
var MENUBAR_HEIGHT = 28.0,
|
||||||
|
MENUBAR_MARGIN = 10.0,
|
||||||
|
MENUBAR_LEFT_MARGIN = 10.0,
|
||||||
|
MENUBAR_RIGHT_MARGIN = 10.0;
|
||||||
|
|
||||||
|
var _CPMenuBarWindowBackgroundColor = nil,
|
||||||
|
_CPMenuBarWindowFont = nil;
|
||||||
|
|
||||||
|
@implementation _CPMenuBarWindow : CPPanel
|
||||||
|
{
|
||||||
|
CPMenu _menu;
|
||||||
|
CPView _highlightView;
|
||||||
|
CPArray _menuItemViews;
|
||||||
|
|
||||||
|
CPMenuItem _trackingMenuItem;
|
||||||
|
|
||||||
|
CPImageView _iconImageView;
|
||||||
|
CPTextField _titleField;
|
||||||
|
|
||||||
|
CPColor _textColor;
|
||||||
|
CPColor _titleColor;
|
||||||
|
|
||||||
|
CPColor _textShadowColor;
|
||||||
|
CPColor _titleShadowColor;
|
||||||
|
|
||||||
|
CPColor _highlightColor;
|
||||||
|
CPColor _highlightTextColor;
|
||||||
|
CPColor _highlightTextShadowColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
if (self != [_CPMenuBarWindow class])
|
||||||
|
return;
|
||||||
|
|
||||||
|
var bundle = [CPBundle bundleForClass:self];
|
||||||
|
|
||||||
|
_CPMenuBarWindowFont = [CPFont boldSystemFontOfSize:12.0];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPFont)font
|
||||||
|
{
|
||||||
|
return _CPMenuBarWindowFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
// This only shows up in browser land, so don't bother calculating metrics in desktop.
|
||||||
|
var contentRect = [[CPPlatformWindow primaryPlatformWindow] contentBounds];
|
||||||
|
|
||||||
|
contentRect.size.height = MENUBAR_HEIGHT;
|
||||||
|
|
||||||
|
self = [super initWithContentRect:contentRect styleMask:CPBorderlessWindowMask];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
[self setLevel:CPMainMenuWindowLevel];
|
||||||
|
[self setAutoresizingMask:CPWindowWidthSizable];
|
||||||
|
|
||||||
|
var contentView = [self contentView];
|
||||||
|
|
||||||
|
[contentView setAutoresizesSubviews:NO];
|
||||||
|
|
||||||
|
[self setBecomesKeyOnlyIfNeeded:YES];
|
||||||
|
|
||||||
|
//
|
||||||
|
_iconImageView = [[CPImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 16.0, 16.0)];
|
||||||
|
|
||||||
|
[contentView addSubview:_iconImageView];
|
||||||
|
|
||||||
|
_titleField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
|
[_titleField setFont:[CPFont boldSystemFontOfSize:13.0]];
|
||||||
|
[_titleField setAlignment:CPCenterTextAlignment];
|
||||||
|
[_titleField setTextShadowOffset:CGSizeMake(0, 1)];
|
||||||
|
|
||||||
|
[contentView addSubview:_titleField];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTitle:(CPString)aTitle
|
||||||
|
{
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
var bundleName = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPBundleName"];
|
||||||
|
|
||||||
|
if (![bundleName length])
|
||||||
|
document.title = aTitle;
|
||||||
|
else if ([aTitle length])
|
||||||
|
document.title = aTitle + @" - " + bundleName;
|
||||||
|
else
|
||||||
|
document.title = bundleName;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[_titleField setStringValue:aTitle];
|
||||||
|
[_titleField sizeToFit];
|
||||||
|
|
||||||
|
[self tile];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setIconImage:(CPImage)anImage
|
||||||
|
{
|
||||||
|
[_iconImageView setImage:anImage];
|
||||||
|
[_iconImageView setHidden:anImage == nil];
|
||||||
|
|
||||||
|
[self tile];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setIconImageAlphaValue:(float)anAlphaValue
|
||||||
|
{
|
||||||
|
[_iconImageView setAlphaValue:anAlphaValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
if (!aColor)
|
||||||
|
{
|
||||||
|
if (!_CPMenuBarWindowBackgroundColor)
|
||||||
|
_CPMenuBarWindowBackgroundColor = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[_CPMenuBarWindow class]] pathForResource:@"_CPMenuBarWindow/_CPMenuBarWindowBackground.png"] size:CGSizeMake(1.0, 28.0)]];
|
||||||
|
|
||||||
|
[[self contentView] setBackgroundColor:_CPMenuBarWindowBackgroundColor];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[[self contentView] setBackgroundColor:aColor];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTextColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
if (_textColor == aColor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_textColor = aColor;
|
||||||
|
|
||||||
|
[_menuItemViews makeObjectsPerformSelector:@selector(setTextColor:) withObject:_textColor];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTitleColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
if (_titleColor == aColor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_titleColor = aColor;
|
||||||
|
|
||||||
|
[_titleField setTextColor:aColor ? aColor : [CPColor blackColor]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTextShadowColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
if (_textShadowColor == aColor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_textShadowColor = aColor;
|
||||||
|
|
||||||
|
[_menuItemViews makeObjectsPerformSelector:@selector(setTextShadowColor:) withObject:_textShadowColor];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTitleShadowColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
if (_titleShadowColor == aColor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_titleShadowColor = aColor;
|
||||||
|
|
||||||
|
[_titleField setTextShadowColor:aColor ? aColor : [CPColor whiteColor]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setHighlightColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
if (_highlightColor == aColor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_highlightColor = aColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setHighlightTextColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
if (_highlightTextColor == aColor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_highlightTextColor = aColor;
|
||||||
|
|
||||||
|
// [_menuItemViews makeObjectsPerformSelector:@selector(setActivateColor:) withObject:_highlightTextColor];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setHighlightTextShadowColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
if (_highlightTextShadowColor == aColor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_highlightTextShadowColor = aColor;
|
||||||
|
|
||||||
|
// [_menuItemViews makeObjectsPerformSelector:@selector(setActivateShadowColor:) withObject:_highlightTextShadowColor];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setMenu:(CPMenu)aMenu
|
||||||
|
{
|
||||||
|
if (_menu == aMenu)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||||
|
|
||||||
|
if (_menu)
|
||||||
|
{
|
||||||
|
[defaultCenter
|
||||||
|
removeObserver:self
|
||||||
|
name:CPMenuDidAddItemNotification
|
||||||
|
object:_menu];
|
||||||
|
|
||||||
|
[defaultCenter
|
||||||
|
removeObserver:self
|
||||||
|
name:CPMenuDidChangeItemNotification
|
||||||
|
object:_menu];
|
||||||
|
|
||||||
|
[defaultCenter
|
||||||
|
removeObserver:self
|
||||||
|
name:CPMenuDidRemoveItemNotification
|
||||||
|
object:_menu];
|
||||||
|
|
||||||
|
var items = [_menu itemArray],
|
||||||
|
count = items.length;
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
[[items[count] _menuItemView] removeFromSuperview];
|
||||||
|
}
|
||||||
|
|
||||||
|
_menu = aMenu;
|
||||||
|
|
||||||
|
if (_menu)
|
||||||
|
{
|
||||||
|
[defaultCenter
|
||||||
|
addObserver:self
|
||||||
|
selector:@selector(menuDidAddItem:)
|
||||||
|
name:CPMenuDidAddItemNotification
|
||||||
|
object:_menu];
|
||||||
|
|
||||||
|
[defaultCenter
|
||||||
|
addObserver:self
|
||||||
|
selector:@selector(menuDidChangeItem:)
|
||||||
|
name:CPMenuDidChangeItemNotification
|
||||||
|
object:_menu];
|
||||||
|
|
||||||
|
[defaultCenter
|
||||||
|
addObserver:self
|
||||||
|
selector:@selector(menuDidRemoveItem:)
|
||||||
|
name:CPMenuDidRemoveItemNotification
|
||||||
|
object:_menu];
|
||||||
|
}
|
||||||
|
|
||||||
|
_menuItemViews = [];
|
||||||
|
|
||||||
|
var contentView = [self contentView],
|
||||||
|
items = [_menu itemArray],
|
||||||
|
count = items.length;
|
||||||
|
|
||||||
|
for (index = 0; index < count; ++index)
|
||||||
|
{
|
||||||
|
var item = items[index],
|
||||||
|
menuItemView = [item _menuItemView];
|
||||||
|
|
||||||
|
_menuItemViews.push(menuItemView);
|
||||||
|
|
||||||
|
[menuItemView setTextColor:_textColor];
|
||||||
|
[menuItemView setHidden:[item isHidden]];
|
||||||
|
|
||||||
|
[menuItemView synchronizeWithMenuItem];
|
||||||
|
|
||||||
|
[contentView addSubview:menuItemView];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self tile];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)menuDidChangeItem:(CPNotification)aNotification
|
||||||
|
{
|
||||||
|
var menuItem = [_menu itemAtIndex:[[aNotification userInfo] objectForKey:@"CPMenuItemIndex"]],
|
||||||
|
menuItemView = [menuItem _menuItemView];
|
||||||
|
|
||||||
|
[menuItemView setHidden:[menuItem isHidden]];
|
||||||
|
[menuItemView synchronizeWithMenuItem];
|
||||||
|
|
||||||
|
[self tile];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)menuDidAddItem:(CPNotification)aNotification
|
||||||
|
{
|
||||||
|
var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"],
|
||||||
|
menuItem = [_menu itemAtIndex:index],
|
||||||
|
menuItemView = [menuItem _menuItemView];
|
||||||
|
|
||||||
|
[_menuItemViews insertObject:menuItemView atIndex:index];
|
||||||
|
|
||||||
|
[menuItemView setTextColor:_textColor];
|
||||||
|
[menuItemView setHidden:[menuItem isHidden]];
|
||||||
|
|
||||||
|
[menuItemView synchronizeWithMenuItem];
|
||||||
|
|
||||||
|
[[self contentView] addSubview:menuItemView];
|
||||||
|
|
||||||
|
[self tile];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)menuDidRemoveItem:(CPNotification)aNotification
|
||||||
|
{
|
||||||
|
var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"],
|
||||||
|
menuItemView = [_menuItemViews objectAtIndex:index];
|
||||||
|
|
||||||
|
[_menuItemViews removeObjectAtIndex:index];
|
||||||
|
|
||||||
|
[menuItemView removeFromSuperview];
|
||||||
|
|
||||||
|
[self tile];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseDown:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
var constraintRect = CGRectInset([[self platformWindow] visibleFrame], 5.0, 0.0);
|
||||||
|
|
||||||
|
constraintRect.size.height -= 5.0;
|
||||||
|
|
||||||
|
[[_CPMenuManager sharedMenuManager]
|
||||||
|
beginTracking:anEvent
|
||||||
|
menuContainer:self
|
||||||
|
constraintRect:constraintRect
|
||||||
|
callback:function(aMenuContainer, aMenu)
|
||||||
|
{
|
||||||
|
[aMenu _performActionOfHighlightedItemChain];
|
||||||
|
[aMenu _highlightItemAtIndex:CPNotFound];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPFont)font
|
||||||
|
{
|
||||||
|
[CPFont systemFontOfSize:12.0];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tile
|
||||||
|
{
|
||||||
|
var items = [_menu itemArray],
|
||||||
|
index = 0,
|
||||||
|
count = items.length,
|
||||||
|
|
||||||
|
x = MENUBAR_LEFT_MARGIN,
|
||||||
|
y = 0.0,
|
||||||
|
isLeftAligned = YES;
|
||||||
|
|
||||||
|
for (; index < count; ++index)
|
||||||
|
{
|
||||||
|
var item = items[index];
|
||||||
|
|
||||||
|
if ([item isSeparatorItem])
|
||||||
|
{
|
||||||
|
x = CGRectGetWidth([self frame]) - MENUBAR_RIGHT_MARGIN;
|
||||||
|
isLeftAligned = NO;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([item isHidden])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var menuItemView = [item _menuItemView],
|
||||||
|
frame = [menuItemView frame];
|
||||||
|
|
||||||
|
if (isLeftAligned)
|
||||||
|
{
|
||||||
|
[menuItemView setFrame:CGRectMake(x, 0.0, CGRectGetWidth(frame), MENUBAR_HEIGHT)];
|
||||||
|
|
||||||
|
x += CGRectGetWidth([menuItemView frame]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[menuItemView setFrame:CGRectMake(x - CGRectGetWidth(frame), 0.0, CGRectGetWidth(frame), MENUBAR_HEIGHT)];
|
||||||
|
|
||||||
|
x = CGRectGetMinX([menuItemView frame]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var bounds = [[self contentView] bounds],
|
||||||
|
titleFrame = [_titleField frame];
|
||||||
|
|
||||||
|
if ([_iconImageView isHidden])
|
||||||
|
[_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(titleFrame)) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var iconFrame = [_iconImageView frame],
|
||||||
|
iconWidth = CGRectGetWidth(iconFrame),
|
||||||
|
totalWidth = iconWidth + CGRectGetWidth(titleFrame);
|
||||||
|
|
||||||
|
[_iconImageView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(iconFrame)) / 2.0)];
|
||||||
|
[_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0 + iconWidth, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFrame:(CGRect)aRect display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
|
||||||
|
{
|
||||||
|
var size = [self frame].size;
|
||||||
|
|
||||||
|
[super setFrame:aRect display:shouldDisplay animate:shouldAnimate];
|
||||||
|
|
||||||
|
if (!_CGSizeEqualToSize(size, aRect.size))
|
||||||
|
[self tile];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPMenuBarWindow (CPMenuContainer)
|
||||||
|
|
||||||
|
- (BOOL)isMenuBar
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)globalFrame
|
||||||
|
{
|
||||||
|
return [self frame];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (_CPManagerScrollingState)scrollingStateForPoint:(CGPoint)aGlobalLocation
|
||||||
|
{
|
||||||
|
return _CPMenuManagerScrollingStateNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPInteger)itemIndexAtPoint:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
var items = [_menu itemArray],
|
||||||
|
index = items.length;
|
||||||
|
|
||||||
|
while (index--)
|
||||||
|
{
|
||||||
|
var item = items[index];
|
||||||
|
|
||||||
|
if ([item isHidden] || [item isSeparatorItem])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (CGRectContainsPoint([self rectForItemAtIndex:index], aPoint))
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CPNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)rectForItemAtIndex:(CPInteger)anIndex
|
||||||
|
{
|
||||||
|
var menuItem = [_menu itemAtIndex:anIndex === CPNotFound ? 0 : anIndex];
|
||||||
|
|
||||||
|
return [[menuItem _menuItemView] frame];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPMenuBarView : _CPMenuView
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)rectForItemAtIndex:(int)anIndex
|
||||||
|
{
|
||||||
|
return [_menuItemViews[anIndex === CPNotFound ? 0 : anIndex] frame];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int)itemIndexAtPoint:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
var bounds = [self bounds];
|
||||||
|
|
||||||
|
if (!CGRectContainsPoint(bounds, aPoint))
|
||||||
|
return CPNotFound;
|
||||||
|
|
||||||
|
var x = aPoint.x,
|
||||||
|
low = 0,
|
||||||
|
high = _visibleMenuItemInfos.length - 1;
|
||||||
|
|
||||||
|
while (low <= high)
|
||||||
|
{
|
||||||
|
var middle = FLOOR(low + (high - low) / 2),
|
||||||
|
info = _visibleMenuItemInfos[middle],
|
||||||
|
frame = [info.view frame];
|
||||||
|
|
||||||
|
if (x < CGRectGetMinX(frame))
|
||||||
|
high = middle - 1;
|
||||||
|
|
||||||
|
else if (x > CGRectGetMaxX(frame))
|
||||||
|
low = middle + 1;
|
||||||
|
|
||||||
|
else
|
||||||
|
return info.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CPNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tile
|
||||||
|
{
|
||||||
|
var items = [_menu itemArray],
|
||||||
|
index = 0,
|
||||||
|
count = items.length,
|
||||||
|
|
||||||
|
x = MENUBAR_LEFT_MARGIN,
|
||||||
|
y = 0.0,
|
||||||
|
isLeftAligned = YES;
|
||||||
|
|
||||||
|
for (; index < count; ++index)
|
||||||
|
{
|
||||||
|
var item = items[index];
|
||||||
|
|
||||||
|
if ([item isSeparatorItem])
|
||||||
|
{
|
||||||
|
x = CGRectGetWidth([self frame]) - MENUBAR_RIGHT_MARGIN;
|
||||||
|
isLeftAligned = NO;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([item isHidden])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var menuItemView = [item _menuItemView],
|
||||||
|
frame = [menuItemView frame];
|
||||||
|
|
||||||
|
if (isLeftAligned)
|
||||||
|
{
|
||||||
|
[menuItemView setFrameOrigin:CGPointMake(x, (MENUBAR_HEIGHT - 1.0 - CGRectGetHeight(frame)) / 2.0)];
|
||||||
|
|
||||||
|
x += CGRectGetWidth([menuItemView frame]) + MENUBAR_MARGIN;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[menuItemView setFrameOrigin:CGPointMake(x - CGRectGetWidth(frame), (MENUBAR_HEIGHT - 1.0 - CGRectGetHeight(frame)) / 2.0)];
|
||||||
|
|
||||||
|
x = CGRectGetMinX([menuItemView frame]) - MENUBAR_MARGIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var bounds = [[self contentView] bounds],
|
||||||
|
titleFrame = [_titleField frame];
|
||||||
|
|
||||||
|
if ([_iconImageView isHidden])
|
||||||
|
[_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(titleFrame)) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var iconFrame = [_iconImageView frame],
|
||||||
|
iconWidth = CGRectGetWidth(iconFrame),
|
||||||
|
totalWidth = iconWidth + CGRectGetWidth(titleFrame);
|
||||||
|
|
||||||
|
[_iconImageView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(iconFrame)) / 2.0)];
|
||||||
|
[_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0 + iconWidth, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,370 @@
|
|||||||
|
|
||||||
|
#include "../CoreGraphics/CGGeometry.h"
|
||||||
|
|
||||||
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
|
|
||||||
|
_CPMenuManagerScrollingStateUp = -1,
|
||||||
|
_CPMenuManagerScrollingStateDown = 1,
|
||||||
|
_CPMenuManagerScrollingStateNone = 0;
|
||||||
|
|
||||||
|
var STICKY_TIME_INTERVAL = 500;
|
||||||
|
|
||||||
|
var SharedMenuManager = nil;
|
||||||
|
|
||||||
|
@implementation _CPMenuManager: CPObject
|
||||||
|
{
|
||||||
|
CPTimeInterval _startTime;
|
||||||
|
int _scrollingState;
|
||||||
|
CGPoint _lastGlobalLocation;
|
||||||
|
|
||||||
|
CPView _lastMouseOverMenuView;
|
||||||
|
|
||||||
|
CGRect _constraintRect;
|
||||||
|
CPMutableArray _menuContainerStack;
|
||||||
|
|
||||||
|
Function _trackingCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (_CPMenuManager)sharedMenuManager
|
||||||
|
{
|
||||||
|
if (!SharedMenuManager)
|
||||||
|
SharedMenuManager = [[_CPMenuManager alloc] init];
|
||||||
|
|
||||||
|
return SharedMenuManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
if (SharedMenuManager)
|
||||||
|
return SharedMenuManager;
|
||||||
|
|
||||||
|
return [super init];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)trackingMenuContainer
|
||||||
|
{
|
||||||
|
return _menuContainerStack[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPMenu)trackingMenu
|
||||||
|
{
|
||||||
|
return [[self trackingMenuContainer] menu];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)beginTracking:(CPEvent)anEvent
|
||||||
|
menuContainer:(id)aMenuContainer
|
||||||
|
constraintRect:(CGRect)aRect
|
||||||
|
callback:(Function)aCallback
|
||||||
|
{
|
||||||
|
var menu = [aMenuContainer menu];
|
||||||
|
|
||||||
|
CPApp._activeMenu = menu;
|
||||||
|
|
||||||
|
_startTime = [anEvent timestamp];//new Date();
|
||||||
|
_scrollingState = _CPMenuManagerScrollingStateNone;
|
||||||
|
|
||||||
|
_constraintRect = aRect;
|
||||||
|
_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];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)trackEvent:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
var type = [anEvent type],
|
||||||
|
trackingMenu = [self trackingMenu];
|
||||||
|
|
||||||
|
// Close Menu Event.
|
||||||
|
if (type === CPAppKitDefined)
|
||||||
|
return [self completeTracking]
|
||||||
|
|
||||||
|
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask untilDate:nil inMode:nil dequeue:YES];
|
||||||
|
|
||||||
|
// Periodic events don't have a valid location.
|
||||||
|
var globalLocation = type === CPPeriodic ? _lastGlobalLocation : [anEvent globalLocation];
|
||||||
|
|
||||||
|
// Remember this for the next periodic event.
|
||||||
|
_lastGlobalLocation = globalLocation;
|
||||||
|
|
||||||
|
// Find which menu window the mouse is currently on top of
|
||||||
|
var activeMenuContainer = [self menuContainerForPoint:globalLocation],
|
||||||
|
activeMenu = [activeMenuContainer menu],
|
||||||
|
menuLocation = [activeMenuContainer convertGlobalToBase:globalLocation];
|
||||||
|
|
||||||
|
// Find out the item the mouse is currently on top of
|
||||||
|
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 (_scrollingState === _CPMenuManagerScrollingStateUp)
|
||||||
|
[activeMenuContainer scrollUp];
|
||||||
|
|
||||||
|
else if (_scrollingState === _CPMenuManagerScrollingStateDown)
|
||||||
|
[activeMenuContainer scrollDown];
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're over a custom menu view...
|
||||||
|
if (mouseOverMenuView)
|
||||||
|
{
|
||||||
|
if (!_lastMouseOverMenuView)
|
||||||
|
[activeMenu _highlightItemAtIndex:CPNotFound];
|
||||||
|
|
||||||
|
if (_lastMouseOverMenuView != mouseOverMenuView)
|
||||||
|
{
|
||||||
|
[mouseOverMenuView mouseExited:anEvent];
|
||||||
|
// FIXME: Possibly multiple of these?
|
||||||
|
[_lastMouseOverMenuView mouseEntered:anEvent];
|
||||||
|
|
||||||
|
_lastMouseOverMenuView = mouseOverMenuView;
|
||||||
|
}
|
||||||
|
|
||||||
|
var menuContainerWindow = activeMenuContainer;
|
||||||
|
|
||||||
|
if (![menuContainerWindow isKindOfClass:[CPWindow class]])
|
||||||
|
menuContainerWindow = [menuContainerWindow window];
|
||||||
|
|
||||||
|
[menuContainerWindow
|
||||||
|
sendEvent:[CPEvent mouseEventWithType:type location:menuLocation modifierFlags:[anEvent modifierFlags]
|
||||||
|
timestamp:[anEvent timestamp]
|
||||||
|
windowNumber:menuContainerWindow
|
||||||
|
context:nil
|
||||||
|
eventNumber:0
|
||||||
|
clickCount:[anEvent clickCount]
|
||||||
|
pressure:[anEvent pressure]]];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_lastMouseOverMenuView)
|
||||||
|
{
|
||||||
|
[_lastMouseOverMenuView mouseExited:anEvent];
|
||||||
|
_lastMouseOverMenuView = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
[activeMenu _highlightItemAtIndex:activeItemIndex];
|
||||||
|
|
||||||
|
if (type === CPMouseMoved || type === CPLeftMouseDragged || type === CPLeftMouseDown)
|
||||||
|
{
|
||||||
|
var oldScrollingState = _scrollingState;
|
||||||
|
|
||||||
|
_scrollingState = [activeMenuContainer scrollingStateForPoint:globalLocation];
|
||||||
|
|
||||||
|
if (_scrollingState !== oldScrollingState)
|
||||||
|
{
|
||||||
|
if (_scrollingState === _CPMenuManagerScrollingStateNone)
|
||||||
|
[CPEvent stopPeriodicEvents];
|
||||||
|
|
||||||
|
else if (oldScrollingState === _CPMenuManagerScrollingStateNone)
|
||||||
|
[CPEvent startPeriodicEventsAfterDelay:0.0 withPeriod:0.04];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type === CPLeftMouseUp && ([anEvent timestamp] - _startTime > STICKY_TIME_INTERVAL))
|
||||||
|
[trackingMenu cancelTracking];
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the item has a submenu, show it.
|
||||||
|
if ([activeItem hasSubmenu])// && [activeItem action] === @selector(submenuAction:))
|
||||||
|
{
|
||||||
|
var activeItemRect = [activeMenuContainer rectForItemAtIndex:activeItemIndex];
|
||||||
|
|
||||||
|
if ([activeMenuContainer isMenuBar])
|
||||||
|
var newMenuOrigin = CGPointMake(CGRectGetMinX(activeItemRect), CGRectGetMaxY(activeItemRect));
|
||||||
|
else
|
||||||
|
var newMenuOrigin = CGPointMake(CGRectGetMaxX(activeItemRect), CGRectGetMinY(activeItemRect));
|
||||||
|
|
||||||
|
newMenuOrigin = [activeMenuContainer convertBaseToGlobal:newMenuOrigin];
|
||||||
|
|
||||||
|
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:newMenuOrigin];
|
||||||
|
}
|
||||||
|
|
||||||
|
// This handles both the case where we've moved away from the menu, and where
|
||||||
|
// we've moved to an item without a submenu.
|
||||||
|
else
|
||||||
|
[self showMenu:nil fromMenu:activeMenu atPoint:CGPointMakeZero()];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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
|
||||||
|
{
|
||||||
|
var count = [_menuContainerStack count],
|
||||||
|
firstMenuContainer = _menuContainerStack[0];
|
||||||
|
|
||||||
|
// Trivial case.
|
||||||
|
if (count === 1)
|
||||||
|
return firstMenuContainer;
|
||||||
|
|
||||||
|
var firstMenuWindowIndex = 0,
|
||||||
|
lastMenuWindowIndex = count - 1;
|
||||||
|
|
||||||
|
// If the first menu container is a bar, then it has to fall strictly within its bounds.
|
||||||
|
if ([firstMenuContainer isMenuBar])
|
||||||
|
{
|
||||||
|
if (CGRectContainsPoint([firstMenuContainer globalFrame], aGlobalLocation))
|
||||||
|
return firstMenuContainer;
|
||||||
|
|
||||||
|
firstMenuWindowIndex = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var index = count,
|
||||||
|
x = aGlobalLocation.x,
|
||||||
|
closerDeltaX = Infinity,
|
||||||
|
closerMenuContainer = nil;
|
||||||
|
|
||||||
|
while (index-- > firstMenuWindowIndex)
|
||||||
|
{
|
||||||
|
var menuContainer = _menuContainerStack[index],
|
||||||
|
menuContainerFrame = [menuContainer globalFrame],
|
||||||
|
menuContainerMinX = _CGRectGetMinX(menuContainerFrame),
|
||||||
|
menuContainerMaxX = _CGRectGetMaxX(menuContainerFrame);
|
||||||
|
|
||||||
|
// If within the x bounds of this menu container, return it.
|
||||||
|
if (x < menuContainerMaxX && x >= menuContainerMinX)
|
||||||
|
return menuContainer;
|
||||||
|
|
||||||
|
// If this is either the first or last menu *window*, check to see how close we are to it.
|
||||||
|
if (index === firstMenuWindowIndex || index === lastMenuWindowIndex)
|
||||||
|
{
|
||||||
|
var deltaX = ABS(x < menuContainerMinX ? menuContainerMinX - x : menuContainerMaxX - x);
|
||||||
|
|
||||||
|
if (deltaX < closerDeltaX)
|
||||||
|
{
|
||||||
|
closerMenuContainer = menuContainer;
|
||||||
|
closerDeltaX = deltaX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closerMenuContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)showMenu:(CPMenu)newMenu fromMenu:(CPMenu)baseMenu atPoint:(CGPoint)aGlobalLocation
|
||||||
|
{
|
||||||
|
var count = _menuContainerStack.length,
|
||||||
|
index = count;
|
||||||
|
|
||||||
|
// Hide all menus up to the base menu...
|
||||||
|
while (index--)
|
||||||
|
{
|
||||||
|
var menuContainer = _menuContainerStack[index],
|
||||||
|
menu = [menuContainer menu];
|
||||||
|
|
||||||
|
// If we reach the base menu, or this menu is already being shown, break.
|
||||||
|
if (menu === baseMenu)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// If this menu is already being shown, unhighlight and return.
|
||||||
|
if (menu === newMenu)//&& [menu supermenu] === baseMenu)
|
||||||
|
return [newMenu _highlightItemAtIndex:CPNotFound];
|
||||||
|
|
||||||
|
[menuContainer orderOut:self];
|
||||||
|
[menuContainer setMenu:nil];
|
||||||
|
|
||||||
|
[_CPMenuWindow poolMenuWindow:menuContainer];
|
||||||
|
[_menuContainerStack removeObjectAtIndex:index];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newMenu)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Unhighlight any previously highlighted item.
|
||||||
|
[newMenu _highlightItemAtIndex:CPNotFound];
|
||||||
|
|
||||||
|
var menuWindow = [_CPMenuWindow menuWindowWithMenu:newMenu font:[_menuContainerStack[0] font]];
|
||||||
|
|
||||||
|
[_menuContainerStack addObject:menuWindow];
|
||||||
|
|
||||||
|
[menuWindow setConstraintRect:_constraintRect];
|
||||||
|
|
||||||
|
// If our parent menu is a menu bar...
|
||||||
|
if (baseMenu === [self trackingMenu] && [[self trackingMenuContainer] isMenuBar])
|
||||||
|
[menuWindow setBackgroundStyle:_CPMenuWindowMenuBarBackgroundStyle];
|
||||||
|
else
|
||||||
|
[menuWindow setBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle];
|
||||||
|
|
||||||
|
[menuWindow setFrameOrigin:aGlobalLocation];
|
||||||
|
[menuWindow orderFront:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,548 @@
|
|||||||
|
|
||||||
|
#include "../CoreGraphics/CGGeometry.h"
|
||||||
|
|
||||||
|
|
||||||
|
var _CPMenuWindowPool = [],
|
||||||
|
_CPMenuWindowPoolCapacity = 5,
|
||||||
|
|
||||||
|
_CPMenuWindowBackgroundColors = [];
|
||||||
|
|
||||||
|
_CPMenuWindowMenuBarBackgroundStyle = 0;
|
||||||
|
_CPMenuWindowPopUpBackgroundStyle = 1;
|
||||||
|
_CPMenuWindowAttachedMenuBackgroundStyle = 2;
|
||||||
|
|
||||||
|
var STICKY_TIME_INTERVAL = 500,
|
||||||
|
|
||||||
|
TOP_MARGIN = 5.0,
|
||||||
|
LEFT_MARGIN = 1.0,
|
||||||
|
RIGHT_MARGIN = 1.0,
|
||||||
|
BOTTOM_MARGIN = 5.0,
|
||||||
|
|
||||||
|
SCROLL_INDICATOR_HEIGHT = 16.0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
@ignore
|
||||||
|
*/
|
||||||
|
@implementation _CPMenuWindow : CPWindow
|
||||||
|
{
|
||||||
|
_CPMenuView _menuView;
|
||||||
|
CPClipView _menuClipView;
|
||||||
|
|
||||||
|
CPImageView _moreAboveView;
|
||||||
|
CPImageView _moreBelowView;
|
||||||
|
|
||||||
|
CGRect _unconstrainedFrame;
|
||||||
|
CGRect _constraintRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)menuWindowWithMenu:(CPMenu)aMenu font:(CPFont)aFont
|
||||||
|
{
|
||||||
|
var menuWindow = nil;
|
||||||
|
|
||||||
|
if (_CPMenuWindowPool.length)
|
||||||
|
{
|
||||||
|
menuWindow = _CPMenuWindowPool.pop();
|
||||||
|
|
||||||
|
// Do this so that coordinates will be accurate.
|
||||||
|
[menuWindow setFrameOrigin:CGPointMakeZero()];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
menuWindow = [[_CPMenuWindow alloc] init];
|
||||||
|
|
||||||
|
[menuWindow setFont:aFont];
|
||||||
|
[menuWindow setMenu:aMenu];
|
||||||
|
[menuWindow setMinWidth:[aMenu minimumWidth]];
|
||||||
|
|
||||||
|
return menuWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)poolMenuWindow:(_CPMenuWindow)aMenuWindow
|
||||||
|
{
|
||||||
|
if (!aMenuWindow || _CPMenuWindowPool.length >= _CPMenuWindowPoolCapacity)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_CPMenuWindowPool.push(aMenuWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
if (self != [_CPMenuWindow class])
|
||||||
|
return;
|
||||||
|
|
||||||
|
var bundle = [CPBundle bundleForClass:self];
|
||||||
|
|
||||||
|
_CPMenuWindowMoreAboveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowMoreAbove.png"] size:CGSizeMake(38.0, 18.0)];
|
||||||
|
_CPMenuWindowMoreBelowImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowMoreBelow.png"] size:CGSizeMake(38.0, 18.0)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithContentRect:(CGRect)aRect styleMask:(unsigned)aStyleMask
|
||||||
|
{
|
||||||
|
_constraintRect = _CGRectMakeZero();
|
||||||
|
_unconstrainedFrame = _CGRectMakeZero();
|
||||||
|
|
||||||
|
self = [super initWithContentRect:aRect styleMask:CPBorderlessWindowMask];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
[self setLevel:CPPopUpMenuWindowLevel];
|
||||||
|
[self setHasShadow:YES];
|
||||||
|
[self setShadowStyle:CPMenuWindowShadowStyle];
|
||||||
|
[self setAcceptsMouseMovedEvents:YES];
|
||||||
|
|
||||||
|
var contentView = [self contentView];
|
||||||
|
|
||||||
|
_menuView = [[_CPMenuView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
|
_menuClipView = [[CPClipView alloc] initWithFrame:CGRectMake(LEFT_MARGIN, TOP_MARGIN, 0.0, 0.0)];
|
||||||
|
[_menuClipView setDocumentView:_menuView];
|
||||||
|
|
||||||
|
[contentView addSubview:_menuClipView];
|
||||||
|
|
||||||
|
_moreAboveView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
|
[_moreAboveView setImage:_CPMenuWindowMoreAboveImage];
|
||||||
|
[_moreAboveView setFrameSize:[_CPMenuWindowMoreAboveImage size]];
|
||||||
|
|
||||||
|
[contentView addSubview:_moreAboveView];
|
||||||
|
|
||||||
|
_moreBelowView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
|
[_moreBelowView setImage:_CPMenuWindowMoreBelowImage];
|
||||||
|
[_moreBelowView setFrameSize:[_CPMenuWindowMoreBelowImage size]];
|
||||||
|
|
||||||
|
[contentView addSubview:_moreBelowView];
|
||||||
|
|
||||||
|
[self setShadowStyle:CPWindowShadowStyleMenu];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (float)_standardLeftMargin
|
||||||
|
{
|
||||||
|
return LEFT_MARGIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFont:(CPFont)aFont
|
||||||
|
{
|
||||||
|
[_menuView setFont:aFont];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPFont)font
|
||||||
|
{
|
||||||
|
return [_menuView font];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPColor)backgroundColorForBackgroundStyle:(_CPMenuWindowBackgroundStyle)aBackgroundStyle
|
||||||
|
{
|
||||||
|
var color = _CPMenuWindowBackgroundColors[aBackgroundStyle];
|
||||||
|
|
||||||
|
if (!color)
|
||||||
|
{
|
||||||
|
var bundle = [CPBundle bundleForClass:[self class]];
|
||||||
|
|
||||||
|
if (aBackgroundStyle == _CPMenuWindowPopUpBackgroundStyle)
|
||||||
|
color = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
||||||
|
[
|
||||||
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded0.png"] size:CGSizeMake(4.0, 4.0)],
|
||||||
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow1.png"] size:CGSizeMake(1.0, 4.0)],
|
||||||
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded2.png"] size:CGSizeMake(4.0, 4.0)],
|
||||||
|
|
||||||
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 1.0)],
|
||||||
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 1.0)],
|
||||||
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 1.0)],
|
||||||
|
|
||||||
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded6.png"] size:CGSizeMake(4.0, 4.0)],
|
||||||
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow7.png"] size:CGSizeMake(1.0, 4.0)],
|
||||||
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded8.png"] size:CGSizeMake(4.0, 4.0)]
|
||||||
|
]]];
|
||||||
|
|
||||||
|
else if (aBackgroundStyle == _CPMenuWindowMenuBarBackgroundStyle)
|
||||||
|
color = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
||||||
|
[
|
||||||
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 0.0)],
|
||||||
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 0.0)],
|
||||||
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 0.0)],
|
||||||
|
|
||||||
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 1.0)],
|
||||||
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 1.0)],
|
||||||
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 1.0)],
|
||||||
|
|
||||||
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded6.png"] size:CGSizeMake(4.0, 4.0)],
|
||||||
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow7.png"] size:CGSizeMake(1.0, 4.0)],
|
||||||
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded8.png"] size:CGSizeMake(4.0, 4.0)]
|
||||||
|
]]];
|
||||||
|
|
||||||
|
_CPMenuWindowBackgroundColors[aBackgroundStyle] = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setBackgroundStyle:(_CPMenuWindowBackgroundStyle)aBackgroundStyle
|
||||||
|
{
|
||||||
|
[self setBackgroundColor:[[self class] backgroundColorForBackgroundStyle:aBackgroundStyle]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setMenu:(CPMenu)aMenu
|
||||||
|
{
|
||||||
|
[aMenu _setMenuWindow:self];
|
||||||
|
[_menuView setMenu:aMenu];
|
||||||
|
|
||||||
|
var menuViewSize = [_menuView frame].size;
|
||||||
|
|
||||||
|
[self setFrameSize:CGSizeMake(LEFT_MARGIN + menuViewSize.width + RIGHT_MARGIN, TOP_MARGIN + menuViewSize.height + BOTTOM_MARGIN)];
|
||||||
|
|
||||||
|
[_menuView scrollPoint:CGPointMake(0.0, 0.0)];
|
||||||
|
[_menuClipView setFrame:CGRectMake(LEFT_MARGIN, TOP_MARGIN, menuViewSize.width, menuViewSize.height)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setMinWidth:(float)aWidth
|
||||||
|
{
|
||||||
|
var size = [self unconstrainedFrame].size;
|
||||||
|
|
||||||
|
[self setFrameSize:CGSizeMake(MAX(size.width, aWidth), size.height)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPMenu)menu
|
||||||
|
{
|
||||||
|
return [_menuView menu];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)orderFront:(id)aSender
|
||||||
|
{
|
||||||
|
[self setFrame:_unconstrainedFrame];
|
||||||
|
|
||||||
|
[super orderFront:aSender];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setConstraintRect:(CGRect)aRect
|
||||||
|
{
|
||||||
|
_constraintRect = aRect;
|
||||||
|
|
||||||
|
[self setFrame:_unconstrainedFrame];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)unconstrainedFrame
|
||||||
|
{
|
||||||
|
return _CGRectMakeCopy(_unconstrainedFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need this because if not this will call setFrame: with -frame instead of -unconstrainedFrame, turning
|
||||||
|
// the constrained frame into the unconstrained frame.
|
||||||
|
- (void)setFrameOrigin:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
[super setFrame:_CGRectMake(aPoint.x, aPoint.y, _CGRectGetWidth(_unconstrainedFrame), _CGRectGetHeight(_unconstrainedFrame))];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFrameSize:(CGSize)aSize
|
||||||
|
{
|
||||||
|
[super setFrame:_CGRectMake(_CGRectGetMinX(_unconstrainedFrame), _CGRectGetMinY(_unconstrainedFrame), aSize.width, aSize.height)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
|
||||||
|
{
|
||||||
|
// FIXME: There are integral window issues with platform windows.
|
||||||
|
// FIXME: This gets called far too often.
|
||||||
|
_unconstrainedFrame = _CGRectMakeCopy(aFrame);
|
||||||
|
|
||||||
|
var constrainedFrame = CGRectIntersection(_unconstrainedFrame, _constraintRect);
|
||||||
|
|
||||||
|
// We don't want to simply intersect the visible frame and the unconstrained frame.
|
||||||
|
// We should be allowing as much of the width to fit as possible (pushing back and forward).
|
||||||
|
constrainedFrame.origin.x = CGRectGetMinX(_unconstrainedFrame);
|
||||||
|
constrainedFrame.size.width = CGRectGetWidth(_unconstrainedFrame);
|
||||||
|
|
||||||
|
if (CGRectGetWidth(constrainedFrame) > CGRectGetWidth(_constraintRect))
|
||||||
|
constrainedFrame.size.width = CGRectGetWidth(_constraintRect);
|
||||||
|
|
||||||
|
if (CGRectGetMaxX(constrainedFrame) > CGRectGetMaxX(_constraintRect))
|
||||||
|
constrainedFrame.origin.x -= CGRectGetMaxX(constrainedFrame) - CGRectGetMaxX(_constraintRect);
|
||||||
|
|
||||||
|
if (CGRectGetMinX(constrainedFrame) < CGRectGetMinX(_constraintRect))
|
||||||
|
constrainedFrame.origin.x = CGRectGetMinX(_constraintRect);
|
||||||
|
|
||||||
|
[super setFrame:constrainedFrame display:shouldDisplay animate:shouldAnimate];
|
||||||
|
|
||||||
|
// This needs to happen before changing the frame.
|
||||||
|
var menuViewOrigin = CGPointMake(CGRectGetMinX(aFrame) + LEFT_MARGIN, CGRectGetMinY(aFrame) + TOP_MARGIN),
|
||||||
|
moreAbove = menuViewOrigin.y < CGRectGetMinY(constrainedFrame) + TOP_MARGIN,
|
||||||
|
moreBelow = menuViewOrigin.y + CGRectGetHeight([_menuView frame]) > CGRectGetMaxY(constrainedFrame) - BOTTOM_MARGIN,
|
||||||
|
|
||||||
|
topMargin = TOP_MARGIN,
|
||||||
|
bottomMargin = BOTTOM_MARGIN,
|
||||||
|
|
||||||
|
contentView = [self contentView],
|
||||||
|
bounds = [contentView bounds];
|
||||||
|
|
||||||
|
if (moreAbove)
|
||||||
|
{
|
||||||
|
topMargin += SCROLL_INDICATOR_HEIGHT;
|
||||||
|
|
||||||
|
var frame = [_moreAboveView frame];
|
||||||
|
|
||||||
|
[_moreAboveView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(frame)) / 2.0, (TOP_MARGIN + SCROLL_INDICATOR_HEIGHT - CGRectGetHeight(frame)) / 2.0)];
|
||||||
|
}
|
||||||
|
|
||||||
|
[_moreAboveView setHidden:!moreAbove];
|
||||||
|
|
||||||
|
if (moreBelow)
|
||||||
|
{
|
||||||
|
bottomMargin += SCROLL_INDICATOR_HEIGHT;
|
||||||
|
|
||||||
|
[_moreBelowView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth([_moreBelowView frame])) / 2.0, CGRectGetHeight(bounds) - SCROLL_INDICATOR_HEIGHT - BOTTOM_MARGIN)];
|
||||||
|
}
|
||||||
|
|
||||||
|
[_moreBelowView setHidden:!moreBelow];
|
||||||
|
|
||||||
|
var clipFrame = CGRectMake(LEFT_MARGIN, topMargin, CGRectGetWidth(constrainedFrame) - LEFT_MARGIN - RIGHT_MARGIN, CGRectGetHeight(constrainedFrame) - topMargin - bottomMargin)
|
||||||
|
|
||||||
|
[_menuClipView setFrame:clipFrame];
|
||||||
|
[_menuView setFrameSize:CGSizeMake(CGRectGetWidth(clipFrame), CGRectGetHeight([_menuView frame]))];
|
||||||
|
|
||||||
|
[_menuView scrollPoint:CGPointMake(0.0, [self convertBaseToGlobal:clipFrame.origin].y - menuViewOrigin.y)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)hasMinimumNumberOfVisibleItems
|
||||||
|
{
|
||||||
|
var visibleRect = [_menuView visibleRect];
|
||||||
|
|
||||||
|
// Clearly if the entire view isn't visible the minimum won't be visible.
|
||||||
|
if (CGRectIsEmpty(visibleRect))
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
var numberOfUnhiddenItems = [_menuView numberOfUnhiddenItems],
|
||||||
|
minimumNumberOfVisibleItems = MIN(numberOfUnhiddenItems, 3),
|
||||||
|
count = 0,
|
||||||
|
index = [_menuView itemIndexAtPoint:[_menuView convertPoint:[_menuClipView frame].origin fromView:nil]];
|
||||||
|
|
||||||
|
for (; index < numberOfUnhiddenItems && count < minimumNumberOfVisibleItems; ++index)
|
||||||
|
{
|
||||||
|
var itemRect = [_menuView rectForUnhiddenItemAtIndex:index],
|
||||||
|
visibleItemRect = CGRectIntersection(visibleRect, itemRect);
|
||||||
|
|
||||||
|
// As soon as we get to the first unhidden item that is no longer visible, stop.
|
||||||
|
if (CGRectIsEmpty(visibleItemRect))
|
||||||
|
break;
|
||||||
|
|
||||||
|
// If the item is *completely* visible, count it.
|
||||||
|
if (CGRectEqualToRect(visibleItemRect, itemRect))
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count >= minimumNumberOfVisibleItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)canScrollUp
|
||||||
|
{
|
||||||
|
return ![_moreAboveView isHidden];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)canScrollDown
|
||||||
|
{
|
||||||
|
return ![_moreBelowView isHidden];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)canScroll
|
||||||
|
{
|
||||||
|
return [self canScrollUp] || [self canScrollDown];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)scrollUp
|
||||||
|
{
|
||||||
|
if (CGRectGetMinY(_unconstrainedFrame) >= CGRectGetMinY(_constraintRect))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_unconstrainedFrame.origin.y += 10;
|
||||||
|
|
||||||
|
[self setFrame:_unconstrainedFrame];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)scrollDown
|
||||||
|
{
|
||||||
|
if (CGRectGetMaxY(_unconstrainedFrame) <= CGRectGetHeight(_constraintRect))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_unconstrainedFrame.origin.y -= 10;
|
||||||
|
|
||||||
|
[self setFrame:_unconstrainedFrame];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPMenuWindow (CPMenuContainer)
|
||||||
|
|
||||||
|
- (CGRect)globalFrame
|
||||||
|
{
|
||||||
|
return [self frame];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isMenuBar
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (_CPManagerScrollingState)scrollingStateForPoint:(CGPoint)aGlobalLocation
|
||||||
|
{
|
||||||
|
var frame = [self frame];
|
||||||
|
|
||||||
|
if (![self canScroll])
|
||||||
|
return _CPMenuManagerScrollingStateNone;
|
||||||
|
|
||||||
|
// If we're at or above of the top scroll indicator...
|
||||||
|
if (aGlobalLocation.y < CGRectGetMinY(frame) + TOP_MARGIN + SCROLL_INDICATOR_HEIGHT)
|
||||||
|
return _CPMenuManagerScrollingStateUp;
|
||||||
|
|
||||||
|
// If we're at or below the bottom scroll indicator...
|
||||||
|
if (aGlobalLocation.y > CGRectGetMaxY(frame) - BOTTOM_MARGIN - SCROLL_INDICATOR_HEIGHT)
|
||||||
|
return _CPMenuManagerScrollingStateDown;
|
||||||
|
|
||||||
|
return _CPMenuManagerScrollingStateNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (float)deltaYForItemAtIndex:(int)anIndex
|
||||||
|
{
|
||||||
|
return TOP_MARGIN + CGRectGetMinY([_menuView rectForItemAtIndex:anIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGPoint)rectForItemAtIndex:(int)anIndex
|
||||||
|
{
|
||||||
|
return [_menuView convertRect:[_menuView rectForItemAtIndex:anIndex] toView:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int)itemIndexAtPoint:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
// Don't return indexes of items that aren't visible.
|
||||||
|
if (!CGRectContainsPoint([_menuClipView bounds], [_menuClipView convertPoint:aPoint fromView:nil]))
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
return [_menuView itemIndexAtPoint:[_menuView convertPoint:aPoint fromView:nil]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
/*
|
||||||
|
@ignore
|
||||||
|
*/
|
||||||
|
|
||||||
|
@implementation _CPMenuView : CPView
|
||||||
|
{
|
||||||
|
CPArray _menuItemViews;
|
||||||
|
CPArray _visibleMenuItemInfos;
|
||||||
|
|
||||||
|
CPFont _font @accessors(property=font);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (unsigned)numberOfUnhiddenItems
|
||||||
|
{
|
||||||
|
return _visibleMenuItemInfos.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)rectForUnhiddenItemAtIndex:(int)anIndex
|
||||||
|
{
|
||||||
|
return [self rectForItemAtIndex:_visibleMenuItemInfos[anIndex].index];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)rectForItemAtIndex:(int)anIndex
|
||||||
|
{
|
||||||
|
return [_menuItemViews[anIndex === CPNotFound ? 0 : anIndex] frame];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int)itemIndexAtPoint:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
var x = aPoint.x,
|
||||||
|
bounds = [self bounds];
|
||||||
|
|
||||||
|
if (x < CGRectGetMinX(bounds) || x > CGRectGetMaxX(bounds))
|
||||||
|
return CPNotFound;
|
||||||
|
|
||||||
|
var y = aPoint.y,
|
||||||
|
low = 0,
|
||||||
|
high = _visibleMenuItemInfos.length - 1;
|
||||||
|
|
||||||
|
while (low <= high)
|
||||||
|
{
|
||||||
|
var middle = FLOOR(low + (high - low) / 2),
|
||||||
|
info = _visibleMenuItemInfos[middle]
|
||||||
|
frame = [info.view frame];
|
||||||
|
|
||||||
|
if (y < CGRectGetMinY(frame))
|
||||||
|
high = middle - 1;
|
||||||
|
|
||||||
|
else if (y > CGRectGetMaxY(frame))
|
||||||
|
low = middle + 1;
|
||||||
|
|
||||||
|
else
|
||||||
|
return info.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CPNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tile
|
||||||
|
{
|
||||||
|
[_menuItemViews makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||||
|
|
||||||
|
_menuItemViews = [];
|
||||||
|
_visibleMenuItemInfos = [];
|
||||||
|
|
||||||
|
var menu = [self menu];
|
||||||
|
|
||||||
|
if (!menu)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var items = [menu itemArray],
|
||||||
|
index = 0,
|
||||||
|
count = [items count],
|
||||||
|
maxWidth = 0,
|
||||||
|
y = 0,
|
||||||
|
showsStateColumn = [menu showsStateColumn];
|
||||||
|
|
||||||
|
for (; index < count; ++index)
|
||||||
|
{
|
||||||
|
var item = items[index],
|
||||||
|
view = [item _menuItemView];
|
||||||
|
|
||||||
|
_menuItemViews.push(view);
|
||||||
|
|
||||||
|
if ([item isHidden])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
_visibleMenuItemInfos.push({ view:view, index:index });
|
||||||
|
|
||||||
|
[view setFont:_font];
|
||||||
|
[view setShowsStateColumn:showsStateColumn];
|
||||||
|
[view synchronizeWithMenuItem];
|
||||||
|
|
||||||
|
[view setFrameOrigin:CGPointMake(0.0, y)];
|
||||||
|
|
||||||
|
[self addSubview:view];
|
||||||
|
|
||||||
|
var size = [view minSize],
|
||||||
|
width = size.width;
|
||||||
|
|
||||||
|
if (maxWidth < width)
|
||||||
|
maxWidth = width;
|
||||||
|
|
||||||
|
y += size.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (index = 0; index < count; ++index)
|
||||||
|
{
|
||||||
|
var view = _menuItemViews[index];
|
||||||
|
|
||||||
|
[view setFrameSize:CGSizeMake(maxWidth, CGRectGetHeight([view frame]))];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self setAutoresizesSubviews:NO];
|
||||||
|
[self setFrameSize:CGSizeMake(maxWidth, y)];
|
||||||
|
[self setAutoresizesSubviews:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setMenu:(CPMenu)aMenu
|
||||||
|
{
|
||||||
|
[super setMenu:aMenu];
|
||||||
|
[self tile];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -24,9 +24,10 @@
|
|||||||
@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/CPMenu.j>
|
@import "CPMenu.j"
|
||||||
@import <AppKit/CPView.j>
|
@import "CPView.j"
|
||||||
|
@import "_CPMenuItemView.j"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -38,6 +39,8 @@
|
|||||||
*/
|
*/
|
||||||
@implementation CPMenuItem : CPObject
|
@implementation CPMenuItem : CPObject
|
||||||
{
|
{
|
||||||
|
BOOL _isSeparator;
|
||||||
|
|
||||||
CPString _title;
|
CPString _title;
|
||||||
//CPAttributedString _attributedTitle;
|
//CPAttributedString _attributedTitle;
|
||||||
|
|
||||||
@@ -76,6 +79,11 @@
|
|||||||
_CPMenuItemView _menuItemView;
|
_CPMenuItemView _menuItemView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
return [self initWithTitle:@"" action:nil keyEquivalent:nil];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Initializes the menu item with a title, action, and keyboard equivalent.
|
Initializes the menu item with a title, action, and keyboard equivalent.
|
||||||
@param aTitle the menu item's title
|
@param aTitle the menu item's title
|
||||||
@@ -89,6 +97,8 @@
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
|
_isSeparator = NO;
|
||||||
|
|
||||||
_title = aTitle;
|
_title = aTitle;
|
||||||
_action = anAction;
|
_action = anAction;
|
||||||
|
|
||||||
@@ -100,6 +110,8 @@
|
|||||||
_keyEquivalent = aKeyEquivalent || @"";
|
_keyEquivalent = aKeyEquivalent || @"";
|
||||||
_keyEquivalentModifierMask = CPPlatformActionKeyMask;
|
_keyEquivalentModifierMask = CPPlatformActionKeyMask;
|
||||||
|
|
||||||
|
_indentationLevel = 0;
|
||||||
|
|
||||||
_mnemonicLocation = CPNotFound;
|
_mnemonicLocation = CPNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +121,7 @@
|
|||||||
// Enabling a Menu Item
|
// Enabling a Menu Item
|
||||||
/*!
|
/*!
|
||||||
Sets whether the menu item is enabled or not
|
Sets whether the menu item is enabled or not
|
||||||
@param isEnabled <code>YES</code> enables the item. <code>NO</code> disables it.
|
@param isEnabled \c YES enables the item. \c NO disables it.
|
||||||
*/
|
*/
|
||||||
- (void)setEnabled:(BOOL)isEnabled
|
- (void)setEnabled:(BOOL)isEnabled
|
||||||
{
|
{
|
||||||
@@ -124,7 +136,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the item is enabled.
|
Returns \c YES if the item is enabled.
|
||||||
*/
|
*/
|
||||||
- (BOOL)isEnabled
|
- (BOOL)isEnabled
|
||||||
{
|
{
|
||||||
@@ -134,7 +146,7 @@
|
|||||||
// Managing Hidden Status
|
// Managing Hidden Status
|
||||||
/*!
|
/*!
|
||||||
Sets whether the item should be hidden. A hidden item can not be triggered by keyboard shortcuts.
|
Sets whether the item should be hidden. A hidden item can not be triggered by keyboard shortcuts.
|
||||||
@param isHidden <code>YES</code> hides the item. <code>NO</code> reveals it.
|
@param isHidden \c YES hides the item. \c NO reveals it.
|
||||||
*/
|
*/
|
||||||
- (void)setHidden:(BOOL)isHidden
|
- (void)setHidden:(BOOL)isHidden
|
||||||
{
|
{
|
||||||
@@ -147,7 +159,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the item is hidden.
|
Returns \c YES if the item is hidden.
|
||||||
*/
|
*/
|
||||||
- (BOOL)isHidden
|
- (BOOL)isHidden
|
||||||
{
|
{
|
||||||
@@ -155,7 +167,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the item is hidden or if one of it's supermenus is hidden.
|
Returns \c YES if the item is hidden or if one of it's supermenus is hidden.
|
||||||
*/
|
*/
|
||||||
- (BOOL)isHiddenOrHasHiddenAncestor
|
- (BOOL)isHiddenOrHasHiddenAncestor
|
||||||
{
|
{
|
||||||
@@ -439,25 +451,37 @@ CPOffState
|
|||||||
*/
|
*/
|
||||||
- (void)setSubmenu:(CPMenu)aMenu
|
- (void)setSubmenu:(CPMenu)aMenu
|
||||||
{
|
{
|
||||||
var supermenu = [_submenu supermenu];
|
if (_submenu === aMenu)
|
||||||
|
|
||||||
if (supermenu == self)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (supermenu)
|
var supermenu = [_submenu supermenu];
|
||||||
return alert("bad");
|
|
||||||
|
|
||||||
[_submenu setSupermenu:_menu];
|
if (supermenu)
|
||||||
|
[CPException raise:CPInvalidArgumentException
|
||||||
|
reason: @"Can't add submenu \"" + [aMenu title] + "\" to item \"" + [self title] + "\", because it is already submenu of \"" + [[aMenu supermenu] title] + "\""];
|
||||||
|
|
||||||
_submenu = aMenu;
|
_submenu = aMenu;
|
||||||
|
|
||||||
|
if (_submenu)
|
||||||
|
{
|
||||||
|
[_submenu setSupermenu:_menu];
|
||||||
|
|
||||||
|
[self setTarget:_menu];
|
||||||
|
[self setAction:@selector(submenuAction:)];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[self setTarget:nil];
|
||||||
|
[self setAction:NULL];
|
||||||
|
}
|
||||||
|
|
||||||
[_menuItemView setDirty];
|
[_menuItemView setDirty];
|
||||||
|
|
||||||
[_menu itemChanged:self];
|
[_menu itemChanged:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the submenu of the item. <code>nil</code> if there is no submenu.
|
Returns the submenu of the item. \c nil if there is no submenu.
|
||||||
*/
|
*/
|
||||||
- (CPMenu)submenu
|
- (CPMenu)submenu
|
||||||
{
|
{
|
||||||
@@ -465,7 +489,7 @@ CPOffState
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the menu item has a submenu.
|
Returns \c YES if the menu item has a submenu.
|
||||||
*/
|
*/
|
||||||
- (BOOL)hasSubmenu
|
- (BOOL)hasSubmenu
|
||||||
{
|
{
|
||||||
@@ -479,15 +503,19 @@ CPOffState
|
|||||||
*/
|
*/
|
||||||
+ (CPMenuItem)separatorItem
|
+ (CPMenuItem)separatorItem
|
||||||
{
|
{
|
||||||
return [[_CPMenuItemSeparator alloc] init];
|
var separatorItem = [[self alloc] initWithTitle:@"" action:nil keyEquivalent:nil];
|
||||||
|
|
||||||
|
separatorItem._isSeparator = YES;
|
||||||
|
|
||||||
|
return separatorItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the menu item is a separator.
|
Returns \c YES if the menu item is a separator.
|
||||||
*/
|
*/
|
||||||
- (BOOL)isSeparatorItem
|
- (BOOL)isSeparatorItem
|
||||||
{
|
{
|
||||||
return NO;
|
return _isSeparator;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Managing the Owning Menu
|
// Managing the Owning Menu
|
||||||
@@ -557,6 +585,43 @@ CPControlKeyMask
|
|||||||
return _keyEquivalentModifierMask;
|
return _keyEquivalentModifierMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (CPString)keyEquivalentStringRepresentation
|
||||||
|
{
|
||||||
|
if (![_keyEquivalent length])
|
||||||
|
return @"";
|
||||||
|
|
||||||
|
var string = _keyEquivalent.toUpperCase(),
|
||||||
|
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask || string === _keyEquivalent;
|
||||||
|
|
||||||
|
if (CPBrowserIsOperatingSystem(CPMacOperatingSystem))
|
||||||
|
{
|
||||||
|
if (_keyEquivalentModifierMask & CPCommandKeyMask)
|
||||||
|
string = "⌘" + string;
|
||||||
|
|
||||||
|
if (needsShift)
|
||||||
|
string = "⇧" + string;
|
||||||
|
|
||||||
|
if (_keyEquivalentModifierMask & CPAlternateKeyMask)
|
||||||
|
string = "⌥" + string;
|
||||||
|
|
||||||
|
if (_keyEquivalentModifierMask & CPControlKeyMask)
|
||||||
|
string = "^" + string;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (needsShift)
|
||||||
|
string = "Shift-" + string;
|
||||||
|
|
||||||
|
if (_keyEquivalentModifierMask & CPAlternateKeyMask)
|
||||||
|
string = "Alt-" + string;
|
||||||
|
|
||||||
|
if (_keyEquivalentModifierMask & CPControlKeyMask || _keyEquivalentModifierMask & CPCommandKeyMask)
|
||||||
|
string = "Ctrl-" + string;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
// Managing Mnemonics
|
// Managing Mnemonics
|
||||||
/*!
|
/*!
|
||||||
Sets the index of the mnemonic character in the title. The character
|
Sets the index of the mnemonic character in the title. The character
|
||||||
@@ -605,7 +670,7 @@ CPControlKeyMask
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether this item is an alternate for the previous menu item.
|
Sets whether this item is an alternate for the previous menu item.
|
||||||
@param isAlternate <code>YES</code> denotes that this menu item is an alternate
|
@param isAlternate \c YES denotes that this menu item is an alternate
|
||||||
*/
|
*/
|
||||||
- (void)setAlternate:(BOOL)isAlternate
|
- (void)setAlternate:(BOOL)isAlternate
|
||||||
{
|
{
|
||||||
@@ -613,7 +678,7 @@ CPControlKeyMask
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the menu item is an alternate for the previous item.
|
Returns \c YES if the menu item is an alternate for the previous item.
|
||||||
*/
|
*/
|
||||||
- (BOOL)isAlternate
|
- (BOOL)isAlternate
|
||||||
{
|
{
|
||||||
@@ -630,7 +695,7 @@ CPControlKeyMask
|
|||||||
- (void)setIndentationLevel:(unsigned)aLevel
|
- (void)setIndentationLevel:(unsigned)aLevel
|
||||||
{
|
{
|
||||||
if (aLevel < 0)
|
if (aLevel < 0)
|
||||||
[CPException raise:CPInvalidArgumentException reason:"setIndentationLevel: argument must be greater than 0."];
|
[CPException raise:CPInvalidArgumentException reason:"setIndentationLevel: argument must be greater than or equal to 0."];
|
||||||
|
|
||||||
_indentationLevel = MIN(15, aLevel);
|
_indentationLevel = MIN(15, aLevel);
|
||||||
}
|
}
|
||||||
@@ -709,7 +774,7 @@ CPControlKeyMask
|
|||||||
// Getting Highlighted Status
|
// Getting Highlighted Status
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the menu item is highlighted.
|
Returns \c YES if the menu item is highlighted.
|
||||||
*/
|
*/
|
||||||
- (BOOL)isHighlighted
|
- (BOOL)isHighlighted
|
||||||
{
|
{
|
||||||
@@ -729,48 +794,43 @@ CPControlKeyMask
|
|||||||
return _menuItemView;
|
return _menuItemView;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
- (BOOL)_isSelectable
|
||||||
|
|
||||||
/* @ignore */
|
|
||||||
@implementation _CPMenuItemSeparator : CPMenuItem
|
|
||||||
{
|
{
|
||||||
|
return ![self submenu] || [self action] !== @selector(submenuAction:) || [self target] !== [self menu];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)init
|
- (BOOL)_isMenuBarButton
|
||||||
{
|
{
|
||||||
self = [super initWithTitle:@"" action:nil keyEquivalent:nil];
|
return ![self submenu] && [self menu] === [CPApp mainMenu];
|
||||||
|
|
||||||
if (self)
|
|
||||||
[self setEnabled:NO];
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)isSeparatorItem
|
|
||||||
{
|
|
||||||
return YES;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPMenuItemTitleKey = @"CPMenuItemTitleKey",
|
var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
||||||
CPMenuItemTargetKey = @"CPMenuItemTargetKey",
|
|
||||||
CPMenuItemActionKey = @"CPMenuItemActionKey",
|
|
||||||
|
|
||||||
CPMenuItemIsEnabledKey = @"CPMenuItemIsEnabledKey",
|
CPMenuItemTitleKey = @"CPMenuItemTitleKey",
|
||||||
CPMenuItemIsHiddenKey = @"CPMenuItemIsHiddenKey",
|
CPMenuItemTargetKey = @"CPMenuItemTargetKey",
|
||||||
|
CPMenuItemActionKey = @"CPMenuItemActionKey",
|
||||||
|
|
||||||
CPMenuItemTagKey = @"CPMenuItemTagKey",
|
CPMenuItemIsEnabledKey = @"CPMenuItemIsEnabledKey",
|
||||||
CPMenuItemStateKey = @"CPMenuItemStateKey",
|
CPMenuItemIsHiddenKey = @"CPMenuItemIsHiddenKey",
|
||||||
|
|
||||||
CPMenuItemImageKey = @"CPMenuItemImageKey",
|
CPMenuItemTagKey = @"CPMenuItemTagKey",
|
||||||
CPMenuItemAlternateImageKey = @"CPMenuItemAlternateImageKey",
|
CPMenuItemStateKey = @"CPMenuItemStateKey",
|
||||||
|
|
||||||
CPMenuItemSubmenuKey = @"CPMenuItemSubmenuKey",
|
CPMenuItemImageKey = @"CPMenuItemImageKey",
|
||||||
CPMenuItemMenuKey = @"CPMenuItemMenuKey",
|
CPMenuItemAlternateImageKey = @"CPMenuItemAlternateImageKey",
|
||||||
|
|
||||||
CPMenuItemRepresentedObjectKey = @"CPMenuItemRepresentedObjectKey",
|
CPMenuItemSubmenuKey = @"CPMenuItemSubmenuKey",
|
||||||
CPMenuItemViewKey = @"CPMenuItemViewKey";
|
CPMenuItemMenuKey = @"CPMenuItemMenuKey",
|
||||||
|
|
||||||
|
CPMenuItemKeyEquivalentKey = @"CPMenuItemKeyEquivalentKey",
|
||||||
|
CPMenuItemKeyEquivalentModifierMaskKey = @"CPMenuItemKeyEquivalentModifierMaskKey",
|
||||||
|
|
||||||
|
CPMenuItemIndentationLevelKey = @"CPMenuItemIndentationLevelKey",
|
||||||
|
|
||||||
|
CPMenuItemRepresentedObjectKey = @"CPMenuItemRepresentedObjectKey",
|
||||||
|
CPMenuItemViewKey = @"CPMenuItemViewKey";
|
||||||
|
|
||||||
#define DEFAULT_VALUE(aKey, aDefaultValue) [aCoder containsValueForKey:(aKey)] ? [aCoder decodeObjectForKey:(aKey)] : (aDefaultValue)
|
#define DEFAULT_VALUE(aKey, aDefaultValue) [aCoder containsValueForKey:(aKey)] ? [aCoder decodeObjectForKey:(aKey)] : (aDefaultValue)
|
||||||
#define ENCODE_IFNOT(aKey, aValue, aDefaultValue) if ((aValue) !== (aDefaultValue)) [aCoder encodeObject:(aValue) forKey:(aKey)];
|
#define ENCODE_IFNOT(aKey, aValue, aDefaultValue) if ((aValue) !== (aDefaultValue)) [aCoder encodeObject:(aValue) forKey:(aKey)];
|
||||||
@@ -787,6 +847,8 @@ var CPMenuItemTitleKey = @"CPMenuItemTitleKey",
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
|
_isSeparator = [aCoder containsValueForKey:CPMenuItemIsSeparatorKey] && [aCoder decodeBoolForKey:CPMenuItemIsSeparatorKey];
|
||||||
|
|
||||||
_title = [aCoder decodeObjectForKey:CPMenuItemTitleKey];
|
_title = [aCoder decodeObjectForKey:CPMenuItemTitleKey];
|
||||||
|
|
||||||
// _font;
|
// _font;
|
||||||
@@ -806,16 +868,19 @@ var CPMenuItemTitleKey = @"CPMenuItemTitleKey",
|
|||||||
// CPImage _offStateImage;
|
// CPImage _offStateImage;
|
||||||
// CPImage _mixedStateImage;
|
// CPImage _mixedStateImage;
|
||||||
|
|
||||||
_submenu = DEFAULT_VALUE(CPMenuItemSubmenuKey, nil);
|
// This order matters because setSubmenu: needs _menu to be around.
|
||||||
_menu = DEFAULT_VALUE(CPMenuItemMenuKey, nil);
|
_menu = DEFAULT_VALUE(CPMenuItemMenuKey, nil);
|
||||||
|
[self setSubmenu:DEFAULT_VALUE(CPMenuItemSubmenuKey, nil)];
|
||||||
|
|
||||||
// CPString _keyEquivalent;
|
_keyEquivalent = [aCoder decodeObjectForKey:CPMenuItemKeyEquivalentKey] || @"";
|
||||||
// unsigned _keyEquivalentModifierMask;
|
_keyEquivalentModifierMask = [aCoder decodeObjectForKey:CPMenuItemKeyEquivalentModifierMaskKey] || 0;
|
||||||
|
|
||||||
// int _mnemonicLocation;
|
// int _mnemonicLocation;
|
||||||
|
|
||||||
// BOOL _isAlternate;
|
// BOOL _isAlternate;
|
||||||
// int _indentationLevel;
|
|
||||||
|
// Default is 0.
|
||||||
|
[self setIndentationLevel:[aCoder decodeIntForKey:CPMenuItemIndentationLevelKey] || 0];
|
||||||
|
|
||||||
// CPString _toolTip;
|
// CPString _toolTip;
|
||||||
|
|
||||||
@@ -832,6 +897,9 @@ var CPMenuItemTitleKey = @"CPMenuItemTitleKey",
|
|||||||
*/
|
*/
|
||||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
{
|
{
|
||||||
|
if (_isSeparator)
|
||||||
|
[aCoder encodeBool:_isSeparator forKey:CPMenuItemIsSeparatorKey];
|
||||||
|
|
||||||
[aCoder encodeObject:_title forKey:CPMenuItemTitleKey];
|
[aCoder encodeObject:_title forKey:CPMenuItemTitleKey];
|
||||||
|
|
||||||
[aCoder encodeObject:_target forKey:CPMenuItemTargetKey];
|
[aCoder encodeObject:_target forKey:CPMenuItemTargetKey];
|
||||||
@@ -849,423 +917,17 @@ var CPMenuItemTitleKey = @"CPMenuItemTitleKey",
|
|||||||
ENCODE_IFNOT(CPMenuItemSubmenuKey, _submenu, nil);
|
ENCODE_IFNOT(CPMenuItemSubmenuKey, _submenu, nil);
|
||||||
ENCODE_IFNOT(CPMenuItemMenuKey, _menu, nil);
|
ENCODE_IFNOT(CPMenuItemMenuKey, _menu, nil);
|
||||||
|
|
||||||
|
if (_keyEquivalent && _keyEquivalent.length)
|
||||||
|
[aCoder encodeObject:_keyEquivalent forKey:CPMenuItemKeyEquivalentKey];
|
||||||
|
|
||||||
|
if (_keyEquivalentModifierMask)
|
||||||
|
[aCoder encodeObject:_keyEquivalentModifierMask forKey:CPMenuItemKeyEquivalentModifierMaskKey];
|
||||||
|
|
||||||
|
if (_indentationLevel > 0)
|
||||||
|
[aCoder encodeInt:_indentationLevel forKey:CPMenuItemIndentationLevelKey];
|
||||||
|
|
||||||
ENCODE_IFNOT(CPMenuItemRepresentedObjectKey, _representedObject, nil);
|
ENCODE_IFNOT(CPMenuItemRepresentedObjectKey, _representedObject, nil);
|
||||||
ENCODE_IFNOT(CPMenuItemViewKey, _view, nil);
|
ENCODE_IFNOT(CPMenuItemViewKey, _view, nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var LEFT_MARGIN = 3.0,
|
|
||||||
RIGHT_MARGIN = 16.0,
|
|
||||||
STATE_COLUMN_WIDTH = 14.0,
|
|
||||||
INDENTATION_WIDTH = 17.0,
|
|
||||||
VERTICAL_MARGIN = 4.0;
|
|
||||||
|
|
||||||
var _CPMenuItemSelectionColor = nil,
|
|
||||||
_CPMenuItemTextShadowColor = nil,
|
|
||||||
|
|
||||||
_CPMenuItemDefaultStateImages = [],
|
|
||||||
_CPMenuItemDefaultStateHighlightedImages = [];
|
|
||||||
|
|
||||||
/*
|
|
||||||
@ignore
|
|
||||||
*/
|
|
||||||
@implementation _CPMenuItemView : CPView
|
|
||||||
{
|
|
||||||
CPMenuItem _menuItem;
|
|
||||||
|
|
||||||
CPFont _font;
|
|
||||||
CPColor _textColor;
|
|
||||||
CPColor _textShadowColor;
|
|
||||||
CPColor _activateColor;
|
|
||||||
CPColor _activateShadowColor;
|
|
||||||
|
|
||||||
CGSize _minSize;
|
|
||||||
BOOL _isDirty;
|
|
||||||
BOOL _showsStateColumn;
|
|
||||||
BOOL _belongsToMenuBar;
|
|
||||||
|
|
||||||
CPImageView _stateView;
|
|
||||||
_CPImageAndTextView _imageAndTextView;
|
|
||||||
CPView _submenuView;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)initialize
|
|
||||||
{
|
|
||||||
if (self != [_CPMenuItemView class])
|
|
||||||
return;
|
|
||||||
|
|
||||||
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
|
|
||||||
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]
|
|
||||||
|
|
||||||
var bundle = [CPBundle bundleForClass:self];
|
|
||||||
|
|
||||||
_CPMenuItemDefaultStateImages[CPOffState] = nil;
|
|
||||||
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
|
|
||||||
|
|
||||||
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
|
|
||||||
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
|
|
||||||
|
|
||||||
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
|
|
||||||
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (float)leftMargin
|
|
||||||
{
|
|
||||||
return LEFT_MARGIN + STATE_COLUMN_WIDTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame forMenuItem:(CPMenuItem)aMenuItem
|
|
||||||
{
|
|
||||||
self = [super initWithFrame:aFrame];
|
|
||||||
|
|
||||||
if (self)
|
|
||||||
{
|
|
||||||
_menuItem = aMenuItem;
|
|
||||||
_showsStateColumn = YES;
|
|
||||||
_isDirty = YES;
|
|
||||||
|
|
||||||
[self setAutoresizingMask:CPViewWidthSizable];
|
|
||||||
|
|
||||||
[self synchronizeWithMenuItem];
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGSize)minSize
|
|
||||||
{
|
|
||||||
return _minSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setDirty
|
|
||||||
{
|
|
||||||
_isDirty = YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)synchronizeWithMenuItem
|
|
||||||
{
|
|
||||||
if (!_isDirty)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_isDirty = NO;
|
|
||||||
|
|
||||||
var view = [_menuItem view];
|
|
||||||
|
|
||||||
if ([_menuItem isSeparatorItem])
|
|
||||||
{
|
|
||||||
var line = [[CPView alloc] initWithFrame:CGRectMake(0.0, 5.0, 10.0, 1.0)];
|
|
||||||
|
|
||||||
view = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 10.0)];
|
|
||||||
|
|
||||||
[view setAutoresizingMask:CPViewWidthSizable];
|
|
||||||
[line setAutoresizingMask:CPViewWidthSizable];
|
|
||||||
|
|
||||||
[line setBackgroundColor:[CPColor lightGrayColor]];
|
|
||||||
|
|
||||||
[view addSubview:line];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (view)
|
|
||||||
{
|
|
||||||
[_imageAndTextView removeFromSuperview];
|
|
||||||
_imageAndTextView = nil;
|
|
||||||
|
|
||||||
[_stateView removeFromSuperview];
|
|
||||||
_stateView = nil;
|
|
||||||
|
|
||||||
[_submenuView removeFromSuperview];
|
|
||||||
_submenuView = nil;
|
|
||||||
|
|
||||||
_minSize = [view frame].size;
|
|
||||||
|
|
||||||
[self setFrameSize:_minSize];
|
|
||||||
|
|
||||||
[self addSubview:view];
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// State Column
|
|
||||||
var x = _belongsToMenuBar ? 0.0 : (LEFT_MARGIN + [_menuItem indentationLevel] * INDENTATION_WIDTH);
|
|
||||||
|
|
||||||
if (_showsStateColumn)
|
|
||||||
{
|
|
||||||
if (!_stateView)
|
|
||||||
{
|
|
||||||
_stateView = [[CPImageView alloc] initWithFrame:CGRectMake(x, (CGRectGetHeight([self frame]) - STATE_COLUMN_WIDTH) / 2.0, STATE_COLUMN_WIDTH, STATE_COLUMN_WIDTH)];
|
|
||||||
|
|
||||||
[_stateView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
|
|
||||||
|
|
||||||
[self addSubview:_stateView];
|
|
||||||
}
|
|
||||||
|
|
||||||
var state = [_menuItem state];
|
|
||||||
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case CPOffState:
|
|
||||||
case CPOnState:
|
|
||||||
case CPMixedState: [_stateView setImage:_CPMenuItemDefaultStateImages[state]];
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: [_stateView setImage:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
x += STATE_COLUMN_WIDTH;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
[_stateView removeFromSuperview];
|
|
||||||
|
|
||||||
_stateView = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Image and Title
|
|
||||||
|
|
||||||
if (!_imageAndTextView)
|
|
||||||
{
|
|
||||||
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
|
|
||||||
|
|
||||||
[_imageAndTextView setImagePosition:CPImageLeft];
|
|
||||||
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
|
||||||
|
|
||||||
[self addSubview:_imageAndTextView];
|
|
||||||
}
|
|
||||||
|
|
||||||
var font = [_menuItem font];
|
|
||||||
|
|
||||||
if (!font)
|
|
||||||
font = _font;
|
|
||||||
|
|
||||||
[_imageAndTextView setFont:font];
|
|
||||||
[_imageAndTextView setVerticalAlignment:CPCenterVerticalTextAlignment];
|
|
||||||
[_imageAndTextView setImage:[_menuItem image]];
|
|
||||||
[_imageAndTextView setText:[_menuItem title]];
|
|
||||||
[_imageAndTextView setTextColor:[self textColor]];
|
|
||||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
|
||||||
[_imageAndTextView setTextShadowOffset:CGSizeMake(0, 1)];
|
|
||||||
[_imageAndTextView setFrameOrigin:CGPointMake(x, VERTICAL_MARGIN)];
|
|
||||||
[_imageAndTextView sizeToFit];
|
|
||||||
|
|
||||||
var frame = [_imageAndTextView frame];
|
|
||||||
|
|
||||||
// frame.size.height += 1.0;
|
|
||||||
// [_imageAndTextView setFrame:frame];
|
|
||||||
|
|
||||||
frame.size.height += 2 * VERTICAL_MARGIN;
|
|
||||||
|
|
||||||
x += CGRectGetWidth(frame);
|
|
||||||
|
|
||||||
// Submenu Arrow
|
|
||||||
if ([_menuItem hasSubmenu])
|
|
||||||
{
|
|
||||||
x += 3.0;
|
|
||||||
|
|
||||||
if (!_submenuView)
|
|
||||||
{
|
|
||||||
_submenuView = [[_CPMenuItemArrowView alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 10.0)];
|
|
||||||
|
|
||||||
[self addSubview:_submenuView];
|
|
||||||
}
|
|
||||||
|
|
||||||
[_submenuView setHidden:NO];
|
|
||||||
[_submenuView setColor:_belongsToMenuBar ? [self textColor] : nil];
|
|
||||||
[_submenuView setFrameOrigin:CGPointMake(x, (CGRectGetHeight(frame) - 10.0) / 2.0)];
|
|
||||||
|
|
||||||
x += 10.0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
[_submenuView setHidden:YES];
|
|
||||||
|
|
||||||
_minSize = CGSizeMake(x + (_belongsToMenuBar ? 0.0 : RIGHT_MARGIN) + 3.0, CGRectGetHeight(frame));
|
|
||||||
|
|
||||||
[self setFrameSize:_minSize];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)overlapOffsetWidth
|
|
||||||
{
|
|
||||||
return LEFT_MARGIN + ([[_menuItem menu] showsStateColumn] ? STATE_COLUMN_WIDTH : 0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setShowsStateColumn:(BOOL)shouldShowStateColumn
|
|
||||||
{
|
|
||||||
_showsStateColumn = shouldShowStateColumn;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setBelongsToMenuBar:(BOOL)shouldBelongToMenuBar
|
|
||||||
{
|
|
||||||
_belongsToMenuBar = shouldBelongToMenuBar;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)highlight:(BOOL)shouldHighlight
|
|
||||||
{
|
|
||||||
// ASSERT(![_menuItem view]);
|
|
||||||
|
|
||||||
if (_belongsToMenuBar)
|
|
||||||
[_imageAndTextView setImage:shouldHighlight ? [_menuItem alternateImage] : [_menuItem image]];
|
|
||||||
|
|
||||||
else if ([_menuItem isEnabled])
|
|
||||||
{
|
|
||||||
if (shouldHighlight)
|
|
||||||
{
|
|
||||||
[self setBackgroundColor:_CPMenuItemSelectionColor];
|
|
||||||
|
|
||||||
[_imageAndTextView setTextColor:[CPColor whiteColor]];
|
|
||||||
[_imageAndTextView setTextShadowColor:_CPMenuItemTextShadowColor];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
[self setBackgroundColor:nil];
|
|
||||||
|
|
||||||
[_imageAndTextView setTextColor:[self textColor]];
|
|
||||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
|
||||||
}
|
|
||||||
|
|
||||||
var state = [_menuItem state];
|
|
||||||
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case CPOffState:
|
|
||||||
case CPOnState:
|
|
||||||
case CPMixedState: [_stateView setImage:shouldHighlight ? _CPMenuItemDefaultStateHighlightedImages[state] : _CPMenuItemDefaultStateImages[state]];
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: [_stateView setImage:nil];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (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
|
|
||||||
{
|
|
||||||
if (![_menuItem hasSubmenu])
|
|
||||||
return NO;
|
|
||||||
|
|
||||||
return CGRectContainsPoint([_submenuView frame], [self convertPoint:[anEvent locationInWindow] fromView:nil]);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)isHidden
|
|
||||||
{
|
|
||||||
return [_menuItem isHidden];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPMenuItem)menuItem
|
|
||||||
{
|
|
||||||
return _menuItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setFont:(CPFont)aFont
|
|
||||||
{
|
|
||||||
if (_font == aFont)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_font = aFont;
|
|
||||||
|
|
||||||
[self setDirty];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setTextColor:(CPColor)aColor
|
|
||||||
{
|
|
||||||
if (_textColor == aColor)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_textColor = aColor;
|
|
||||||
|
|
||||||
[_imageAndTextView setTextColor:[self textColor]];
|
|
||||||
[_submenuView setColor:[self textColor]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPColor)textColor
|
|
||||||
{
|
|
||||||
return [_menuItem isEnabled] ? (_textColor ? _textColor : [CPColor colorWithCalibratedRed:70.0 / 255.0 green:69.0 / 255.0 blue:69.0 / 255.0 alpha:1.0]) : [CPColor darkGrayColor];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setTextShadowColor:(CPColor)aColor
|
|
||||||
{
|
|
||||||
if (_textShadowColor == aColor)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_textShadowColor = aColor;
|
|
||||||
|
|
||||||
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
|
||||||
//[_submenuView setColor:[self textColor]];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPColor)textShadowColor
|
|
||||||
{
|
|
||||||
return [_menuItem isEnabled] ? (_textShadowColor ? _textShadowColor : [CPColor colorWithWhite:1.0 alpha:0.8]) : [CPColor colorWithWhite:0.8 alpha:0.8];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setActivateColor:(CPColor)aColor
|
|
||||||
{
|
|
||||||
_activateColor = aColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPColor)activateColor
|
|
||||||
{
|
|
||||||
return _activateColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setActivateShadowColor:(CPColor)aColor
|
|
||||||
{
|
|
||||||
_activateShadowColor = aColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPColor)activateShadowColor
|
|
||||||
{
|
|
||||||
return _activateShadowColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation _CPMenuItemArrowView : CPView
|
|
||||||
{
|
|
||||||
CPColor _color;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setColor:(CPColor)aColor
|
|
||||||
{
|
|
||||||
if (_color == aColor)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_color = aColor;
|
|
||||||
|
|
||||||
[self setNeedsDisplay:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)drawRect:(CGRect)aRect
|
|
||||||
{
|
|
||||||
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
|
||||||
|
|
||||||
CGContextBeginPath(context);
|
|
||||||
|
|
||||||
CGContextMoveToPoint(context, 1.0, 4.0);
|
|
||||||
CGContextAddLineToPoint(context, 9.0, 4.0);
|
|
||||||
CGContextAddLineToPoint(context, 5.0, 8.0);
|
|
||||||
CGContextAddLineToPoint(context, 1.0, 4.0);
|
|
||||||
|
|
||||||
CGContextClosePath(context);
|
|
||||||
|
|
||||||
CGContextSetFillColor(context, _color);
|
|
||||||
CGContextFillPath(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
var HORIZONTAL_MARGIN = 8.0,
|
||||||
|
SUBMENU_INDICATOR_MARGIN = 3.0,
|
||||||
|
VERTICAL_MARGIN = 4.0;
|
||||||
|
|
||||||
|
var SelectionColor = nil,
|
||||||
|
SUBMENU_INDICATOR_COLOR = nil,
|
||||||
|
_CPMenuItemSelectionColor = nil,
|
||||||
|
_CPMenuItemTextShadowColor = nil,
|
||||||
|
|
||||||
|
_CPMenuItemDefaultStateImages = [],
|
||||||
|
_CPMenuItemDefaultStateHighlightedImages = [];
|
||||||
|
|
||||||
|
@implementation _CPMenuItemMenuBarView : CPView
|
||||||
|
{
|
||||||
|
CPMenuItem _menuItem @accessors(property=menuItem);
|
||||||
|
|
||||||
|
CPFont _font;
|
||||||
|
CPColor _textColor;
|
||||||
|
CPColor _textShadowColor;
|
||||||
|
|
||||||
|
BOOL _isDirty;
|
||||||
|
|
||||||
|
_CPImageAndTextView _imageAndTextView;
|
||||||
|
CPView _submenuIndicatorView;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
if (self !== [_CPMenuItemMenuBarView class])
|
||||||
|
return;
|
||||||
|
|
||||||
|
var bundle = [CPBundle bundleForClass:self];
|
||||||
|
|
||||||
|
SelectionColor = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuBarWindow/_CPMenuBarWindowBackgroundSelected.png"] size:CGSizeMake(1.0, 28.0)]];
|
||||||
|
|
||||||
|
SUBMENU_INDICATOR_COLOR = [CPColor grayColor];
|
||||||
|
|
||||||
|
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
|
||||||
|
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0];
|
||||||
|
|
||||||
|
_CPMenuItemDefaultStateImages[CPOffState] = nil;
|
||||||
|
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
|
||||||
|
|
||||||
|
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
|
||||||
|
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
|
||||||
|
|
||||||
|
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
|
||||||
|
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)view
|
||||||
|
{
|
||||||
|
return [[self alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
|
{
|
||||||
|
self = [super initWithFrame:aFrame];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(HORIZONTAL_MARGIN, 0.0, 0.0, 0.0)];
|
||||||
|
|
||||||
|
[_imageAndTextView setImagePosition:CPImageLeft];
|
||||||
|
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||||
|
[_imageAndTextView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
|
||||||
|
|
||||||
|
[self addSubview:_imageAndTextView];
|
||||||
|
|
||||||
|
_submenuIndicatorView = [[_CPMenuItemMenuBarSubmenuIndicatorView alloc] initWithFrame:CGRectMake(0.0, 0.0, 9.0, 6.0)];
|
||||||
|
|
||||||
|
[_submenuIndicatorView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
|
||||||
|
|
||||||
|
[self addSubview:_submenuIndicatorView];
|
||||||
|
|
||||||
|
[self setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPColor)textColor
|
||||||
|
{
|
||||||
|
if (![_menuItem isEnabled])
|
||||||
|
return [CPColor lightGrayColor];
|
||||||
|
|
||||||
|
return _textColor || [CPColor colorWithCalibratedRed:70.0 / 255.0 green:69.0 / 255.0 blue:69.0 / 255.0 alpha:1.0];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPColor)textShadowColor
|
||||||
|
{
|
||||||
|
if (![_menuItem isEnabled])
|
||||||
|
return [CPColor colorWithWhite:0.8 alpha:0.8];
|
||||||
|
|
||||||
|
return _textShadowColor || [CPColor colorWithWhite:1.0 alpha:0.8];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)update
|
||||||
|
{
|
||||||
|
var x = HORIZONTAL_MARGIN,
|
||||||
|
height = 0.0;
|
||||||
|
|
||||||
|
[_imageAndTextView setFont:[_menuItem font] || [_CPMenuBarWindow font]];
|
||||||
|
[_imageAndTextView setVerticalAlignment:CPCenterVerticalTextAlignment];
|
||||||
|
[_imageAndTextView setImage:[_menuItem image]];
|
||||||
|
[_imageAndTextView setText:[_menuItem title]];
|
||||||
|
[_imageAndTextView setTextColor:[self textColor]];
|
||||||
|
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||||
|
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||||
|
[_imageAndTextView sizeToFit];
|
||||||
|
|
||||||
|
var imageAndTextViewFrame = [_imageAndTextView frame];
|
||||||
|
|
||||||
|
imageAndTextViewFrame.origin.x = x;
|
||||||
|
x += CGRectGetWidth(imageAndTextViewFrame);
|
||||||
|
height = MAX(height, CGRectGetHeight(imageAndTextViewFrame));
|
||||||
|
|
||||||
|
var hasSubmenuIndicator = [_menuItem hasSubmenu] && [_menuItem action];
|
||||||
|
|
||||||
|
if (hasSubmenuIndicator)
|
||||||
|
{
|
||||||
|
[_submenuIndicatorView setHidden:NO];
|
||||||
|
[_submenuIndicatorView setColor:[self textColor]];
|
||||||
|
[_submenuIndicatorView setShadowColor:[self textShadowColor]];
|
||||||
|
|
||||||
|
var submenuViewFrame = [_submenuIndicatorView frame];
|
||||||
|
|
||||||
|
submenuViewFrame.origin.x = x + SUBMENU_INDICATOR_MARGIN;
|
||||||
|
|
||||||
|
x = CGRectGetMaxX(submenuViewFrame);
|
||||||
|
height = MAX(height, CGRectGetHeight(submenuViewFrame));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[_submenuIndicatorView setHidden:YES];
|
||||||
|
|
||||||
|
height += 2.0 * VERTICAL_MARGIN;
|
||||||
|
|
||||||
|
imageAndTextViewFrame.origin.y = FLOOR((height - CGRectGetHeight(imageAndTextViewFrame)) / 2.0);
|
||||||
|
[_imageAndTextView setFrame:imageAndTextViewFrame];
|
||||||
|
|
||||||
|
if (hasSubmenuIndicator)
|
||||||
|
{
|
||||||
|
submenuViewFrame.origin.y = FLOOR((height - CGRectGetHeight(submenuViewFrame)) / 2.0) + 1.0;
|
||||||
|
[_submenuIndicatorView setFrame:submenuViewFrame];
|
||||||
|
}
|
||||||
|
|
||||||
|
_minSize = CGSizeMake(x + HORIZONTAL_MARGIN, height);
|
||||||
|
|
||||||
|
[self setAutoresizesSubviews:NO];
|
||||||
|
[self setFrameSize:_minSize];
|
||||||
|
[self setAutoresizesSubviews:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)highlight:(BOOL)shouldHighlight
|
||||||
|
{
|
||||||
|
// FIXME: This should probably be even throw.
|
||||||
|
if (![_menuItem isEnabled])
|
||||||
|
shouldHighlight = NO;
|
||||||
|
|
||||||
|
if (shouldHighlight)
|
||||||
|
{
|
||||||
|
if (![_menuItem _isMenuBarButton])
|
||||||
|
[self setBackgroundColor:SelectionColor];
|
||||||
|
|
||||||
|
[_imageAndTextView setImage:[_menuItem alternateImage] || [_menuItem image]];
|
||||||
|
[_imageAndTextView setTextColor:[CPColor whiteColor]];
|
||||||
|
[_imageAndTextView setTextShadowColor:_CPMenuItemTextShadowColor];
|
||||||
|
|
||||||
|
[_submenuIndicatorView setColor:[CPColor whiteColor]];
|
||||||
|
[_submenuIndicatorView setShadowColor:[CPColor colorWithWhite:0.1 alpha:0.7]];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[self setBackgroundColor:nil];
|
||||||
|
|
||||||
|
[_imageAndTextView setImage:[_menuItem image]];
|
||||||
|
[_imageAndTextView setTextColor:[self textColor]];
|
||||||
|
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||||
|
|
||||||
|
[_submenuIndicatorView setColor:[self textColor]];
|
||||||
|
[_submenuIndicatorView setShadowColor:[self textShadowColor]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPMenuItemMenuBarSubmenuIndicatorView : CPView
|
||||||
|
{
|
||||||
|
CPColor _color;
|
||||||
|
CPColor _shadowColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
if (_color === aColor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_color = aColor;
|
||||||
|
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setShadowColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
if (_shadowColor === aColor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_shadowColor = aColor;
|
||||||
|
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drawRect:(CGRect)aRect
|
||||||
|
{
|
||||||
|
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||||
|
bounds = [self bounds];
|
||||||
|
|
||||||
|
bounds.size.height -= 1.0;
|
||||||
|
bounds.size.width -= 2.0;
|
||||||
|
bounds.origin.x += 1.0;
|
||||||
|
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, CGRectGetMinX(bounds), CGRectGetMinY(bounds));
|
||||||
|
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), CGRectGetMinY(bounds));
|
||||||
|
CGContextAddLineToPoint(context, CGRectGetMidX(bounds), CGRectGetMaxY(bounds));
|
||||||
|
|
||||||
|
CGContextClosePath(context);
|
||||||
|
|
||||||
|
CGContextSetShadowWithColor(context, CGSizeMake(0.0, 1.0), 1.1, _shadowColor || [CPColor whiteColor]);
|
||||||
|
CGContextSetFillColor(context, _color || [CPColor blackColor]);
|
||||||
|
CGContextFillPath(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
|
||||||
|
@import <AppKit/CPView.j>
|
||||||
|
|
||||||
|
|
||||||
|
@implementation _CPMenuItemSeparatorView : CPView
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)view
|
||||||
|
{
|
||||||
|
return [[self alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 10.0)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
|
{
|
||||||
|
self = [super initWithFrame:aFrame];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
[self setAutoresizingMask:CPViewWidthSizable];
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drawRect:(CGRect)aRect
|
||||||
|
{
|
||||||
|
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||||
|
bounds = [self bounds];
|
||||||
|
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, CGRectGetMinX(bounds), FLOOR(CGRectGetMidY(bounds)) - 0.5);
|
||||||
|
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), FLOOR(CGRectGetMidY(bounds)) - 0.5);
|
||||||
|
|
||||||
|
CGContextSetStrokeColor(context, [CPColor lightGrayColor]);
|
||||||
|
CGContextStrokePath(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,300 @@
|
|||||||
|
var LEFT_MARGIN = 3.0,
|
||||||
|
RIGHT_MARGIN = 14.0 + 3.0,
|
||||||
|
STATE_COLUMN_WIDTH = 14.0,
|
||||||
|
INDENTATION_WIDTH = 17.0,
|
||||||
|
VERTICAL_MARGIN = 4.0,
|
||||||
|
|
||||||
|
RIGHT_COLUMNS_MARGIN = 30.0,
|
||||||
|
KEY_EQUIVALENT_MARGIN = 10.0;
|
||||||
|
|
||||||
|
var SUBMENU_INDICATOR_COLOR = nil,
|
||||||
|
_CPMenuItemSelectionColor = nil,
|
||||||
|
_CPMenuItemTextShadowColor = nil,
|
||||||
|
|
||||||
|
_CPMenuItemDefaultStateImages = [],
|
||||||
|
_CPMenuItemDefaultStateHighlightedImages = [];
|
||||||
|
|
||||||
|
@implementation _CPMenuItemStandardView : CPView
|
||||||
|
{
|
||||||
|
CPMenuItem _menuItem @accessors(property=menuItem);
|
||||||
|
|
||||||
|
CPFont _font;
|
||||||
|
CPColor _textColor;
|
||||||
|
CPColor _textShadowColor;
|
||||||
|
|
||||||
|
CGSize _minSize @accessors(readonly, property=minSize);
|
||||||
|
BOOL _isDirty;
|
||||||
|
|
||||||
|
CPImageView _stateView;
|
||||||
|
_CPImageAndTextView _imageAndTextView;
|
||||||
|
_CPImageAndTextView _keyEquivalentView;
|
||||||
|
CPView _submenuIndicatorView;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
if (self !== [_CPMenuItemStandardView class])
|
||||||
|
return;
|
||||||
|
|
||||||
|
SUBMENU_INDICATOR_COLOR = [CPColor grayColor];
|
||||||
|
|
||||||
|
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
|
||||||
|
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]
|
||||||
|
|
||||||
|
var bundle = [CPBundle bundleForClass:self];
|
||||||
|
|
||||||
|
_CPMenuItemDefaultStateImages[CPOffState] = nil;
|
||||||
|
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
|
||||||
|
|
||||||
|
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
|
||||||
|
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
|
||||||
|
|
||||||
|
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
|
||||||
|
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)view
|
||||||
|
{
|
||||||
|
return [[self alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (float)_standardLeftMargin
|
||||||
|
{
|
||||||
|
return LEFT_MARGIN + STATE_COLUMN_WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
|
{
|
||||||
|
self = [super initWithFrame:aFrame];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_stateView = [[CPImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
|
||||||
|
|
||||||
|
[_stateView setImageScaling:CPScaleNone];
|
||||||
|
|
||||||
|
[self addSubview:_stateView];
|
||||||
|
|
||||||
|
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
|
||||||
|
|
||||||
|
[_imageAndTextView setImagePosition:CPImageLeft];
|
||||||
|
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||||
|
|
||||||
|
[self addSubview:_imageAndTextView];
|
||||||
|
|
||||||
|
_keyEquivalentView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
|
||||||
|
|
||||||
|
[_keyEquivalentView setImagePosition:CPNoImage];
|
||||||
|
[_keyEquivalentView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||||
|
[_keyEquivalentView setAutoresizingMask:CPViewMinXMargin];
|
||||||
|
|
||||||
|
[self addSubview:_keyEquivalentView];
|
||||||
|
|
||||||
|
_submenuIndicatorView = [[_CPMenuItemSubmenuIndicatorView alloc] initWithFrame:CGRectMake(0.0, 0.0, 8.0, 10.0)];
|
||||||
|
|
||||||
|
[_submenuIndicatorView setColor:SUBMENU_INDICATOR_COLOR];
|
||||||
|
[_submenuIndicatorView setAutoresizingMask:CPViewMinXMargin];
|
||||||
|
|
||||||
|
[self addSubview:_submenuIndicatorView];
|
||||||
|
|
||||||
|
[self setAutoresizingMask:CPViewWidthSizable];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPColor)textColor
|
||||||
|
{
|
||||||
|
if (![_menuItem isEnabled])
|
||||||
|
return [CPColor lightGrayColor];
|
||||||
|
|
||||||
|
return _textColor || [CPColor colorWithCalibratedRed:70.0 / 255.0 green:69.0 / 255.0 blue:69.0 / 255.0 alpha:1.0];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPColor)textShadowColor
|
||||||
|
{
|
||||||
|
if (![_menuItem isEnabled])
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
return _textShadowColor || [CPColor colorWithWhite:1.0 alpha:0.8];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFont:(CPFont)aFont
|
||||||
|
{
|
||||||
|
_font = aFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)update
|
||||||
|
{
|
||||||
|
var x = LEFT_MARGIN + [_menuItem indentationLevel] * INDENTATION_WIDTH,
|
||||||
|
height = 0.0,
|
||||||
|
hasStateColumn = [[_menuItem menu] showsStateColumn];
|
||||||
|
|
||||||
|
if (hasStateColumn)
|
||||||
|
{
|
||||||
|
[_stateView setHidden:NO];
|
||||||
|
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
|
||||||
|
|
||||||
|
x += STATE_COLUMN_WIDTH;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[_stateView setHidden:YES];
|
||||||
|
|
||||||
|
[_imageAndTextView setFont:[_menuItem font] || _font];
|
||||||
|
[_imageAndTextView setVerticalAlignment:CPCenterVerticalTextAlignment];
|
||||||
|
[_imageAndTextView setImage:[_menuItem image]];
|
||||||
|
[_imageAndTextView setText:[_menuItem title]];
|
||||||
|
[_imageAndTextView setTextColor:[self textColor]];
|
||||||
|
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||||
|
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||||
|
[_imageAndTextView sizeToFit];
|
||||||
|
|
||||||
|
var imageAndTextViewFrame = [_imageAndTextView frame];
|
||||||
|
|
||||||
|
imageAndTextViewFrame.origin.x = x;
|
||||||
|
x += CGRectGetWidth(imageAndTextViewFrame);
|
||||||
|
height = MAX(height, CGRectGetHeight(imageAndTextViewFrame));
|
||||||
|
|
||||||
|
var hasKeyEquivalent = !![_menuItem keyEquivalent],
|
||||||
|
hasSubmenu = [_menuItem hasSubmenu];
|
||||||
|
|
||||||
|
if (hasKeyEquivalent || hasSubmenu)
|
||||||
|
x += RIGHT_COLUMNS_MARGIN;
|
||||||
|
|
||||||
|
if (hasKeyEquivalent)
|
||||||
|
{
|
||||||
|
[_keyEquivalentView setFont:[_menuItem font] || _font];
|
||||||
|
[_keyEquivalentView setVerticalAlignment:CPCenterVerticalTextAlignment];
|
||||||
|
[_keyEquivalentView setImage:[_menuItem image]];
|
||||||
|
[_keyEquivalentView setText:[_menuItem keyEquivalentStringRepresentation]];
|
||||||
|
[_keyEquivalentView setTextColor:[self textColor]];
|
||||||
|
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
|
||||||
|
[_keyEquivalentView setTextShadowOffset:CGSizeMake(0, 1)];
|
||||||
|
[_keyEquivalentView setFrameOrigin:CGPointMake(x, VERTICAL_MARGIN)];
|
||||||
|
[_keyEquivalentView sizeToFit];
|
||||||
|
|
||||||
|
var keyEquivalentViewFrame = [_keyEquivalentView frame];
|
||||||
|
|
||||||
|
keyEquivalentViewFrame.origin.x = x;
|
||||||
|
x += CGRectGetWidth(keyEquivalentViewFrame);
|
||||||
|
height = MAX(height, CGRectGetHeight(keyEquivalentViewFrame));
|
||||||
|
|
||||||
|
if (hasSubmenu)
|
||||||
|
x += RIGHT_COLUMNS_MARGIN;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[_keyEquivalentView setHidden:YES];
|
||||||
|
|
||||||
|
if (hasSubmenu)
|
||||||
|
{
|
||||||
|
[_submenuIndicatorView setHidden:NO];
|
||||||
|
|
||||||
|
var submenuViewFrame = [_submenuIndicatorView frame];
|
||||||
|
|
||||||
|
submenuViewFrame.origin.x = x;
|
||||||
|
|
||||||
|
x += CGRectGetWidth(submenuViewFrame);
|
||||||
|
height = MAX(height, CGRectGetHeight(submenuViewFrame));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[_submenuIndicatorView setHidden:YES];
|
||||||
|
|
||||||
|
height += 2.0 * VERTICAL_MARGIN;
|
||||||
|
|
||||||
|
imageAndTextViewFrame.origin.y = FLOOR((height - CGRectGetHeight(imageAndTextViewFrame)) / 2.0);
|
||||||
|
[_imageAndTextView setFrame:imageAndTextViewFrame];
|
||||||
|
|
||||||
|
if (hasStateColumn)
|
||||||
|
[_stateView setFrameSize:CGSizeMake(STATE_COLUMN_WIDTH, height)];
|
||||||
|
|
||||||
|
if (hasKeyEquivalent)
|
||||||
|
{
|
||||||
|
keyEquivalentViewFrame.origin.y = FLOOR((height - CGRectGetHeight(keyEquivalentViewFrame)) / 2.0);
|
||||||
|
[_keyEquivalentView setFrame:keyEquivalentViewFrame];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasSubmenu)
|
||||||
|
{
|
||||||
|
submenuViewFrame.origin.y = FLOOR((height - CGRectGetHeight(submenuViewFrame)) / 2.0);
|
||||||
|
[_submenuIndicatorView setFrame:submenuViewFrame];
|
||||||
|
}
|
||||||
|
|
||||||
|
_minSize = CGSizeMake(x + RIGHT_MARGIN, height);
|
||||||
|
|
||||||
|
[self setAutoresizesSubviews:NO];
|
||||||
|
[self setFrameSize:_minSize];
|
||||||
|
[self setAutoresizesSubviews:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)highlight:(BOOL)shouldHighlight
|
||||||
|
{
|
||||||
|
// FIXME: This should probably be even throw.
|
||||||
|
if (![_menuItem isEnabled])
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (shouldHighlight)
|
||||||
|
{
|
||||||
|
[self setBackgroundColor:_CPMenuItemSelectionColor];
|
||||||
|
|
||||||
|
[_imageAndTextView setImage:[_menuItem alternateImage] || [_menuItem image]];
|
||||||
|
[_imageAndTextView setTextColor:[CPColor whiteColor]];
|
||||||
|
[_keyEquivalentView setTextColor:[CPColor whiteColor]];
|
||||||
|
[_submenuIndicatorView setColor:[CPColor whiteColor]];
|
||||||
|
|
||||||
|
[_imageAndTextView setTextShadowColor:_CPMenuItemTextShadowColor];
|
||||||
|
[_keyEquivalentView setTextShadowColor:_CPMenuItemTextShadowColor];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[self setBackgroundColor:nil];
|
||||||
|
|
||||||
|
[_imageAndTextView setImage:[_menuItem image]];
|
||||||
|
[_imageAndTextView setTextColor:[self textColor]];
|
||||||
|
[_keyEquivalentView setTextColor:[self textColor]];
|
||||||
|
[_submenuIndicatorView setColor:SUBMENU_INDICATOR_COLOR];
|
||||||
|
|
||||||
|
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||||
|
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldHighlight)
|
||||||
|
[_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil];
|
||||||
|
else
|
||||||
|
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPMenuItemSubmenuIndicatorView : CPView
|
||||||
|
{
|
||||||
|
CPColor _color;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
if (_color === aColor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_color = aColor;
|
||||||
|
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drawRect:(CGRect)aRect
|
||||||
|
{
|
||||||
|
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||||
|
bounds = [self bounds];
|
||||||
|
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, CGRectGetMinX(bounds), CGRectGetMinY(bounds));
|
||||||
|
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), CGRectGetMidY(bounds));
|
||||||
|
CGContextAddLineToPoint(context, CGRectGetMinX(bounds), CGRectGetMaxY(bounds));
|
||||||
|
|
||||||
|
CGContextClosePath(context);
|
||||||
|
|
||||||
|
CGContextSetFillColor(context, _color);
|
||||||
|
CGContextFillPath(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,255 @@
|
|||||||
|
|
||||||
|
@import "_CPMenuItemSeparatorView.j"
|
||||||
|
@import "_CPMenuItemStandardView.j"
|
||||||
|
@import "_CPMenuItemMenuBarView.j"
|
||||||
|
|
||||||
|
|
||||||
|
var LEFT_MARGIN = 3.0,
|
||||||
|
RIGHT_MARGIN = 16.0,
|
||||||
|
STATE_COLUMN_WIDTH = 14.0,
|
||||||
|
INDENTATION_WIDTH = 17.0,
|
||||||
|
VERTICAL_MARGIN = 4.0;
|
||||||
|
|
||||||
|
var _CPMenuItemSelectionColor = nil,
|
||||||
|
_CPMenuItemTextShadowColor = nil,
|
||||||
|
|
||||||
|
_CPMenuItemDefaultStateImages = [],
|
||||||
|
_CPMenuItemDefaultStateHighlightedImages = [];
|
||||||
|
|
||||||
|
/*
|
||||||
|
@ignore
|
||||||
|
*/
|
||||||
|
@implementation _CPMenuItemView : CPView
|
||||||
|
{
|
||||||
|
CPMenuItem _menuItem;
|
||||||
|
CPView _view;
|
||||||
|
|
||||||
|
CPFont _font;
|
||||||
|
CPColor _textColor;
|
||||||
|
CPColor _textShadowColor;
|
||||||
|
|
||||||
|
CGSize _minSize;
|
||||||
|
BOOL _isDirty;
|
||||||
|
BOOL _showsStateColumn;
|
||||||
|
|
||||||
|
CPImageView _stateView;
|
||||||
|
_CPImageAndTextView _imageAndTextView;
|
||||||
|
CPView _submenuView;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
if (self != [_CPMenuItemView class])
|
||||||
|
return;
|
||||||
|
|
||||||
|
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
|
||||||
|
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]
|
||||||
|
|
||||||
|
var bundle = [CPBundle bundleForClass:self];
|
||||||
|
|
||||||
|
_CPMenuItemDefaultStateImages[CPOffState] = nil;
|
||||||
|
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
|
||||||
|
|
||||||
|
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
|
||||||
|
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
|
||||||
|
|
||||||
|
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
|
||||||
|
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (float)leftMargin
|
||||||
|
{
|
||||||
|
return LEFT_MARGIN + STATE_COLUMN_WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithFrame:(CGRect)aFrame forMenuItem:(CPMenuItem)aMenuItem
|
||||||
|
{
|
||||||
|
self = [super initWithFrame:aFrame];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_menuItem = aMenuItem;
|
||||||
|
_showsStateColumn = YES;
|
||||||
|
_isDirty = YES;
|
||||||
|
|
||||||
|
[self setAutoresizingMask:CPViewWidthSizable];
|
||||||
|
|
||||||
|
[self synchronizeWithMenuItem];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGSize)minSize
|
||||||
|
{
|
||||||
|
return _minSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDirty
|
||||||
|
{
|
||||||
|
_isDirty = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)synchronizeWithMenuItem
|
||||||
|
{
|
||||||
|
var menuItemView = [_menuItem view];
|
||||||
|
|
||||||
|
if ([_menuItem isSeparatorItem])
|
||||||
|
{
|
||||||
|
if (![_view isKindOfClass:[_CPMenuItemSeparatorView class]])
|
||||||
|
{
|
||||||
|
[_view removeFromSuperview];
|
||||||
|
_view = [_CPMenuItemSeparatorView view];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (menuItemView)
|
||||||
|
{
|
||||||
|
if (_view !== menuItemView)
|
||||||
|
{
|
||||||
|
[_view removeFromSuperview];
|
||||||
|
_view = menuItemView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ([_menuItem menu] == [CPApp mainMenu])
|
||||||
|
{
|
||||||
|
if (![_view isKindOfClass:[_CPMenuItemMenuBarView class]])
|
||||||
|
{
|
||||||
|
[_view removeFromSuperview];
|
||||||
|
_view = [_CPMenuItemMenuBarView view];
|
||||||
|
}
|
||||||
|
|
||||||
|
[_view setMenuItem:_menuItem];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (![_view isKindOfClass:[_CPMenuItemStandardView class]])
|
||||||
|
{
|
||||||
|
[_view removeFromSuperview];
|
||||||
|
_view = [_CPMenuItemStandardView view];
|
||||||
|
}
|
||||||
|
|
||||||
|
[_view setMenuItem:_menuItem];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([_view superview] !== self)
|
||||||
|
[self addSubview:_view];
|
||||||
|
|
||||||
|
if ([_view respondsToSelector:@selector(update)])
|
||||||
|
[_view update];
|
||||||
|
|
||||||
|
_minSize = [_view frame].size;
|
||||||
|
[self setAutoresizesSubviews:NO];
|
||||||
|
[self setFrameSize:_minSize];
|
||||||
|
[self setAutoresizesSubviews:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setShowsStateColumn:(BOOL)shouldShowStateColumn
|
||||||
|
{
|
||||||
|
_showsStateColumn = shouldShowStateColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)highlight:(BOOL)shouldHighlight
|
||||||
|
{
|
||||||
|
if ([_view respondsToSelector:@selector(highlight:)])
|
||||||
|
[_view highlight:shouldHighlight];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)eventOnSubmenu:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
if (![_menuItem hasSubmenu])
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
return CGRectContainsPoint([_submenuView frame], [self convertPoint:[anEvent locationInWindow] fromView:nil]);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isHidden
|
||||||
|
{
|
||||||
|
return [_menuItem isHidden];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPMenuItem)menuItem
|
||||||
|
{
|
||||||
|
return _menuItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setFont:(CPFont)aFont
|
||||||
|
{
|
||||||
|
if (_font === aFont)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_font = aFont;
|
||||||
|
|
||||||
|
if ([_view respondsToSelector:@selector(setFont:)])
|
||||||
|
[_view setFont:aFont];
|
||||||
|
|
||||||
|
[self setDirty];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTextColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
if (_textColor == aColor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_textColor = aColor;
|
||||||
|
|
||||||
|
[_imageAndTextView setTextColor:[self textColor]];
|
||||||
|
[_submenuView setColor:[self textColor]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPColor)textColor
|
||||||
|
{
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTextShadowColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
if (_textShadowColor == aColor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_textShadowColor = aColor;
|
||||||
|
|
||||||
|
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
|
||||||
|
//[_submenuView setColor:[self textColor]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPColor)textShadowColor
|
||||||
|
{
|
||||||
|
return [_menuItem isEnabled] ? (_textShadowColor ? _textShadowColor : [CPColor colorWithWhite:1.0 alpha:0.8]) : [CPColor colorWithWhite:0.8 alpha:0.8];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPMenuItemArrowView : CPView
|
||||||
|
{
|
||||||
|
CPColor _color;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setColor:(CPColor)aColor
|
||||||
|
{
|
||||||
|
if (_color == aColor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_color = aColor;
|
||||||
|
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drawRect:(CGRect)aRect
|
||||||
|
{
|
||||||
|
var context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||||
|
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, 1.0, 4.0);
|
||||||
|
CGContextAddLineToPoint(context, 9.0, 4.0);
|
||||||
|
CGContextAddLineToPoint(context, 5.0, 8.0);
|
||||||
|
CGContextAddLineToPoint(context, 1.0, 4.0);
|
||||||
|
|
||||||
|
CGContextClosePath(context);
|
||||||
|
|
||||||
|
CGContextSetFillColor(context, _color);
|
||||||
|
CGContextFillPath(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
@import <AppKit/CPPanel.j>
|
||||||
|
|
||||||
|
|
||||||
|
@implementation CPOpenPanel : CPPanel
|
||||||
|
{
|
||||||
|
BOOL _canChooseFiles @accessors(property=canChooseFiles);
|
||||||
|
BOOL _canChooseDirectories @accessors(property=canChooseDirectories);
|
||||||
|
BOOL _allowsMultipleSelection @accessors(property=allowsMultipleSelection);
|
||||||
|
CPURL _directoryURL @accessors(property=directoryURL);
|
||||||
|
CPArray _URLs;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)openPanel
|
||||||
|
{
|
||||||
|
return [[CPOpenPanel alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPInteger)runModal
|
||||||
|
{
|
||||||
|
if (typeof window["cpOpenPanel"] === "function")
|
||||||
|
{
|
||||||
|
// FIXME: Is this correct???
|
||||||
|
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||||
|
|
||||||
|
var options = { directoryURL: [self directoryURL],
|
||||||
|
canChooseFiles: [self canChooseFiles],
|
||||||
|
canChooseDirectories: [self canChooseDirectories],
|
||||||
|
allowsMultipleSelection: [self allowsMultipleSelection] };
|
||||||
|
|
||||||
|
var result = window.cpOpenPanel(options);
|
||||||
|
|
||||||
|
_URLs = result.URLs;
|
||||||
|
|
||||||
|
return result.button;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw "-runModal is unimplemented.";
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPArray)URLs
|
||||||
|
{
|
||||||
|
return _URLs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
+1027
-51
File diff suppressed because it is too large
Load Diff
+13
-6
@@ -46,6 +46,13 @@ CPCancelButton = 0;
|
|||||||
<li>A panel can be made to work even when there's an attention panel on-screen. This permits actions within the panel to affect the attention panel.</li>
|
<li>A panel can be made to work even when there's an attention panel on-screen. This permits actions within the panel to affect the attention panel.</li>
|
||||||
</ul>
|
</ul>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
@global
|
||||||
|
@class CPWindow
|
||||||
|
*/
|
||||||
|
CPDocModalWindowMask = 1 << 6;
|
||||||
|
|
||||||
@implementation CPPanel : CPWindow
|
@implementation CPPanel : CPWindow
|
||||||
{
|
{
|
||||||
BOOL _becomesKeyOnlyIfNeeded;
|
BOOL _becomesKeyOnlyIfNeeded;
|
||||||
@@ -53,7 +60,7 @@ CPCancelButton = 0;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the receiver is a floating panel (like a palette).
|
Returns \c YES if the receiver is a floating panel (like a palette).
|
||||||
*/
|
*/
|
||||||
- (BOOL)isFloatingPanel
|
- (BOOL)isFloatingPanel
|
||||||
{
|
{
|
||||||
@@ -61,8 +68,8 @@ CPCancelButton = 0;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the receiver to be a floating panel. <code>YES</code>
|
Sets the receiver to be a floating panel. \c YES
|
||||||
makes the window a floating panel. <code>NO</code> makes it a normal window.
|
makes the window a floating panel. \c NO makes it a normal window.
|
||||||
@param isFloatingPanel specifies whether to make it floating
|
@param isFloatingPanel specifies whether to make it floating
|
||||||
*/
|
*/
|
||||||
- (void)setFloatingPanel:(BOOL)isFloatingPanel
|
- (void)setFloatingPanel:(BOOL)isFloatingPanel
|
||||||
@@ -71,8 +78,8 @@ CPCancelButton = 0;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the window only becomes key
|
Returns \c YES if the window only becomes key
|
||||||
if needed. <code>NO</code> means it behaves just like other windows.
|
if needed. \c NO means it behaves just like other windows.
|
||||||
*/
|
*/
|
||||||
- (BOOL)becomesKeyOnlyIfNeeded
|
- (BOOL)becomesKeyOnlyIfNeeded
|
||||||
{
|
{
|
||||||
@@ -81,7 +88,7 @@ CPCancelButton = 0;
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether the the window becomes key only if needed.
|
Sets whether the the window becomes key only if needed.
|
||||||
@param shouldBecomeKeyOnlyIfNeeded <code>YES</code> makes the window become key only if needed
|
@param shouldBecomeKeyOnlyIfNeeded \c YES makes the window become key only if needed
|
||||||
*/
|
*/
|
||||||
- (void)setBecomesKeyOnlyIfNeeded:(BOOL)shouldBecomeKeyOnlyIfNeeded
|
- (void)setBecomesKeyOnlyIfNeeded:(BOOL)shouldBecomeKeyOnlyIfNeeded
|
||||||
{
|
{
|
||||||
|
|||||||
+161
-15
@@ -25,6 +25,8 @@
|
|||||||
@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";
|
||||||
@@ -38,9 +40,17 @@ CPFontPboardType = @"CPFontPboardType";
|
|||||||
CPHTMLPboardType = @"CPHTMLPboardType";
|
CPHTMLPboardType = @"CPHTMLPboardType";
|
||||||
CPStringPboardType = @"CPStringPboardType";
|
CPStringPboardType = @"CPStringPboardType";
|
||||||
CPURLPboardType = @"CPURLPboardType";
|
CPURLPboardType = @"CPURLPboardType";
|
||||||
|
CPImagesPboardType = @"CPImagesPboardType";
|
||||||
|
CPVideosPboardType = @"CPVideosPboardType";
|
||||||
|
|
||||||
|
UTF8PboardType = @"public.utf8-plain-text";
|
||||||
|
|
||||||
|
// Deprecated
|
||||||
CPImagePboardType = @"CPImagePboardType";
|
CPImagePboardType = @"CPImagePboardType";
|
||||||
|
|
||||||
var CPPasteboards = nil;
|
|
||||||
|
var CPPasteboards = nil,
|
||||||
|
supportsNativePasteboard = NO;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ingroup appkit
|
@ingroup appkit
|
||||||
@@ -56,6 +66,8 @@ var CPPasteboards = nil;
|
|||||||
|
|
||||||
unsigned _changeCount;
|
unsigned _changeCount;
|
||||||
CPString _stateUID;
|
CPString _stateUID;
|
||||||
|
|
||||||
|
WebScriptObject _nativePasteboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -69,6 +81,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -111,6 +126,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;
|
||||||
@@ -140,6 +161,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,6 +180,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];
|
||||||
|
|
||||||
@@ -161,6 +197,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,12 +213,15 @@ var CPPasteboards = nil;
|
|||||||
Sets the pasteboard data for the specified type
|
Sets the pasteboard data for the specified type
|
||||||
@param aData the data
|
@param aData the data
|
||||||
@param aType the data type being set
|
@param aType the data type being set
|
||||||
@return <code>YES</code> if the data was successfully written to the pasteboard
|
@return \c YES if the data was successfully written to the pasteboard
|
||||||
*/
|
*/
|
||||||
- (BOOL)setData:(CPData)aData forType:(CPString)aType
|
- (BOOL)setData:(CPData)aData forType:(CPString)aType
|
||||||
{
|
{
|
||||||
[_provided setObject:aData forKey:aType];
|
[_provided setObject:aData forKey:aType];
|
||||||
|
|
||||||
|
if (aType === CPStringPboardType)
|
||||||
|
[self setData:aData forType:UTF8PboardType];
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,22 +229,22 @@ var CPPasteboards = nil;
|
|||||||
Writes the specified property list as data for the specified type
|
Writes the specified property list as data for the specified type
|
||||||
@param aPropertyList the property list to write
|
@param aPropertyList the property list to write
|
||||||
@param aType the data type
|
@param aType the data type
|
||||||
@return <code>YES</code> if the property list was successfully written to the pasteboard
|
@return \c YES if the property list was successfully written to the pasteboard
|
||||||
*/
|
*/
|
||||||
- (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];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the specified string as data for the specified type
|
Sets the specified string as data for the specified type
|
||||||
@param aString the string to write
|
@param aString the string to write
|
||||||
@param aType the data type
|
@param aType the data type
|
||||||
@return <code>YES</code> if the string was successfully written to the pasteboard
|
@return \c YES if the string was successfully written to the pasteboard
|
||||||
*/
|
*/
|
||||||
- (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
|
||||||
@@ -204,11 +252,11 @@ var CPPasteboards = nil;
|
|||||||
Checks the pasteboard's types for a match with the types listen in the specified array. The array should
|
Checks the pasteboard's types for a match with the types listen in the specified array. The array should
|
||||||
be ordered by the requestor's most preferred data type first.
|
be ordered by the requestor's most preferred data type first.
|
||||||
@param anArray an array of requested types ordered by preference
|
@param anArray an array of requested types ordered by preference
|
||||||
@return the highest match with the pasteboard's supported types or <code>nil</code> if no match was found
|
@return the highest match with the pasteboard's supported types or \c nil if no match was found
|
||||||
*/
|
*/
|
||||||
- (CPString)availableTypeFromArray:(CPArray)anArray
|
- (CPString)availableTypeFromArray:(CPArray)anArray
|
||||||
{
|
{
|
||||||
return [_types firstObjectCommonWithArray:anArray];
|
return [[self types] firstObjectCommonWithArray:anArray];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -216,6 +264,7 @@ var CPPasteboards = nil;
|
|||||||
*/
|
*/
|
||||||
- (CPArray)types
|
- (CPArray)types
|
||||||
{
|
{
|
||||||
|
[self _synchronizePasteboard];
|
||||||
return _types;
|
return _types;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +280,7 @@ var CPPasteboards = nil;
|
|||||||
/*!
|
/*!
|
||||||
Returns the pasteboard data for the specified data type
|
Returns the pasteboard data for the specified data type
|
||||||
@param aType the requested data type
|
@param aType the requested data type
|
||||||
@return the requested data or <code>nil</code> if the data doesn't exist
|
@return the requested data or \c nil if the data doesn't exist
|
||||||
*/
|
*/
|
||||||
- (CPData)dataForType:(CPString)aType
|
- (CPData)dataForType:(CPString)aType
|
||||||
{
|
{
|
||||||
@@ -245,26 +294,56 @@ 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
|
||||||
@return the property list or <code>nil</code> if the list was not found
|
@return the property list or \c nil if the list was not found
|
||||||
*/
|
*/
|
||||||
- (id)propertyListForType:(CPString)aType
|
- (id)propertyListForType:(CPString)aType
|
||||||
{
|
{
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -272,7 +351,7 @@ var CPPasteboards = nil;
|
|||||||
/*!
|
/*!
|
||||||
Returns the string for the specified data type
|
Returns the string for the specified data type
|
||||||
@param aType the requested data type
|
@param aType the requested data type
|
||||||
@return the string or <code>nil</code> if the string was not found
|
@return the string or \c nil if the string was not found
|
||||||
*/
|
*/
|
||||||
- (CPString)stringForType:(CPString)aType
|
- (CPString)stringForType:(CPString)aType
|
||||||
{
|
{
|
||||||
@@ -299,3 +378,70 @@ var CPPasteboards = nil;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
|
||||||
|
var DOMDataTransferPasteboard = nil;
|
||||||
|
|
||||||
|
@implementation _CPDOMDataTransferPasteboard : CPPasteboard
|
||||||
|
{
|
||||||
|
DataTransfer _dataTransfer;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (_CPDOMDataTransferPasteboard)DOMDataTransferPasteboard
|
||||||
|
{
|
||||||
|
if (!DOMDataTransferPasteboard)
|
||||||
|
DOMDataTransferPasteboard = [[_CPDOMDataTransferPasteboard alloc] init];
|
||||||
|
|
||||||
|
return DOMDataTransferPasteboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_setDataTransfer:(DataTransfer)aDataTransfer
|
||||||
|
{
|
||||||
|
_dataTransfer = aDataTransfer;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_setPasteboard:(CPPasteboard)aPasteboard
|
||||||
|
{
|
||||||
|
_dataTransfer.clearData();
|
||||||
|
|
||||||
|
var types = [aPasteboard types],
|
||||||
|
count = types.length;
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
{
|
||||||
|
var type = types[count];
|
||||||
|
|
||||||
|
if (type === CPStringPboardType)
|
||||||
|
_dataTransfer.setData(type, [aPasteboard stringForType:type]);
|
||||||
|
else
|
||||||
|
_dataTransfer.setData(type, [[aPasteboard dataForType:type] rawString]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPArray)types
|
||||||
|
{
|
||||||
|
return Array.prototype.slice.apply(_dataTransfer.types);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPData)dataForType:(CPString)aType
|
||||||
|
{
|
||||||
|
var dataString = _dataTransfer.getData(aType);
|
||||||
|
|
||||||
|
if (aType === CPStringPboardType)
|
||||||
|
return [CPData dataFromPropertyList:dataString format:kCFPropertyList280NorthFormat_v1_0];
|
||||||
|
|
||||||
|
return [CPData dataWithRawString:dataString];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)propertyListForType:(CPString)aType
|
||||||
|
{
|
||||||
|
if (aType === CPStringPboardType)
|
||||||
|
return _dataTransfer.getData(aType);
|
||||||
|
|
||||||
|
return [CPPropertyListSerialization propertyListFromData:[self dataForType:aType] format:CPPropertyListUnknownFormat];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
+50
-49
@@ -54,7 +54,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
/*!
|
/*!
|
||||||
Initializes the pop-up button to the specified size.
|
Initializes the pop-up button to the specified size.
|
||||||
@param aFrame the size for the button
|
@param aFrame the size for the button
|
||||||
@param shouldPullDown <code>YES</code> makes this a pull-down menu, <code>NO</code> makes it a pop-up menu.
|
@param shouldPullDown \c YES makes this a pull-down menu, \c NO makes it a pop-up menu.
|
||||||
@return the initialized pop-up button
|
@return the initialized pop-up button
|
||||||
*/
|
*/
|
||||||
- (id)initWithFrame:(CGRect)aFrame pullsDown:(BOOL)shouldPullDown
|
- (id)initWithFrame:(CGRect)aFrame pullsDown:(BOOL)shouldPullDown
|
||||||
@@ -87,8 +87,8 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Specifies whether the object is a pull-down or a pop-up menu.
|
Specifies whether the object is a pull-down or a pop-up menu.
|
||||||
@param shouldPullDown <code>YES</code> makes the pop-up button
|
@param shouldPullDown \c YES makes the pop-up button
|
||||||
a pull-down menu. <code>NO</code> makes it a pop-up menu.
|
a pull-down menu. \c NO makes it a pop-up menu.
|
||||||
*/
|
*/
|
||||||
- (void)setPullsDown:(BOOL)shouldPullDown
|
- (void)setPullsDown:(BOOL)shouldPullDown
|
||||||
{
|
{
|
||||||
@@ -111,7 +111,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the button is a pull-down menu. <code>NO</code> if the button is a pop-up menu.
|
Returns \c YES if the button is a pull-down menu. \c NO if the button is a pop-up menu.
|
||||||
*/
|
*/
|
||||||
- (BOOL)pullsDown
|
- (BOOL)pullsDown
|
||||||
{
|
{
|
||||||
@@ -200,18 +200,18 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
|
|
||||||
// Getting the User's Selection
|
// Getting the User's Selection
|
||||||
/*!
|
/*!
|
||||||
Returns the selected item or <code>nil</code> if no item is selected.
|
Returns the selected item or \c nil if no item is selected.
|
||||||
*/
|
*/
|
||||||
- (CPMenuItem)selectedItem
|
- (CPMenuItem)selectedItem
|
||||||
{
|
{
|
||||||
if (_selectedIndex < 0)
|
if (_selectedIndex < 0 || _selectedIndex > [self numberOfItems] - 1)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
return [_menu itemAtIndex:_selectedIndex];
|
return [_menu itemAtIndex:_selectedIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the title of the selected item or <code>nil</code> if no item is selected.
|
Returns the title of the selected item or \c nil if no item is selected.
|
||||||
*/
|
*/
|
||||||
- (CPString)titleOfSelectedItem
|
- (CPString)titleOfSelectedItem
|
||||||
{
|
{
|
||||||
@@ -372,7 +372,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the item at the specified index or <code>nil</code> if the item does not exist.
|
Returns the item at the specified index or \c nil if the item does not exist.
|
||||||
@param anIndex the index of the item to obtain
|
@param anIndex the index of the item to obtain
|
||||||
*/
|
*/
|
||||||
- (CPMenuItem)itemAtIndex:(unsigned)anIndex
|
- (CPMenuItem)itemAtIndex:(unsigned)anIndex
|
||||||
@@ -381,7 +381,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the title of the item at the specified index or <code>nil</code> if no item exists.
|
Returns the title of the item at the specified index or \c nil if no item exists.
|
||||||
@param anIndex the index of the item
|
@param anIndex the index of the item
|
||||||
*/
|
*/
|
||||||
- (CPString)itemTitleAtIndex:(unsigned)anIndex
|
- (CPString)itemTitleAtIndex:(unsigned)anIndex
|
||||||
@@ -628,29 +628,59 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
{
|
{
|
||||||
var numberOfItems = [self numberOfItems];
|
var numberOfItems = [self numberOfItems];
|
||||||
|
|
||||||
if (numberOfItems <= _selectedIndex)
|
if (numberOfItems <= _selectedIndex && numberOfItems > 0)
|
||||||
[self selectItemAtIndex:numberOfItems - 1];
|
[self selectItemAtIndex:numberOfItems - 1];
|
||||||
|
else
|
||||||
|
[self synchronizeTitleAndSelectedItem];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseDown:(CPEvent)anEvent
|
- (void)mouseDown:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
if (![self isEnabled])
|
if (![self isEnabled] || ![self numberOfItems])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[self highlight:YES];
|
[self highlight:YES];
|
||||||
|
|
||||||
var menu = [self menu],
|
var menu = [self menu],
|
||||||
theWindow = [self window],
|
bounds = [self bounds],
|
||||||
menuWindow = [_CPMenuWindow menuWindowWithMenu:menu font:[self font]];
|
minimumWidth = CGRectGetWidth(bounds);
|
||||||
|
|
||||||
[menuWindow setDelegate:self];
|
// FIXME: setFont: should set the font on the menu.
|
||||||
[menuWindow setBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle];
|
[menu setFont:[self font]];
|
||||||
|
|
||||||
// Pull Down Menus show up directly below their buttons.
|
|
||||||
if ([self pullsDown])
|
if ([self pullsDown])
|
||||||
var menuOrigin = [theWindow convertBaseToBridge:[self convertPoint:CGPointMake(0.0, CGRectGetMaxY([self bounds])) toView:nil]];
|
{
|
||||||
|
var positionedItem = nil,
|
||||||
|
location = CGPointMake(0.0, CGRectGetMaxY(bounds));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var contentRect = [self contentRectForBounds:bounds],
|
||||||
|
positionedItem = [self selectedItem],
|
||||||
|
standardLeftMargin = [_CPMenuWindow _standardLeftMargin] + [_CPMenuItemStandardView _standardLeftMargin],
|
||||||
|
location = CGPointMake(CGRectGetMinX(contentRect) - standardLeftMargin, 0.0);
|
||||||
|
|
||||||
// Pop Up Menus attempt to show up "on top" of the selected item.
|
minimumWidth += standardLeftMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
[menu setMinimumWidth:minimumWidth];
|
||||||
|
|
||||||
|
[menu
|
||||||
|
_popUpMenuPositioningItem:positionedItem
|
||||||
|
atLocation:location
|
||||||
|
topY:CGRectGetMinY(bounds)
|
||||||
|
bottomY:CGRectGetMaxY(bounds)
|
||||||
|
inView:self
|
||||||
|
callback:function(aMenu)
|
||||||
|
{
|
||||||
|
[self highlight:NO];
|
||||||
|
|
||||||
|
var highlightedItem = [aMenu highlightedItem];
|
||||||
|
|
||||||
|
if ([highlightedItem _isSelectable])
|
||||||
|
[self selectItem:highlightedItem];
|
||||||
|
}];
|
||||||
|
/*
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// This is confusing, I KNOW, so let me explain it to you.
|
// This is confusing, I KNOW, so let me explain it to you.
|
||||||
@@ -658,43 +688,14 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
|||||||
// 1. So calculate where our content is, then calculate where the menu item is.
|
// 1. So calculate where our content is, then calculate where the menu item is.
|
||||||
// 2. Move LEFT by whatever indentation we have (offsetWidths, aka, window margin, item margin, etc).
|
// 2. Move LEFT by whatever indentation we have (offsetWidths, aka, window margin, item margin, etc).
|
||||||
// 3. MOVE UP by the difference in sizes of the content and menu item, this will only work if the content is vertically centered.
|
// 3. MOVE UP by the difference in sizes of the content and menu item, this will only work if the content is vertically centered.
|
||||||
var contentRect = [self convertRect:[self contentRectForBounds:[self bounds]] toView:nil],
|
var contentRect = [self convertRect:[self contentRectForBounds:bounds] toView:nil],
|
||||||
menuOrigin = [theWindow convertBaseToBridge:contentRect.origin],
|
menuOrigin = [theWindow convertBaseToGlobal:contentRect.origin],
|
||||||
menuItemRect = [menuWindow rectForItemAtIndex:_selectedIndex];
|
menuItemRect = [menuWindow rectForItemAtIndex:_selectedIndex];
|
||||||
|
|
||||||
menuOrigin.x -= CGRectGetMinX(menuItemRect) + [menuWindow overlapOffsetWidth] + [[[menu itemAtIndex:_selectedIndex] _menuItemView] overlapOffsetWidth];
|
menuOrigin.x -= CGRectGetMinX(menuItemRect) + [menuWindow overlapOffsetWidth] + [[[menu itemAtIndex:_selectedIndex] _menuItemView] overlapOffsetWidth];
|
||||||
menuOrigin.y -= CGRectGetMinY(menuItemRect) + (CGRectGetHeight(menuItemRect) - CGRectGetHeight(contentRect)) / 2.0;
|
menuOrigin.y -= CGRectGetMinY(menuItemRect) + (CGRectGetHeight(menuItemRect) - CGRectGetHeight(contentRect)) / 2.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
[menuWindow setFrameOrigin:menuOrigin];
|
|
||||||
|
|
||||||
var menuMaxX = CGRectGetMaxX([menuWindow frame]),
|
|
||||||
buttonMaxX = [theWindow convertBaseToBridge:CGPointMake(CGRectGetMaxX([self convertRect:[self bounds] toView:nil]), 0.0)].x;
|
|
||||||
|
|
||||||
if (menuMaxX < buttonMaxX)
|
|
||||||
[menuWindow setMinWidth:CGRectGetWidth([menuWindow frame]) + buttonMaxX - menuMaxX - ([self pullsDown] ? 0.0 : VISIBLE_MARGIN)];
|
|
||||||
|
|
||||||
[menuWindow orderFront:self];
|
|
||||||
[menuWindow beginTrackingWithEvent:anEvent sessionDelegate:self didEndSelector:@selector(menuWindowDidFinishTracking:highlightedItem:)];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
@ignore
|
|
||||||
*/
|
*/
|
||||||
- (void)menuWindowDidFinishTracking:(_CPMenuWindow)aMenuWindow highlightedItem:(CPMenuItem)aMenuItem
|
|
||||||
{
|
|
||||||
[_CPMenuWindow poolMenuWindow:aMenuWindow];
|
|
||||||
|
|
||||||
[self highlight:NO];
|
|
||||||
|
|
||||||
var index = [_menu indexOfItem:aMenuItem];
|
|
||||||
|
|
||||||
if (index == CPNotFound)
|
|
||||||
return;
|
|
||||||
|
|
||||||
[self selectItemAtIndex:index];
|
|
||||||
|
|
||||||
[CPApp sendAction:[aMenuItem action] to:[aMenuItem target] from:aMenuItem];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_popUpItemAction:(id)aSender
|
- (void)_popUpItemAction:(id)aSender
|
||||||
|
|||||||
@@ -104,15 +104,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 +123,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
|
||||||
@@ -205,7 +192,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Always returns <code>NO</code>. Cappuccino does not have multiple threads.
|
Always returns \c NO. Cappuccino does not have multiple threads.
|
||||||
*/
|
*/
|
||||||
- (BOOL)usesThreadedAnimation
|
- (BOOL)usesThreadedAnimation
|
||||||
{
|
{
|
||||||
@@ -329,7 +316,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Specifies whether this progress indicator should be indeterminate or display progress based on it's max and min.
|
Specifies whether this progress indicator should be indeterminate or display progress based on it's max and min.
|
||||||
@param isDeterminate <code>YES</code> makes the indicator indeterminate
|
@param isDeterminate \c YES makes the indicator indeterminate
|
||||||
*/
|
*/
|
||||||
- (void)setIndeterminate:(BOOL)isIndeterminate
|
- (void)setIndeterminate:(BOOL)isIndeterminate
|
||||||
{
|
{
|
||||||
@@ -342,7 +329,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the progress bar is indeterminate.
|
Returns \c YES if the progress bar is indeterminate.
|
||||||
*/
|
*/
|
||||||
- (BOOL)isIndeterminate
|
- (BOOL)isIndeterminate
|
||||||
{
|
{
|
||||||
@@ -377,9 +364,9 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether the indicator should be displayed when it isn't animating. By default this is <code>YES</code> if the style
|
Sets whether the indicator should be displayed when it isn't animating. By default this is \c YES if the style
|
||||||
is CPProgressIndicatorBarStyle, and <code>NO</code> if it's CPProgressIndicatorSpinningStyle.
|
is CPProgressIndicatorBarStyle, and \c NO if it's CPProgressIndicatorSpinningStyle.
|
||||||
@param isDisplayedWhenStopped <code>YES</code> means the indicator will be displayed when it's not animating.
|
@param isDisplayedWhenStopped \c YES means the indicator will be displayed when it's not animating.
|
||||||
*/
|
*/
|
||||||
- (void)setDisplayedWhenStopped:(BOOL)isDisplayedWhenStopped
|
- (void)setDisplayedWhenStopped:(BOOL)isDisplayedWhenStopped
|
||||||
{
|
{
|
||||||
@@ -394,7 +381,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the progress bar is displayed when not animating.
|
Returns \c YES if the progress bar is displayed when not animating.
|
||||||
*/
|
*/
|
||||||
- (BOOL)isDisplayedWhenStopped
|
- (BOOL)isDisplayedWhenStopped
|
||||||
{
|
{
|
||||||
@@ -428,21 +415,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 */
|
||||||
|
|||||||
+7
-2
@@ -98,7 +98,7 @@
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
[self setRadioGroup:aRadioGroup || [CPRadioGroup new]];
|
[self setRadioGroup:aRadioGroup];
|
||||||
|
|
||||||
[self setHighlightsBy:CPContentsCellMask];
|
[self setHighlightsBy:CPContentsCellMask];
|
||||||
[self setShowsStateBy:CPContentsCellMask];
|
[self setShowsStateBy:CPContentsCellMask];
|
||||||
@@ -115,7 +115,7 @@
|
|||||||
|
|
||||||
- (id)initWithFrame:(CGRect)aFrame
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
{
|
{
|
||||||
return [self initWithFrame:aFrame radioGroup:nil];
|
return [self initWithFrame:aFrame radioGroup:[CPRadioGroup new]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPInteger)nextState
|
- (CPInteger)nextState
|
||||||
@@ -175,6 +175,9 @@ var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
|
|||||||
{
|
{
|
||||||
CPSet _radios;
|
CPSet _radios;
|
||||||
CPRadio _selectedRadio;
|
CPRadio _selectedRadio;
|
||||||
|
|
||||||
|
id _target @accessors(property=target);
|
||||||
|
SEL _action @accessors(property=action);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
@@ -213,6 +216,8 @@ var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
|
|||||||
|
|
||||||
[_selectedRadio setState:CPOffState];
|
[_selectedRadio setState:CPOffState];
|
||||||
_selectedRadio = aRadio;
|
_selectedRadio = aRadio;
|
||||||
|
|
||||||
|
[CPApp sendAction:_action to:_target from:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPRadio)selectedRadio
|
- (CPRadio)selectedRadio
|
||||||
|
|||||||
+49
-30
@@ -27,6 +27,9 @@ 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;
|
||||||
@@ -46,7 +49,7 @@ CPDownArrowKeyCode = 40;
|
|||||||
|
|
||||||
// Changing the first responder
|
// Changing the first responder
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the receiver is able to become the first responder. <code>NO</code> otherwise.
|
Returns \c YES if the receiver is able to become the first responder. \c NO otherwise.
|
||||||
*/
|
*/
|
||||||
- (BOOL)acceptsFirstResponder
|
- (BOOL)acceptsFirstResponder
|
||||||
{
|
{
|
||||||
@@ -55,8 +58,8 @@ CPDownArrowKeyCode = 40;
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Notifies the receiver that it will become the first responder. The receiver can reject first
|
Notifies the receiver that it will become the first responder. The receiver can reject first
|
||||||
responder if it returns <code>NO</code>. The default implementation always returns <code>YES</code>.
|
responder if it returns \c NO. The default implementation always returns \c YES.
|
||||||
@return <code>YES</code> if the receiver accepts first responder status.
|
@return \c YES if the receiver accepts first responder status.
|
||||||
*/
|
*/
|
||||||
- (BOOL)becomeFirstResponder
|
- (BOOL)becomeFirstResponder
|
||||||
{
|
{
|
||||||
@@ -65,7 +68,7 @@ CPDownArrowKeyCode = 40;
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Notifies the receiver that it has been asked to give up first responder status.
|
Notifies the receiver that it has been asked to give up first responder status.
|
||||||
@return <code>YES</code> if the receiver is willing to give up first responder status.
|
@return \c YES if the receiver is willing to give up first responder status.
|
||||||
*/
|
*/
|
||||||
- (BOOL)resignFirstResponder
|
- (BOOL)resignFirstResponder
|
||||||
{
|
{
|
||||||
@@ -96,36 +99,42 @@ CPDownArrowKeyCode = 40;
|
|||||||
*/
|
*/
|
||||||
- (void)interpretKeyEvents:(CPArray)events
|
- (void)interpretKeyEvents:(CPArray)events
|
||||||
{
|
{
|
||||||
var event,
|
var index = 0,
|
||||||
index = 0;
|
count = [events count];
|
||||||
|
|
||||||
while(event = events[index++])
|
for (; index < count; ++index)
|
||||||
{
|
{
|
||||||
|
var event = events[index];
|
||||||
|
|
||||||
switch([event keyCode])
|
switch([event keyCode])
|
||||||
{
|
{
|
||||||
case CPLeftArrowKeyCode: [self moveBackward:self];
|
case CPPageUpKeyCode: [self doCommandBySelector:@selector(pageUp:)];
|
||||||
break;
|
break;
|
||||||
case CPRightArrowKeyCode: [self moveForward:self];
|
case CPPageDownKeyCode: [self doCommandBySelector:@selector(pageDown:)];
|
||||||
break;
|
break;
|
||||||
case CPUpArrowKeyCode: [self moveUp:self];
|
case CPLeftArrowKeyCode: [self doCommandBySelector:@selector(moveLeft:)];
|
||||||
break;
|
break;
|
||||||
case CPDownArrowKeyCode: [self moveDown:self];
|
case CPRightArrowKeyCode: [self doCommandBySelector:@selector(moveRight:)];
|
||||||
break;
|
break;
|
||||||
case CPDeleteKeyCode: [self deleteBackward:self];
|
case CPUpArrowKeyCode: [self doCommandBySelector:@selector(moveUp:)];
|
||||||
|
break;
|
||||||
|
case CPDownArrowKeyCode: [self doCommandBySelector:@selector(moveDown:)];
|
||||||
|
break;
|
||||||
|
case CPDeleteKeyCode: [self doCommandBySelector:@selector(deleteBackward:)];
|
||||||
break;
|
break;
|
||||||
case CPReturnKeyCode:
|
case CPReturnKeyCode:
|
||||||
case 3: [self insertLineBreak:self];
|
case 3: [self doCommandBySelector:@selector(insertLineBreak:)];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPEscapeKeyCode: [self cancel:self];
|
case CPEscapeKeyCode: [self doCommandBySelector:@selector(cancel:)];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPTabKeyCode: var shift = [event modifierFlags] & CPShiftKeyMask;
|
case CPTabKeyCode: var shift = [event modifierFlags] & CPShiftKeyMask;
|
||||||
|
|
||||||
if (!shift)
|
if (!shift)
|
||||||
[self insertTab:self];
|
[self doCommandBySelector:@selector(insertTab:)];
|
||||||
else
|
else
|
||||||
[self insertBackTab:self];
|
[self doCommandBySelector:@selector(insertBackTab:)];
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -143,6 +152,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.
|
||||||
@@ -162,6 +180,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,9 +241,9 @@ CPDownArrowKeyCode = 40;
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
FIXME This description is bad.
|
FIXME This description is bad.
|
||||||
Based on <code>anEvent</code>, the receiver should simulate the event.
|
Based on \c anEvent, the receiver should simulate the event.
|
||||||
@param anEvent the event to simulate
|
@param anEvent the event to simulate
|
||||||
@return <code>YES</code> if the event receiver simulated the event
|
@return \c YES if the event receiver simulated the event
|
||||||
*/
|
*/
|
||||||
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
|
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
@@ -224,14 +251,6 @@ CPDownArrowKeyCode = 40;
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Action Methods
|
// Action Methods
|
||||||
/*!
|
|
||||||
Deletes one character backward, or the selection if anything is selected.
|
|
||||||
@param aSender the object requesting this
|
|
||||||
*/
|
|
||||||
- (void)deleteBackward:(id)aSender
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Insert a line break at the caret position or selection.
|
Insert a line break at the caret position or selection.
|
||||||
@param aSender the object requesting this
|
@param aSender the object requesting this
|
||||||
@@ -247,7 +266,7 @@ CPDownArrowKeyCode = 40;
|
|||||||
*/
|
*/
|
||||||
- (void)insertNewline:(id)aSender
|
- (void)insertNewline:(id)aSender
|
||||||
{
|
{
|
||||||
[self insertNewline:aSender];
|
[[self nextResponder] insertNewline:aSender];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)cancel:(id)sender
|
- (void)cancel:(id)sender
|
||||||
@@ -273,12 +292,12 @@ CPDownArrowKeyCode = 40;
|
|||||||
// Dispatch methods
|
// Dispatch methods
|
||||||
/*!
|
/*!
|
||||||
The receiver will attempt to perform the command,
|
The receiver will attempt to perform the command,
|
||||||
if it responds to it. If not, the <code>nextResponder</code> will be called to do it.
|
if it responds to it. If not, the \c -nextResponder will be called to do it.
|
||||||
@param aSelector the command to attempt
|
@param aSelector the command to attempt
|
||||||
*/
|
*/
|
||||||
- (void)doCommandBySelector:(SEL)aSelector
|
- (void)doCommandBySelector:(SEL)aSelector
|
||||||
{
|
{
|
||||||
if([self respondsToSelector:aSelector])
|
if ([self respondsToSelector:aSelector])
|
||||||
[self performSelector:aSelector];
|
[self performSelector:aSelector];
|
||||||
else
|
else
|
||||||
[_nextResponder doCommandBySelector:aSelector];
|
[_nextResponder doCommandBySelector:aSelector];
|
||||||
@@ -288,7 +307,7 @@ CPDownArrowKeyCode = 40;
|
|||||||
The receiver will attempt to perform the command, or pass it on to the next responder if it doesn't respond to it.
|
The receiver will attempt to perform the command, or pass it on to the next responder if it doesn't respond to it.
|
||||||
@param aSelector the command to perform
|
@param aSelector the command to perform
|
||||||
@param anObject the argument to the method
|
@param anObject the argument to the method
|
||||||
@return <code>YES</code> if the receiver was able to perform the command, or a responder down the chain was
|
@return \c YES if the receiver was able to perform the command, or a responder down the chain was
|
||||||
able to perform the command.
|
able to perform the command.
|
||||||
*/
|
*/
|
||||||
- (BOOL)tryToPerform:(SEL)aSelector with:(id)anObject
|
- (BOOL)tryToPerform:(SEL)aSelector with:(id)anObject
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
@import <AppKit/CPPanel.j>
|
||||||
|
|
||||||
|
|
||||||
|
@implementation CPSavePanel : CPPanel
|
||||||
|
{
|
||||||
|
CPURL _URL;
|
||||||
|
|
||||||
|
BOOL _isExtensionHidden @accessors(getter=isExtensionHidden, setter=setExtensionHidden:);
|
||||||
|
BOOL _canSelectHiddenExtension @accessors(property=canSelectHiddenExtension);
|
||||||
|
BOOL _allowsOtherFileTypes @accessors(property=allowsOtherFileTypes);
|
||||||
|
BOOL _canCreateDirectories @accessors(property=canCreateDirectories);
|
||||||
|
|
||||||
|
CPArray _allowedFileTypes @accessors(property=allowedFileTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)savePanel
|
||||||
|
{
|
||||||
|
return [[CPSavePanel alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
if (self = [super init])
|
||||||
|
{
|
||||||
|
_canCreateDirectories = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPInteger)runModal
|
||||||
|
{
|
||||||
|
// FIXME: Is this correct???
|
||||||
|
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||||
|
|
||||||
|
if (typeof window["cpSavePanel"] === "function")
|
||||||
|
{
|
||||||
|
var resultObject = window.cpSavePanel({
|
||||||
|
isExtensionHidden: _isExtensionHidden,
|
||||||
|
canSelectHiddenExtension: _canSelectHiddenExtension,
|
||||||
|
allowsOtherFileTypes: _allowsOtherFileTypes,
|
||||||
|
canCreateDirectories: _canCreateDirectories,
|
||||||
|
allowedFileTypes: _allowedFileTypes
|
||||||
|
}),
|
||||||
|
result = resultObject.button;
|
||||||
|
|
||||||
|
_URL = result ? [CPURL URLWithString:resultObject.URL] : nil;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// FIXME: This is not the best way to do this.
|
||||||
|
var documentName = window.prompt("Document Name:"),
|
||||||
|
result = documentName !== null;
|
||||||
|
|
||||||
|
_URL = result ? [[self class] proposedFileURLWithDocumentName:documentName] : nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPURL)URL
|
||||||
|
{
|
||||||
|
return _URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
|
#import "CoreGraphics/CGGeometry.h"
|
||||||
|
#import "Platform/Platform.h"
|
||||||
|
|
||||||
|
@implementation CPScreen : CPObject
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)visibleFrame
|
||||||
|
{
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
return _CGRectMake(window.screen.availLeft, window.screen.availTop, window.screen.availWidth, window.screen.availHeight);
|
||||||
|
#else
|
||||||
|
return _CGRectMakeZero();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
+226
-117
@@ -38,6 +38,8 @@
|
|||||||
@implementation CPScrollView : CPView
|
@implementation CPScrollView : CPView
|
||||||
{
|
{
|
||||||
CPClipView _contentView;
|
CPClipView _contentView;
|
||||||
|
CPClipView _headerClipView;
|
||||||
|
CPView _cornerView;
|
||||||
|
|
||||||
BOOL _hasVerticalScroller;
|
BOOL _hasVerticalScroller;
|
||||||
BOOL _hasHorizontalScroller;
|
BOOL _hasHorizontalScroller;
|
||||||
@@ -70,6 +72,10 @@
|
|||||||
|
|
||||||
[self addSubview:_contentView];
|
[self addSubview:_contentView];
|
||||||
|
|
||||||
|
_headerClipView = [[CPClipView alloc] init];
|
||||||
|
|
||||||
|
[self addSubview:_headerClipView];
|
||||||
|
|
||||||
[self setHasVerticalScroller:YES];
|
[self setHasVerticalScroller:YES];
|
||||||
[self setHasHorizontalScroller:YES];
|
[self setHasHorizontalScroller:YES];
|
||||||
}
|
}
|
||||||
@@ -100,7 +106,7 @@
|
|||||||
*/
|
*/
|
||||||
- (void)setContentView:(CPClipView)aContentView
|
- (void)setContentView:(CPClipView)aContentView
|
||||||
{
|
{
|
||||||
if (!aContentView)
|
if (_contentView !== aContentView || !aContentView)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var documentView = [aContentView documentView];
|
var documentView = [aContentView documentView];
|
||||||
@@ -110,14 +116,14 @@
|
|||||||
|
|
||||||
[_contentView removeFromSuperview];
|
[_contentView removeFromSuperview];
|
||||||
|
|
||||||
var size = [self contentSize];
|
|
||||||
|
|
||||||
_contentView = aContentView;
|
_contentView = aContentView;
|
||||||
|
|
||||||
[_contentView setFrame:CGRectMake(0.0, 0.0, size.width, size.height)];
|
|
||||||
[_contentView setDocumentView:documentView];
|
[_contentView setDocumentView:documentView];
|
||||||
|
|
||||||
[self addSubview:_contentView];
|
[self addSubview:_contentView];
|
||||||
|
|
||||||
|
// This will size the content view appropriately, so no need to size it in this method.
|
||||||
|
[self reflectScrolledClipView:_contentView];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -134,8 +140,11 @@
|
|||||||
*/
|
*/
|
||||||
- (void)setDocumentView:(CPView)aView
|
- (void)setDocumentView:(CPView)aView
|
||||||
{
|
{
|
||||||
[_contentView setDocumentView:aView];
|
[_contentView setDocumentView:aView];
|
||||||
[self reflectScrolledClipView:_contentView];
|
|
||||||
|
// FIXME: This should be observed.
|
||||||
|
[self _updateCornerAndHeaderView];
|
||||||
|
[self reflectScrolledClipView:_contentView];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -168,69 +177,95 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
[_contentView setFrame:[self bounds]];
|
[_contentView setFrame:[self bounds]];
|
||||||
|
[_headerClipView setFrame:_CGRectMakeZero()];
|
||||||
|
|
||||||
--_recursionCount;
|
--_recursionCount;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var documentFrame = [documentView frame],
|
var documentFrame = [documentView frame], // the size of the whole document
|
||||||
contentViewFrame = [self bounds],
|
contentFrame = [self bounds], // assume it takes up the entire size of the scrollview (no scrollers)
|
||||||
scrollPoint = [_contentView bounds].origin,
|
headerClipViewFrame = [self _headerClipViewFrame],
|
||||||
difference = _CGSizeMake(CPRectGetWidth(documentFrame) - CPRectGetWidth(contentViewFrame), CPRectGetHeight(documentFrame) - CPRectGetHeight(contentViewFrame)),
|
headerClipViewHeight = _CGRectGetHeight(headerClipViewFrame);
|
||||||
shouldShowVerticalScroller = (!_autohidesScrollers || difference.height > 0.0) && _hasVerticalScroller,
|
|
||||||
shouldShowHorizontalScroller = (!_autohidesScrollers || difference.width > 0.0) && _hasHorizontalScroller,
|
|
||||||
wasShowingVerticalScroller = ![_verticalScroller isHidden],
|
|
||||||
wasShowingHorizontalScroller = ![_horizontalScroller isHidden],
|
|
||||||
verticalScrollerWidth = _CGRectGetWidth([_verticalScroller frame]);
|
|
||||||
horizontalScrollerHeight = _CGRectGetHeight([_horizontalScroller frame]);
|
|
||||||
|
|
||||||
if (_autohidesScrollers)
|
contentFrame.origin.y += headerClipViewHeight;
|
||||||
{
|
contentFrame.size.height -= headerClipViewHeight;
|
||||||
// Check to see if either affected the other!
|
|
||||||
if (shouldShowVerticalScroller)
|
|
||||||
shouldShowHorizontalScroller = (!_autohidesScrollers || difference.width > -verticalScrollerWidth) && _hasHorizontalScroller;
|
|
||||||
|
|
||||||
if (shouldShowHorizontalScroller)
|
var difference = _CGSizeMake(_CGRectGetWidth(documentFrame) - _CGRectGetWidth(contentFrame), _CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentFrame)),
|
||||||
shouldShowVerticalScroller = (!_autohidesScrollers || difference.height > -horizontalScrollerHeight) && _hasVerticalScroller;
|
verticalScrollerWidth = _CGRectGetWidth([_verticalScroller frame]),
|
||||||
}
|
horizontalScrollerHeight = _CGRectGetHeight([_horizontalScroller frame]),
|
||||||
|
hasVerticalScroll = difference.height > 0.0,
|
||||||
[_verticalScroller setHidden:!shouldShowVerticalScroller];
|
hasHorizontalScroll = difference.width > 0.0,
|
||||||
[_verticalScroller setEnabled:difference.height > 0.0];
|
shouldShowVerticalScroller = _hasVerticalScroller && (!_autohidesScrollers || hasVerticalScroll),
|
||||||
|
shouldShowHorizontalScroller = _hasHorizontalScroller && (!_autohidesScrollers || hasHorizontalScroll);
|
||||||
[_horizontalScroller setHidden:!shouldShowHorizontalScroller];
|
|
||||||
[_horizontalScroller setEnabled:difference.width > 0.0];
|
|
||||||
|
|
||||||
|
// Now we have to account for the shown scrollers affecting the deltas.
|
||||||
if (shouldShowVerticalScroller)
|
if (shouldShowVerticalScroller)
|
||||||
{
|
{
|
||||||
var verticalScrollerHeight = CPRectGetHeight(contentViewFrame);
|
|
||||||
|
|
||||||
if (shouldShowHorizontalScroller)
|
|
||||||
verticalScrollerHeight -= horizontalScrollerHeight;
|
|
||||||
|
|
||||||
difference.width += verticalScrollerWidth;
|
difference.width += verticalScrollerWidth;
|
||||||
contentViewFrame.size.width -= verticalScrollerWidth;
|
hasHorizontalScroll = difference.width > 0.0;
|
||||||
|
shouldShowHorizontalScroller = _hasHorizontalScroller && (!_autohidesScrollers || hasHorizontalScroll);
|
||||||
[_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height
|
|
||||||
knobProportion:CPRectGetHeight(contentViewFrame) / CPRectGetHeight(documentFrame)];
|
|
||||||
[_verticalScroller setFrame:CPRectMake(CPRectGetMaxX(contentViewFrame), 0.0, verticalScrollerWidth, verticalScrollerHeight)];
|
|
||||||
}
|
}
|
||||||
else if (wasShowingVerticalScroller)
|
|
||||||
[_verticalScroller setFloatValue:0.0 knobProportion:1.0];
|
|
||||||
|
|
||||||
if (shouldShowHorizontalScroller)
|
if (shouldShowHorizontalScroller)
|
||||||
{
|
{
|
||||||
difference.height += horizontalScrollerHeight;
|
difference.height += horizontalScrollerHeight;
|
||||||
contentViewFrame.size.height -= horizontalScrollerHeight;
|
hasVerticalScroll = difference.height > 0.0;
|
||||||
|
shouldShowVerticalScroller = _hasVerticalScroller && (!_autohidesScrollers || hasVerticalScroll);
|
||||||
|
}
|
||||||
|
|
||||||
[_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width
|
// We now definitively know which scrollers are shown or not, as well as whether they are showing scroll values.
|
||||||
knobProportion:CPRectGetWidth(contentViewFrame) / CPRectGetWidth(documentFrame)];
|
[_verticalScroller setHidden:!shouldShowVerticalScroller];
|
||||||
[_horizontalScroller setFrame:CPRectMake(0.0, CPRectGetMaxY(contentViewFrame), CPRectGetWidth(contentViewFrame), horizontalScrollerHeight)];
|
[_verticalScroller setEnabled:hasVerticalScroll];
|
||||||
|
|
||||||
|
[_horizontalScroller setHidden:!shouldShowHorizontalScroller];
|
||||||
|
[_horizontalScroller setEnabled:hasHorizontalScroll];
|
||||||
|
|
||||||
|
// We can thus appropriately account for them changing the content size.
|
||||||
|
if (shouldShowVerticalScroller)
|
||||||
|
contentFrame.size.width -= verticalScrollerWidth;
|
||||||
|
|
||||||
|
if (shouldShowHorizontalScroller)
|
||||||
|
contentFrame.size.height -= horizontalScrollerHeight;
|
||||||
|
|
||||||
|
var scrollPoint = [_contentView bounds].origin,
|
||||||
|
wasShowingVerticalScroller = ![_verticalScroller isHidden],
|
||||||
|
wasShowingHorizontalScroller = ![_horizontalScroller isHidden];
|
||||||
|
|
||||||
|
if (shouldShowVerticalScroller)
|
||||||
|
{
|
||||||
|
var verticalScrollerY = MAX(_CGRectGetHeight([self _cornerViewFrame]), headerClipViewHeight),
|
||||||
|
verticalScrollerHeight = _CGRectGetHeight([self bounds]) - verticalScrollerY;
|
||||||
|
|
||||||
|
if (shouldShowHorizontalScroller)
|
||||||
|
verticalScrollerHeight -= horizontalScrollerHeight;
|
||||||
|
|
||||||
|
[_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height];
|
||||||
|
[_verticalScroller setKnobProportion:_CGRectGetHeight(contentFrame) / _CGRectGetHeight(documentFrame)];
|
||||||
|
[_verticalScroller setFrame:_CGRectMake(_CGRectGetMaxX(contentFrame), verticalScrollerY, verticalScrollerWidth, verticalScrollerHeight)];
|
||||||
|
}
|
||||||
|
else if (wasShowingVerticalScroller)
|
||||||
|
{
|
||||||
|
[_verticalScroller setFloatValue:0.0];
|
||||||
|
[_verticalScroller setKnobProportion:1.0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldShowHorizontalScroller)
|
||||||
|
{
|
||||||
|
[_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width];
|
||||||
|
[_horizontalScroller setKnobProportion:_CGRectGetWidth(contentFrame) / _CGRectGetWidth(documentFrame)];
|
||||||
|
[_horizontalScroller setFrame:_CGRectMake(0.0, _CGRectGetMaxY(contentFrame), _CGRectGetWidth(contentFrame), horizontalScrollerHeight)];
|
||||||
}
|
}
|
||||||
else if (wasShowingHorizontalScroller)
|
else if (wasShowingHorizontalScroller)
|
||||||
[_horizontalScroller setFloatValue:0.0 knobProportion:1.0];
|
{
|
||||||
|
[_horizontalScroller setFloatValue:0.0];
|
||||||
|
[_horizontalScroller setKnobProportion:1.0];
|
||||||
|
}
|
||||||
|
|
||||||
[_contentView setFrame:contentViewFrame];
|
[_contentView setFrame:contentFrame];
|
||||||
|
[_headerClipView setFrame:headerClipViewFrame];
|
||||||
|
[_cornerView setFrame:[self _cornerViewFrame]];
|
||||||
|
|
||||||
--_recursionCount;
|
--_recursionCount;
|
||||||
}
|
}
|
||||||
@@ -269,7 +304,7 @@
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Specifies whether the scroll view can have a horizontal scroller.
|
Specifies whether the scroll view can have a horizontal scroller.
|
||||||
@param hasHorizontalScroller <code>YES</code> lets the scroll view
|
@param hasHorizontalScroller \c YES lets the scroll view
|
||||||
allocate a horizontal scroller if necessary.
|
allocate a horizontal scroller if necessary.
|
||||||
*/
|
*/
|
||||||
- (void)setHasHorizontalScroller:(BOOL)shouldHaveHorizontalScroller
|
- (void)setHasHorizontalScroller:(BOOL)shouldHaveHorizontalScroller
|
||||||
@@ -280,18 +315,16 @@
|
|||||||
_hasHorizontalScroller = shouldHaveHorizontalScroller;
|
_hasHorizontalScroller = shouldHaveHorizontalScroller;
|
||||||
|
|
||||||
if (_hasHorizontalScroller && !_horizontalScroller)
|
if (_hasHorizontalScroller && !_horizontalScroller)
|
||||||
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, CPRectGetWidth([self bounds]), [CPScroller scrollerWidth])]];
|
|
||||||
|
|
||||||
else if (!_hasHorizontalScroller && _horizontalScroller)
|
|
||||||
{
|
{
|
||||||
[_horizontalScroller setHidden:YES];
|
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(_CGRectGetWidth([self bounds]), [CPScroller scrollerWidth]+1), [CPScroller scrollerWidth])]];
|
||||||
|
[[self horizontalScroller] setFrameSize:CGSizeMake(_CGRectGetWidth([self bounds]), [CPScroller scrollerWidth])];
|
||||||
[self reflectScrolledClipView:_contentView];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[self reflectScrolledClipView:_contentView];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the scroll view can have a horizontal scroller.
|
Returns \c YES if the scroll view can have a horizontal scroller.
|
||||||
*/
|
*/
|
||||||
- (BOOL)hasHorizontalScroller
|
- (BOOL)hasHorizontalScroller
|
||||||
{
|
{
|
||||||
@@ -332,7 +365,7 @@
|
|||||||
/*!
|
/*!
|
||||||
Specifies whether the scroll view has can have
|
Specifies whether the scroll view has can have
|
||||||
a vertical scroller. It allocates it if necessary.
|
a vertical scroller. It allocates it if necessary.
|
||||||
@param hasVerticalScroller <code>YES</code> allows
|
@param hasVerticalScroller \c YES allows
|
||||||
the scroll view to display a vertical scroller
|
the scroll view to display a vertical scroller
|
||||||
*/
|
*/
|
||||||
- (void)setHasVerticalScroller:(BOOL)shouldHaveVerticalScroller
|
- (void)setHasVerticalScroller:(BOOL)shouldHaveVerticalScroller
|
||||||
@@ -343,18 +376,16 @@
|
|||||||
_hasVerticalScroller = shouldHaveVerticalScroller;
|
_hasVerticalScroller = shouldHaveVerticalScroller;
|
||||||
|
|
||||||
if (_hasVerticalScroller && !_verticalScroller)
|
if (_hasVerticalScroller && !_verticalScroller)
|
||||||
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:CPRectMake(0.0, 0.0, [CPScroller scrollerWidth], CPRectGetHeight([self bounds]))]];
|
|
||||||
|
|
||||||
else if (!_hasVerticalScroller && _verticalScroller)
|
|
||||||
{
|
{
|
||||||
[_verticalScroller setHidden:YES];
|
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], MAX(_CGRectGetHeight([self bounds]), [CPScroller scrollerWidth]+1))]];
|
||||||
|
[[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidth], _CGRectGetHeight([self bounds]))];
|
||||||
[self reflectScrolledClipView:_contentView];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[self reflectScrolledClipView:_contentView];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the scroll view can have a vertical scroller.
|
Returns \c YES if the scroll view can have a vertical scroller.
|
||||||
*/
|
*/
|
||||||
- (BOOL)hasVerticalScroller
|
- (BOOL)hasVerticalScroller
|
||||||
{
|
{
|
||||||
@@ -363,7 +394,7 @@
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether the scroll view hides its scoll bars when not needed.
|
Sets whether the scroll view hides its scoll bars when not needed.
|
||||||
@param autohidesScrollers <code>YES</code> causes the scroll bars
|
@param autohidesScrollers \c YES causes the scroll bars
|
||||||
to be hidden when not needed.
|
to be hidden when not needed.
|
||||||
*/
|
*/
|
||||||
- (void)setAutohidesScrollers:(BOOL)autohidesScrollers
|
- (void)setAutohidesScrollers:(BOOL)autohidesScrollers
|
||||||
@@ -377,20 +408,76 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the scroll view hides its scroll
|
Returns \c YES if the scroll view hides its scroll
|
||||||
bars when not necessary.
|
bars when not necessary.
|
||||||
*/
|
*/
|
||||||
- (BOOL)autohidesScrollers
|
- (BOOL)autohidesScrollers
|
||||||
{
|
{
|
||||||
return _autohidesScrollers;
|
return _autohidesScrollers;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
- (void)setFrameSize:(CPRect)aSize
|
- (void)_updateCornerAndHeaderView
|
||||||
{
|
{
|
||||||
[super setFrameSize:aSize];
|
var documentView = [self documentView],
|
||||||
|
currentHeaderView = [self _headerView],
|
||||||
|
documentHeaderView = [documentView respondsToSelector:@selector(headerView)] ? [documentView headerView] : nil;
|
||||||
|
|
||||||
|
if (currentHeaderView !== documentHeaderView)
|
||||||
|
{
|
||||||
|
[currentHeaderView removeFromSuperview];
|
||||||
|
[_headerClipView setDocumentView:documentHeaderView];
|
||||||
|
}
|
||||||
|
|
||||||
|
var documentCornerView = [documentView respondsToSelector:@selector(cornerView)] ? [documentView cornerView] : nil;
|
||||||
|
|
||||||
|
if (_cornerView !== documentCornerView)
|
||||||
|
{
|
||||||
|
[_cornerView removeFromSuperview];
|
||||||
|
|
||||||
|
_cornerView = documentCornerView;
|
||||||
|
|
||||||
|
if (_cornerView)
|
||||||
|
[self addSubview:_cornerView];
|
||||||
|
}
|
||||||
|
|
||||||
[self reflectScrolledClipView:_contentView];
|
[self reflectScrolledClipView:_contentView];
|
||||||
}*/
|
}
|
||||||
|
|
||||||
|
- (CPView)_headerView
|
||||||
|
{
|
||||||
|
var headerClipViewSubviews = [_headerClipView subviews];
|
||||||
|
|
||||||
|
return [headerClipViewSubviews count] ? headerClipViewSubviews[0] : nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)_cornerViewFrame
|
||||||
|
{
|
||||||
|
if (!_cornerView)
|
||||||
|
return _CGRectMakeZero();
|
||||||
|
|
||||||
|
var bounds = [self bounds],
|
||||||
|
frame = [_cornerView frame];
|
||||||
|
|
||||||
|
frame.origin.x = _CGRectGetMaxX(bounds) - _CGRectGetWidth(frame);
|
||||||
|
frame.origin.y = 0;
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)_headerClipViewFrame
|
||||||
|
{
|
||||||
|
var headerView = [self _headerView];
|
||||||
|
|
||||||
|
if (!headerView)
|
||||||
|
return _CGRectMakeZero();
|
||||||
|
|
||||||
|
var frame = [self bounds];
|
||||||
|
|
||||||
|
frame.size.height = _CGRectGetHeight([headerView frame]);
|
||||||
|
frame.size.width -= _CGRectGetWidth([self _cornerViewFrame]);
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
- (void)_verticalScrollerDidScroll:(CPScroller)aScroller
|
- (void)_verticalScrollerDidScroll:(CPScroller)aScroller
|
||||||
@@ -415,7 +502,8 @@
|
|||||||
|
|
||||||
case CPScrollerKnobSlot:
|
case CPScrollerKnobSlot:
|
||||||
case CPScrollerKnob:
|
case CPScrollerKnob:
|
||||||
default: contentBounds.origin.y = value * (_CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds));
|
// We want integral bounds!
|
||||||
|
default: contentBounds.origin.y = ROUND(value * (_CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[_contentView scrollToPoint:contentBounds.origin];
|
[_contentView scrollToPoint:contentBounds.origin];
|
||||||
@@ -444,10 +532,12 @@
|
|||||||
|
|
||||||
case CPScrollerKnobSlot:
|
case CPScrollerKnobSlot:
|
||||||
case CPScrollerKnob:
|
case CPScrollerKnob:
|
||||||
default: contentBounds.origin.x = value * (_CGRectGetWidth(documentFrame) - _CGRectGetWidth(contentBounds));
|
// We want integral bounds!
|
||||||
|
default: contentBounds.origin.x = ROUND(value * (_CGRectGetWidth(documentFrame) - _CGRectGetWidth(contentBounds)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[_contentView scrollToPoint:contentBounds.origin];
|
[_contentView scrollToPoint:contentBounds.origin];
|
||||||
|
[_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0.0)];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -580,67 +670,80 @@
|
|||||||
*/
|
*/
|
||||||
- (void)scrollWheel:(CPEvent)anEvent
|
- (void)scrollWheel:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
var value = [_verticalScroller floatValue],
|
var documentFrame = [[self documentView] frame],
|
||||||
documentFrame = [[self documentView] frame],
|
|
||||||
contentBounds = [_contentView bounds];
|
contentBounds = [_contentView bounds];
|
||||||
|
|
||||||
contentBounds.origin.x += [anEvent deltaX] * _horizontalLineScroll;
|
// We want integral bounds!
|
||||||
contentBounds.origin.y += [anEvent deltaY] * _verticalLineScroll;
|
contentBounds.origin.x = ROUND(contentBounds.origin.x + [anEvent deltaX] * _horizontalLineScroll);
|
||||||
|
contentBounds.origin.y = ROUND(contentBounds.origin.y + [anEvent deltaY] * _verticalLineScroll);
|
||||||
|
|
||||||
[_contentView scrollToPoint:contentBounds.origin];
|
[_contentView scrollToPoint:contentBounds.origin];
|
||||||
|
[_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0.0)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)keyDown:(CPEvent)anEvent
|
- (void)keyDown:(CPEvent)anEvent
|
||||||
{
|
{
|
||||||
var keyCode = [anEvent keyCode],
|
[self interpretKeyEvents:[anEvent]];
|
||||||
value = [_verticalScroller floatValue],
|
}
|
||||||
documentFrame = [[self documentView] frame],
|
|
||||||
|
- (void)pageUp:(id)sender
|
||||||
|
{
|
||||||
|
var contentBounds = [_contentView bounds];
|
||||||
|
[self moveByOffset:CGSizeMake(0.0, -(_CGRectGetHeight(contentBounds) - _verticalPageScroll))];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)pageDown:(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],
|
||||||
contentBounds = [_contentView bounds];
|
contentBounds = [_contentView bounds];
|
||||||
|
|
||||||
switch (keyCode)
|
contentBounds.origin.x += aSize.width;
|
||||||
{
|
contentBounds.origin.y += aSize.height;
|
||||||
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)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@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";
|
||||||
|
|
||||||
@implementation CPScrollView (CPCoding)
|
@implementation CPScrollView (CPCoding)
|
||||||
|
|
||||||
@@ -655,6 +758,7 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
|||||||
_horizontalPageScroll = [aCoder decodeFloatForKey:CPScrollViewHPageScrollKey];
|
_horizontalPageScroll = [aCoder decodeFloatForKey:CPScrollViewHPageScrollKey];
|
||||||
|
|
||||||
_contentView = [aCoder decodeObjectForKey:CPScrollViewContentViewKey];
|
_contentView = [aCoder decodeObjectForKey:CPScrollViewContentViewKey];
|
||||||
|
_headerClipView = [aCoder decodeObjectForKey:CPScrollViewHeaderClipViewKey];
|
||||||
|
|
||||||
_verticalScroller = [aCoder decodeObjectForKey:CPScrollViewVScrollerKey];
|
_verticalScroller = [aCoder decodeObjectForKey:CPScrollViewVScrollerKey];
|
||||||
_horizontalScroller = [aCoder decodeObjectForKey:CPScrollViewHScrollerKey];
|
_horizontalScroller = [aCoder decodeObjectForKey:CPScrollViewHScrollerKey];
|
||||||
@@ -663,6 +767,8 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
|||||||
_hasHorizontalScroller = [aCoder decodeBoolForKey:CPScrollViewHasHScrollerKey];
|
_hasHorizontalScroller = [aCoder decodeBoolForKey:CPScrollViewHasHScrollerKey];
|
||||||
_autohidesScrollers = [aCoder decodeBoolForKey:CPScrollViewAutohidesScrollerKey];
|
_autohidesScrollers = [aCoder decodeBoolForKey:CPScrollViewAutohidesScrollerKey];
|
||||||
|
|
||||||
|
_cornerView = [aCoder decodeObjectForKey:CPScrollViewCornerViewKey];
|
||||||
|
|
||||||
// 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]];
|
||||||
}
|
}
|
||||||
@@ -675,6 +781,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];
|
||||||
@@ -687,6 +794,8 @@ 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];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+55
-35
@@ -79,7 +79,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
|||||||
|
|
||||||
+ (id)themeAttributes
|
+ (id)themeAttributes
|
||||||
{
|
{
|
||||||
return [CPDictionary dictionaryWithObjects:[ nil, nil, nil, nil,
|
return [CPDictionary dictionaryWithObjects:[ [CPNull null], [CPNull null], [CPNull null], [CPNull null],
|
||||||
_CGSizeMakeZero(), _CGSizeMakeZero(), _CGInsetMakeZero(), _CGInsetMakeZero(), _CGSizeMakeZero()]
|
_CGSizeMakeZero(), _CGSizeMakeZero(), _CGInsetMakeZero(), _CGInsetMakeZero(), _CGSizeMakeZero()]
|
||||||
forKeys:[ @"knob-slot-color",
|
forKeys:[ @"knob-slot-color",
|
||||||
@"decrement-line-color",
|
@"decrement-line-color",
|
||||||
@@ -104,11 +104,12 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
|||||||
_controlSize = CPRegularControlSize;
|
_controlSize = CPRegularControlSize;
|
||||||
_partRects = [];
|
_partRects = [];
|
||||||
|
|
||||||
[self setFloatValue:0.0 knobProportion:1.0];
|
[self setFloatValue:0.0];
|
||||||
|
[self setKnobProportion:1.0];
|
||||||
|
|
||||||
_hitPart = CPScrollerNoPart;
|
_hitPart = CPScrollerNoPart;
|
||||||
|
|
||||||
[self _recalculateIsVertical];
|
[self _calculateIsVertical];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -120,7 +121,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
|||||||
*/
|
*/
|
||||||
+ (float)scrollerWidth
|
+ (float)scrollerWidth
|
||||||
{
|
{
|
||||||
return 17.0;//[self scrollerWidthForControlSize:CPRegularControlSize];
|
return 15.0;//[self scrollerWidthForControlSize:CPRegularControlSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -129,7 +130,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
|||||||
*/
|
*/
|
||||||
+ (float)scrollerWidthForControlSize:(CPControlSize)aControlSize
|
+ (float)scrollerWidthForControlSize:(CPControlSize)aControlSize
|
||||||
{
|
{
|
||||||
return 17.0;//_CPScrollerWidths[aControlSize];
|
return 15.0;//_CPScrollerWidths[aControlSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -155,28 +156,17 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
|||||||
return _controlSize;
|
return _controlSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setting the Knob Position
|
- (void)setObjectValue:(id)aValue
|
||||||
/*!
|
|
||||||
Sets the scroller's knob position (ranges from 0.0 to 1.0).
|
|
||||||
@param aValue the knob position (ranges from 0.0 to 1.0)
|
|
||||||
*/
|
|
||||||
- (void)setFloatValue:(float)aValue
|
|
||||||
{
|
{
|
||||||
[super setFloatValue:MIN(1.0, MAX(0.0, aValue))];
|
[super setObjectValue:MIN(1.0, MAX(0.0, +aValue))];
|
||||||
|
|
||||||
[self setNeedsLayout];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
- (void)setKnobProportion:(float)aProportion
|
||||||
Sets the position and proportion of the knob.
|
|
||||||
@param aValue the knob position (ranges from 0.0 to 1.0)
|
|
||||||
@param aProportion the knob's proportion (ranges from 0.0 to 1.0)
|
|
||||||
*/
|
|
||||||
- (void)setFloatValue:(float)aValue knobProportion:(float)aProportion
|
|
||||||
{
|
{
|
||||||
_knobProportion = MIN(1.0, MAX(0.0001, aProportion));
|
_knobProportion = MIN(1.0, MAX(0.0001, aProportion));
|
||||||
|
|
||||||
[self setFloatValue:aValue];
|
[self setNeedsDisplay:YES];
|
||||||
|
[self setNeedsLayout];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -208,7 +198,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the part of the scroller that would be hit by <code>aPoint</code>.
|
Returns the part of the scroller that would be hit by \c aPoint.
|
||||||
@param aPoint the simulated point hit
|
@param aPoint the simulated point hit
|
||||||
@return the part of the scroller that intersects the point
|
@return the part of the scroller that intersects the point
|
||||||
*/
|
*/
|
||||||
@@ -252,14 +242,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;
|
||||||
}
|
}
|
||||||
@@ -290,8 +280,17 @@ 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"],
|
||||||
@@ -310,6 +309,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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,7 +542,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_recalculateIsVertical
|
- (void)_calculateIsVertical
|
||||||
{
|
{
|
||||||
// Recalculate isVertical.
|
// Recalculate isVertical.
|
||||||
var bounds = [self bounds],
|
var bounds = [self bounds],
|
||||||
@@ -552,8 +561,6 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
|||||||
{
|
{
|
||||||
[super setFrameSize:aSize];
|
[super setFrameSize:aSize];
|
||||||
|
|
||||||
[self _recalculateIsVertical];
|
|
||||||
|
|
||||||
[self checkSpaceForParts];
|
[self checkSpaceForParts];
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
}
|
}
|
||||||
@@ -599,9 +606,7 @@ var CPScrollerControlSizeKey = "CPScrollerControlSize",
|
|||||||
|
|
||||||
_hitPart = CPScrollerNoPart;
|
_hitPart = CPScrollerNoPart;
|
||||||
|
|
||||||
[self _recalculateIsVertical];
|
[self _calculateIsVertical];
|
||||||
// [self checkSpaceForParts];
|
|
||||||
// [self setNeedsLayout];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -616,3 +621,18 @@ var CPScrollerControlSizeKey = "CPScrollerControlSize",
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@implementation CPScroller (Deprecated)
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the position and proportion of the knob.
|
||||||
|
@param aValue the knob position (ranges from 0.0 to 1.0)
|
||||||
|
@param aProportion the knob's proportion (ranges from 0.0 to 1.0)
|
||||||
|
*/
|
||||||
|
- (void)setFloatValue:(float)aValue knobProportion:(float)aProportion
|
||||||
|
{
|
||||||
|
[self setFloatValue:aValue];
|
||||||
|
[self setKnobProportion:aProportion];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|||||||
@@ -0,0 +1,718 @@
|
|||||||
|
/*
|
||||||
|
* CPSearchField.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by cacaodev.
|
||||||
|
* Copyright 2009.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import "CPTextField.j"
|
||||||
|
|
||||||
|
#include "Platform/Platform.h"
|
||||||
|
|
||||||
|
CPSearchFieldRecentsTitleMenuItemTag = 1000;
|
||||||
|
CPSearchFieldRecentsMenuItemTag = 1001;
|
||||||
|
CPSearchFieldClearRecentsMenuItemTag = 1002;
|
||||||
|
CPSearchFieldNoRecentsMenuItemTag = 1003;
|
||||||
|
|
||||||
|
var CPSearchFieldSearchImage = nil,
|
||||||
|
CPSearchFieldFindImage = nil,
|
||||||
|
CPSearchFieldCancelImage = nil,
|
||||||
|
CPSearchFieldCancelPressedImage = nil;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ingroup appkit
|
||||||
|
@class CPSearchField
|
||||||
|
The CPSearchField class defines the programmatic interface for text fields that are optimized for text-based searches. A CPSearchField object directly inherits from the CPTextField class. The search field implemented by these classes presents a standard user interface for searches, including a search button, a cancel button, and a pop-up icon menu for listing recent search strings and custom search categories.
|
||||||
|
|
||||||
|
When the user types and then pauses, the text field's action message is sent to its target. You can query the text field's string value for the current text to search for. Do not rely on the sender of the action to be an CPMenu object because the menu may change. If you need to change the menu, modify the search menu template and call the setSearchMenuTemplate: method to update.
|
||||||
|
*/
|
||||||
|
@implementation CPSearchField : CPTextField
|
||||||
|
{
|
||||||
|
CPButton _searchButton;
|
||||||
|
CPButton _cancelButton;
|
||||||
|
CPMenu _searchMenuTemplate;
|
||||||
|
CPMenu _searchMenu;
|
||||||
|
|
||||||
|
CPString _recentsAutosaveName;
|
||||||
|
CPArray _recentSearches;
|
||||||
|
|
||||||
|
int _maximumRecents;
|
||||||
|
BOOL _sendsWholeSearchString;
|
||||||
|
BOOL _sendsSearchStringImmediately;
|
||||||
|
CPTimer _partialStringTimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
if (self != [CPSearchField class])
|
||||||
|
return;
|
||||||
|
|
||||||
|
var bundle = [CPBundle bundleForClass:self];
|
||||||
|
CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:CGSizeMake(25, 22)];
|
||||||
|
CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"] size:CGSizeMake(25, 22)];
|
||||||
|
CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"] size:CGSizeMake(22, 22)];
|
||||||
|
CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:CGSizeMake(22, 22)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithFrame:(CGRect)frame
|
||||||
|
{
|
||||||
|
if (self = [super initWithFrame:frame])
|
||||||
|
{
|
||||||
|
_recentSearches = [CPArray array];
|
||||||
|
_maximumRecents = 10;
|
||||||
|
_sendsWholeSearchString = NO;
|
||||||
|
_sendsSearchStringImmediately = NO;
|
||||||
|
_recentsAutosaveName = nil;
|
||||||
|
|
||||||
|
[self _initWithFrame:frame];
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
_cancelButton._DOMElement.style.cursor = "default";
|
||||||
|
_searchButton._DOMElement.style.cursor = "default";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_initWithFrame:(CGRect)frame
|
||||||
|
{
|
||||||
|
[self setBezeled:YES];
|
||||||
|
[self setBezelStyle:CPTextFieldRoundedBezel];
|
||||||
|
[self setBordered:YES];
|
||||||
|
[self setEditable:YES];
|
||||||
|
[self setDelegate:self];
|
||||||
|
|
||||||
|
_cancelButton = [[CPButton alloc] initWithFrame:CGRectMake(frame.size.width - 27,(frame.size.height-22)/2,22,22)];
|
||||||
|
[self resetCancelButton];
|
||||||
|
[_cancelButton setHidden:YES];
|
||||||
|
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
|
||||||
|
[self addSubview:_cancelButton];
|
||||||
|
|
||||||
|
_searchButton = [[CPButton alloc] initWithFrame:CGRectMake(5,(frame.size.height-25)/2,25,25)];
|
||||||
|
[self resetSearchButton];
|
||||||
|
[self addSubview:_searchButton];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Managing Buttons
|
||||||
|
/*!
|
||||||
|
Sets the button used to display the search-button image
|
||||||
|
@param button The search button.
|
||||||
|
*/
|
||||||
|
- (void)setSearchButton:(CPButton)button
|
||||||
|
{
|
||||||
|
_searchButton = button;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the button used to display the search-button image.
|
||||||
|
@return The search button.
|
||||||
|
*/
|
||||||
|
- (CPButton)searchButton
|
||||||
|
{
|
||||||
|
return _searchButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Resets the search button to its default attributes.
|
||||||
|
This method resets the target, action, regular image, and pressed image. By default, when users click the search button or press the Return key, the action defined for the receiver is sent to its designated target. This method gives you a way to customize the search button for specific situations and then reset the button defaults without having to undo changes individually.
|
||||||
|
*/
|
||||||
|
- (void)resetSearchButton
|
||||||
|
{
|
||||||
|
var searchButtonImage,
|
||||||
|
action,
|
||||||
|
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 setImageScaling:CPScaleToFit];
|
||||||
|
[button setImage:searchButtonImage];
|
||||||
|
[button setAutoresizingMask:CPViewMaxXMargin];
|
||||||
|
[button setTarget:target];
|
||||||
|
[button setAction:action];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the button object used to display the cancel-button image.
|
||||||
|
@param button The cancel button.
|
||||||
|
*/
|
||||||
|
- (void)setCancelButton:(CPButton)button
|
||||||
|
{
|
||||||
|
_cancelButton = button;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the button object used to display the cancel-button image.
|
||||||
|
@return The cancel button.
|
||||||
|
*/
|
||||||
|
- (CPButton)cancelButton
|
||||||
|
{
|
||||||
|
return _cancelButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Resets the cancel button to its default attributes.
|
||||||
|
This method resets the target, action, regular image, and pressed image. By default, when users click the cancel button, the delete: action message is sent up the responder chain. This method gives you a way to customize the cancel button for specific situations and then reset the button defaults without having to undo changes individually.
|
||||||
|
*/
|
||||||
|
- (void)resetCancelButton
|
||||||
|
{
|
||||||
|
var button = [self cancelButton];
|
||||||
|
[button setBordered:NO];
|
||||||
|
[button setImageScaling:CPScaleToFit];
|
||||||
|
[button setImage:CPSearchFieldCancelImage];
|
||||||
|
[button setAlternateImage:CPSearchFieldCancelPressedImage];
|
||||||
|
[button setAutoresizingMask:CPViewMinXMargin];
|
||||||
|
[button setTarget:self];
|
||||||
|
[button setAction:@selector(_searchFieldCancel:)];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom Layout
|
||||||
|
/*!
|
||||||
|
Modifies the bounding rectangle for the search-text field.
|
||||||
|
@param rect The current bounding rectangle for the search text field.
|
||||||
|
@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.
|
||||||
|
*/
|
||||||
|
- (CPRect)searchTextRectForBounds:(CPRect)rect
|
||||||
|
{
|
||||||
|
var leftOffset = 0, width = rect.size.width;
|
||||||
|
|
||||||
|
if (_searchButton)
|
||||||
|
{
|
||||||
|
var searchRect = [_searchButton frame];
|
||||||
|
leftOffset = searchRect.origin.x + searchRect.size.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_cancelButton)
|
||||||
|
{
|
||||||
|
var cancelRect = [_cancelButton frame];
|
||||||
|
width = cancelRect.origin.x - leftOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CPMakeRect(leftOffset,rect.origin.y,width,rect.size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Modifies the 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.
|
||||||
|
*/
|
||||||
|
- (CPRect)searchButtonRectForBounds:(CPRect)rect
|
||||||
|
{
|
||||||
|
return [_searchButton frame];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Modifies the bounding rectangle for the cancel button.
|
||||||
|
@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.
|
||||||
|
*/
|
||||||
|
- (CPRect)cancelButtonRectForBounds:(CPRect)rect
|
||||||
|
{
|
||||||
|
return [_cancelButton frame];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Managing Menu Templates
|
||||||
|
/*!
|
||||||
|
Returns the menu template object used to dynamically construct the search pop-up icon menu.
|
||||||
|
@return The current menu template.
|
||||||
|
*/
|
||||||
|
- (CPMenu)searchMenuTemplate
|
||||||
|
{
|
||||||
|
return _searchMenuTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the menu template object used to dynamically construct the receiver's pop-up icon menu.
|
||||||
|
@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.
|
||||||
|
*/
|
||||||
|
- (void)setSearchMenuTemplate:(CPMenu)menu
|
||||||
|
{
|
||||||
|
_searchMenuTemplate = menu;
|
||||||
|
|
||||||
|
[self resetSearchButton];
|
||||||
|
[self _loadRecentSearchList];
|
||||||
|
[self _updateSearchMenu];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Managing Search Modes
|
||||||
|
/*!
|
||||||
|
Returns a Boolean value indicating whether the receiver sends the search action message when the user clicks the search button (or presses return) or after each keystroke.
|
||||||
|
@return \c YES if the action message is sent all at once when the user clicks the search button or presses return; otherwise, NO if the search string is sent after each keystroke. The default value is NO.
|
||||||
|
*/
|
||||||
|
- (BOOL)sendsWholeSearchString
|
||||||
|
{
|
||||||
|
return _sendsWholeSearchString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets whether the receiver sends the search action message when the user clicks the search button (or presses return) or after each keystroke.
|
||||||
|
@param flag \c YES to send the action message all at once when the user clicks the search button or presses return; otherwise, NO to send the search string after each keystroke.
|
||||||
|
*/
|
||||||
|
- (void)setSendsWholeSearchString:(BOOL)flag
|
||||||
|
{
|
||||||
|
_sendsWholeSearchString = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns a Boolean value indicating whether the receiver sends its action immediately upon being notified of changes to the search field text or after a brief pause.
|
||||||
|
@return \c YES if the text field sends its action immediately upon notification of any changes to the search field; otherwise, NO.
|
||||||
|
*/
|
||||||
|
- (BOOL)sendsSearchStringImmediately
|
||||||
|
{
|
||||||
|
return _sendsSearchStringImmediately;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets whether the text field sends its action message to the target immediately upon notification of any changes to the search field text or after a brief pause.
|
||||||
|
@param flag \c YES to send the text field's action immediately upon notification of any changes to the search field; otherwise, NO if you want the text field to pause briefly before sending its action message. Pausing gives the user the opportunity to type more text into the search field before initiating the search.
|
||||||
|
*/
|
||||||
|
- (void)setSendsSearchStringImmediately:(BOOL)flag
|
||||||
|
{
|
||||||
|
_sendsSearchStringImmediately = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Managing Recent Search Strings
|
||||||
|
/*!
|
||||||
|
Returns the maximum number of recent search strings to display in the custom search menu.
|
||||||
|
@return The maximum number of search strings that can appear in the menu. This value is between 0 and 254.
|
||||||
|
*/
|
||||||
|
- (int)maximumRecents
|
||||||
|
{
|
||||||
|
return _maximumRecents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the maximum number of search strings that can appear in the search menu.
|
||||||
|
@param maxRecents The maximum number of search strings that can appear in the menu. This value can be between 0 and 254. Specifying a value less than 0 sets the value to the default, which is 10. Specifying a value greater than 254 sets the maximum to 254.
|
||||||
|
*/
|
||||||
|
- (void)setMaximumRecents:(int)max
|
||||||
|
{
|
||||||
|
if (max > 254)
|
||||||
|
max = 254;
|
||||||
|
else if (max < 0)
|
||||||
|
max = 10;
|
||||||
|
|
||||||
|
_maximumRecents = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the list of recent search strings for the control.
|
||||||
|
@return An array of \c CPString objects, each of which contains a search string either displayed in the search menu or from a recent autosave archive. If there have been no recent searches and no prior searches saved under an autosave name, this array may be empty.
|
||||||
|
*/
|
||||||
|
- (CPArray)recentSearches
|
||||||
|
{
|
||||||
|
return _recentSearches;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the list of recent search strings to list in the pop-up icon menu of the receiver.
|
||||||
|
@param searches An array of CPString objects containing the search strings.
|
||||||
|
You might use this method to set the recent list of searches from an archived copy.
|
||||||
|
*/
|
||||||
|
- (void)setRecentSearches:(CPArray)searches
|
||||||
|
{
|
||||||
|
var max = MIN([self maximumRecents], [searches count]),
|
||||||
|
searches = [searches subarrayWithRange:CPMakeRange(0, max)];
|
||||||
|
|
||||||
|
_recentSearches = searches;
|
||||||
|
[self _autosaveRecentSearchList];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the key under which the prior list of recent search strings has been archived.
|
||||||
|
@return The autosave name, which is used as a key in the standard user defaults to save the recent searches. The default value is nil, which causes searches not to be autosaved.
|
||||||
|
*/
|
||||||
|
- (CPString)recentsAutosaveName
|
||||||
|
{
|
||||||
|
return _recentsAutosaveName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the autosave name under which the receiver automatically archives the list of recent search strings.
|
||||||
|
@param name The autosave name, which is used as a key in the standard user defaults to save the recent searches. If you specify nil or an empty string for this parameter, no autosave name is set and searches are not autosaved.
|
||||||
|
*/
|
||||||
|
- (void)setRecentsAutosaveName:(CPString)name
|
||||||
|
{
|
||||||
|
if (_recentsAutosaveName != nil)
|
||||||
|
[self _deregisterForAutosaveNotification];
|
||||||
|
|
||||||
|
_recentsAutosaveName = name;
|
||||||
|
|
||||||
|
if (_recentsAutosaveName != nil)
|
||||||
|
[self _registerForAutosaveNotification];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private methods and subclassing
|
||||||
|
|
||||||
|
- (CPRect)contentRectForBounds:(CPRect)bounds
|
||||||
|
{
|
||||||
|
var superbounds = [super contentRectForBounds:bounds];
|
||||||
|
return [self searchTextRectForBounds:superbounds];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (double)_keyboardDelayForPartialSearchString:(CPString)string
|
||||||
|
{
|
||||||
|
return (6 - MIN([string length],4))/10;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPMenu)menu
|
||||||
|
{
|
||||||
|
return _searchMenu;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isOpaque
|
||||||
|
{
|
||||||
|
return [super isOpaque] && [_cancelButton isOpaque] && [_searchButton isOpaque];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_updateCancelButtonVisibility
|
||||||
|
{
|
||||||
|
[_cancelButton setHidden:([[self stringValue] length] === 0)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)controlTextDidChange:(CPNotification)aNotification
|
||||||
|
{
|
||||||
|
if (![self sendsWholeSearchString])
|
||||||
|
{
|
||||||
|
if ([self sendsSearchStringImmediately])
|
||||||
|
[self _sendPartialString];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[_partialStringTimer invalidate];
|
||||||
|
var timeInterval = [CPSearchField _keyboardDelayForPartialSearchString:[self stringValue]];
|
||||||
|
|
||||||
|
_partialStringTimer = [CPTimer scheduledTimerWithTimeInterval:timeInterval
|
||||||
|
target:self
|
||||||
|
selector:@selector(_sendPartialString)
|
||||||
|
userInfo:nil
|
||||||
|
repeats:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[self _updateCancelButtonVisibility];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_sendAction:(id)sender
|
||||||
|
{
|
||||||
|
[self sendAction:[self action] to:[self target]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sendAction:(SEL)anAction to:(id)anObject
|
||||||
|
{
|
||||||
|
[super sendAction:anAction to:anObject];
|
||||||
|
|
||||||
|
[_partialStringTimer invalidate];
|
||||||
|
|
||||||
|
[self _addStringToRecentSearches:[self stringValue]];
|
||||||
|
[self _updateCancelButtonVisibility];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_addStringToRecentSearches:(CPString)string
|
||||||
|
{
|
||||||
|
if (string === nil || string === @"" || [_recentSearches containsObject:string])
|
||||||
|
return;
|
||||||
|
|
||||||
|
var searches = [CPMutableArray arrayWithArray:_recentSearches];
|
||||||
|
[searches addObject:string];
|
||||||
|
[self setRecentSearches:searches];
|
||||||
|
[self _updateSearchMenu];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)trackMouse:(CPEvent)event
|
||||||
|
{
|
||||||
|
var rect,
|
||||||
|
point,
|
||||||
|
location = [event locationInWindow];
|
||||||
|
|
||||||
|
point = [self convertPoint:location fromView:nil];
|
||||||
|
|
||||||
|
rect = [self searchButtonRectForBounds:[self frame]];
|
||||||
|
if (CPRectContainsPoint(rect,point))
|
||||||
|
{
|
||||||
|
return [[self searchButton] trackMouse:event];
|
||||||
|
}
|
||||||
|
|
||||||
|
rect = [self cancelButtonRectForBounds:[self frame]];
|
||||||
|
if (CPRectContainsPoint(rect,point))
|
||||||
|
{
|
||||||
|
return [[self cancelButton] trackMouse:event];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [super trackMouse:event];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPMenu)_defaultSearchMenuTemplate
|
||||||
|
{
|
||||||
|
var template, item;
|
||||||
|
|
||||||
|
template = [[CPMenu alloc] init];
|
||||||
|
|
||||||
|
item = [[CPMenuItem alloc] initWithTitle:@"Recent searches"
|
||||||
|
action:NULL
|
||||||
|
keyEquivalent:@""];
|
||||||
|
[item setTag:CPSearchFieldRecentsTitleMenuItemTag];
|
||||||
|
[item setEnabled:NO];
|
||||||
|
[template addItem:item];
|
||||||
|
|
||||||
|
item = [[CPMenuItem alloc] initWithTitle:@"Recent search item"
|
||||||
|
action:@selector(_searchFieldSearch:)
|
||||||
|
keyEquivalent:@""];
|
||||||
|
[item setTag:CPSearchFieldRecentsMenuItemTag];
|
||||||
|
[item setTarget:self];
|
||||||
|
[template addItem:item];
|
||||||
|
|
||||||
|
item = [[CPMenuItem alloc] initWithTitle:@"Clear recent searches"
|
||||||
|
action:@selector(_searchFieldClearRecents:)
|
||||||
|
keyEquivalent:@""];
|
||||||
|
[item setTag:CPSearchFieldClearRecentsMenuItemTag];
|
||||||
|
[item setTarget:self];
|
||||||
|
[template addItem:item];
|
||||||
|
|
||||||
|
item = [[CPMenuItem alloc] initWithTitle:@"No recent searches"
|
||||||
|
action:NULL
|
||||||
|
keyEquivalent:@""];
|
||||||
|
[item setTag:CPSearchFieldNoRecentsMenuItemTag];
|
||||||
|
[item setEnabled:NO];
|
||||||
|
[template addItem:item];
|
||||||
|
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_updateSearchMenu
|
||||||
|
{
|
||||||
|
if (_searchMenuTemplate === nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var i, menu = [[CPMenu alloc] init],
|
||||||
|
countOfRecents = [_recentSearches count],
|
||||||
|
numberOfItems = [_searchMenuTemplate numberOfItems];
|
||||||
|
|
||||||
|
for (i = 0; i < numberOfItems; i++)
|
||||||
|
{
|
||||||
|
var item = [_searchMenuTemplate itemAtIndex:i],
|
||||||
|
tag = [item tag];
|
||||||
|
|
||||||
|
if (!(tag === CPSearchFieldRecentsTitleMenuItemTag && countOfRecents === 0) &&
|
||||||
|
!(tag === CPSearchFieldClearRecentsMenuItemTag && countOfRecents === 0) &&
|
||||||
|
!(tag === CPSearchFieldNoRecentsMenuItemTag && countOfRecents != 0) &&
|
||||||
|
!(tag === CPSearchFieldRecentsMenuItemTag))
|
||||||
|
{
|
||||||
|
var itemAction, itemTarget;
|
||||||
|
switch (tag)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
var separator = [CPMenuItem separatorItem];
|
||||||
|
[separator setEnabled:NO];
|
||||||
|
[menu addItem:separator];
|
||||||
|
}
|
||||||
|
|
||||||
|
var templateItem = [[CPMenuItem alloc] initWithTitle:[item title]
|
||||||
|
action:itemAction
|
||||||
|
keyEquivalent:[item keyEquivalent]];
|
||||||
|
[templateItem setTarget:itemTarget];
|
||||||
|
[templateItem setEnabled:([item isEnabled] && itemAction != NULL)];
|
||||||
|
[templateItem setTag:tag];
|
||||||
|
[menu addItem:templateItem];
|
||||||
|
}
|
||||||
|
else if (tag === CPSearchFieldRecentsMenuItemTag)
|
||||||
|
{
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_searchMenu = menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_showMenu:(id)sender
|
||||||
|
{
|
||||||
|
if (_searchMenu === nil || [_searchMenu numberOfItems] === 0 || ![self isEnabled])
|
||||||
|
return;
|
||||||
|
|
||||||
|
var aFrame = [[self superview] convertRect:[self frame] toView:nil],
|
||||||
|
location = CPMakePoint(aFrame.origin.x + 10, aFrame.origin.y + aFrame.size.height - 4);
|
||||||
|
|
||||||
|
var anEvent = [CPEvent mouseEventWithType:CPRightMouseDown location:location modifierFlags:0 timestamp:[[CPApp currentEvent] timestamp] windowNumber:[[self window] windowNumber] context:nil eventNumber:1 clickCount:1 pressure:0];
|
||||||
|
|
||||||
|
[CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:sender];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_sendPartialString
|
||||||
|
{
|
||||||
|
[[self target] performSelector:[self action] withObject:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_searchFieldCancel:(id)sender
|
||||||
|
{
|
||||||
|
[self setObjectValue:@""];
|
||||||
|
[self _sendPartialString];
|
||||||
|
[self _updateCancelButtonVisibility];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_searchFieldSearch:(id)sender
|
||||||
|
{
|
||||||
|
var searchString = [sender title];
|
||||||
|
|
||||||
|
if ([sender tag] != CPSearchFieldRecentsMenuItemTag)
|
||||||
|
[self _addStringToRecentSearches:searchString];
|
||||||
|
|
||||||
|
[self setObjectValue:searchString];
|
||||||
|
[self _sendPartialString];
|
||||||
|
|
||||||
|
[self _updateCancelButtonVisibility];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_searchFieldClearRecents:(id)sender
|
||||||
|
{
|
||||||
|
[self setRecentSearches:[CPArray array]];
|
||||||
|
[self _updateSearchMenu];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_registerForAutosaveNotification
|
||||||
|
{
|
||||||
|
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_updateAutosavedRecents:) name:@"CPAutosavedRecentsChangedNotification" object:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_deregisterForAutosaveNotification
|
||||||
|
{
|
||||||
|
[[CPNotificationCenter defaultCenter] removeObserver:self name:@"CPAutosavedRecentsChangedNotification" object:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_autosaveRecentSearchList
|
||||||
|
{
|
||||||
|
if (_recentsAutosaveName != nil)
|
||||||
|
[[CPNotificationCenter defaultCenter] postNotificationName:@"CPAutosavedRecentsChangedNotification" object:_recentsAutosaveName];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_updateAutosavedRecents:(id)notification
|
||||||
|
{
|
||||||
|
var list = [self recentSearches],
|
||||||
|
name = [notification object],
|
||||||
|
bundle_name = [[[CPBundle mainBundle] infoDictionary] objectForKey:"CPBundleName"],
|
||||||
|
cookie_name = [bundle_name lowercaseString] + "." + [notification object],
|
||||||
|
|
||||||
|
cookie = [[CPCookie alloc] initWithName:cookie_name],
|
||||||
|
cookie_value = [list componentsJoinedByString:@","];
|
||||||
|
|
||||||
|
[cookie setValue:cookie_value
|
||||||
|
expires:[[CPDate alloc] initWithTimeIntervalSinceNow:3600*24*365]
|
||||||
|
domain:(window.location.href.hostname)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_loadRecentSearchList
|
||||||
|
{
|
||||||
|
var list,
|
||||||
|
name = [self recentsAutosaveName];
|
||||||
|
|
||||||
|
if (name === nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var bundle_name = [[[CPBundle mainBundle] infoDictionary] objectForKey:"CPBundleName"],
|
||||||
|
cookie_name = [bundle_name lowercaseString] + "." + name,
|
||||||
|
|
||||||
|
cookie = [[CPCookie alloc] initWithName:cookie_name];
|
||||||
|
|
||||||
|
if (cookie != nil)
|
||||||
|
{
|
||||||
|
var cookie_value = [cookie value];
|
||||||
|
list = (cookie_value != @"") ? [cookie_value componentsSeparatedByString:@","] : [CPArray array];
|
||||||
|
_recentSearches = list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
|
||||||
|
CPSendsWholeSearchStringKey = @"CPSendsWholeSearchStringKey",
|
||||||
|
CPSendsSearchStringImmediatelyKey = @"CPSendsSearchStringImmediatelyKey",
|
||||||
|
CPMaximumRecentsKey = @"CPMaximumRecentsKey",
|
||||||
|
CPSearchMenuTemplateKey = @"CPSearchMenuTemplateKey";
|
||||||
|
|
||||||
|
@implementation CPSearchField (CPCoding)
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(CPCoder)coder
|
||||||
|
{
|
||||||
|
[_searchButton removeFromSuperview];
|
||||||
|
[_cancelButton removeFromSuperview];
|
||||||
|
|
||||||
|
[super encodeWithCoder:coder];
|
||||||
|
|
||||||
|
if (_searchButton)
|
||||||
|
[self addSubview:_searchButton];
|
||||||
|
if (_cancelButton)
|
||||||
|
[self addSubview:_cancelButton];
|
||||||
|
|
||||||
|
[coder encodeBool:_sendsWholeSearchString forKey:CPSendsWholeSearchStringKey];
|
||||||
|
[coder encodeBool:_sendsSearchStringImmediately forKey:CPSendsSearchStringImmediatelyKey];
|
||||||
|
[coder encodeInt:_maximumRecents forKey:CPMaximumRecentsKey];
|
||||||
|
|
||||||
|
if (_recentsAutosaveName)
|
||||||
|
[coder encodeObject:_recentsAutosaveName forKey:CPRecentsAutosaveNameKey];
|
||||||
|
if (_searchMenuTemplate)
|
||||||
|
[coder encodeObject:_searchMenuTemplate forKey:CPSearchMenuTemplateKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)coder
|
||||||
|
{
|
||||||
|
if (self = [super initWithCoder:coder])
|
||||||
|
{
|
||||||
|
[self _initWithFrame:[self frame]];
|
||||||
|
|
||||||
|
_recentsAutosaveName = [coder decodeObjectForKey:CPRecentsAutosaveNameKey];
|
||||||
|
_sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey];
|
||||||
|
_sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey];
|
||||||
|
_maximumRecents = [coder decodeIntForKey:CPMaximumRecentsKey];
|
||||||
|
|
||||||
|
var template = [coder decodeObjectForKey:CPSearchMenuTemplateKey];
|
||||||
|
if (template)
|
||||||
|
[self setSearchMenuTemplate:template];
|
||||||
|
|
||||||
|
[self setDelegate:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
+79
-53
@@ -26,20 +26,8 @@
|
|||||||
|
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
#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;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -68,7 +56,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
|
|
||||||
+ (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"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,11 +107,11 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
}
|
}
|
||||||
else if (aCount < _segments.length)
|
else if (aCount < _segments.length)
|
||||||
{
|
{
|
||||||
for (var index = aCount; index < _segments.length; ++index)
|
_segments.length = aCount;
|
||||||
_segments[index] = nil;
|
_themeStates.length = aCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_selectedSegment < _segments.length)
|
if (_selectedSegment >= _segments.length)
|
||||||
_selectedSegment = -1;
|
_selectedSegment = -1;
|
||||||
|
|
||||||
[self tileWithChangedSegment:0];
|
[self tileWithChangedSegment:0];
|
||||||
@@ -141,7 +129,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
/*!
|
/*!
|
||||||
Selects a segment.
|
Selects a segment.
|
||||||
@param aSegment the segment to select
|
@param aSegment the segment to select
|
||||||
@throws CPRangeException if <code>aSegment</code> is out of bounds
|
@throws CPRangeException if \c aSegment is out of bounds
|
||||||
*/
|
*/
|
||||||
- (void)setSelectedSegment:(unsigned)aSegment
|
- (void)setSelectedSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
@@ -225,7 +213,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
Sets the width of the specified segment.
|
Sets the width of the specified segment.
|
||||||
@param aWidth the new width for the segment
|
@param aWidth the new width for the segment
|
||||||
@param aSegment the segment to set the width for
|
@param aSegment the segment to set the width for
|
||||||
@throws CPRangeException if <code>aSegment</code> is out of bounds
|
@throws CPRangeException if \c aSegment is out of bounds
|
||||||
*/
|
*/
|
||||||
- (void)setWidth:(float)aWidth forSegment:(unsigned)aSegment
|
- (void)setWidth:(float)aWidth forSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
@@ -237,7 +225,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
/*!
|
/*!
|
||||||
Returns the width for the specified segment.
|
Returns the width for the specified segment.
|
||||||
@param aSegment the segment to get the width for
|
@param aSegment the segment to get the width for
|
||||||
@throws CPRangeException if <code>aSegment</code> is out of bounds
|
@throws CPRangeException if \c aSegment is out of bounds
|
||||||
*/
|
*/
|
||||||
- (float)widthForSegment:(unsigned)aSegment
|
- (float)widthForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
@@ -248,7 +236,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
Sets the image for the specified segment.
|
Sets the image for the specified segment.
|
||||||
@param anImage the image for the segment
|
@param anImage the image for the segment
|
||||||
@param aSegment the segment to set the image on
|
@param aSegment the segment to set the image on
|
||||||
@throws CPRangeException if <code>aSegment</code> is out of bounds
|
@throws CPRangeException if \c aSegment is out of bounds
|
||||||
*/
|
*/
|
||||||
- (void)setImage:(CPImage)anImage forSegment:(unsigned)aSegment
|
- (void)setImage:(CPImage)anImage forSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
@@ -262,7 +250,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
/*!
|
/*!
|
||||||
Returns the image for the specified segment
|
Returns the image for the specified segment
|
||||||
@param aSegment the segment to obtain the image for
|
@param aSegment the segment to obtain the image for
|
||||||
@throws CPRangeException if <code>aSegment</code> is out of bounds
|
@throws CPRangeException if \c aSegment is out of bounds
|
||||||
*/
|
*/
|
||||||
- (CPImage)imageForSegment:(unsigned)aSegment
|
- (CPImage)imageForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
@@ -273,7 +261,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
Sets the label for the specified segment
|
Sets the label for the specified segment
|
||||||
@param aLabel the label for the segment
|
@param aLabel the label for the segment
|
||||||
@param aSegment the segment to label
|
@param aSegment the segment to label
|
||||||
@throws CPRangeException if <code>aSegment</code> is out of bounds
|
@throws CPRangeException if \c aSegment is out of bounds
|
||||||
*/
|
*/
|
||||||
- (void)setLabel:(CPString)aLabel forSegment:(unsigned)aSegment
|
- (void)setLabel:(CPString)aLabel forSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
@@ -287,7 +275,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
/*!
|
/*!
|
||||||
Returns the label for the specified segment
|
Returns the label for the specified segment
|
||||||
@param the segment to obtain the label for
|
@param the segment to obtain the label for
|
||||||
@throws CPRangeException if <code>aSegment</code> is out of bounds
|
@throws CPRangeException if \c aSegment is out of bounds
|
||||||
*/
|
*/
|
||||||
- (CPString)labelForSegment:(unsigned)aSegment
|
- (CPString)labelForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
@@ -298,7 +286,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
Sets the menu for the specified segment
|
Sets the menu for the specified segment
|
||||||
@param aMenu the menu to set
|
@param aMenu the menu to set
|
||||||
@param aSegment the segment to set the menu on
|
@param aSegment the segment to set the menu on
|
||||||
@throws CPRangeException if <code>aSegment</code> is out of bounds
|
@throws CPRangeException if \c aSegment is out of bounds
|
||||||
*/
|
*/
|
||||||
- (void)setMenu:(CPMenu)aMenu forSegment:(unsigned)aSegment
|
- (void)setMenu:(CPMenu)aMenu forSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
@@ -308,7 +296,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
/*!
|
/*!
|
||||||
Returns the menu for the specified segment.
|
Returns the menu for the specified segment.
|
||||||
@param aSegment the segment to obtain the menu for
|
@param aSegment the segment to obtain the menu for
|
||||||
@throws CPRangeException if <code>aSegment</code> is out of bounds
|
@throws CPRangeException if \c aSegment is out of bounds
|
||||||
*/
|
*/
|
||||||
- (CPMenu)menuForSegment:(unsigned)aSegment
|
- (CPMenu)menuForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
@@ -318,9 +306,9 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
/*!
|
/*!
|
||||||
Sets the selection for the specified segment. If only one segment
|
Sets the selection for the specified segment. If only one segment
|
||||||
can be selected at a time, any other segment will be deselected.
|
can be selected at a time, any other segment will be deselected.
|
||||||
@param isSelected <code>YES</code> selects the segment. <code>NO</code> deselects it.
|
@param isSelected \c YES selects the segment. \c NO deselects it.
|
||||||
@param aSegment the segment to set the selection for
|
@param aSegment the segment to set the selection for
|
||||||
@throws CPRangeException if <code>aSegment</code> is out of bounds
|
@throws CPRangeException if \c aSegment is out of bounds
|
||||||
*/
|
*/
|
||||||
- (void)setSelected:(BOOL)isSelected forSegment:(unsigned)aSegment
|
- (void)setSelected:(BOOL)isSelected forSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
@@ -358,9 +346,9 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the specified segment is selected.
|
Returns \c YES if the specified segment is selected.
|
||||||
@param aSegment the segment to check for selection
|
@param aSegment the segment to check for selection
|
||||||
@throws CPRangeException if <code>aSegment</code> is out of bounds
|
@throws CPRangeException if \c aSegment is out of bounds
|
||||||
*/
|
*/
|
||||||
- (BOOL)isSelectedForSegment:(unsigned)aSegment
|
- (BOOL)isSelectedForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
@@ -369,26 +357,29 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Enables/diables the specified segment.
|
Enables/diables the specified segment.
|
||||||
@param isEnabled <code>YES</code> enables the segment
|
@param isEnabled \c YES enables the segment
|
||||||
@param aSegment the segment to enable/disble
|
@param aSegment the segment to enable/disble
|
||||||
@throws CPRangeException if <code>aSegment</code> is out of bounds
|
@throws CPRangeException if \c aSegment is out of bounds
|
||||||
*/
|
*/
|
||||||
- (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
|
- (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
_segments[aSegment].enabled = isEnabled;
|
if (isEnabled)
|
||||||
|
_themeStates[aSegment] &= ~CPThemeStateDisabled;
|
||||||
|
else
|
||||||
|
_themeStates[aSegment] |= CPThemeStateDisabled;
|
||||||
|
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the specified segment is enabled.
|
Returns \c YES if the specified segment is enabled.
|
||||||
@param aSegment the segment to check
|
@param aSegment the segment to check
|
||||||
@throws CPRangeException if <code>aSegment</code> is out of bounds
|
@throws CPRangeException if \c aSegment is out of bounds
|
||||||
*/
|
*/
|
||||||
- (BOOL)isEnabledForSegment:(unsigned)aSegment
|
- (BOOL)isEnabledForSegment:(unsigned)aSegment
|
||||||
{
|
{
|
||||||
return _segments[aSegment].enabled;
|
return !(_themeStates[aSegment] & CPThemeStateDisabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -414,7 +405,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
/*!
|
/*!
|
||||||
Draws the specified segment bezel
|
Draws the specified segment bezel
|
||||||
@param aSegment the segment to draw the bezel for
|
@param aSegment the segment to draw the bezel for
|
||||||
@param shouldHighlight <code>YES</code> highlights the bezel
|
@param shouldHighlight \c YES highlights the bezel
|
||||||
*/
|
*/
|
||||||
- (void)drawSegmentBezel:(int)aSegment highlight:(BOOL)shouldHighlight
|
- (void)drawSegmentBezel:(int)aSegment highlight:(BOOL)shouldHighlight
|
||||||
{
|
{
|
||||||
@@ -439,6 +430,16 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
return [self _leftOffsetForSegment:segment - 1] + [self widthForSegment:segment - 1] + thickness;
|
return [self _leftOffsetForSegment:segment - 1] + [self widthForSegment:segment - 1] + thickness;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (unsigned)_indexOfLastSegment
|
||||||
|
{
|
||||||
|
var lastSegmentIndex = [_segments count] - 1;
|
||||||
|
|
||||||
|
if (lastSegmentIndex < 0)
|
||||||
|
lastSegmentIndex = 0;
|
||||||
|
|
||||||
|
return lastSegmentIndex;
|
||||||
|
}
|
||||||
|
|
||||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
||||||
{
|
{
|
||||||
var height = [self currentValueForThemeAttribute:@"default-height"],
|
var height = [self currentValueForThemeAttribute:@"default-height"],
|
||||||
@@ -452,25 +453,28 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
}
|
}
|
||||||
else if (aName === "right-segment-bezel")
|
else if (aName === "right-segment-bezel")
|
||||||
{
|
{
|
||||||
return CGRectMake(CGRectGetMaxX(bounds) - contentInset.right - bezelInset.right, bezelInset.top, contentInset.right, height);
|
return CPRectMake(CGRectGetWidth([self bounds]) - contentInset.right,
|
||||||
|
bezelInset.top,
|
||||||
|
contentInset.right,
|
||||||
|
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],
|
||||||
@@ -479,7 +483,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);
|
||||||
|
|
||||||
@@ -499,8 +503,15 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
|
|
||||||
- (void)layoutSubviews
|
- (void)layoutSubviews
|
||||||
{
|
{
|
||||||
|
if (_segments.length <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var themeState = _themeStates[0];
|
||||||
|
|
||||||
|
themeState |= _themeState & CPThemeStateDisabled;
|
||||||
|
|
||||||
var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
|
var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
|
||||||
inState:_themeStates[0]];
|
inState:themeState];
|
||||||
|
|
||||||
var leftBezelView = [self layoutEphemeralSubviewNamed:@"left-segment-bezel"
|
var leftBezelView = [self layoutEphemeralSubviewNamed:@"left-segment-bezel"
|
||||||
positioned:CPWindowBelow
|
positioned:CPWindowBelow
|
||||||
@@ -508,8 +519,12 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
|
|
||||||
[leftBezelView setBackgroundColor:leftCapColor];
|
[leftBezelView setBackgroundColor:leftCapColor];
|
||||||
|
|
||||||
|
var themeState = _themeStates[_themeStates.length - 1];
|
||||||
|
|
||||||
|
themeState |= _themeState & CPThemeStateDisabled;
|
||||||
|
|
||||||
var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color"
|
var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color"
|
||||||
inState:_themeStates[_themeStates.length - 1]];
|
inState:themeState];
|
||||||
|
|
||||||
var rightBezelView = [self layoutEphemeralSubviewNamed:@"right-segment-bezel"
|
var rightBezelView = [self layoutEphemeralSubviewNamed:@"right-segment-bezel"
|
||||||
positioned:CPWindowBelow
|
positioned:CPWindowBelow
|
||||||
@@ -582,7 +597,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
/*!
|
/*!
|
||||||
Draws the specified segment
|
Draws the specified segment
|
||||||
@param aSegment the segment to draw
|
@param aSegment the segment to draw
|
||||||
@param shouldHighlight <code>YES</code> highlights the bezel
|
@param shouldHighlight \c YES highlights the bezel
|
||||||
*/
|
*/
|
||||||
- (void)drawSegment:(int)aSegment highlight:(BOOL)shouldHighlight
|
- (void)drawSegment:(int)aSegment highlight:(BOOL)shouldHighlight
|
||||||
{
|
{
|
||||||
@@ -686,6 +701,15 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -716,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)
|
||||||
{
|
{
|
||||||
@@ -747,10 +771,13 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
|
|
||||||
if (type == CPLeftMouseDown)
|
if (type == CPLeftMouseDown)
|
||||||
{
|
{
|
||||||
_trackingHighlighted = YES;
|
var trackingSegment = [self testSegment:location];
|
||||||
_trackingSegment = [self testSegment:location];
|
if (trackingSegment > -1 && [self isEnabledForSegment:trackingSegment])
|
||||||
|
{
|
||||||
[self drawSegmentBezel:_trackingSegment highlight:YES];
|
_trackingHighlighted = YES;
|
||||||
|
_trackingSegment = trackingSegment;
|
||||||
|
[self drawSegmentBezel:_trackingSegment highlight:YES];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (type == CPLeftMouseDragged)
|
else if (type == CPLeftMouseDragged)
|
||||||
@@ -758,8 +785,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
|||||||
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;
|
||||||
|
|||||||
+9
-1
@@ -49,7 +49,7 @@ CPCircularSlider = 1;
|
|||||||
|
|
||||||
+ (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"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,6 +83,10 @@ CPCircularSlider = 1;
|
|||||||
|
|
||||||
if (doubleValue < _minValue)
|
if (doubleValue < _minValue)
|
||||||
[self setDoubleValue:_minValue];
|
[self setDoubleValue:_minValue];
|
||||||
|
|
||||||
|
// The relative position may have (did) change.
|
||||||
|
[self setNeedsLayout];
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (float)minValue
|
- (float)minValue
|
||||||
@@ -101,6 +105,10 @@ CPCircularSlider = 1;
|
|||||||
|
|
||||||
if (doubleValue > _maxValue)
|
if (doubleValue > _maxValue)
|
||||||
[self setDoubleValue:_maxValue];
|
[self setDoubleValue:_maxValue];
|
||||||
|
|
||||||
|
// The relative position may have (did) change.
|
||||||
|
[self setNeedsLayout];
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (float)maxValue
|
- (float)maxValue
|
||||||
|
|||||||
@@ -46,6 +46,7 @@
|
|||||||
CPTextField _brightnessLabel;
|
CPTextField _brightnessLabel;
|
||||||
CPTextField _hexLabel;
|
CPTextField _hexLabel;
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
DOMElement _redValue;
|
DOMElement _redValue;
|
||||||
DOMElement _greenValue;
|
DOMElement _greenValue;
|
||||||
DOMElement _blueValue;
|
DOMElement _blueValue;
|
||||||
@@ -53,6 +54,7 @@
|
|||||||
DOMElement _saturationValue;
|
DOMElement _saturationValue;
|
||||||
DOMElement _brightnessValue;
|
DOMElement _brightnessValue;
|
||||||
DOMElement _hexValue;
|
DOMElement _hexValue;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
|
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
|
||||||
@@ -82,6 +84,7 @@
|
|||||||
[_redSlider setAction: @selector(sliderChanged:)];
|
[_redSlider setAction: @selector(sliderChanged:)];
|
||||||
[_redSlider setAutoresizingMask: CPViewWidthSizable];
|
[_redSlider setAutoresizingMask: CPViewWidthSizable];
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
var updateFunction = function(aDOMEvent)
|
var updateFunction = function(aDOMEvent)
|
||||||
{
|
{
|
||||||
if(isNaN(this.value))
|
if(isNaN(this.value))
|
||||||
@@ -147,6 +150,7 @@
|
|||||||
|
|
||||||
redValue._DOMElement.appendChild(_redValue);
|
redValue._DOMElement.appendChild(_redValue);
|
||||||
[_contentView addSubview: redValue];
|
[_contentView addSubview: redValue];
|
||||||
|
#endif
|
||||||
|
|
||||||
_greenLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 58, 15, 20)];
|
_greenLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 58, 15, 20)];
|
||||||
[_greenLabel setStringValue: "G"];
|
[_greenLabel setStringValue: "G"];
|
||||||
@@ -159,6 +163,7 @@
|
|||||||
[_greenSlider setAction: @selector(sliderChanged:)];
|
[_greenSlider setAction: @selector(sliderChanged:)];
|
||||||
[_greenSlider setAutoresizingMask: CPViewWidthSizable];
|
[_greenSlider setAutoresizingMask: CPViewWidthSizable];
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
//green value input box
|
//green value input box
|
||||||
var greenValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 58, 45, 20)];
|
var greenValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 58, 45, 20)];
|
||||||
[greenValue setAutoresizingMask: CPViewMinXMargin];
|
[greenValue setAutoresizingMask: CPViewMinXMargin];
|
||||||
@@ -168,6 +173,7 @@
|
|||||||
|
|
||||||
greenValue._DOMElement.appendChild(_greenValue);
|
greenValue._DOMElement.appendChild(_greenValue);
|
||||||
[_contentView addSubview: greenValue];
|
[_contentView addSubview: greenValue];
|
||||||
|
#endif
|
||||||
|
|
||||||
_blueLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 81, 15, 20)];
|
_blueLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 81, 15, 20)];
|
||||||
[_blueLabel setStringValue: "B"];
|
[_blueLabel setStringValue: "B"];
|
||||||
@@ -180,6 +186,7 @@
|
|||||||
[_blueSlider setAction: @selector(sliderChanged:)];
|
[_blueSlider setAction: @selector(sliderChanged:)];
|
||||||
[_blueSlider setAutoresizingMask: CPViewWidthSizable];
|
[_blueSlider setAutoresizingMask: CPViewWidthSizable];
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
//blue value input box
|
//blue value input box
|
||||||
var blueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 81, 45, 20)];
|
var blueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 81, 45, 20)];
|
||||||
[blueValue setAutoresizingMask: CPViewMinXMargin];
|
[blueValue setAutoresizingMask: CPViewMinXMargin];
|
||||||
@@ -189,7 +196,7 @@
|
|||||||
|
|
||||||
blueValue._DOMElement.appendChild(_blueValue);
|
blueValue._DOMElement.appendChild(_blueValue);
|
||||||
[_contentView addSubview: blueValue];
|
[_contentView addSubview: blueValue];
|
||||||
|
#endif
|
||||||
_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"];
|
||||||
[_hsbLabel setTextColor:[CPColor blackColor]];
|
[_hsbLabel setTextColor:[CPColor blackColor]];
|
||||||
@@ -205,6 +212,7 @@
|
|||||||
[_hueSlider setAction: @selector(sliderChanged:)];
|
[_hueSlider setAction: @selector(sliderChanged:)];
|
||||||
[_hueSlider setAutoresizingMask: CPViewWidthSizable];
|
[_hueSlider setAutoresizingMask: CPViewWidthSizable];
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
//red value input box
|
//red value input box
|
||||||
var hueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 145, 45, 20)];
|
var hueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 145, 45, 20)];
|
||||||
[hueValue setAutoresizingMask: CPViewMinXMargin];
|
[hueValue setAutoresizingMask: CPViewMinXMargin];
|
||||||
@@ -214,7 +222,7 @@
|
|||||||
|
|
||||||
hueValue._DOMElement.appendChild(_hueValue);
|
hueValue._DOMElement.appendChild(_hueValue);
|
||||||
[_contentView addSubview: hueValue];
|
[_contentView addSubview: hueValue];
|
||||||
|
#endif
|
||||||
_saturationLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 168, 15, 20)];
|
_saturationLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 168, 15, 20)];
|
||||||
[_saturationLabel setStringValue: "S"];
|
[_saturationLabel setStringValue: "S"];
|
||||||
[_saturationLabel setTextColor:[CPColor blackColor]];
|
[_saturationLabel setTextColor:[CPColor blackColor]];
|
||||||
@@ -226,6 +234,7 @@
|
|||||||
[_saturationSlider setAction: @selector(sliderChanged:)];
|
[_saturationSlider setAction: @selector(sliderChanged:)];
|
||||||
[_saturationSlider setAutoresizingMask: CPViewWidthSizable];
|
[_saturationSlider setAutoresizingMask: CPViewWidthSizable];
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
//green value input box
|
//green value input box
|
||||||
var saturationValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 168, 45, 20)];
|
var saturationValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 168, 45, 20)];
|
||||||
[saturationValue setAutoresizingMask: CPViewMinXMargin];
|
[saturationValue setAutoresizingMask: CPViewMinXMargin];
|
||||||
@@ -235,7 +244,7 @@
|
|||||||
|
|
||||||
saturationValue._DOMElement.appendChild(_saturationValue);
|
saturationValue._DOMElement.appendChild(_saturationValue);
|
||||||
[_contentView addSubview: saturationValue];
|
[_contentView addSubview: saturationValue];
|
||||||
|
#endif
|
||||||
_brightnessLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 191, 15, 20)];
|
_brightnessLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 191, 15, 20)];
|
||||||
[_brightnessLabel setStringValue: "B"];
|
[_brightnessLabel setStringValue: "B"];
|
||||||
[_brightnessLabel setTextColor:[CPColor blackColor]];
|
[_brightnessLabel setTextColor:[CPColor blackColor]];
|
||||||
@@ -247,6 +256,7 @@
|
|||||||
[_brightnessSlider setAction: @selector(sliderChanged:)];
|
[_brightnessSlider setAction: @selector(sliderChanged:)];
|
||||||
[_brightnessSlider setAutoresizingMask: CPViewWidthSizable];
|
[_brightnessSlider setAutoresizingMask: CPViewWidthSizable];
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
//blue value input box
|
//blue value input box
|
||||||
var brightnessValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 191, 45, 20)];
|
var brightnessValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 191, 45, 20)];
|
||||||
[brightnessValue setAutoresizingMask: CPViewMinXMargin];
|
[brightnessValue setAutoresizingMask: CPViewMinXMargin];
|
||||||
@@ -256,11 +266,12 @@
|
|||||||
|
|
||||||
brightnessValue._DOMElement.appendChild(_brightnessValue);
|
brightnessValue._DOMElement.appendChild(_brightnessValue);
|
||||||
[_contentView addSubview: brightnessValue];
|
[_contentView addSubview: brightnessValue];
|
||||||
|
#endif
|
||||||
_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]];
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
//hex input box
|
//hex input box
|
||||||
_hexValue = _redValue.cloneNode(false);
|
_hexValue = _redValue.cloneNode(false);
|
||||||
_hexValue.style.top = "228px";
|
_hexValue.style.top = "228px";
|
||||||
@@ -289,6 +300,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
_contentView._DOMElement.appendChild(_hexValue);
|
_contentView._DOMElement.appendChild(_hexValue);
|
||||||
|
#endif
|
||||||
|
|
||||||
[_contentView addSubview: _rgbLabel];
|
[_contentView addSubview: _rgbLabel];
|
||||||
[_contentView addSubview: _redLabel];
|
[_contentView addSubview: _redLabel];
|
||||||
@@ -380,7 +392,9 @@
|
|||||||
|
|
||||||
- (void)updateHex:(CPColor)aColor
|
- (void)updateHex:(CPColor)aColor
|
||||||
{
|
{
|
||||||
|
#if PLATFORM(DOM)
|
||||||
_hexValue.value = [aColor hexString];
|
_hexValue.value = [aColor hexString];
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateRGBSliders:(CPColor)aColor
|
- (void)updateRGBSliders:(CPColor)aColor
|
||||||
@@ -394,6 +408,7 @@
|
|||||||
|
|
||||||
- (void)updateLabels
|
- (void)updateLabels
|
||||||
{
|
{
|
||||||
|
#if PLATFORM(DOM)
|
||||||
_hueValue.value = ROUND([_hueSlider floatValue]);
|
_hueValue.value = ROUND([_hueSlider floatValue]);
|
||||||
_saturationValue.value = ROUND([_saturationSlider floatValue]);
|
_saturationValue.value = ROUND([_saturationSlider floatValue]);
|
||||||
_brightnessValue.value = ROUND([_brightnessSlider floatValue]);
|
_brightnessValue.value = ROUND([_brightnessSlider floatValue]);
|
||||||
@@ -401,6 +416,7 @@
|
|||||||
_redValue.value = ROUND([_redSlider floatValue] * 255);
|
_redValue.value = ROUND([_redSlider floatValue] * 255);
|
||||||
_greenValue.value = ROUND([_greenSlider floatValue] * 255);
|
_greenValue.value = ROUND([_greenSlider floatValue] * 255);
|
||||||
_blueValue.value = ROUND([_blueSlider floatValue] * 255);
|
_blueValue.value = ROUND([_blueSlider floatValue] * 255);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPImage)provideNewButtonImage
|
- (CPImage)provideNewButtonImage
|
||||||
|
|||||||
+180
-33
@@ -20,6 +20,7 @@
|
|||||||
* 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"
|
||||||
|
|
||||||
@@ -55,6 +56,8 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
int _drawingDivider;
|
int _drawingDivider;
|
||||||
|
|
||||||
BOOL _needsResizeSubviews;
|
BOOL _needsResizeSubviews;
|
||||||
|
|
||||||
|
CPArray _buttonBars;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -77,6 +80,7 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
_currentDivider = CPNotFound;
|
_currentDivider = CPNotFound;
|
||||||
|
|
||||||
_DOMDividerElements = [];
|
_DOMDividerElements = [];
|
||||||
|
_buttonBars = [];
|
||||||
|
|
||||||
[self _setVertical:YES];
|
[self _setVertical:YES];
|
||||||
}
|
}
|
||||||
@@ -147,17 +151,18 @@ 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
|
||||||
|
// subviews need to change size too.
|
||||||
|
_needsResizeSubviews = YES;
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)didAddSubview:(CPView)aSubview
|
- (void)didAddSubview:(CPView)aSubview
|
||||||
{
|
{
|
||||||
_needsResizeSubviews = YES;
|
_needsResizeSubviews = YES;
|
||||||
// [self adjustSubviews];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isSubviewCollapsed:(CPView)subview
|
- (BOOL)isSubviewCollapsed:(CPView)subview
|
||||||
@@ -207,22 +212,13 @@ 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]);
|
||||||
|
|
||||||
if (_isPaneSplitter)
|
[self _setupDOMDivider];
|
||||||
{
|
|
||||||
_DOMDividerElements[_drawingDivider].style.backgroundColor = "#A5A5A5";
|
|
||||||
_DOMDividerElements[_drawingDivider].style.backgroundImage = "";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_DOMDividerElements[_drawingDivider].style.backgroundColor = "";
|
|
||||||
_DOMDividerElements[_drawingDivider].style.backgroundImage = "url('"+_dividerImagePath+"')";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CPDOMDisplayServerSetStyleLeftTop(_DOMDividerElements[_drawingDivider], NULL, _CGRectGetMinX(aRect), _CGRectGetMinY(aRect));
|
CPDOMDisplayServerSetStyleLeftTop(_DOMDividerElements[_drawingDivider], NULL, _CGRectGetMinX(aRect), _CGRectGetMinY(aRect));
|
||||||
@@ -230,6 +226,20 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)_setupDOMDivider
|
||||||
|
{
|
||||||
|
if (_isPaneSplitter)
|
||||||
|
{
|
||||||
|
_DOMDividerElements[_drawingDivider].style.backgroundColor = "#A5A5A5";
|
||||||
|
_DOMDividerElements[_drawingDivider].style.backgroundImage = "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_DOMDividerElements[_drawingDivider].style.backgroundColor = "";
|
||||||
|
_DOMDividerElements[_drawingDivider].style.backgroundImage = "url('"+_dividerImagePath+"')";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)viewWillDraw
|
- (void)viewWillDraw
|
||||||
{
|
{
|
||||||
[self _adjustSubviewsWithCalculatedSize];
|
[self _adjustSubviewsWithCalculatedSize];
|
||||||
@@ -268,15 +278,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
|
||||||
@@ -309,6 +329,7 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
if (_currentDivider != CPNotFound)
|
if (_currentDivider != CPNotFound)
|
||||||
{
|
{
|
||||||
_currentDivider = CPNotFound;
|
_currentDivider = CPNotFound;
|
||||||
|
[self _updateResizeCursor:anEvent];
|
||||||
[self _postNotificationDidResize];
|
[self _postNotificationDidResize];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,6 +380,9 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_currentDivider === CPNotFound)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (type == CPLeftMouseDragged && _currentDivider != CPNotFound)
|
else if (type == CPLeftMouseDragged && _currentDivider != CPNotFound)
|
||||||
@@ -366,6 +390,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];
|
||||||
@@ -377,6 +403,74 @@ 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],
|
||||||
|
startPosition = frame.origin[_originComponent] + frame.size[_sizeComponent],
|
||||||
|
canShrink = [self _realPositionForPosition:startPosition-1 ofDividerAtIndex:i] < startPosition,
|
||||||
|
canGrow = [self _realPositionForPosition:startPosition+1 ofDividerAtIndex:i] > startPosition,
|
||||||
|
cursor = [CPCursor arrowCursor];
|
||||||
|
|
||||||
|
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];
|
||||||
@@ -399,10 +493,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];
|
||||||
@@ -418,19 +510,28 @@ 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];
|
||||||
|
|
||||||
frameA.size[_sizeComponent] = realPosition - frameA.origin[_originComponent];
|
frameA.size[_sizeComponent] = realPosition - frameA.origin[_originComponent];
|
||||||
[_subviews[dividerIndex] setFrame:frameA];
|
[_subviews[dividerIndex] setFrame:frameA];
|
||||||
|
|
||||||
@@ -488,8 +589,9 @@ var CPSplitViewHorizontalImage = nil,
|
|||||||
totalSizableSpace = 0;
|
totalSizableSpace = 0;
|
||||||
|
|
||||||
var nonSizableSpace = totalSizableSpace ? bounds.size[_sizeComponent] - totalSizableSpace : 0,
|
var nonSizableSpace = totalSizableSpace ? bounds.size[_sizeComponent] - totalSizableSpace : 0,
|
||||||
ratio = (bounds.size[_sizeComponent] - totalDividers*dividerThickness - nonSizableSpace) / (oldSize[_sizeComponent]- totalDividers*dividerThickness - nonSizableSpace),
|
remainingFlexibleSpace = bounds.size[_sizeComponent] - oldSize[_sizeComponent],
|
||||||
remainingFlexibleSpace = bounds.size[_sizeComponent] - oldSize[_sizeComponent];
|
oldDimension = (oldSize[_sizeComponent]- totalDividers*dividerThickness - nonSizableSpace),
|
||||||
|
ratio = oldDimension <= 0 ? 0 : (bounds.size[_sizeComponent] - totalDividers*dividerThickness - nonSizableSpace) / oldDimension;
|
||||||
|
|
||||||
for (index = 0; index < count; ++index)
|
for (index = 0; index < count; ++index)
|
||||||
{
|
{
|
||||||
@@ -508,8 +610,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;
|
||||||
|
|
||||||
@@ -540,6 +640,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];
|
||||||
@@ -554,12 +695,13 @@ 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)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Initializes the split view by unarchiving data from <code>aCoder</code>.
|
Initializes the split view by unarchiving data from \c aCoder.
|
||||||
@param aCoder the coder containing the archived CPSplitView.
|
@param aCoder the coder containing the archived CPSplitView.
|
||||||
*/
|
*/
|
||||||
- (id)initWithCoder:(CPCoder)aCoder
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
@@ -572,7 +714,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]];
|
||||||
@@ -589,6 +733,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];
|
||||||
|
|||||||
@@ -22,13 +22,9 @@
|
|||||||
|
|
||||||
@import <Foundation/CPString.j>
|
@import <Foundation/CPString.j>
|
||||||
|
|
||||||
#include "CoreGraphics/CGGeometry.h"
|
@import "CPPlatformString.j"
|
||||||
#include "Platform/Platform.h"
|
|
||||||
|
|
||||||
|
|
||||||
var CPStringReferenceElement = nil,
|
|
||||||
CPStringDefaultFont = nil;
|
|
||||||
|
|
||||||
@implementation CPString (CPStringDrawing)
|
@implementation CPString (CPStringDrawing)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -46,75 +42,7 @@ var CPStringReferenceElement = nil,
|
|||||||
|
|
||||||
- (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth
|
- (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth
|
||||||
{
|
{
|
||||||
#if PLATFORM(DOM)
|
return [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
|
||||||
if (!CPStringReferenceElement)
|
|
||||||
{
|
|
||||||
CPStringReferenceElement = document.createElement("span");
|
|
||||||
|
|
||||||
var style = CPStringReferenceElement.style;
|
|
||||||
|
|
||||||
style.position = "absolute";
|
|
||||||
style.whiteSpace = "pre";
|
|
||||||
style.visibility = "visible";
|
|
||||||
style.padding = "0px";
|
|
||||||
style.margin = "0px";
|
|
||||||
|
|
||||||
style.left = "-100000px";
|
|
||||||
style.top = "-100000px";
|
|
||||||
style.zIndex = "10000";
|
|
||||||
style.background = "red";
|
|
||||||
|
|
||||||
document.getElementsByTagName("body")[0].appendChild(CPStringReferenceElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!aFont)
|
|
||||||
{
|
|
||||||
if (!CPStringDefaultFont)
|
|
||||||
CPStringDefaultFont = [CPFont systemFontOfSize:12.0];
|
|
||||||
|
|
||||||
aFont = CPStringDefaultFont;
|
|
||||||
}
|
|
||||||
|
|
||||||
var style = CPStringReferenceElement.style;
|
|
||||||
|
|
||||||
if (aWidth === NULL)
|
|
||||||
{
|
|
||||||
style.width = "";
|
|
||||||
style.whiteSpace = "pre";
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
style.width = ROUND(aWidth) + "px";
|
|
||||||
|
|
||||||
if (document.attachEvent)
|
|
||||||
style.wordWrap = "break-word";
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
style.whiteSpace = "-o-pre-wrap";
|
|
||||||
style.whiteSpace = "-pre-wrap";
|
|
||||||
style.whiteSpace = "-moz-pre-wrap";
|
|
||||||
style.whiteSpace = "pre-wrap";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
style.font = [aFont cssString];
|
|
||||||
|
|
||||||
if (CPFeatureIsCompatible(CPJavascriptInnerTextFeature))
|
|
||||||
CPStringReferenceElement.innerText = self;
|
|
||||||
|
|
||||||
else if (CPFeatureIsCompatible(CPJavascriptTextContentFeature))
|
|
||||||
CPStringReferenceElement.textContent = self;
|
|
||||||
|
|
||||||
return _CGSizeMake(CPStringReferenceElement.clientWidth, CPStringReferenceElement.clientHeight);
|
|
||||||
#endif
|
|
||||||
return _CGSizeMakeZero();
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)_resetSize
|
|
||||||
{
|
|
||||||
CPStringReferenceElement = nil;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+17
-4
@@ -247,6 +247,8 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
|
|
||||||
[_labelsView tabView:self didAddTabViewItem:aTabViewItem];
|
[_labelsView tabView:self didAddTabViewItem:aTabViewItem];
|
||||||
|
|
||||||
|
[aTabViewItem _setTabView:self];
|
||||||
|
|
||||||
if ([_tabViewItems count] == 1)
|
if ([_tabViewItems count] == 1)
|
||||||
[self selectFirstTabViewItem:self];
|
[self selectFirstTabViewItem:self];
|
||||||
|
|
||||||
@@ -260,9 +262,13 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
*/
|
*/
|
||||||
- (void)removeTabViewItem:(CPTabViewItem)aTabViewItem
|
- (void)removeTabViewItem:(CPTabViewItem)aTabViewItem
|
||||||
{
|
{
|
||||||
|
var index = [self indexOfTabViewItem:aTabViewItem];
|
||||||
|
|
||||||
[_tabViewItems removeObjectIdenticalTo:aTabViewItem];
|
[_tabViewItems removeObjectIdenticalTo:aTabViewItem];
|
||||||
|
|
||||||
[_labelsView tabView:self didRemoveTabViewItem:aTabViewItem];
|
[_labelsView tabView:self didRemoveTabViewItemAtIndex:index];
|
||||||
|
|
||||||
|
[aTabViewItem _setTabView:nil];
|
||||||
|
|
||||||
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
|
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
|
||||||
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
|
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
|
||||||
@@ -490,6 +496,14 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
|||||||
return contentRect;
|
return contentRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the receiver's delegate.
|
||||||
|
*/
|
||||||
|
- (id)delegate
|
||||||
|
{
|
||||||
|
return _delegate;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the delegate for this tab view.
|
Sets the delegate for this tab view.
|
||||||
@param aDelegate the tab view's delegate
|
@param aDelegate the tab view's delegate
|
||||||
@@ -648,10 +662,9 @@ var _CPTabLabelsViewBackgroundColor = nil,
|
|||||||
[self layoutSubviews];
|
[self layoutSubviews];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)tabView:(CPTabView)aTabView didRemoveTabViewItem:(CPTabViewItem)aTabViewItem
|
- (void)tabView:(CPTabView)aTabView didRemoveTabViewItemAtIndex:(unsigned)index
|
||||||
{
|
{
|
||||||
var index = [aTabView indexOfTabViewItem:aTabViewItem],
|
var label = _tabLabels[index];
|
||||||
label = _tabLabels[index];
|
|
||||||
|
|
||||||
[_tabLabels removeObjectAtIndex:index];
|
[_tabLabels removeObjectAtIndex:index];
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,13 @@ CPPressedTab = 2;
|
|||||||
|
|
||||||
CPView _view;
|
CPView _view;
|
||||||
CPView _auxiliaryView;
|
CPView _auxiliaryView;
|
||||||
|
|
||||||
|
CPTabView _tabView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
return [self initWithIdentifier:@""];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -163,6 +170,14 @@ CPPressedTab = 2;
|
|||||||
return _tabView;
|
return _tabView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@ignore
|
||||||
|
*/
|
||||||
|
- (void)_setTabView:(CPTabView)aView
|
||||||
|
{
|
||||||
|
_tabView = aView;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var CPTabViewItemIdentifierKey = "CPTabViewItemIdentifierKey",
|
var CPTabViewItemIdentifierKey = "CPTabViewItemIdentifierKey",
|
||||||
|
|||||||
+292
-297
@@ -3,7 +3,7 @@
|
|||||||
* AppKit
|
* AppKit
|
||||||
*
|
*
|
||||||
* Created by Francisco Tolmasky.
|
* Created by Francisco Tolmasky.
|
||||||
* Copyright 2008, 280 North, Inc.
|
* Copyright 2009, 280 North, Inc.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
@@ -20,412 +20,368 @@
|
|||||||
* 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/Foundation.j>
|
@import <Foundation/CPDictionary.j>
|
||||||
|
@import <Foundation/CPObject.j>
|
||||||
|
@import <Foundation/CPSortDescriptor.j>
|
||||||
|
@import <Foundation/CPString.j>
|
||||||
|
|
||||||
|
@import "CPTableHeaderView.j"
|
||||||
|
|
||||||
/*
|
#include "CoreGraphics/CGGeometry.h"
|
||||||
@ignore
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@class CPTableColumn
|
|
||||||
*/
|
|
||||||
CPTableColumnNoResizing = 0;
|
CPTableColumnNoResizing = 0;
|
||||||
/*
|
CPTableColumnAutoresizingMask = 1 << 0;
|
||||||
@global
|
CPTableColumnUserResizingMask = 1 << 1;
|
||||||
@class CPTableColumn
|
|
||||||
*/
|
|
||||||
CPTableColumnAutoresizingMask = 1;
|
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@class CPTableColumn
|
|
||||||
*/
|
|
||||||
CPTableColumnUserResizingMask = 2;
|
|
||||||
|
|
||||||
#define PurgableInfoMake(aView, aRow) { view:(aView), row:(aRow) }
|
|
||||||
#define PurgableInfoView(anInfo) ((anInfo).view)
|
|
||||||
#define PurgableInfoRow(anInfo) ((anInfo).row)
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@ingroup appkit
|
|
||||||
@class CPTableColumn
|
|
||||||
|
|
||||||
An CPTableColumn object mainly keeps information about the width of the column, its minimum and maximum width; whether the column can be edited or resized; and the cells used to draw the column header and the data in the column. You can change all these attributes of the column by calling the appropriate methods. Please note that the table column does not hold nor has access to the data to be displayed in the column; this data is maintained in the table view's data source.</p>
|
|
||||||
|
|
||||||
<p>Each CPTableColumn object is identified by a CPString, called the column identifier. The reason is that, after a column has been added to a table view, the user might move the columns around, so there is a need to identify the columns regardless of its position in the table.
|
|
||||||
|
|
||||||
@ignore
|
|
||||||
*/
|
|
||||||
@implementation CPTableColumn : CPObject
|
@implementation CPTableColumn : CPObject
|
||||||
{
|
{
|
||||||
CPString _identifier;
|
CPTableView _tableView;
|
||||||
CPView _headerView;
|
CPView _headerView;
|
||||||
|
CPView _dataView;
|
||||||
|
Object _dataViewData;
|
||||||
|
|
||||||
CPTableView _tableView;
|
float _width;
|
||||||
|
float _minWidth;
|
||||||
|
float _maxWidth;
|
||||||
|
unsigned _resizingMask;
|
||||||
|
|
||||||
float _width;
|
id _identifier;
|
||||||
float _minWidth;
|
BOOL _isEditable;
|
||||||
float _maxWidth;
|
CPSortDescriptor _sortDescriptorPrototype;
|
||||||
|
BOOL _isHidden;
|
||||||
|
CPString _headerToolTip;
|
||||||
|
|
||||||
unsigned _resizingMask;
|
BOOL _disableResizingPosting @accessors(property=disableResizingPosting);
|
||||||
|
|
||||||
CPView _dataView; // default data view for this column
|
|
||||||
|
|
||||||
Object _dataViewData; // cache of data view archives (key=data view hash, value=data view archive)
|
|
||||||
Object _dataViewForView; // mapping from view instances back to their data view prototype (key=view instance hash, value=data view)
|
|
||||||
Object _purgableInfosForDataView; // (key=data view hash, value=)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
- (id)init
|
||||||
Initializes the table column with the specified identifier.
|
{
|
||||||
@param anIdentifier the identifier
|
return [self initWithIdentifier:@""];
|
||||||
@return the initialized table column
|
}
|
||||||
*/
|
|
||||||
- (id)initWithIdentifier:(CPString)anIdentifier
|
- (id)initWithIdentifier:(id)anIdentifier
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
[self _init];
|
_dataViewData = { };
|
||||||
|
|
||||||
_identifier = anIdentifier;
|
_width = 100.0;
|
||||||
|
_minWidth = 10.0;
|
||||||
|
_maxWidth = 1000000.0;
|
||||||
|
_resizingMask = CPTableColumnAutoresizingMask | CPTableColumnUserResizingMask;
|
||||||
|
_disableResizingPosting = NO;
|
||||||
|
|
||||||
_width = 40.0;
|
[self setIdentifier:anIdentifier];
|
||||||
_minWidth = 8.0;
|
|
||||||
_maxWidth = 1000.0;
|
|
||||||
|
|
||||||
var dataView = [[CPTextField alloc] initWithFrame:CPRectMakeZero()];
|
var header = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMakeZero()];
|
||||||
[dataView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateHighlighted];
|
[self setHeaderView:header];
|
||||||
|
|
||||||
[self setDataView:dataView];
|
var textDataView = [CPTextField new];
|
||||||
|
[textDataView setLineBreakMode:CPLineBreakByTruncatingTail];
|
||||||
_headerView = [[CPTextField alloc] initWithFrame:CPRectMakeZero()];
|
[textDataView setValue:[CPColor colorWithHexString:@"333333"] forThemeAttribute:@"text-color"];
|
||||||
[_headerView setBackgroundColor:[CPColor greenColor]];
|
[textDataView setValue:[CPColor whiteColor] forThemeAttribute:@"text-color" inState:CPThemeStateSelected];
|
||||||
|
[textDataView setValue:[CPFont boldSystemFontOfSize:12] forThemeAttribute:@"font" inState:CPThemeStateSelected];
|
||||||
|
[textDataView setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"];
|
||||||
|
[self setDataView:textDataView];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_init
|
|
||||||
{
|
|
||||||
_dataViewData = {};
|
|
||||||
_dataViewForView = {};
|
|
||||||
_purgableInfosForDataView = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Sets the table column's identifier
|
|
||||||
@param anIdentifier the new identifier
|
|
||||||
*/
|
|
||||||
- (void)setIdentifier:(CPString)anIdentifier
|
|
||||||
{
|
|
||||||
_identifier = anIdentifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns the table column's identifier
|
|
||||||
*/
|
|
||||||
- (CPString)identifier
|
|
||||||
{
|
|
||||||
return _identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setting the CPTableView
|
|
||||||
/*!
|
|
||||||
Sets the table's view. This is called automatically by Cappuccino.
|
|
||||||
@param aTableView the new table view
|
|
||||||
*/
|
|
||||||
- (void)setTableView:(CPTableView)aTableView
|
- (void)setTableView:(CPTableView)aTableView
|
||||||
{
|
{
|
||||||
_tableView = aTableView;
|
_tableView = aTableView;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns the column's table view.
|
|
||||||
*/
|
|
||||||
- (CPTableView)tableView
|
- (CPTableView)tableView
|
||||||
{
|
{
|
||||||
return _tableView;
|
return _tableView;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Controlling size
|
|
||||||
/*!
|
|
||||||
Sets the column's width.
|
|
||||||
@param aWidth the new column width
|
|
||||||
*/
|
|
||||||
- (void)setWidth:(float)aWidth
|
- (void)setWidth:(float)aWidth
|
||||||
{
|
{
|
||||||
_width = aWidth;
|
aWidth = +aWidth;
|
||||||
|
|
||||||
|
if (_width === aWidth)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var newWidth = MIN(MAX(aWidth, [self minWidth]), [self maxWidth]);
|
||||||
|
|
||||||
|
if (_width === newWidth)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var oldWidth = _width;
|
||||||
|
|
||||||
|
_width = newWidth;
|
||||||
|
|
||||||
|
var tableView = [self tableView];
|
||||||
|
|
||||||
|
if (tableView)
|
||||||
|
{
|
||||||
|
var index = [[tableView tableColumns] indexOfObjectIdenticalTo:self],
|
||||||
|
dirtyTableColumnRangeIndex = tableView._dirtyTableColumnRangeIndex;
|
||||||
|
|
||||||
|
if (dirtyTableColumnRangeIndex < 0)
|
||||||
|
tableView._dirtyTableColumnRangeIndex = index;
|
||||||
|
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];
|
||||||
|
|
||||||
|
if (!_disableResizingPosting)
|
||||||
|
[self _postDidResizeNotificationWithOldWidth:oldWidth];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns the column's width
|
|
||||||
*/
|
|
||||||
- (float)width
|
- (float)width
|
||||||
{
|
{
|
||||||
return _width;
|
return _width;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
- (void)setMinWidth:(float)aMinWidth
|
||||||
Sets column's minimum width.
|
|
||||||
@param aWidth the new minimum column width
|
|
||||||
*/
|
|
||||||
- (void)setMinWidth:(float)aWidth
|
|
||||||
{
|
{
|
||||||
if (_width < (_minWidth = aWidth))
|
aMinWidth = +aMinWidth;
|
||||||
[self setWidth:_minWidth];
|
|
||||||
|
if (_minWidth === aMinWidth)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_minWidth = aMinWidth;
|
||||||
|
|
||||||
|
var width = [self width],
|
||||||
|
newWidth = MAX(width, [self minWidth]);
|
||||||
|
|
||||||
|
if (width !== newWidth)
|
||||||
|
[self setWidth:newWidth];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
The column's minimum width
|
|
||||||
*/
|
|
||||||
- (float)minWidth
|
- (float)minWidth
|
||||||
{
|
{
|
||||||
return _minWidth;
|
return _minWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
- (void)setMaxWidth:(float)aMaxWidth
|
||||||
Sets the column's maximum width.
|
|
||||||
@param aWidth the new maximum width
|
|
||||||
*/
|
|
||||||
- (void)setMaxWidth:(float)aWidth
|
|
||||||
{
|
{
|
||||||
if (_width > (_maxmimumWidth = aWidth))
|
aMaxWidth = +aMaxWidth;
|
||||||
[self setWidth:_maxWidth];
|
|
||||||
|
if (_maxWidth === aMaxWidth)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_maxWidth = aMaxWidth;
|
||||||
|
|
||||||
|
var width = [self width],
|
||||||
|
newWidth = MIN(width, [self maxWidth]);
|
||||||
|
|
||||||
|
if (width !== newWidth)
|
||||||
|
[self setWidth:newWidth];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
- (float)maxWidth
|
||||||
Sets the resizing mask. The mask is one of:
|
|
||||||
<pre>
|
|
||||||
CPTableColumnNoResizing;
|
|
||||||
CPTableColumnAutoresizingMask;
|
|
||||||
CPTableColumnUserResizingMask;
|
|
||||||
</pre>
|
|
||||||
@param aMask the new resizing mask
|
|
||||||
*/
|
|
||||||
- (void)setResizingMask:(unsigned)aMask
|
|
||||||
{
|
{
|
||||||
_resizingMask = aMask;
|
return _maxWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setResizingMask:(unsigned)aResizingMask
|
||||||
|
{
|
||||||
|
_resizingMask = aResizingMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns the column's resizing mask. One of:
|
|
||||||
<pre>
|
|
||||||
CPTableColumnNoResizing;
|
|
||||||
CPTableColumnAutoresizingMask;
|
|
||||||
CPTableColumnUserResizingMask;
|
|
||||||
</pre>
|
|
||||||
*/
|
|
||||||
- (unsigned)resizingMask
|
- (unsigned)resizingMask
|
||||||
{
|
{
|
||||||
return _resizingMask;
|
return _resizingMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
Resizes the column according to the min, max and set width.
|
|
||||||
*/
|
|
||||||
- (void)sizeToFit
|
- (void)sizeToFit
|
||||||
{
|
{
|
||||||
var width = CPRectGetWidth([_headerView frame]);
|
var width = _CGRectGetWidth([_headerView frame]);
|
||||||
|
|
||||||
if (width < _minWidth)
|
if (width < [self minWidth])
|
||||||
[self setMinWidth:width];
|
[self setMinWidth:width];
|
||||||
else if (width > _maxWidth)
|
else if (width > [self maxWidth])
|
||||||
[self setMaxWidth:width]
|
[self setMaxWidth:width]
|
||||||
|
|
||||||
if (_width != width)
|
if (_width !== width)
|
||||||
[self setWidth:width];
|
[self setWidth:width];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
//Setting Component Cells
|
||||||
Sets whether the column in this data is editable.
|
|
||||||
@param aFlag <code>YES</code> means the column data is editable
|
|
||||||
*/
|
|
||||||
- (void)setEditable:(BOOL)aFlag
|
|
||||||
{
|
|
||||||
_isEditable = aFlag;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Returns <code>YES</code> if the column data is editable.
|
|
||||||
*/
|
|
||||||
- (BOOL)isEditable
|
|
||||||
{
|
|
||||||
return _isEditable;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Setting the column header view
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Sets the view that draws the column's header.
|
|
||||||
@param aHeaderView the view that will draws the column header
|
|
||||||
*/
|
|
||||||
|
|
||||||
- (void)setHeaderView:(CPView)aView
|
- (void)setHeaderView:(CPView)aView
|
||||||
{
|
{
|
||||||
|
if (!aView)
|
||||||
|
[CPException raise:CPInvalidArgumentException reason:@"Attempt to set nil header view on " + [self description]];
|
||||||
|
|
||||||
_headerView = aView;
|
_headerView = aView;
|
||||||
|
|
||||||
|
var tableHeaderView = [_tableView headerView];
|
||||||
|
|
||||||
|
[tableHeaderView setNeedsLayout];
|
||||||
|
[tableHeaderView setNeedsDisplay:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
Return the view that draws the column's header
|
|
||||||
*/
|
|
||||||
- (CPView)headerView
|
- (CPView)headerView
|
||||||
{
|
{
|
||||||
return _headerView;
|
return _headerView;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the data cell that draws rows in this column.
|
This method set's the "prototype" view which will be used to create all table cells in this column.
|
||||||
*/
|
|
||||||
- (void)setDataCell:(CPView <CPCoding>)aView
|
|
||||||
{
|
|
||||||
[self setDataView:aView];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
It creates a snapshot of aView, using keyed archiving, which is then copied over and over for each
|
||||||
Sets the data view that draws rows in this column.
|
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 <CPCoding>)aView
|
- (void)setDataView:(CPView)aView
|
||||||
{
|
{
|
||||||
|
if (_dataView === aView)
|
||||||
|
return;
|
||||||
|
|
||||||
if (_dataView)
|
if (_dataView)
|
||||||
_dataViewData[[_dataView hash]] = nil;
|
_dataViewData[[_dataView UID]] = nil;
|
||||||
|
|
||||||
_dataView = aView;
|
_dataView = aView;
|
||||||
_dataViewData[[aView hash]] = [CPKeyedArchiver archivedDataWithRootObject:aView];
|
_dataViewData[[aView UID]] = [CPKeyedArchiver archivedDataWithRootObject:aView];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
- (CPView)dataView
|
||||||
Returns the data cell that draws rows in this column
|
|
||||||
*/
|
|
||||||
- (CPCell)dataCell
|
|
||||||
{
|
{
|
||||||
return _dataView;
|
return _dataView;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Returns the data view that draws rows in this column
|
Returns the CPView object used by the CPTableView to draw values for the receiver.
|
||||||
*/
|
|
||||||
- (CPView)dataView
|
|
||||||
{
|
|
||||||
return [self dataCell];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
By default, this method just calls dataView. Subclassers can override if they need to
|
||||||
By default returns the value from <code>dataCell</code>. This can
|
potentially use different cells for different rows. Subclasses should expect this method
|
||||||
be overridden by a subclass to return different cells for different
|
to be invoked with row equal to -1 in cases where no actual row is involved but the table
|
||||||
rows.
|
view needs to get some generic cell info.
|
||||||
@param aRowIndex the index of the row to obtain the cell for
|
|
||||||
*/
|
*/
|
||||||
- (CPCell)dataCellForRow:(int)aRowIndex
|
- (id)dataViewForRow:(int)aRowIndex
|
||||||
{
|
{
|
||||||
return [self dataView];
|
return [self dataView];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPView)dataViewForRow:(int)aRowIndex
|
- (id)_newDataViewForRow:(int)aRowIndex
|
||||||
{
|
{
|
||||||
return [self dataCellForRow:aRowIndex];
|
var dataView = [self dataViewForRow:aRowIndex],
|
||||||
}
|
dataViewUID = [dataView UID];
|
||||||
/*
|
|
||||||
- (void)_markViewAsPurgable:(CPView)aView
|
|
||||||
{
|
|
||||||
var viewHash = [aView hash],
|
|
||||||
dataViewHash = [_dataViewForView[viewHash] hash];
|
|
||||||
|
|
||||||
if (!_purgableInfosForDataView[dataViewHash])
|
var x = [self tableView]._cachedDataViews[dataViewUID];
|
||||||
_purgableInfosForDataView[dataViewHash] = [CPDictionary dictionary];
|
if (x && x.length)
|
||||||
|
return x.pop();
|
||||||
[_purgableInfosForDataView[dataViewHash] setObject:aView forKey:viewHash];
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
- (void)_markView:(CPView)aView inRow:(unsigned)aRow asPurgable:(BOOL)isPurgable
|
|
||||||
{
|
|
||||||
var viewHash = [aView hash],
|
|
||||||
dataViewHash = [_dataViewForView[viewHash] hash];
|
|
||||||
|
|
||||||
if (!_purgableInfosForDataView[dataViewHash])
|
|
||||||
{
|
|
||||||
if (!isPurgable)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_purgableInfosForDataView[dataViewHash] = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isPurgable) {
|
|
||||||
if (_purgableInfosForDataView[dataViewHash][viewHash])
|
|
||||||
CPLog.warn("removing unpurgable " + _purgableInfosForDataView[dataViewHash][viewHash]);
|
|
||||||
delete _purgableInfosForDataView[dataViewHash][viewHash];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_purgableInfosForDataView[dataViewHash][viewHash] = PurgableInfoMake(aView, aRow);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPView)_newDataViewForRow:(int)aRowIndex avoidingRows:(CPRange)rows
|
|
||||||
{
|
|
||||||
var view = [self dataViewForRow:aRowIndex],
|
|
||||||
viewHash = [view hash],
|
|
||||||
purgableInfos = _purgableInfosForDataView[viewHash];
|
|
||||||
|
|
||||||
if (purgableInfos)
|
|
||||||
{
|
|
||||||
for (var key in purgableInfos)
|
|
||||||
{
|
|
||||||
var info = purgableInfos[key];
|
|
||||||
//if (!CPLocationInRange(PurgableInfoRow(info), rows))
|
|
||||||
//{
|
|
||||||
//CPLog.debug("yes, a purged view is usable, its called: " + PurgableInfoView(info));
|
|
||||||
delete purgableInfos[key];
|
|
||||||
return PurgableInfoView(info);
|
|
||||||
//}
|
|
||||||
//else
|
|
||||||
// CPLog.warn("avoiding");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we haven't cached an archive of the data view, do it now
|
// if we haven't cached an archive of the data view, do it now
|
||||||
if (!_dataViewData[viewHash])
|
if (!_dataViewData[dataViewUID])
|
||||||
_dataViewData[viewHash] = [CPKeyedArchiver archivedDataWithRootObject:view];
|
_dataViewData[dataViewUID] = [CPKeyedArchiver archivedDataWithRootObject:dataView];
|
||||||
|
|
||||||
// unarchive the data view cache
|
// unarchive the data view cache
|
||||||
var newView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[viewHash]];
|
var newDataView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[dataViewUID]];
|
||||||
|
newDataView.identifier = dataViewUID;
|
||||||
|
|
||||||
// map the new view's hash to it's data view prototype
|
return newDataView;
|
||||||
_dataViewForView[[newView hash]] = view;
|
|
||||||
|
|
||||||
CPLog.warn("creating cell: %s", newView);
|
|
||||||
|
|
||||||
return newView;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_purge
|
//Setting the Identifier
|
||||||
|
|
||||||
|
/*
|
||||||
|
Sets the receiver identifier to anIdentifier.
|
||||||
|
*/
|
||||||
|
- (void)setIdentifier:(id)anIdentifier
|
||||||
{
|
{
|
||||||
for (var viewHash in _purgableInfosForDataView)
|
_identifier = anIdentifier;
|
||||||
{
|
}
|
||||||
var purgableInfos = _purgableInfosForDataView[viewHash];
|
|
||||||
|
|
||||||
for (var key in purgableInfos)
|
/*
|
||||||
{
|
Returns the object used by the data source to identify the attribute corresponding to the receiver.
|
||||||
var view = PurgableInfoView(purgableInfos[key]);
|
*/
|
||||||
|
- (id)identifier
|
||||||
|
{
|
||||||
|
return _identifier;
|
||||||
|
}
|
||||||
|
|
||||||
if (!view)
|
//Controlling Editability
|
||||||
CPLog.info("key="+key+" view=" + view + " purgableInfos[key]="+purgableInfos[key])
|
|
||||||
else if (view._superview) {
|
|
||||||
//CPLog.error("PURGING: (removing)" + view);
|
|
||||||
//[view removeFromSuperview];
|
|
||||||
[view setHidden:YES];
|
|
||||||
}
|
|
||||||
//else
|
|
||||||
// CPLog.warn("PURGING: (already removed)" + view);
|
|
||||||
|
|
||||||
//delete purgableInfos[key];
|
/*
|
||||||
}
|
Controls whether the user can edit cells in the receiver by double-clicking them.
|
||||||
}
|
*/
|
||||||
|
- (void)setEditable:(BOOL)shouldBeEditable
|
||||||
|
{
|
||||||
|
_isEditable = shouldBeEditable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Returns YES if the user can edit cells associated with the receiver by double-clicking the
|
||||||
|
column in the NSTableView, NO otherwise.
|
||||||
|
*/
|
||||||
|
- (BOOL)isEditable
|
||||||
|
{
|
||||||
|
return _isEditable;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Sorting
|
||||||
|
- (void)setSortDescriptorPrototype:(CPSortDescriptor)aSortDescriptor
|
||||||
|
{
|
||||||
|
_sortDescriptorPrototype = aSortDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPSortDescriptor)sortDescriptorPrototype
|
||||||
|
{
|
||||||
|
return _sortDescriptorPrototype;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Setting Column Visibility
|
||||||
|
|
||||||
|
- (void)setHidden:(BOOL)shouldBeHidden
|
||||||
|
{
|
||||||
|
_isHidden = shouldBeHidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isHidden
|
||||||
|
{
|
||||||
|
return _isHidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Setting Tool Tips
|
||||||
|
|
||||||
|
/*
|
||||||
|
Sets the tooltip string that is displayed when the cursor pauses over the
|
||||||
|
header cell of the receiver.
|
||||||
|
*/
|
||||||
|
- (void)setHeaderToolTip:(CPString)aToolTip
|
||||||
|
{
|
||||||
|
_headerToolTip = aToolTip;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)headerToolTip
|
||||||
|
{
|
||||||
|
return _headerToolTip;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_postDidResizeNotificationWithOldWidth:(float)oldWidth
|
||||||
|
{
|
||||||
|
[[CPNotificationCenter defaultCenter]
|
||||||
|
postNotificationName:CPTableViewColumnDidResizeNotification
|
||||||
|
object:[self tableView]
|
||||||
|
userInfo:[CPDictionary dictionaryWithObjects:[self, oldWidth] forKeys:[@"CPTableColumn", "CPOldWidth"]]];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
||||||
CPTableColumnHeaderViewKey = @"CPTableColumnHeaderViewKey",
|
CPTableColumnHeaderViewKey = @"CPTableColumnHeaderViewKey",
|
||||||
CPTableColumnDataViewKey = @"CPTableColumnDataViewKey",
|
CPTableColumnDataViewKey = @"CPTableColumnDataViewKey",
|
||||||
@@ -438,18 +394,23 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
|||||||
|
|
||||||
- (id)initWithCoder:(CPCoder)aCoder
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
{
|
{
|
||||||
[self _init];
|
self = [super init];
|
||||||
|
|
||||||
_identifier = [aCoder decodeObjectForKey:CPTableColumnIdentifierKey];
|
if (self)
|
||||||
|
{
|
||||||
|
_dataViewData = { };
|
||||||
|
|
||||||
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
|
_width = [aCoder decodeFloatForKey:CPTableColumnWidthKey];
|
||||||
[self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
|
_minWidth = [aCoder decodeFloatForKey:CPTableColumnMinWidthKey];
|
||||||
|
_maxWidth = [aCoder decodeFloatForKey:CPTableColumnMaxWidthKey];
|
||||||
|
|
||||||
_width = [aCoder decodeFloatForKey:CPTableColumnWidthKey];
|
[self setIdentifier:[aCoder decodeObjectForKey:CPTableColumnIdentifierKey]];
|
||||||
_minWidth = [aCoder decodeFloatForKey:CPTableColumnMinWidthKey];
|
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
|
||||||
_maxWidth = [aCoder decodeFloatForKey:CPTableColumnMaxWidthKey];
|
[self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
|
||||||
|
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
|
||||||
|
|
||||||
_resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey];
|
_resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey];
|
||||||
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -458,14 +419,48 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
|||||||
{
|
{
|
||||||
[aCoder encodeObject:_identifier forKey:CPTableColumnIdentifierKey];
|
[aCoder encodeObject:_identifier forKey:CPTableColumnIdentifierKey];
|
||||||
|
|
||||||
[aCoder encodeObject:_headerView forKey:CPTableColumnHeaderViewKey];
|
|
||||||
[aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
|
|
||||||
|
|
||||||
[aCoder encodeObject:_width forKey:CPTableColumnWidthKey];
|
[aCoder encodeObject:_width forKey:CPTableColumnWidthKey];
|
||||||
[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:_dataView forKey:CPTableColumnDataViewKey];
|
||||||
|
|
||||||
[aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
|
[aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@implementation CPTableColumn (NSInCompatibility)
|
||||||
|
|
||||||
|
- (void)setHeaderCell:(CPView)aView
|
||||||
|
{
|
||||||
|
[CPException raise:CPUnsupportedMethodException
|
||||||
|
reason:@"setHeaderCell: is not supported. -setHeaderCell:aView instead."];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPView)headerCell
|
||||||
|
{
|
||||||
|
[CPException raise:CPUnsupportedMethodException
|
||||||
|
reason:@"headCell is not supported. -headerView instead."];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDataCell:(CPView)aView
|
||||||
|
{
|
||||||
|
[CPException raise:CPUnsupportedMethodException
|
||||||
|
reason:@"setDataCell: is not supported. Use -setHeaderCell:aView instead."];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPView)dataCell
|
||||||
|
{
|
||||||
|
[CPException raise:CPUnsupportedMethodException
|
||||||
|
reason:@"dataCell is not supported. Use -dataCell instead."];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)dataCellForRow:(int)row
|
||||||
|
{
|
||||||
|
[CPException raise:CPUnsupportedMethodException
|
||||||
|
reason:@"dataCellForRow: is not supported. Use -dataViewForRow:row instead."];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,499 @@
|
|||||||
|
/*
|
||||||
|
* CPTableHeaderView.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Ross Boucher.
|
||||||
|
* Copyright 2009 280 North, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import "CPTableColumn.j"
|
||||||
|
@import "CPTableView.j"
|
||||||
|
@import "CPView.j"
|
||||||
|
|
||||||
|
@implementation _CPTableColumnHeaderView : CPView
|
||||||
|
{
|
||||||
|
_CPImageAndTextView _textField;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)initWithFrame:(CGRect)frame
|
||||||
|
{
|
||||||
|
self = [super initWithFrame:frame];
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
[self _init];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_init
|
||||||
|
{
|
||||||
|
_textField = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(5, 1, CGRectGetWidth([self bounds]) - 10, CGRectGetHeight([self bounds]) - 1)];
|
||||||
|
[_textField setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||||
|
|
||||||
|
[_textField setLineBreakMode:CPLineBreakByTruncatingTail];
|
||||||
|
[_textField setTextColor: [CPColor colorWithHexString: @"333333"]];
|
||||||
|
[_textField setFont:[CPFont boldSystemFontOfSize:12.0]];
|
||||||
|
[_textField setAlignment:CPLeftTextAlignment];
|
||||||
|
[_textField setVerticalAlignment:CPCenterVerticalTextAlignment];
|
||||||
|
[_textField setTextShadowColor:[CPColor whiteColor]];
|
||||||
|
[_textField setTextShadowOffset:CGSizeMake(0,1)];
|
||||||
|
|
||||||
|
[self addSubview:_textField];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)layoutSubviews
|
||||||
|
{
|
||||||
|
var themeState = [self themeState];
|
||||||
|
|
||||||
|
if(themeState & CPThemeStateSelected && themeState & CPThemeStateHighlighted)
|
||||||
|
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted-pressed.png", CGSizeMake(1.0, 22.0))]];
|
||||||
|
else if (themeState & CPThemeStateSelected)
|
||||||
|
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted.png", CGSizeMake(1.0, 22.0))]];
|
||||||
|
else if (themeState & CPThemeStateHighlighted)
|
||||||
|
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-pressed.png", CGSizeMake(1.0, 22.0))]];
|
||||||
|
else
|
||||||
|
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 22.0))]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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)setValue:(id)aValue forThemeAttribute:(id)aKey
|
||||||
|
{
|
||||||
|
[_textField setValue:aValue forThemeAttribute:aKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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
|
||||||
|
{
|
||||||
|
int _resizedColumn @accessors(readonly, property=resizedColumn);
|
||||||
|
int _draggedColumn @accessors(readonly, property=draggedColumn);
|
||||||
|
int _pressedColumn @accessors(readonly, property=pressedColumn);
|
||||||
|
|
||||||
|
float _draggedDistance @accessors(readonly, property=draggedDistance);
|
||||||
|
float _lastLocation;
|
||||||
|
float _columnOldWidth;
|
||||||
|
|
||||||
|
CPTableView _tableView @accessors(property=tableView);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_init
|
||||||
|
{
|
||||||
|
_resizedColumn = -1;
|
||||||
|
_draggedColumn = -1;
|
||||||
|
_pressedColumn = -1;
|
||||||
|
_draggedDistance = 0.0;
|
||||||
|
_lastLocation = nil;
|
||||||
|
_columnOldWidth = nil;
|
||||||
|
|
||||||
|
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 22.0))]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithFrame:(CGRect)aFrame
|
||||||
|
{
|
||||||
|
self = [super initWithFrame:aFrame];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
[self _init];
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int)columnAtPoint:(CGPoint)aPoint
|
||||||
|
{
|
||||||
|
return [_tableView columnAtPoint:CGPointMake(aPoint.x, 0)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)headerRectOfColumn:(int)aColumnIndex
|
||||||
|
{
|
||||||
|
var tableColumns = [_tableView tableColumns];
|
||||||
|
|
||||||
|
if (aColumnIndex < 0 || aColumnIndex > [tableColumns count])
|
||||||
|
[CPException raise:"invalid" reason:"tried to get headerRectOfColumn: on invalid column"];
|
||||||
|
|
||||||
|
// UPDATE COLUMN RANGES ?
|
||||||
|
|
||||||
|
var tableRange = _tableView._tableColumnRanges[aColumnIndex],
|
||||||
|
bounds = [self bounds];
|
||||||
|
|
||||||
|
var rMinX = ROUND(tableRange.location);
|
||||||
|
bounds.origin.x = rMinX;
|
||||||
|
bounds.size.width = FLOOR(tableRange.length + tableRange.location - rMinX);
|
||||||
|
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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
|
||||||
|
{
|
||||||
|
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
|
||||||
|
clickedColumn = [self columnAtPoint:mouseLocation];
|
||||||
|
|
||||||
|
// should we send column -1 ?
|
||||||
|
[_tableView _sendDelegateDidMouseDownInHeader:clickedColumn];
|
||||||
|
|
||||||
|
var resizeLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y),
|
||||||
|
resizedColumn = [self columnAtPoint:resizeLocation];
|
||||||
|
|
||||||
|
if (resizedColumn == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 2 different tracking methods: one for resizing/stop-resizing, another one for selection/reordering
|
||||||
|
if ([_tableView allowsColumnResizing]
|
||||||
|
&& CGRectContainsPoint([self _cursorRectForColumn:resizedColumn], mouseLocation))
|
||||||
|
{
|
||||||
|
_resizedColumn = resizedColumn;
|
||||||
|
[_tableView._tableColumns[_resizedColumn] setDisableResizingPosting:YES];
|
||||||
|
[_tableView setDisableAutomaticResizing:YES];
|
||||||
|
[self trackResizeWithEvent:theEvent];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[self _setPressedColumn:clickedColumn];
|
||||||
|
[self trackMouseWithEvent:theEvent];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)trackMouseWithEvent:(CPEvent)theEvent
|
||||||
|
{
|
||||||
|
var type = [theEvent type];
|
||||||
|
|
||||||
|
if (type == CPLeftMouseUp)
|
||||||
|
{
|
||||||
|
var location = [self convertPoint:[theEvent locationInWindow] fromView:nil],
|
||||||
|
clickedColumn = [self columnAtPoint:location];
|
||||||
|
|
||||||
|
[self _setPressedColumn:-1];
|
||||||
|
|
||||||
|
if (clickedColumn != -1)
|
||||||
|
[_tableView _didClickTableColumn:clickedColumn modifierFlags:[theEvent modifierFlags]];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CPApp setTarget:self selector:@selector(trackMouseWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPLeftMouseDownMask untilDate:nil inMode:nil dequeue:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)trackResizeWithEvent:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||||
|
tableColumn = [[_tableView tableColumns] objectAtIndex:_resizedColumn],
|
||||||
|
type = [anEvent type];
|
||||||
|
|
||||||
|
if (_lastLocation == nil)
|
||||||
|
_lastLocation = location;
|
||||||
|
|
||||||
|
if (_columnOldWidth == nil)
|
||||||
|
_columnOldWidth = [tableColumn width];
|
||||||
|
|
||||||
|
if (type === CPLeftMouseUp)
|
||||||
|
{
|
||||||
|
[self _updateResizeCursor:anEvent];
|
||||||
|
|
||||||
|
[tableColumn _postDidResizeNotificationWithOldWidth:_columnOldWidth];
|
||||||
|
[tableColumn setDisableResizingPosting:NO];
|
||||||
|
[_tableView setDisableAutomaticResizing:NO];
|
||||||
|
|
||||||
|
_resizedColumn = -1;
|
||||||
|
_lastLocation = nil;
|
||||||
|
_columnOldWidth = nil;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (type === CPLeftMouseDragged)
|
||||||
|
{
|
||||||
|
var newWidth = [tableColumn width] + location.x - _lastLocation.x;
|
||||||
|
|
||||||
|
if (newWidth < [tableColumn minWidth])
|
||||||
|
[[CPCursor resizeRightCursor] set];
|
||||||
|
else if (newWidth > [tableColumn maxWidth])
|
||||||
|
[[CPCursor resizeLeftCursor] set];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_tableView._lastColumnShouldSnap = NO;
|
||||||
|
[tableColumn setWidth:newWidth];
|
||||||
|
// FIXME: there has to be a better way to do this...
|
||||||
|
// We should refactor the auto resizing crap.
|
||||||
|
// We need to figure out the exact cocoa behavior here though.
|
||||||
|
_lastLocation = location;
|
||||||
|
|
||||||
|
[[CPCursor resizeLeftRightCursor] set];
|
||||||
|
[self setNeedsLayout];
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[CPApp setTarget:self selector:@selector(trackResizeWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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)viewDidMoveToWindow
|
||||||
|
{
|
||||||
|
//if ([_tableView allowsColumnResizing])
|
||||||
|
// [[self window] setAcceptsMouseMovedEvents:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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
|
||||||
|
{
|
||||||
|
var tableColumns = [_tableView tableColumns],
|
||||||
|
count = [tableColumns count];
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var column = [tableColumns objectAtIndex:i],
|
||||||
|
headerView = [column headerView];
|
||||||
|
|
||||||
|
var frame = [self headerRectOfColumn:i];
|
||||||
|
frame.size.height -= 0.5;
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
frame.origin.x += 0.5;
|
||||||
|
frame.size.width -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
[headerView setFrame:frame];
|
||||||
|
|
||||||
|
if([headerView superview] != self)
|
||||||
|
[self addSubview:headerView];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drawRect:(CGRect)aRect
|
||||||
|
{
|
||||||
|
if (!_tableView)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||||
|
exposedColumnIndexes = [_tableView columnIndexesInRect:aRect],
|
||||||
|
columnsArray = [],
|
||||||
|
tableColumns = [_tableView tableColumns],
|
||||||
|
exposedTableColumns = _tableView._exposedColumns,
|
||||||
|
firstIndex = [exposedTableColumns firstIndex],
|
||||||
|
exposedRange = CPMakeRange(firstIndex, [exposedTableColumns lastIndex] - firstIndex + 1);
|
||||||
|
|
||||||
|
CGContextSetLineWidth(context, 1);
|
||||||
|
CGContextSetStrokeColor(context, [_tableView gridColor]);
|
||||||
|
|
||||||
|
[exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:exposedRange];
|
||||||
|
|
||||||
|
var columnArrayIndex = 0,
|
||||||
|
columnArrayCount = columnsArray.length,
|
||||||
|
columnMaxX;
|
||||||
|
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
for(; columnArrayIndex < columnArrayCount; columnArrayIndex++)
|
||||||
|
{
|
||||||
|
// grab each column rect and add vertical lines
|
||||||
|
var columnIndex = columnsArray[columnArrayIndex],
|
||||||
|
columnToStroke = [self headerRectOfColumn:columnIndex];
|
||||||
|
|
||||||
|
columnMaxX = CGRectGetMaxX(columnToStroke);
|
||||||
|
|
||||||
|
CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMinY(columnToStroke)));
|
||||||
|
CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMaxY(columnToStroke)));
|
||||||
|
}
|
||||||
|
|
||||||
|
CGContextClosePath(context);
|
||||||
|
CGContextStrokePath(context);
|
||||||
|
|
||||||
|
/*
|
||||||
|
var maxY = CGRectGetMaxY([self bounds]);
|
||||||
|
// draw normal gradient for remaining space
|
||||||
|
if (supportsCanvasGradient)
|
||||||
|
{
|
||||||
|
aRect.origin.x = columnMaxX - 0.5;
|
||||||
|
aRect.size.width -= columnMaxX;
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
CGContextAddRect(context, CGRectMake(columnMaxX + 1, 0, CGRectGetMaxX([self bounds]) - columnMaxX, CGRectGetHeight([self bounds])));
|
||||||
|
CGContextClosePath(context);
|
||||||
|
CGContextDrawLinearGradient(context, [_CPTableColumnHeaderView headerGradient], CGPointMake(0,0), CGPointMake(0, maxY - 1),0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw bottom line
|
||||||
|
CGContextBeginPath(context);
|
||||||
|
CGContextMoveToPoint(context, 0, maxY - 0.5);
|
||||||
|
CGContextAddLineToPoint(context, CGRectGetMaxX([self bounds]), maxY - 0.5);
|
||||||
|
CGContextClosePath(context);
|
||||||
|
CGContextStrokePath(context);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
|
||||||
|
|
||||||
|
@implementation CPTableHeaderView (CPCoding)
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
if (self = [super initWithCoder:aCoder])
|
||||||
|
{
|
||||||
|
[self _init];
|
||||||
|
_tableView = [aCoder decodeObjectForKey:CPTableHeaderViewTableViewKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
[super encodeWithCoder:aCoder];
|
||||||
|
[aCoder encodeObject:_tableView forKey:CPTableHeaderViewTableViewKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
+3125
-1036
File diff suppressed because it is too large
Load Diff
+319
-154
@@ -24,56 +24,17 @@
|
|||||||
@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 "CoreGraphics/CGGeometry.h"
|
||||||
#include "Platform/Platform.h"
|
#include "Platform/Platform.h"
|
||||||
#include "Platform/DOM/CPDOMDisplayServer.h"
|
#include "Platform/DOM/CPDOMDisplayServer.h"
|
||||||
|
|
||||||
|
CPTextFieldSquareBezel = 0; /*! A textfield bezel with a squared corners. */
|
||||||
|
CPTextFieldRoundedBezel = 1; /*! A textfield bezel with rounded corners. */
|
||||||
|
|
||||||
/*
|
CPTextFieldDidFocusNotification = @"CPTextFieldDidFocusNotification";
|
||||||
@global
|
CPTextFieldDidBlurNotification = @"CPTextFieldDidBlurNotification";
|
||||||
@group CPLineBreakMode
|
|
||||||
*/
|
|
||||||
CPLineBreakByWordWrapping = 0;
|
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPLineBreakMode
|
|
||||||
*/
|
|
||||||
CPLineBreakByCharWrapping = 1;
|
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPLineBreakMode
|
|
||||||
*/
|
|
||||||
CPLineBreakByClipping = 2;
|
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPLineBreakMode
|
|
||||||
*/
|
|
||||||
CPLineBreakByTruncatingHead = 3;
|
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPLineBreakMode
|
|
||||||
*/
|
|
||||||
CPLineBreakByTruncatingTail = 4;
|
|
||||||
/*
|
|
||||||
@global
|
|
||||||
@group CPLineBreakMode
|
|
||||||
*/
|
|
||||||
CPLineBreakByTruncatingMiddle = 5;
|
|
||||||
|
|
||||||
/*
|
|
||||||
A textfield bezel with a squared corners.
|
|
||||||
@global
|
|
||||||
@group CPTextFieldBezelStyle
|
|
||||||
*/
|
|
||||||
CPTextFieldSquareBezel = 0;
|
|
||||||
/*
|
|
||||||
A textfield bezel with rounded corners.
|
|
||||||
@global
|
|
||||||
@group CPTextFieldBezelStyle
|
|
||||||
*/
|
|
||||||
CPTextFieldRoundedBezel = 1;
|
|
||||||
|
|
||||||
|
|
||||||
#if PLATFORM(DOM)
|
#if PLATFORM(DOM)
|
||||||
|
|
||||||
@@ -87,11 +48,7 @@ var CPTextFieldDOMInputElement = nil,
|
|||||||
CPTextFieldInputIsActive = NO,
|
CPTextFieldInputIsActive = NO,
|
||||||
CPTextFieldCachedSelectStartFunction = nil,
|
CPTextFieldCachedSelectStartFunction = nil,
|
||||||
CPTextFieldCachedDragFunction = nil,
|
CPTextFieldCachedDragFunction = nil,
|
||||||
|
CPTextFieldBlurFunction = nil;
|
||||||
CPTextFieldBlurFunction = nil,
|
|
||||||
CPTextFieldKeyUpFunction = nil,
|
|
||||||
CPTextFieldKeyPressFunction = nil,
|
|
||||||
CPTextFieldKeyDownFunction = nil;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -100,7 +57,7 @@ var CPSecureTextFieldCharacter = "\u2022";
|
|||||||
@implementation CPString (CPTextFieldAdditions)
|
@implementation CPString (CPTextFieldAdditions)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the string (<code>self</code>).
|
Returns the string (\c self).
|
||||||
*/
|
*/
|
||||||
- (CPString)string
|
- (CPString)string
|
||||||
{
|
{
|
||||||
@@ -118,6 +75,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
*/
|
*/
|
||||||
@implementation CPTextField : CPControl
|
@implementation CPTextField : CPControl
|
||||||
{
|
{
|
||||||
|
BOOL _isEditing;
|
||||||
|
|
||||||
BOOL _isEditable;
|
BOOL _isEditable;
|
||||||
BOOL _isSelectable;
|
BOOL _isSelectable;
|
||||||
BOOL _isSecure;
|
BOOL _isSecure;
|
||||||
@@ -203,7 +162,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
|
|
||||||
+ (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"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,80 +198,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CPTextFieldKeyDownFunction = function(anEvent)
|
|
||||||
{
|
|
||||||
CPTextFieldTextDidChangeValue = [CPTextFieldInputOwner stringValue];
|
|
||||||
|
|
||||||
CPTextFieldKeyPressFunction(anEvent);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
CPTextFieldKeyPressFunction = function(aDOMEvent)
|
|
||||||
{
|
|
||||||
aDOMEvent = aDOMEvent || window.event;
|
|
||||||
|
|
||||||
if (aDOMEvent.keyCode == CPReturnKeyCode || aDOMEvent.keyCode == CPTabKeyCode)
|
|
||||||
{
|
|
||||||
if (aDOMEvent.preventDefault)
|
|
||||||
aDOMEvent.preventDefault();
|
|
||||||
if (aDOMEvent.stopPropagation)
|
|
||||||
aDOMEvent.stopPropagation();
|
|
||||||
aDOMEvent.cancelBubble = true;
|
|
||||||
|
|
||||||
var owner = CPTextFieldInputOwner;
|
|
||||||
|
|
||||||
if (aDOMEvent && aDOMEvent.keyCode == CPReturnKeyCode)
|
|
||||||
{
|
|
||||||
[owner sendAction:[owner action] to:[owner target]];
|
|
||||||
[[owner window] makeFirstResponder:nil];
|
|
||||||
}
|
|
||||||
else if (aDOMEvent && aDOMEvent.keyCode == CPTabKeyCode)
|
|
||||||
{
|
|
||||||
if (!aDOMEvent.shiftKey)
|
|
||||||
[[owner window] selectNextKeyView:owner];
|
|
||||||
else
|
|
||||||
[[owner window] selectPreviousKeyView:owner];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
|
||||||
}
|
|
||||||
|
|
||||||
CPTextFieldKeyUpFunction = function()
|
|
||||||
{
|
|
||||||
[CPTextFieldInputOwner setStringValue:CPTextFieldDOMInputElement.value];
|
|
||||||
|
|
||||||
if ([CPTextFieldInputOwner stringValue] !== CPTextFieldTextDidChangeValue)
|
|
||||||
{
|
|
||||||
CPTextFieldTextDidChangeValue = [CPTextFieldInputOwner stringValue];
|
|
||||||
[CPTextFieldInputOwner textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:CPTextFieldInputOwner userInfo:nil]];
|
|
||||||
}
|
|
||||||
|
|
||||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
|
||||||
}
|
|
||||||
|
|
||||||
CPTextFieldHandleBlur = function(anEvent)
|
CPTextFieldHandleBlur = function(anEvent)
|
||||||
{
|
{
|
||||||
var owner = CPTextFieldInputOwner;
|
|
||||||
CPTextFieldInputOwner = nil;
|
CPTextFieldInputOwner = nil;
|
||||||
|
|
||||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (document.attachEvent)
|
|
||||||
{
|
|
||||||
CPTextFieldDOMInputElement.attachEvent("on" + CPDOMEventKeyUp, CPTextFieldKeyUpFunction);
|
|
||||||
CPTextFieldDOMInputElement.attachEvent("on" + CPDOMEventKeyDown, CPTextFieldKeyDownFunction);
|
|
||||||
CPTextFieldDOMInputElement.attachEvent("on" + CPDOMEventKeyPress, CPTextFieldKeyPressFunction);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CPTextFieldDOMInputElement.addEventListener(CPDOMEventKeyUp, CPTextFieldKeyUpFunction, NO);
|
|
||||||
CPTextFieldDOMInputElement.addEventListener(CPDOMEventKeyDown, CPTextFieldKeyDownFunction, NO);
|
|
||||||
CPTextFieldDOMInputElement.addEventListener(CPDOMEventKeyPress, CPTextFieldKeyPressFunction, NO);
|
|
||||||
}
|
|
||||||
|
|
||||||
//FIXME make this not onblur
|
//FIXME make this not onblur
|
||||||
CPTextFieldDOMInputElement.onblur = CPTextFieldBlurFunction;
|
CPTextFieldDOMInputElement.onblur = CPTextFieldBlurFunction;
|
||||||
|
|
||||||
@@ -343,10 +235,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
CPTextFieldDOMPasswordInputElement.style.outline = "none";
|
CPTextFieldDOMPasswordInputElement.style.outline = "none";
|
||||||
CPTextFieldDOMPasswordInputElement.type = "password";
|
CPTextFieldDOMPasswordInputElement.type = "password";
|
||||||
|
|
||||||
CPTextFieldDOMPasswordInputElement.attachEvent("on" + CPDOMEventKeyUp, CPTextFieldKeyUpFunction);
|
|
||||||
CPTextFieldDOMPasswordInputElement.attachEvent("on" + CPDOMEventKeyDown, CPTextFieldKeyDownFunction);
|
|
||||||
CPTextFieldDOMPasswordInputElement.attachEvent("on" + CPDOMEventKeyPress, CPTextFieldKeyPressFunction);
|
|
||||||
|
|
||||||
CPTextFieldDOMPasswordInputElement.onblur = CPTextFieldBlurFunction;
|
CPTextFieldDOMPasswordInputElement.onblur = CPTextFieldBlurFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,7 +277,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the textfield is currently editable by the user.
|
Returns \c YES if the textfield is currently editable by the user.
|
||||||
*/
|
*/
|
||||||
- (BOOL)isEditable
|
- (BOOL)isEditable
|
||||||
{
|
{
|
||||||
@@ -398,7 +286,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether the field's text is selectable by the user.
|
Sets whether the field's text is selectable by the user.
|
||||||
@param aFlag <code>YES</code> makes the text selectable
|
@param aFlag \c YES makes the text selectable
|
||||||
*/
|
*/
|
||||||
- (void)setSelectable:(BOOL)aFlag
|
- (void)setSelectable:(BOOL)aFlag
|
||||||
{
|
{
|
||||||
@@ -406,7 +294,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the field's text is selectable by the user.
|
Returns \c YES if the field's text is selectable by the user.
|
||||||
*/
|
*/
|
||||||
- (BOOL)isSelectable
|
- (BOOL)isSelectable
|
||||||
{
|
{
|
||||||
@@ -415,7 +303,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether the field's text is secure.
|
Sets whether the field's text is secure.
|
||||||
@param aFlag <code>YES</code> makes the text secure
|
@param aFlag \c YES makes the text secure
|
||||||
*/
|
*/
|
||||||
- (void)setSecure:(BOOL)aFlag
|
- (void)setSecure:(BOOL)aFlag
|
||||||
{
|
{
|
||||||
@@ -423,7 +311,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the field's text is secure (password entry).
|
Returns \c YES if the field's text is secure (password entry).
|
||||||
*/
|
*/
|
||||||
- (BOOL)isSecure
|
- (BOOL)isSecure
|
||||||
{
|
{
|
||||||
@@ -433,7 +321,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
// Setting the Bezel Style
|
// Setting the Bezel Style
|
||||||
/*!
|
/*!
|
||||||
Sets whether the textfield will have a bezeled border.
|
Sets whether the textfield will have a bezeled border.
|
||||||
@param shouldBeBezeled <code>YES</code> means the textfield will draw a bezeled border
|
@param shouldBeBezeled \c YES means the textfield will draw a bezeled border
|
||||||
*/
|
*/
|
||||||
- (void)setBezeled:(BOOL)shouldBeBezeled
|
- (void)setBezeled:(BOOL)shouldBeBezeled
|
||||||
{
|
{
|
||||||
@@ -444,7 +332,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the textfield draws a bezeled border.
|
Returns \c YES if the textfield draws a bezeled border.
|
||||||
*/
|
*/
|
||||||
- (BOOL)isBezeled
|
- (BOOL)isBezeled
|
||||||
{
|
{
|
||||||
@@ -478,7 +366,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether the textfield will have a border drawn.
|
Sets whether the textfield will have a border drawn.
|
||||||
@param shouldBeBordered <code>YES</code> makes the textfield draw a border
|
@param shouldBeBordered \c YES makes the textfield draw a border
|
||||||
*/
|
*/
|
||||||
- (void)setBordered:(BOOL)shouldBeBordered
|
- (void)setBordered:(BOOL)shouldBeBordered
|
||||||
{
|
{
|
||||||
@@ -489,7 +377,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the textfield has a border.
|
Returns \c YES if the textfield has a border.
|
||||||
*/
|
*/
|
||||||
- (BOOL)isBordered
|
- (BOOL)isBordered
|
||||||
{
|
{
|
||||||
@@ -498,7 +386,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether the textfield will have a background drawn.
|
Sets whether the textfield will have a background drawn.
|
||||||
@param shouldDrawBackground <code>YES</code> makes the textfield draw a background
|
@param shouldDrawBackground \c YES makes the textfield draw a background
|
||||||
*/
|
*/
|
||||||
- (void)setDrawsBackground:(BOOL)shouldDrawBackground
|
- (void)setDrawsBackground:(BOOL)shouldDrawBackground
|
||||||
{
|
{
|
||||||
@@ -512,7 +400,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the textfield draws a background.
|
Returns \c YES if the textfield draws a background.
|
||||||
*/
|
*/
|
||||||
- (BOOL)drawsBackground
|
- (BOOL)drawsBackground
|
||||||
{
|
{
|
||||||
@@ -551,8 +439,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
/* @ignore */
|
/* @ignore */
|
||||||
- (BOOL)becomeFirstResponder
|
- (BOOL)becomeFirstResponder
|
||||||
{
|
{
|
||||||
|
#if PLATFORM(DOM)
|
||||||
if (CPTextFieldInputOwner && [CPTextFieldInputOwner window] !== [self window])
|
if (CPTextFieldInputOwner && [CPTextFieldInputOwner window] !== [self window])
|
||||||
[[CPTextFieldInputOwner window] makeFirstResponder:nil];
|
[[CPTextFieldInputOwner window] makeFirstResponder:nil];
|
||||||
|
#endif
|
||||||
|
|
||||||
[self setThemeState:CPThemeStateEditing];
|
[self setThemeState:CPThemeStateEditing];
|
||||||
|
|
||||||
@@ -560,6 +450,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
|
|
||||||
[self setNeedsLayout];
|
[self setNeedsLayout];
|
||||||
|
|
||||||
|
_isEditing = NO;
|
||||||
|
|
||||||
#if PLATFORM(DOM)
|
#if PLATFORM(DOM)
|
||||||
|
|
||||||
var string = [self stringValue],
|
var string = [self stringValue],
|
||||||
@@ -570,6 +462,15 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
element.style.font = [[self currentValueForThemeAttribute:@"font"] cssString];
|
element.style.font = [[self currentValueForThemeAttribute:@"font"] cssString];
|
||||||
element.style.zIndex = 1000;
|
element.style.zIndex = 1000;
|
||||||
|
|
||||||
|
switch ([self alignment])
|
||||||
|
{
|
||||||
|
case CPCenterTextAlignment: element.style.textAlign = "center";
|
||||||
|
break;
|
||||||
|
case CPRightTextAlignment: element.style.textAlign = "right";
|
||||||
|
break;
|
||||||
|
default: element.style.textAlign = "left";
|
||||||
|
}
|
||||||
|
|
||||||
var contentRect = [self contentRectForBounds:[self bounds]];
|
var contentRect = [self contentRectForBounds:[self bounds]];
|
||||||
|
|
||||||
element.style.top = _CGRectGetMinY(contentRect) + "px";
|
element.style.top = _CGRectGetMinY(contentRect) + "px";
|
||||||
@@ -582,25 +483,24 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
window.setTimeout(function()
|
window.setTimeout(function()
|
||||||
{
|
{
|
||||||
element.focus();
|
element.focus();
|
||||||
|
[self textDidFocus:[CPNotification notificationWithName:CPTextFieldDidFocusNotification object:self userInfo:nil]];
|
||||||
CPTextFieldInputOwner = self;
|
CPTextFieldInputOwner = self;
|
||||||
}, 0.0);
|
}, 0.0);
|
||||||
|
|
||||||
//post CPControlTextDidBeginEditingNotification
|
element.value = [self stringValue];
|
||||||
[self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
|
|
||||||
|
|
||||||
[[CPDOMWindowBridge sharedDOMWindowBridge] _propagateCurrentDOMEvent:YES];
|
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||||
|
|
||||||
CPTextFieldInputIsActive = YES;
|
CPTextFieldInputIsActive = YES;
|
||||||
|
|
||||||
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 () {};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
@@ -640,15 +540,32 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
CPTextFieldCachedSelectStartFunction = nil;
|
CPTextFieldCachedSelectStartFunction = nil;
|
||||||
CPTextFieldCachedDragFunction = nil;
|
CPTextFieldCachedDragFunction = nil;
|
||||||
|
|
||||||
document.body.ondrag = CPTextFieldCachedDragFunction
|
[[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
|
||||||
document.body.onselectstart = CPTextFieldCachedSelectStartFunction
|
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//post CPControlTextDidEndEditingNotification
|
//post CPControlTextDidEndEditingNotification
|
||||||
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
|
if (_isEditing)
|
||||||
|
{
|
||||||
|
_isEditing = NO;
|
||||||
|
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
|
||||||
|
|
||||||
|
if ([self sendsActionOnEndEditing])
|
||||||
|
[self sendAction:[self action] to:[self target]];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self textDidBlur:[CPNotification notificationWithName:CPTextFieldDidBlurNotification object:self userInfo:nil]];
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Text fields require panels to become key window, so this returns \c YES.
|
||||||
|
*/
|
||||||
|
- (BOOL)needsPanelToBecomeKey
|
||||||
|
{
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -661,6 +578,89 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
return [[self nextResponder] mouseDown:anEvent];
|
return [[self nextResponder] mouseDown:anEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)mouseUp:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
if (![self isEditable] || ![self isEnabled])
|
||||||
|
[[self nextResponder] mouseUp:anEvent];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseDragged:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
if (![self isEditable] || ![self isEnabled])
|
||||||
|
[[self nextResponder] mouseDragged:anEvent];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)keyUp:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
var oldValue = [self stringValue];
|
||||||
|
[self _setStringValue:[self _inputElement].value];
|
||||||
|
|
||||||
|
if (oldValue !== [self stringValue])
|
||||||
|
{
|
||||||
|
if (!_isEditing)
|
||||||
|
{
|
||||||
|
_isEditing = YES;
|
||||||
|
[self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
|
||||||
|
}
|
||||||
|
|
||||||
|
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)keyDown:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
if ([anEvent keyCode] === CPReturnKeyCode)
|
||||||
|
{
|
||||||
|
if (_isEditing)
|
||||||
|
{
|
||||||
|
_isEditing = NO;
|
||||||
|
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self sendAction:[self action] to:[self target]];
|
||||||
|
[self selectText:nil];
|
||||||
|
|
||||||
|
[[[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
|
||||||
|
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||||
|
|
||||||
|
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)textDidBlur:(CPNotification)note
|
||||||
|
{
|
||||||
|
//this looks to prevent false propagation of notifications for other objects
|
||||||
|
if([note object] != self)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[[CPNotificationCenter defaultCenter] postNotification:note];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)textDidFocus:(CPNotification)note
|
||||||
|
{
|
||||||
|
//this looks to prevent false propagation of notifications for other objects
|
||||||
|
if([note object] != self)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[[CPNotificationCenter defaultCenter] postNotification:note];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the string the text field.
|
Returns the string the text field.
|
||||||
*/
|
*/
|
||||||
@@ -672,10 +672,24 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
/*
|
/*
|
||||||
@ignore
|
@ignore
|
||||||
*/
|
*/
|
||||||
|
- (void)_setStringValue:(id)aValue
|
||||||
|
{
|
||||||
|
[self willChangeValueForKey:@"objectValue"];
|
||||||
|
[super setObjectValue:String(aValue)];
|
||||||
|
[self _updatePlaceholderState];
|
||||||
|
[self didChangeValueForKey:@"objectValue"];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setObjectValue:(id)aValue
|
- (void)setObjectValue:(id)aValue
|
||||||
{
|
{
|
||||||
[super setObjectValue:aValue];
|
[super setObjectValue:aValue];
|
||||||
|
|
||||||
|
#if PLATFORM(DOM)
|
||||||
|
|
||||||
|
if (CPTextFieldInputOwner === self || [[self window] firstResponder] === self)
|
||||||
|
[self _inputElement].value = aValue;
|
||||||
|
#endif
|
||||||
|
|
||||||
[self _updatePlaceholderState];
|
[self _updatePlaceholderState];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -683,7 +697,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
{
|
{
|
||||||
var string = [self stringValue];
|
var string = [self stringValue];
|
||||||
|
|
||||||
if ((!string || [string length] === 0) && ![self hasThemeState:CPThemeStateEditing])
|
if ((!string || string.length === 0) && ![self hasThemeState:CPThemeStateEditing])
|
||||||
[self setThemeState:CPTextFieldStatePlaceholder];
|
[self setThemeState:CPTextFieldStatePlaceholder];
|
||||||
else
|
else
|
||||||
[self unsetThemeState:CPTextFieldStatePlaceholder];
|
[self unsetThemeState:CPTextFieldStatePlaceholder];
|
||||||
@@ -763,11 +777,151 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
#if PLATFORM(DOM)
|
#if PLATFORM(DOM)
|
||||||
var element = [self _inputElement];
|
var element = [self _inputElement];
|
||||||
|
|
||||||
if (element.parentNode == _DOMElement && ([self isEditable] || [self isSelectable]))
|
if (([self isEditable] || [self isSelectable]))
|
||||||
element.select();
|
{
|
||||||
|
if ([[self window] firstResponder] === self)
|
||||||
|
window.setTimeout(function() { element.select(); }, 0);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[[self window] makeFirstResponder:self];
|
||||||
|
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
|
||||||
|
{
|
||||||
|
[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
|
||||||
@@ -780,6 +934,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
[defaultCenter removeObserver:_delegate name:CPControlTextDidBeginEditingNotification object:self];
|
[defaultCenter removeObserver:_delegate name:CPControlTextDidBeginEditingNotification object:self];
|
||||||
[defaultCenter removeObserver:_delegate name:CPControlTextDidChangeNotification object:self];
|
[defaultCenter removeObserver:_delegate name:CPControlTextDidChangeNotification object:self];
|
||||||
[defaultCenter removeObserver:_delegate name:CPControlTextDidEndEditingNotification object:self];
|
[defaultCenter removeObserver:_delegate name:CPControlTextDidEndEditingNotification object:self];
|
||||||
|
[defaultCenter removeObserver:_delegate name:CPTextFieldDidFocusNotification object:self];
|
||||||
|
[defaultCenter removeObserver:_delegate name:CPTextFieldDidBlurNotification object:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
_delegate = aDelegate;
|
_delegate = aDelegate;
|
||||||
@@ -806,6 +962,19 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
|||||||
name:CPControlTextDidEndEditingNotification
|
name:CPControlTextDidEndEditingNotification
|
||||||
object:self];
|
object:self];
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(controlTextDidFocus:)])
|
||||||
|
[defaultCenter
|
||||||
|
addObserver:_delegate
|
||||||
|
selector:@selector(controlTextDidFocus:)
|
||||||
|
name:CPTextFieldDidFocusNotification
|
||||||
|
object:self];
|
||||||
|
|
||||||
|
if ([_delegate respondsToSelector:@selector(controlTextDidBlur:)])
|
||||||
|
[defaultCenter
|
||||||
|
addObserver:_delegate
|
||||||
|
selector:@selector(controlTextDidBlur:)
|
||||||
|
name:CPTextFieldDidBlurNotification
|
||||||
|
object:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)delegate
|
- (id)delegate
|
||||||
@@ -869,6 +1038,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -924,13 +1095,7 @@ var secureStringForString = function(aString)
|
|||||||
if (!aString)
|
if (!aString)
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
var secureString = "",
|
return Array(aString.length+1).join(CPSecureTextFieldCharacter);
|
||||||
length = aString.length;
|
|
||||||
|
|
||||||
while (length--)
|
|
||||||
secureString += CPSecureTextFieldCharacter;
|
|
||||||
|
|
||||||
return secureString;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+33
-2
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
@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;
|
||||||
@@ -531,7 +531,7 @@ function CPThemeAttributeEncode(aCoder, aThemeAttribute)
|
|||||||
|
|
||||||
function CPThemeAttributeDecode(aCoder, anAttributeName, aDefaultValue, aTheme, aClass)
|
function CPThemeAttributeDecode(aCoder, anAttributeName, aDefaultValue, aTheme, aClass)
|
||||||
{
|
{
|
||||||
var key = "$a" + anAttributeName;
|
var key = "$a" + anAttributeName;
|
||||||
|
|
||||||
if (![aCoder containsValueForKey:key])
|
if (![aCoder containsValueForKey:key])
|
||||||
var attribute = [[_CPThemeAttribute alloc] initWithName:anAttributeName defaultValue:aDefaultValue];
|
var attribute = [[_CPThemeAttribute alloc] initWithName:anAttributeName defaultValue:aDefaultValue];
|
||||||
@@ -555,3 +555,34 @@ function CPThemeAttributeDecode(aCoder, anAttributeName, aDefaultValue, aTheme,
|
|||||||
|
|
||||||
return attribute;
|
return attribute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TO AUTO CREATE THESE:
|
||||||
|
function bit_count(bits)
|
||||||
|
{
|
||||||
|
var count = 0;
|
||||||
|
|
||||||
|
while (bits)
|
||||||
|
{
|
||||||
|
++count;
|
||||||
|
bits &= (bits - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return count ;
|
||||||
|
}
|
||||||
|
|
||||||
|
zeros = "000000000";
|
||||||
|
|
||||||
|
function pad(string, digits)
|
||||||
|
{
|
||||||
|
return zeros.substr(0, digits - string.length) + string;
|
||||||
|
}
|
||||||
|
|
||||||
|
var str = ""
|
||||||
|
str += '[';
|
||||||
|
for (i = 0;i < Math.pow(2,6);++i)
|
||||||
|
{
|
||||||
|
str += bit_count(i) + " /*" + pad(i.toString(2),6) + "*" + "/, ";
|
||||||
|
}
|
||||||
|
print(str+']');
|
||||||
|
|
||||||
|
*/
|
||||||
+9
-15
@@ -43,7 +43,7 @@
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_bundle = [[CPBundle alloc] initWithPath:aURL + "/Info.plist"];
|
_bundle = [[CPBundle alloc] initWithPath:aURL];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -58,25 +58,19 @@
|
|||||||
|
|
||||||
- (void)bundleDidFinishLoading:(CPBundle)aBundle
|
- (void)bundleDidFinishLoading:(CPBundle)aBundle
|
||||||
{
|
{
|
||||||
var paths = [_bundle objectForInfoDictionaryKey:@"CPBundleReplacedFiles"],
|
var themes = [_bundle objectForInfoDictionaryKey:@"CPKeyedThemes"],
|
||||||
index = 0,
|
count = themes.length;
|
||||||
count = paths.length,
|
|
||||||
bundlePath = [_bundle bundlePath];
|
|
||||||
|
|
||||||
while (count--)
|
while (count--)
|
||||||
{
|
{
|
||||||
var path = paths[count];
|
var path = [aBundle pathForResource:themes[count]],
|
||||||
|
unarchiver = [[_CPThemeKeyedUnarchiver alloc]
|
||||||
|
initForReadingWithData:[[CPURL URLWithString:path] staticResourceData]
|
||||||
|
bundle:_bundle];
|
||||||
|
|
||||||
if ([path pathExtension] === "keyedtheme")
|
[unarchiver decodeObjectForKey:@"root"];
|
||||||
{
|
|
||||||
var unarchiver = [[_CPThemeKeyedUnarchiver alloc]
|
|
||||||
initForReadingWithData:[CPData dataWithString:objj_files[bundlePath + '/' + path].contents]
|
|
||||||
bundle:_bundle];
|
|
||||||
|
|
||||||
[unarchiver decodeObjectForKey:@"root"];
|
[unarchiver finishDecoding];
|
||||||
|
|
||||||
[unarchiver finishDecoding];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[_loadDelegate blendDidFinishLoading:self];
|
[_loadDelegate blendDidFinishLoading:self];
|
||||||
|
|||||||
+506
-229
@@ -28,6 +28,8 @@
|
|||||||
@import "CPPopUpButton.j"
|
@import "CPPopUpButton.j"
|
||||||
@import "CPToolbarItem.j"
|
@import "CPToolbarItem.j"
|
||||||
|
|
||||||
|
#include "CoreGraphics/CGGeometry.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@global
|
@global
|
||||||
@@ -76,9 +78,9 @@ var CPToolbarConfigurationsByIdentifier = nil;
|
|||||||
Called to obtain a toolbar item. Required.
|
Called to obtain a toolbar item. Required.
|
||||||
@param toolbar the toolbar the item belongs to
|
@param toolbar the toolbar the item belongs to
|
||||||
@param itemIdentifier the identifier of the toolbar item
|
@param itemIdentifier the identifier of the toolbar item
|
||||||
@param flag <code>YES</code> means the item will be placed in the toolbar. <code>NO</code> means the item will be displayed for
|
@param flag \c YES means the item will be placed in the toolbar. \c NO means the item will be displayed for
|
||||||
some other purpose (non-functional)
|
some other purpose (non-functional)
|
||||||
@return the toolbar item or <code>nil</code> if no such item belongs in the toolbar
|
@return the toolbar item or \c nil if no such item belongs in the toolbar
|
||||||
*/
|
*/
|
||||||
@implementation CPToolbar : CPObject
|
@implementation CPToolbar : CPObject
|
||||||
{
|
{
|
||||||
@@ -128,6 +130,11 @@ var CPToolbarConfigurationsByIdentifier = nil;
|
|||||||
[toolbarsSharingIdentifier addObject:toolbar];
|
[toolbarsSharingIdentifier addObject:toolbar];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
return [self initWithIdentifier:@""];
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Initializes the toolbar with the specified identifier.
|
Initializes the toolbar with the specified identifier.
|
||||||
@param anIdentifier the identifier for the toolbar
|
@param anIdentifier the identifier for the toolbar
|
||||||
@@ -176,7 +183,7 @@ var CPToolbarConfigurationsByIdentifier = nil;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the toolbar is currently visible
|
Returns \c YES if the toolbar is currently visible
|
||||||
*/
|
*/
|
||||||
- (BOOL)isVisible
|
- (BOOL)isVisible
|
||||||
{
|
{
|
||||||
@@ -185,7 +192,7 @@ var CPToolbarConfigurationsByIdentifier = nil;
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether the toolbar should be visible.
|
Sets whether the toolbar should be visible.
|
||||||
@param aFlag <code>YES</code> makes the toolbar visible
|
@param aFlag \c YES makes the toolbar visible
|
||||||
*/
|
*/
|
||||||
- (void)setVisible:(BOOL)aFlag
|
- (void)setVisible:(BOOL)aFlag
|
||||||
{
|
{
|
||||||
@@ -213,7 +220,7 @@ var CPToolbarConfigurationsByIdentifier = nil;
|
|||||||
*/
|
*/
|
||||||
- (void)setDelegate:(id)aDelegate
|
- (void)setDelegate:(id)aDelegate
|
||||||
{
|
{
|
||||||
if (_delegate == aDelegate)
|
if (_delegate === aDelegate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_delegate = aDelegate;
|
_delegate = aDelegate;
|
||||||
@@ -245,34 +252,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];
|
||||||
}
|
}
|
||||||
@@ -304,13 +322,22 @@ var CPToolbarConfigurationsByIdentifier = nil;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the toolbar items sorted by their <code>visibilityPriority</code>(ies).
|
Returns the toolbar items sorted by their \c visibilityPriority(ies).
|
||||||
*/
|
*/
|
||||||
- (CPArray)itemsSortedByVisibilityPriority
|
- (CPArray)itemsSortedByVisibilityPriority
|
||||||
{
|
{
|
||||||
return _itemsSortedByVisibilityPriority;
|
return _itemsSortedByVisibilityPriority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)validateVisibleToolbarItems
|
||||||
|
{
|
||||||
|
var toolbarItems = [self visibleItems],
|
||||||
|
count = [toolbarItems count];
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
[toolbarItems[count] validate];
|
||||||
|
}
|
||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
- (id)_itemForItemIdentifier:(CPString)identifier willBeInsertedIntoToolbar:(BOOL)toolbar
|
- (id)_itemForItemIdentifier:(CPString)identifier willBeInsertedIntoToolbar:(BOOL)toolbar
|
||||||
{
|
{
|
||||||
@@ -323,7 +350,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];
|
||||||
@@ -343,33 +370,67 @@ 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)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Initializes the toolbar by unarchiving data from <code>aCoder</code>.
|
Initializes the toolbar by unarchiving data from \c aCoder.
|
||||||
@param aCoder the coder containing the archived CPToolbar.
|
@param aCoder the coder containing the archived CPToolbar.
|
||||||
*/
|
*/
|
||||||
- (id)initWithCoder:(CPCoder)aCoder
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
@@ -378,21 +439,34 @@ var CPToolbarIdentifierKey = "CPToolbarIdentifierKey",
|
|||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_identifier = [aCoder decodeObjectForKey:CPToolbarIdentifierKey];
|
_identifier = [aCoder decodeObjectForKey:CPToolbarIdentifierKey];
|
||||||
_displayMode = [aCoder decodeIntForKey:CPToolbarDisplayModeKey];
|
_displayMode = [aCoder decodeIntForKey:CPToolbarDisplayModeKey];
|
||||||
_showsBaselineSeparator = [aCoder decodeBoolForKey:CPToolbarShowsBaselineSeparatorKey];
|
_showsBaselineSeparator = [aCoder decodeBoolForKey:CPToolbarShowsBaselineSeparatorKey];
|
||||||
_allowsUserCustomization = [aCoder decodeBoolForKey:CPToolbarAllowsUserCustomizationKey];
|
_allowsUserCustomization = [aCoder decodeBoolForKey:CPToolbarAllowsUserCustomizationKey];
|
||||||
_isVisible = [aCoder decodeBoolForKey:CPToolbarIsVisibleKey];
|
_isVisible = [aCoder decodeBoolForKey:CPToolbarIsVisibleKey];
|
||||||
|
|
||||||
_identifiedItems = [aCoder decodeObjectForKey:CPToolbarIdentifiedItemsKey];
|
_identifiedItems = [aCoder decodeObjectForKey:CPToolbarIdentifiedItemsKey];
|
||||||
_defaultItems = [aCoder decodeObjectForKey:CPToolbarDefaultItemsKey];
|
_defaultItems = [aCoder decodeObjectForKey:CPToolbarDefaultItemsKey];
|
||||||
_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?
|
||||||
|
[self _reloadToolbarItems];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -404,18 +478,18 @@ var CPToolbarIdentifierKey = "CPToolbarIdentifierKey",
|
|||||||
*/
|
*/
|
||||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
{
|
{
|
||||||
[aCoder encodeObject:_identifier forKey:CPToolbarIdentifierKey];
|
[aCoder encodeObject:_identifier forKey:CPToolbarIdentifierKey];
|
||||||
[aCoder encodeInt:_displayMode forKey:CPToolbarDisplayModeKey];
|
[aCoder encodeInt:_displayMode forKey:CPToolbarDisplayModeKey];
|
||||||
[aCoder encodeBool:_showsBaselineSeparator forKey:CPToolbarShowsBaselineSeparatorKey];
|
[aCoder encodeBool:_showsBaselineSeparator forKey:CPToolbarShowsBaselineSeparatorKey];
|
||||||
[aCoder encodeBool:_allowsUserCustomization forKey:CPToolbarAllowsUserCustomizationKey];
|
[aCoder encodeBool:_allowsUserCustomization forKey:CPToolbarAllowsUserCustomizationKey];
|
||||||
[aCoder encodeBool:_isVisible forKey:CPToolbarIsVisibleKey];
|
[aCoder encodeBool:_isVisible forKey:CPToolbarIsVisibleKey];
|
||||||
|
|
||||||
[aCoder encodeObject:_identifiedItems forKey:CPToolbarIdentifiedItemsKey];
|
[aCoder encodeObject:_identifiedItems forKey:CPToolbarIdentifiedItemsKey];
|
||||||
[aCoder encodeObject:_defaultItems forKey:CPToolbarDefaultItemsKey];
|
[aCoder encodeObject:_defaultItems forKey:CPToolbarDefaultItemsKey];
|
||||||
[aCoder encodeObject:_allowedItems forKey:CPToolbarAllowedItemsKey];
|
[aCoder encodeObject:_allowedItems forKey:CPToolbarAllowedItemsKey];
|
||||||
[aCoder encodeObject:_selectableItems forKey:CPToolbarSelectableItemsKey];
|
[aCoder encodeObject:_selectableItems forKey:CPToolbarSelectableItemsKey];
|
||||||
|
|
||||||
[aCoder encodeConditionalObject:_delegate forKey:CPToolbarDelegateKey];
|
[aCoder encodeConditionalObject:_delegate forKey:CPToolbarDelegateKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -443,8 +517,9 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
|||||||
CPIndexSet _visibleFlexibleWidthIndexes;
|
CPIndexSet _visibleFlexibleWidthIndexes;
|
||||||
|
|
||||||
CPDictionary _itemInfos;
|
CPDictionary _itemInfos;
|
||||||
|
JSObject _viewsForToolbarItems;
|
||||||
|
|
||||||
CPArray _visibleItems;
|
CPArray _visibleItems @accessors(readonly, property=visibleItems);
|
||||||
CPArray _invisibleItems;
|
CPArray _invisibleItems;
|
||||||
|
|
||||||
CPPopUpButton _additionalItemsButton;
|
CPPopUpButton _additionalItemsButton;
|
||||||
@@ -452,11 +527,13 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
|||||||
CPColor _labelShadowColor;
|
CPColor _labelShadowColor;
|
||||||
|
|
||||||
float _minWidth;
|
float _minWidth;
|
||||||
|
|
||||||
|
BOOL _FIXME_isHUD;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)initialize
|
+ (void)initialize
|
||||||
{
|
{
|
||||||
if (self != [_CPToolbarView class])
|
if (self !== [_CPToolbarView class])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var bundle = [CPBundle bundleForClass:self];
|
var bundle = [CPBundle bundleForClass:self];
|
||||||
@@ -499,47 +576,37 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
|||||||
return _toolbar;
|
return _toolbar;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setLabelColor:(CPColor)aColor
|
- (void)FIXME_setIsHUD:(BOOL)shouldBeHUD
|
||||||
{
|
{
|
||||||
if (_labelColor === aColor)
|
if (_FIXME_isHUD === shouldBeHUD)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_labelColor = aColor;
|
_FIXME_isHUD = shouldBeHUD;
|
||||||
|
|
||||||
var items = [_toolbar items],
|
var items = [_toolbar items],
|
||||||
count = [items count];
|
count = [items count];
|
||||||
|
|
||||||
while (count--)
|
while (count--)
|
||||||
[[self labelForItem:items[count]] setTextColor:_labelColor];
|
[[self viewForItem:items[count]] FIXME_setIsHUD:shouldBeHUD];
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setLabelShadowColor:(CPColor)aColor
|
|
||||||
{
|
|
||||||
if (_labelShadowColor === aColor)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_labelShadowColor = aColor;
|
|
||||||
|
|
||||||
var items = [_toolbar items],
|
|
||||||
count = [items count];
|
|
||||||
|
|
||||||
while (count--)
|
|
||||||
[[self labelForItem:items[count]] setTextShadowColor:_labelShadowColor];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This *should* be roughly O(3N) = O(N)
|
// This *should* be roughly O(3N) = O(N)
|
||||||
- (void)resizeSubviewsWithOldSize:(CGSize)aSize
|
- (void)resizeSubviewsWithOldSize:(CGSize)aSize
|
||||||
{
|
{
|
||||||
[self layoutSubviews];
|
[self tile];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)layoutSubviews
|
- (_CPToolbarItemView)viewForItem:(CPToolbarItem)anItem
|
||||||
|
{
|
||||||
|
return _viewsForToolbarItems[[anItem UID]] || nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tile
|
||||||
{
|
{
|
||||||
// We begin by recalculating the visible items.
|
// We begin by recalculating the visible items.
|
||||||
var items = [_toolbar items],
|
var items = [_toolbar items],
|
||||||
width = CGRectGetWidth([self bounds]),
|
itemsWidth = CGRectGetWidth([self bounds]),
|
||||||
minWidth = _minWidth,
|
minWidth = _minWidth,
|
||||||
flexibleItemIndexes = [CPIndexSet indexSet],
|
|
||||||
// FIXME: This should be a CPSet.
|
// FIXME: This should be a CPSet.
|
||||||
invisibleItemsSortedByPriority = [];
|
invisibleItemsSortedByPriority = [];
|
||||||
|
|
||||||
@@ -547,60 +614,72 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
|||||||
|
|
||||||
// We only have hidden items if our actual width is smaller than our
|
// We only have hidden items if our actual width is smaller than our
|
||||||
// minimum width for hiding items.
|
// minimum width for hiding items.
|
||||||
if (width < minWidth)
|
if (itemsWidth < minWidth)
|
||||||
{
|
{
|
||||||
width -= TOOLBAR_EXTRA_ITEMS_WIDTH;
|
itemsWidth -= TOOLBAR_EXTRA_ITEMS_WIDTH;
|
||||||
|
|
||||||
_visibleItems = [_visibleItems copy];
|
_visibleItems = [_visibleItems copy];
|
||||||
|
|
||||||
var itemsSortedByVisibilityPriority = [_toolbar itemsSortedByVisibilityPriority],
|
var itemsSortedByVisibilityPriority = [_toolbar itemsSortedByVisibilityPriority],
|
||||||
count = itemsSortedByVisibilityPriority.length;
|
count = itemsSortedByVisibilityPriority.length;
|
||||||
|
|
||||||
// While our items take up too much space...
|
// Remove items until we fit:
|
||||||
while (minWidth > width)
|
// The assumption here is that there are more visible items than there are
|
||||||
|
// invisible items, if not it would be faster to add items until we *no
|
||||||
|
// longer fit*.
|
||||||
|
while (minWidth > itemsWidth && count)
|
||||||
{
|
{
|
||||||
var item = itemsSortedByVisibilityPriority[count--];
|
var item = itemsSortedByVisibilityPriority[--count],
|
||||||
|
view = [self viewForItem:item];
|
||||||
|
|
||||||
minWidth -= [self minWidthForItem:item] + TOOLBAR_ITEM_MARGIN;
|
minWidth -= [view minSize].width + TOOLBAR_ITEM_MARGIN;
|
||||||
|
|
||||||
[_visibleItems removeObjectIdenticalTo:item];
|
[_visibleItems removeObjectIdenticalTo:item];
|
||||||
[invisibleItemsSortedByPriority addObject:item];
|
[invisibleItemsSortedByPriority addObject:item];
|
||||||
|
|
||||||
[[self viewForItem:item] setHidden:YES];
|
[view setHidden:YES];
|
||||||
[[self labelForItem:item] setHidden:YES];
|
[view FIXME_setIsHUD:_FIXME_isHUD];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine all the items that have flexible width.
|
// FIXME: minHeight?
|
||||||
// Also determine the height of the toolbar.
|
var count = [items count],
|
||||||
// NOTE: height is height without top margin, and bottom margin/label.
|
|
||||||
var index = _visibleItems.length,
|
|
||||||
height = 0.0;
|
height = 0.0;
|
||||||
|
|
||||||
while (index--)
|
while (count--)
|
||||||
{
|
{
|
||||||
var item = _visibleItems[index],
|
var view = [self viewForItem:items[count]],
|
||||||
minSize = [item minSize],
|
minSize = [view minSize];
|
||||||
view = [self viewForItem:item];
|
|
||||||
|
|
||||||
if (minSize.width != [item maxSize].width)
|
|
||||||
[flexibleItemIndexes addIndex:index];
|
|
||||||
|
|
||||||
// If the item doesn't have flexible width, then make sure it's set to the static width (min==max)
|
|
||||||
// This handles the case where the user did setView: with a view of a different size than minSize/maxSize
|
|
||||||
else
|
|
||||||
[view setFrameSize:CGSizeMake([item minSize].width, CGRectGetHeight([view frame]))];
|
|
||||||
|
|
||||||
// FIXME: minHeight?
|
|
||||||
|
|
||||||
[view setHidden:NO];
|
|
||||||
[[self labelForItem:item] setHidden:NO];
|
|
||||||
|
|
||||||
if (height < minSize.height)
|
if (height < minSize.height)
|
||||||
height = minSize.height;
|
height = minSize.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
var remainingSpace = width - minWidth,
|
// Determine all the items that have flexible width.
|
||||||
|
// Also determine the height of the toolbar.
|
||||||
|
var count = _visibleItems.length
|
||||||
|
flexibleItemIndexes = [CPIndexSet indexSet];
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
{
|
||||||
|
var item = _visibleItems[count],
|
||||||
|
view = [self viewForItem:item],
|
||||||
|
minSize = [view minSize];
|
||||||
|
|
||||||
|
if (minSize.width !== [view maxSize].width)
|
||||||
|
[flexibleItemIndexes addIndex:count];
|
||||||
|
|
||||||
|
// FIXME: Is this still necessary? (probably not since we iterate them all below).
|
||||||
|
// If the item doesn't have flexible width, then make sure it's set to the
|
||||||
|
// static width (min==max). This handles the case where the user did setView:
|
||||||
|
// with a view of a different size than minSize/maxSize
|
||||||
|
else
|
||||||
|
[view setFrameSize:CGSizeMake(minSize.width, height)];
|
||||||
|
|
||||||
|
[view setHidden:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
var remainingSpace = itemsWidth - minWidth,
|
||||||
proportionate = 0.0;
|
proportionate = 0.0;
|
||||||
|
|
||||||
// Continue to distribute space proportionately while we have it,
|
// Continue to distribute space proportionately while we have it,
|
||||||
@@ -616,14 +695,12 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
|||||||
|
|
||||||
var index = CPNotFound;
|
var index = CPNotFound;
|
||||||
|
|
||||||
while ((index = [flexibleItemIndexes indexGreaterThanIndex:index]) != CPNotFound)
|
while ((index = [flexibleItemIndexes indexGreaterThanIndex:index]) !== CPNotFound)
|
||||||
{
|
{
|
||||||
var item = _visibleItems[index];
|
var item = _visibleItems[index],
|
||||||
view = [self viewForItem:item],
|
view = [self viewForItem:item],
|
||||||
viewFrame = [view frame],
|
proposedWidth = [view minSize].width + proportionate,
|
||||||
// FIXME: Should this be minWidthForItem: ?
|
constrainedWidth = MIN(proposedWidth, [view maxSize].width);
|
||||||
proposedWidth = [item minSize].width + proportionate,
|
|
||||||
constrainedWidth = MIN(proposedWidth, [item maxSize].width);
|
|
||||||
|
|
||||||
if (constrainedWidth < proposedWidth)
|
if (constrainedWidth < proposedWidth)
|
||||||
{
|
{
|
||||||
@@ -632,50 +709,26 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
|||||||
remainingSpace += proposedWidth - constrainedWidth;
|
remainingSpace += proposedWidth - constrainedWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
[view setFrameSize:CGSizeMake(constrainedWidth, CGRectGetHeight(viewFrame))];
|
[view setFrameSize:CGSizeMake(constrainedWidth, height)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that all the visible items are the correct width, position them accordingly.
|
// Now that all the visible items are the correct width, give them their final frames.
|
||||||
var count = _visibleItems.length,
|
var index = 0,
|
||||||
x = TOOLBAR_ITEM_MARGIN,
|
count = _visibleItems.length,
|
||||||
fullHeightItems = [];
|
x = TOOLBAR_ITEM_MARGIN;
|
||||||
|
|
||||||
for (index = 0; index < count; ++index)
|
for (; index < count; ++index)
|
||||||
{
|
{
|
||||||
var item = _visibleItems[index],
|
var view = [self viewForItem:_visibleItems[index]],
|
||||||
view = [self viewForItem:item],
|
viewWidth = CGRectGetWidth([view frame]);
|
||||||
|
|
||||||
viewFrame = [view frame],
|
[view setFrame:CGRectMake(x, 0.0, viewWidth, height)];
|
||||||
viewWidth = CGRectGetWidth(viewFrame),
|
|
||||||
|
|
||||||
label = [self labelForItem:item],
|
x += viewWidth + TOOLBAR_ITEM_MARGIN;
|
||||||
labelFrame = [label frame],
|
|
||||||
labelWidth = CGRectGetWidth(labelFrame),
|
|
||||||
|
|
||||||
itemWidth = MAX([self minWidthForItem:item], viewWidth),
|
|
||||||
|
|
||||||
viewHeight = CGRectGetHeight(viewFrame);
|
|
||||||
|
|
||||||
// itemWidth != viewWidth. itemWidth is MAX(size of view, size of label). If the label is larger,
|
|
||||||
// *center* the view, don't resize it.
|
|
||||||
[view setFrame:CGRectMake(x + (itemWidth - viewWidth) / 2.0, TOOLBAR_TOP_MARGIN + (height - viewHeight) / 2.0, viewWidth, viewHeight)];
|
|
||||||
[label setFrameOrigin:CGPointMake(x + (itemWidth - labelWidth) / 2.0, TOOLBAR_TOP_MARGIN + height + 2.0)];
|
|
||||||
|
|
||||||
x += itemWidth + TOOLBAR_ITEM_MARGIN;
|
|
||||||
|
|
||||||
if ([item itemIdentifier] == CPToolbarSeparatorItemIdentifier)
|
|
||||||
fullHeightItems.push(item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (index = 0, count = fullHeightItems.length; index < count; ++index)
|
var needsAdditionalItemsButton = NO;
|
||||||
{
|
|
||||||
var view = [self viewForItem:fullHeightItems[index]],
|
|
||||||
viewHeight = 53.0;
|
|
||||||
|
|
||||||
// FIXME: Variable Height
|
|
||||||
[view setFrame:CGRectMake(CGRectGetMinX([view frame]), (59.0 - viewHeight) / 2.0, CGRectGetWidth([view frame]), viewHeight)];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([invisibleItemsSortedByPriority count])
|
if ([invisibleItemsSortedByPriority count])
|
||||||
{
|
{
|
||||||
@@ -688,25 +741,53 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
|||||||
{
|
{
|
||||||
var item = items[index];
|
var item = items[index];
|
||||||
|
|
||||||
if ([invisibleItemsSortedByPriority indexOfObjectIdenticalTo:item] != CPNotFound)
|
if ([invisibleItemsSortedByPriority indexOfObjectIdenticalTo:item] !== CPNotFound)
|
||||||
|
{
|
||||||
[_invisibleItems addObject:item];
|
[_invisibleItems addObject:item];
|
||||||
}
|
|
||||||
|
|
||||||
[_additionalItemsButton setFrameOrigin:CGPointMake(width + 5.0, (CGRectGetHeight([self bounds]) - CGRectGetHeight([_additionalItemsButton frame])) / 2.0)];
|
var identifier = [item itemIdentifier];
|
||||||
|
|
||||||
|
if (identifier !== CPToolbarSpaceItemIdentifier &&
|
||||||
|
identifier !== CPToolbarFlexibleSpaceItemIdentifier &&
|
||||||
|
identifier !== CPToolbarSeparatorItemIdentifier)
|
||||||
|
needsAdditionalItemsButton = YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needsAdditionalItemsButton)
|
||||||
|
{
|
||||||
|
[_additionalItemsButton setFrameOrigin:CGPointMake(itemsWidth + 5.0, (CGRectGetHeight([self bounds]) - CGRectGetHeight([_additionalItemsButton frame])) / 2.0)];
|
||||||
|
|
||||||
[self addSubview:_additionalItemsButton];
|
[self addSubview:_additionalItemsButton];
|
||||||
|
|
||||||
[_additionalItemsButton removeAllItems];
|
[_additionalItemsButton removeAllItems];
|
||||||
|
|
||||||
var index = 0,
|
|
||||||
count = [_invisibleItems count];
|
|
||||||
|
|
||||||
[_additionalItemsButton addItemWithTitle:@"Additional Items"];
|
[_additionalItemsButton addItemWithTitle:@"Additional Items"];
|
||||||
[[_additionalItemsButton itemArray][0] setImage:_CPToolbarViewExtraItemsImage];
|
[[_additionalItemsButton itemArray][0] setImage:_CPToolbarViewExtraItemsImage];
|
||||||
|
|
||||||
|
var index = 0,
|
||||||
|
count = [_invisibleItems count],
|
||||||
|
hasNonSeparatorItem = NO;
|
||||||
|
|
||||||
for (; index < count; ++index)
|
for (; index < count; ++index)
|
||||||
{
|
{
|
||||||
var item = _invisibleItems[index];
|
var item = _invisibleItems[index],
|
||||||
|
identifier = [item itemIdentifier];
|
||||||
|
|
||||||
|
if (identifier === CPToolbarSpaceItemIdentifier ||
|
||||||
|
identifier === CPToolbarFlexibleSpaceItemIdentifier)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (identifier === CPToolbarSeparatorItemIdentifier)
|
||||||
|
{
|
||||||
|
if (hasNonSeparatorItem)
|
||||||
|
[_additionalItemsButton addItem:[CPMenuItem separatorItem]];
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasNonSeparatorItem = YES;
|
||||||
|
|
||||||
[_additionalItemsButton addItemWithTitle:[item label]];
|
[_additionalItemsButton addItemWithTitle:[item label]];
|
||||||
|
|
||||||
@@ -720,37 +801,6 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
[_additionalItemsButton removeFromSuperview];
|
[_additionalItemsButton removeFromSuperview];
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPView)viewForItem:(CPToolbarItem)anItem
|
|
||||||
{
|
|
||||||
var info = [_itemInfos objectForKey:[anItem hash]];
|
|
||||||
|
|
||||||
if (!info)
|
|
||||||
return nil;
|
|
||||||
|
|
||||||
return info.view;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CPTextField)labelForItem:(CPToolbarItem)anItem
|
|
||||||
{
|
|
||||||
var info = [_itemInfos objectForKey:[anItem hash]];
|
|
||||||
|
|
||||||
if (!info)
|
|
||||||
return nil;
|
|
||||||
|
|
||||||
return info.label;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (float)minWidthForItem:(CPToolbarItem)anItem
|
|
||||||
{
|
|
||||||
var info = [_itemInfos objectForKey:[anItem hash]];
|
|
||||||
|
|
||||||
if (!info)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return info.minWidth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)reloadToolbarItems
|
- (void)reloadToolbarItems
|
||||||
@@ -768,62 +818,21 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
|||||||
|
|
||||||
count = items.length;
|
count = items.length;
|
||||||
|
|
||||||
_itemInfos = [CPDictionary dictionary];
|
|
||||||
_minWidth = TOOLBAR_ITEM_MARGIN;
|
_minWidth = TOOLBAR_ITEM_MARGIN;
|
||||||
|
_viewsForToolbarItems = { };
|
||||||
|
|
||||||
for (; index < count; ++index)
|
for (; index < count; ++index)
|
||||||
{
|
{
|
||||||
var item = items[index],
|
var item = items[index],
|
||||||
view = [item view];
|
view = [[_CPToolbarItemView alloc] initWithToolbarItem:item toolbar:self];
|
||||||
|
|
||||||
// If this item doesn't have a custom view, create a standard one.
|
|
||||||
if (!view)
|
|
||||||
{
|
|
||||||
view = [[CPButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 32.0, 32.0)];
|
|
||||||
|
|
||||||
[view setBordered:NO];
|
|
||||||
|
|
||||||
[view setImage:[item image]];
|
|
||||||
[view setAlternateImage:[item alternateImage]];
|
|
||||||
|
|
||||||
[view setTarget:[item target]];
|
|
||||||
[view setAction:[item action]];
|
|
||||||
|
|
||||||
[view setTag:[item tag]];
|
|
||||||
|
|
||||||
[view setImagePosition:CPImageOnly];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
_viewsForToolbarItems[[item UID]] = view;
|
||||||
[self addSubview:view];
|
[self addSubview:view];
|
||||||
|
|
||||||
// Create a lable for this item.
|
_minWidth += [view minSize].width + TOOLBAR_ITEM_MARGIN;
|
||||||
var label = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
|
||||||
|
|
||||||
[label setStringValue:[item label]];
|
|
||||||
[label setFont:[CPFont systemFontOfSize:11.0]];
|
|
||||||
[label setTextColor:_labelColor];
|
|
||||||
[label setTextShadowColor:_labelShadowColor];
|
|
||||||
[label setTextShadowOffset:CGSizeMake(0, 1)];
|
|
||||||
[label sizeToFit];
|
|
||||||
|
|
||||||
[label setTarget:[item target]];
|
|
||||||
[label setAction:[item action]];
|
|
||||||
|
|
||||||
[self addSubview:label];
|
|
||||||
|
|
||||||
var minSize = [item minSize],
|
|
||||||
minWidth = MAX(minSize.width, CGRectGetWidth([label frame]));
|
|
||||||
|
|
||||||
[_itemInfos setObject:_CPToolbarItemInfoMake(index, view, label, minWidth) forKey:[item hash]];
|
|
||||||
|
|
||||||
_minWidth += minWidth + TOOLBAR_ITEM_MARGIN;
|
|
||||||
|
|
||||||
// If the minSize is different than the maxSize, then this item has flexible width.
|
|
||||||
//if (minSize.width != [item maxSize].width)
|
|
||||||
// [_flexibleWidthIndexes addIndex:index];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[self layoutSubviews];
|
[self tile];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -842,3 +851,271 @@ var _CPToolbarItemVisibilityPriorityCompare = function(lhs, rhs)
|
|||||||
|
|
||||||
return CPOrderedDescending;
|
return CPOrderedDescending;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var TOP_MARGIN = 5.0,
|
||||||
|
LABEL_MARGIN = 2.0;
|
||||||
|
|
||||||
|
@implementation _CPToolbarItemView : CPControl
|
||||||
|
{
|
||||||
|
CGSize _minSize @accessors(readonly, property=minSize);
|
||||||
|
CGSize _maxSize @accessors(readonly, property=maxSize);
|
||||||
|
CGSize _labelSize;
|
||||||
|
|
||||||
|
CPToolbarItem _toolbarItem;
|
||||||
|
CPToolbar _toolbar;
|
||||||
|
|
||||||
|
CPImageView _imageView;
|
||||||
|
CPView _view;
|
||||||
|
|
||||||
|
CPTextField _labelField;
|
||||||
|
|
||||||
|
BOOL _FIXME_isHUD;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithToolbarItem:(CPToolbarItem)aToolbarItem toolbar:(CPToolbar)aToolbar
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_toolbarItem = aToolbarItem;
|
||||||
|
|
||||||
|
_labelField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||||
|
|
||||||
|
[_labelField setFont:[CPFont systemFontOfSize:11.0]];
|
||||||
|
[_labelField setTextColor:[self FIXME_labelColor]];
|
||||||
|
[_labelField setTextShadowColor:[self FIXME_labelShadowColor]];
|
||||||
|
[_labelField setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||||
|
[_labelField setAutoresizingMask:CPViewWidthSizable | CPViewMinXMargin];
|
||||||
|
|
||||||
|
[self addSubview:_labelField];
|
||||||
|
|
||||||
|
[self updateFromItem];
|
||||||
|
|
||||||
|
_toolbar = aToolbar;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)FIXME_setIsHUD:(BOOL)shouldBeHUD
|
||||||
|
{
|
||||||
|
_FIXME_isHUD = shouldBeHUD;
|
||||||
|
[_labelField setTextColor:[self FIXME_labelColor]];
|
||||||
|
[_labelField setTextShadowColor:[self FIXME_labelShadowColor]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateFromItem
|
||||||
|
{
|
||||||
|
var identifier = [_toolbarItem itemIdentifier];
|
||||||
|
|
||||||
|
if (identifier === CPToolbarSpaceItemIdentifier ||
|
||||||
|
identifier === CPToolbarFlexibleSpaceItemIdentifier ||
|
||||||
|
identifier === CPToolbarSeparatorItemIdentifier)
|
||||||
|
{
|
||||||
|
[_view removeFromSuperview];
|
||||||
|
[_imageView removeFromSuperview];
|
||||||
|
|
||||||
|
_minSize = [_toolbarItem minSize];
|
||||||
|
_maxSize = [_toolbarItem maxSize];
|
||||||
|
|
||||||
|
if (identifier === CPToolbarSeparatorItemIdentifier)
|
||||||
|
{
|
||||||
|
_view = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 2.0, 32.0)];
|
||||||
|
|
||||||
|
// FIXME: Get rid of this old API!!!
|
||||||
|
sizes = {};
|
||||||
|
sizes[@"CPToolbarItemSeparator"] = [CGSizeMake(2.0, 26.0), CGSizeMake(2.0, 1.0), CGSizeMake(2.0, 26.0)];
|
||||||
|
[_view setBackgroundColor:_CPControlThreePartImagePattern(YES, sizes, @"CPToolbarItem", @"Separator")];
|
||||||
|
|
||||||
|
[self addSubview:_view];
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self setTarget:[_toolbarItem target]];
|
||||||
|
[self setAction:[_toolbarItem action]];
|
||||||
|
|
||||||
|
var view = [_toolbarItem view] || nil;
|
||||||
|
|
||||||
|
if (view !== _view)
|
||||||
|
{
|
||||||
|
if (!view)
|
||||||
|
[_view removeFromSuperview];
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[self addSubview:view];
|
||||||
|
[_imageView removeFromSuperview];
|
||||||
|
}
|
||||||
|
|
||||||
|
_view = view;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_view)
|
||||||
|
{
|
||||||
|
if (!_imageView)
|
||||||
|
{
|
||||||
|
_imageView = [[CPImageView alloc] initWithFrame:[self bounds]];
|
||||||
|
|
||||||
|
[_imageView setImageScaling:CPScaleNone];
|
||||||
|
|
||||||
|
[self addSubview:_imageView];
|
||||||
|
}
|
||||||
|
|
||||||
|
[_imageView setImage:[_toolbarItem image]];
|
||||||
|
}
|
||||||
|
|
||||||
|
var minSize = [_toolbarItem minSize],
|
||||||
|
maxSize = [_toolbarItem maxSize];
|
||||||
|
|
||||||
|
[_labelField setStringValue:[_toolbarItem label]];
|
||||||
|
[_labelField sizeToFit]; // FIXME
|
||||||
|
|
||||||
|
[self setEnabled:[_toolbarItem isEnabled]];
|
||||||
|
|
||||||
|
_labelSize = [_labelField frame].size;
|
||||||
|
|
||||||
|
_minSize = CGSizeMake(MAX(_labelSize.width, minSize.width), _labelSize.height + minSize.height + LABEL_MARGIN + TOP_MARGIN);
|
||||||
|
_maxSize = CGSizeMake(MAX(_labelSize.width, minSize.width), 100000000.0);
|
||||||
|
|
||||||
|
[_toolbar tile];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)layoutSubviews
|
||||||
|
{
|
||||||
|
var identifier = [_toolbarItem itemIdentifier];
|
||||||
|
|
||||||
|
if (identifier === CPToolbarSpaceItemIdentifier ||
|
||||||
|
identifier === CPToolbarFlexibleSpaceItemIdentifier)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var bounds = [self bounds],
|
||||||
|
width = _CGRectGetWidth(bounds);
|
||||||
|
|
||||||
|
if (identifier === CPToolbarSeparatorItemIdentifier)
|
||||||
|
return [_view setFrame:CGRectMake(ROUND((width - 2.0) / 2.0), 0.0, 2.0, _CGRectGetHeight(bounds))];
|
||||||
|
|
||||||
|
var view = _view || _imageView,
|
||||||
|
itemMaxSize = [_toolbarItem maxSize],
|
||||||
|
height = _CGRectGetHeight(bounds) - _labelSize.height - LABEL_MARGIN - TOP_MARGIN,
|
||||||
|
viewWidth = MIN(itemMaxSize.width, width),
|
||||||
|
viewHeight = MIN(itemMaxSize.height, height);
|
||||||
|
|
||||||
|
[view setFrame:CGRectMake( ROUND((width - viewWidth) / 2.0),
|
||||||
|
TOP_MARGIN + ROUND((height - viewHeight) / 2.0),
|
||||||
|
viewWidth,
|
||||||
|
viewHeight)];
|
||||||
|
|
||||||
|
[_labelField setFrameOrigin:CGPointMake(ROUND((width - _labelSize.width) / 2.0), TOP_MARGIN + height + LABEL_MARGIN)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseDown:(CPEvent)anEvent
|
||||||
|
{
|
||||||
|
if ([_toolbarItem view])
|
||||||
|
return [[self nextResponder] mouseDown:anEvent];
|
||||||
|
|
||||||
|
var identifier = [_toolbarItem itemIdentifier];
|
||||||
|
|
||||||
|
if (identifier === CPToolbarSpaceItemIdentifier ||
|
||||||
|
identifier === CPToolbarFlexibleSpaceItemIdentifier ||
|
||||||
|
identifier === CPToolbarSeparatorItemIdentifier)
|
||||||
|
return [[self nextResponder] mouseDown:anEvent];
|
||||||
|
|
||||||
|
[super mouseDown:anEvent];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setEnabled:(BOOL)shouldBeEnabled
|
||||||
|
{
|
||||||
|
[super setEnabled:shouldBeEnabled];
|
||||||
|
|
||||||
|
if (shouldBeEnabled)
|
||||||
|
{
|
||||||
|
[_imageView setAlphaValue:1.0];
|
||||||
|
[_labelField setAlphaValue:1.0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[_imageView setAlphaValue:0.5];
|
||||||
|
[_labelField setAlphaValue:0.5];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPColor)FIXME_labelColor
|
||||||
|
{
|
||||||
|
if (_FIXME_isHUD)
|
||||||
|
return [CPColor whiteColor];
|
||||||
|
|
||||||
|
return [CPColor blackColor];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPColor)FIXME_labelShadowColor
|
||||||
|
{
|
||||||
|
if (_FIXME_isHUD)
|
||||||
|
return [self isHighlighted] ? [CPColor colorWithWhite:1.0 alpha:0.5] : [CPColor clearColor];
|
||||||
|
|
||||||
|
return [self isHighlighted] ? [CPColor colorWithWhite:0.0 alpha:0.3] : [CPColor colorWithWhite:1.0 alpha:0.75];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setHighlighted:(BOOL)shouldBeHighlighted
|
||||||
|
{
|
||||||
|
[super setHighlighted:shouldBeHighlighted];
|
||||||
|
|
||||||
|
if (shouldBeHighlighted)
|
||||||
|
{
|
||||||
|
var alternateImage = [_toolbarItem alternateImage];
|
||||||
|
|
||||||
|
if (alternateImage)
|
||||||
|
[_imageView setImage:alternateImage];
|
||||||
|
|
||||||
|
[_labelField setTextShadowOffset:CGSizeMakeZero()];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var image = [_toolbarItem image];
|
||||||
|
|
||||||
|
if (image)
|
||||||
|
[_imageView setImage:image];
|
||||||
|
|
||||||
|
[_labelField setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||||
|
}
|
||||||
|
|
||||||
|
[_labelField setTextShadowColor:[self FIXME_labelShadowColor]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sendAction:(SEL)anAction to:(id)aSender
|
||||||
|
{
|
||||||
|
[CPApp sendAction:anAction to:aSender from:_toolbarItem];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)observeValueForKeyPath:(CPString)aKeyPath
|
||||||
|
ofObject:(id)anObject
|
||||||
|
change:(CPDictionary)aChange
|
||||||
|
context:(id)aContext
|
||||||
|
{
|
||||||
|
if (aKeyPath === "enabled")
|
||||||
|
[self setEnabled:[anObject isEnabled]];
|
||||||
|
|
||||||
|
else if (aKeyPath === @"target")
|
||||||
|
[self setTarget:[anObject target]];
|
||||||
|
|
||||||
|
else if (aKeyPath === @"action")
|
||||||
|
[self setAction:[anObject action]];
|
||||||
|
|
||||||
|
else
|
||||||
|
[self updateFromItem];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|||||||
+172
-82
@@ -26,35 +26,18 @@
|
|||||||
@import <AppKit/CPImage.j>
|
@import <AppKit/CPImage.j>
|
||||||
@import <AppKit/CPView.j>
|
@import <AppKit/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
|
||||||
@@ -84,6 +67,13 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
|||||||
CGSize _maxSize;
|
CGSize _maxSize;
|
||||||
|
|
||||||
int _visibilityPriority;
|
int _visibilityPriority;
|
||||||
|
|
||||||
|
BOOL _autovalidates;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
return [self initWithItemIdentifier:@""];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creating a Toolbar Item
|
// Creating a Toolbar Item
|
||||||
@@ -107,6 +97,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
|||||||
_maxSize = CGSizeMakeZero();
|
_maxSize = CGSizeMakeZero();
|
||||||
|
|
||||||
_visibilityPriority = CPToolbarItemVisibilityPriorityStandard;
|
_visibilityPriority = CPToolbarItemVisibilityPriorityStandard;
|
||||||
|
_autovalidates = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -129,6 +120,12 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
|||||||
return _toolbar;
|
return _toolbar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* @ignore */
|
||||||
|
- (void)_setToolbar:(CPToolbar)aToolbar
|
||||||
|
{
|
||||||
|
_toolbar = aToolbar;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the item's label
|
Returns the item's label
|
||||||
*/
|
*/
|
||||||
@@ -183,7 +180,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;
|
||||||
}
|
}
|
||||||
@@ -223,7 +220,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the target of the action that is triggered when the user clicks this item. <code>nil</code> will cause
|
Sets the target of the action that is triggered when the user clicks this item. \c nil will cause
|
||||||
the action to be passed on to the first responder.
|
the action to be passed on to the first responder.
|
||||||
@param aTarget the new target
|
@param aTarget the new target
|
||||||
*/
|
*/
|
||||||
@@ -261,7 +258,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the item is enabled.
|
Returns \c YES if the item is enabled.
|
||||||
*/
|
*/
|
||||||
- (BOOL)isEnabled
|
- (BOOL)isEnabled
|
||||||
{
|
{
|
||||||
@@ -273,7 +270,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether the item is enabled.
|
Sets whether the item is enabled.
|
||||||
@param aFlag <code>YES</code> enables the item
|
@param aFlag \c YES enables the item
|
||||||
*/
|
*/
|
||||||
- (void)setEnabled:(BOOL)shouldBeEnabled
|
- (void)setEnabled:(BOOL)shouldBeEnabled
|
||||||
{
|
{
|
||||||
@@ -308,8 +305,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];
|
||||||
|
|
||||||
@@ -388,6 +385,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
|
||||||
@@ -408,6 +408,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
|
||||||
@@ -444,6 +447,128 @@ CPToolbarItemVisibilityPriorityUser
|
|||||||
_visibilityPriority = aVisibilityPriority;
|
_visibilityPriority = aVisibilityPriority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)validate
|
||||||
|
{
|
||||||
|
// View items do not do any target-action analysis.
|
||||||
|
if (_view)
|
||||||
|
{
|
||||||
|
if ([target respondsToSelector:@selector(validateToolbarItem:)])
|
||||||
|
[self setEnabled:[target validateToolbarItem:self]];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var action = [self action];
|
||||||
|
|
||||||
|
if (!action)
|
||||||
|
return [self setEnabled:NO];
|
||||||
|
|
||||||
|
var target = [self target];
|
||||||
|
|
||||||
|
if (target && ![target respondsToSelector:action])
|
||||||
|
return [self setEnabled:NO];
|
||||||
|
|
||||||
|
target = [CPApp targetForAction:action to:target from:self];
|
||||||
|
|
||||||
|
if (!target)
|
||||||
|
return [self setEnabled:NO];
|
||||||
|
|
||||||
|
if ([target respondsToSelector:@selector(validateToolbarItem:)])
|
||||||
|
[self setEnabled:[target validateToolbarItem:self]];
|
||||||
|
else
|
||||||
|
[self setEnabled:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)autovalidates
|
||||||
|
{
|
||||||
|
return _autovalidates;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setAutovalidates:(BOOL)shouldAutovalidate
|
||||||
|
{
|
||||||
|
_autovalidates = !!shouldAutovalidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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
|
@end
|
||||||
|
|
||||||
@implementation CPToolbarItem (CPCopying)
|
@implementation CPToolbarItem (CPCopying)
|
||||||
@@ -455,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]];
|
||||||
@@ -464,13 +591,15 @@ CPToolbarItemVisibilityPriorityUser
|
|||||||
[copy setAction:[self action]];
|
[copy setAction:[self action]];
|
||||||
|
|
||||||
[copy setEnabled:[self isEnabled]];
|
[copy setEnabled:[self isEnabled]];
|
||||||
[copy setImage:_image];
|
|
||||||
[copy setAlternateImage:_alternateImage];
|
[copy setImage:[self image]];
|
||||||
|
[copy setAlternateImage:[self alternateImage]];
|
||||||
|
|
||||||
[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;
|
||||||
}
|
}
|
||||||
@@ -479,62 +608,17 @@ CPToolbarItemVisibilityPriorityUser
|
|||||||
|
|
||||||
// Standard toolbar identifiers
|
// Standard toolbar identifiers
|
||||||
|
|
||||||
var _CPToolbarSeparatorItemView = nil,
|
|
||||||
_CPToolbarSpaceItemView = nil;
|
|
||||||
|
|
||||||
@implementation CPToolbarItem (Standard)
|
@implementation CPToolbarItem (Standard)
|
||||||
|
|
||||||
+ (CPView)_separatorItemView
|
|
||||||
{
|
|
||||||
if (!_CPToolbarSeparatorItemView)
|
|
||||||
{
|
|
||||||
_CPToolbarSeparatorItemView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 2.0, 32.0)];
|
|
||||||
|
|
||||||
sizes = {};
|
|
||||||
sizes[@"CPToolbarItemSeparator"] = [CGSizeMake(2.0, 26.0), CGSizeMake(2.0, 1.0), CGSizeMake(2.0, 26.0)];
|
|
||||||
[_CPToolbarSeparatorItemView setBackgroundColor:_CPControlThreePartImagePattern(YES, sizes, @"CPToolbarItem", @"Separator")];
|
|
||||||
}
|
|
||||||
|
|
||||||
return _CPToolbarSeparatorItemView;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (CPView)_spaceItemView
|
|
||||||
{
|
|
||||||
if (!_CPToolbarSpaceItemView)
|
|
||||||
_CPToolbarSpaceItemView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
|
||||||
|
|
||||||
return _CPToolbarSpaceItemView;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
+ (CPToolbarItem)_standardItemWithItemIdentifier:(CPString)anItemIdentifier
|
+ (CPToolbarItem)_standardItemWithItemIdentifier:(CPString)anItemIdentifier
|
||||||
{
|
{
|
||||||
var item = [[CPToolbarItem alloc] initWithItemIdentifier:anItemIdentifier];
|
|
||||||
|
|
||||||
switch (anItemIdentifier)
|
switch (anItemIdentifier)
|
||||||
{
|
{
|
||||||
case CPToolbarSeparatorItemIdentifier: [item setView:[self _separatorItemView]];
|
case CPToolbarSeparatorItemIdentifier: return [_CPToolbarSeparatorItem new];
|
||||||
|
case CPToolbarSpaceItemIdentifier: return [_CPToolbarSpaceItem new];
|
||||||
[item setMinSize:CGSizeMake(2.0, 0.0)];
|
case CPToolbarFlexibleSpaceItemIdentifier: return [_CPToolbarFlexibleSpaceItem new];
|
||||||
[item setMaxSize:CGSizeMake(2.0, 100000.0)];
|
case CPToolbarShowColorsItemIdentifier: return [_CPToolbarShowColorsItem new];
|
||||||
|
|
||||||
return item;
|
|
||||||
|
|
||||||
case CPToolbarSpaceItemIdentifier: [item setView:[self _spaceItemView]];
|
|
||||||
|
|
||||||
[item setMinSize:CGSizeMake(32.0, 32.0)];
|
|
||||||
[item setMaxSize:CGSizeMake(32.0, 32.0)];
|
|
||||||
|
|
||||||
return item;
|
|
||||||
|
|
||||||
case CPToolbarFlexibleSpaceItemIdentifier: [item setView:[self _spaceItemView]];
|
|
||||||
|
|
||||||
[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;
|
||||||
@@ -544,3 +628,9 @@ var _CPToolbarSeparatorItemView = nil,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@import "_CPToolbarFlexibleSpaceItem.j"
|
||||||
|
@import "_CPToolbarShowColorsItem.j"
|
||||||
|
@import "_CPToolbarSeparatorItem.j"
|
||||||
|
@import "_CPToolbarSpaceItem.j"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
|
||||||
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
|
|
||||||
|
@implementation CPTreeNode : CPObject
|
||||||
|
{
|
||||||
|
id _representedObject @accessors(readonly, property=representedObject);
|
||||||
|
|
||||||
|
CPTreeNode _parentNode @accessors(readonly, property=parentNode);
|
||||||
|
CPMutableArray _childNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)treeNodeWithRepresentedObject:(id)anObject
|
||||||
|
{
|
||||||
|
return [[self alloc] initWithRepresentedObject:anObject];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithRepresentedObject:(id)anObject
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_representedObject = anObject;
|
||||||
|
_childNodes = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isLeaf
|
||||||
|
{
|
||||||
|
return [_childNodes count] <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPArray)childNodes
|
||||||
|
{
|
||||||
|
return [_childNodes copy];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPMutableArray)mutableChildNodes
|
||||||
|
{
|
||||||
|
return [self mutableArrayValueForKey:@"childNodes"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)insertObject:(id)aTreeNode inChildNodesAtIndex:(CPInteger)anIndex
|
||||||
|
{
|
||||||
|
[[aTreeNode._parentNode mutableChildNodes] removeObjectIdenticalTo:aTreeNode];
|
||||||
|
|
||||||
|
aTreeNode._parentNode = self;
|
||||||
|
|
||||||
|
[_childNodes insertObject:aTreeNode atIndex:anIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeObjectFromChildNodesAtIndex:(CPInteger)anIndex
|
||||||
|
{
|
||||||
|
[_childNodes objectAtIndex:anIndex]._parentNode = nil;
|
||||||
|
|
||||||
|
[_childNodes removeObjectAtIndex:anIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)replaceObjectFromChildNodesAtIndex:(CPInteger)anIndex withObject:(id)aTreeNode
|
||||||
|
{
|
||||||
|
var oldTreeNode = [_childNodes objectAtIndex:anIndex];
|
||||||
|
|
||||||
|
oldTreeNode._parentNode = nil;
|
||||||
|
aTreeNode._parentNode = self;
|
||||||
|
|
||||||
|
[_childNodes replaceObjectAtIndex:anIndex withObject:aTreeNode];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)objectInChildNodesAtIndex:(CPInteger)anIndex
|
||||||
|
{
|
||||||
|
return _childNodes[anIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)sortWithSortDescriptors:(CPArray)sortDescriptors recursively:(BOOL)shouldSortRecursively
|
||||||
|
{
|
||||||
|
[_childNodes sortUsingDescriptors:sortDescriptors];
|
||||||
|
|
||||||
|
if (!shouldSortRecursively)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var count = [_childNodes count];
|
||||||
|
|
||||||
|
while (count--)
|
||||||
|
[_childNodes[count] sortWithSortDescriptors:sortDescriptors recursively:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
@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
|
||||||
+360
-127
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
* CPFlashView.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 <AppKit/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:(NSAnimationProgress)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 = CPRectMakeZero();
|
||||||
|
|
||||||
|
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 = CPRectMakeZero();
|
||||||
|
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:CPRectIsNull(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:CPRectIsNull(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPRect)_startFrame:(CPDictionary)dictionary
|
||||||
|
{
|
||||||
|
var startFrame = [dictionary valueForKey:CPViewAnimationStartFrameKey];
|
||||||
|
if (!startFrame)
|
||||||
|
return [[self _targetView:dictionary] frame];
|
||||||
|
|
||||||
|
return startFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPRect)_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
|
||||||
@@ -0,0 +1,294 @@
|
|||||||
|
/*
|
||||||
|
* CPViewController.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Nicholas Small and Francisco Tolmasky.
|
||||||
|
* Copyright 2009, 280 North, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import <AppKit/CPResponder.j>
|
||||||
|
|
||||||
|
var CPViewControllerCachedCibs;
|
||||||
|
|
||||||
|
/*! @class CPViewController
|
||||||
|
The CPViewController class provides the fundamental view-management controller for Cappuccino applications.
|
||||||
|
The basic view controller class supports the presentation of an associated view in addition to basic support
|
||||||
|
for managing modal views and, in the future, animations. Subclasses such as CPNavigationController and
|
||||||
|
CPTabBarController provide additional behavior for managing complex hierarchies of view controllers and views.
|
||||||
|
|
||||||
|
You use each instance of CPViewController to manage a single view (and hierarchy). For a simple view controller,
|
||||||
|
this entails managing the view hierarchy responsible for presenting your application content.
|
||||||
|
A typical view hierarchy consists of a root viewŃa reference to which is available in the view property of this classŃ
|
||||||
|
and one or more subviews presenting the actual content. In the case of navigation and tab bar controllers, the view
|
||||||
|
controller manages not only the high-level view hierarchy (which provides the navigation controls) but also one
|
||||||
|
or more additional view controllers that handle the presentation of the application content.
|
||||||
|
|
||||||
|
Unlike UIViewController in Cocoa Touch, a CPViewController does not represent an entire screen of content. You
|
||||||
|
will add your root view to an existing view or window's content view. You can manage many view controllers
|
||||||
|
on screen at once. CPViewController is also the preferred way of working with Cibs.
|
||||||
|
|
||||||
|
Subclasses can override -loadView to create their custom view hierarchy, or specify a cib name to be loaded automatically.
|
||||||
|
It has methods that are called when a view appears or disappears.
|
||||||
|
This class is also a good place for delegate & datasource methods, and other controller stuff.
|
||||||
|
*/
|
||||||
|
@implementation CPViewController : CPResponder
|
||||||
|
{
|
||||||
|
CPView _view;
|
||||||
|
|
||||||
|
id _representedObject @accessors(property=representedObject);
|
||||||
|
CPString _title;
|
||||||
|
|
||||||
|
CPString _cibName @accessors(property=cibName, readonly);
|
||||||
|
CPBundle _cibBundle @accessors(property=cibBundle, readonly);
|
||||||
|
CPDictionary _cibExternalNameTable @accessors(property=cibExternalNameTable, readonly);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
if (self === CPViewController)
|
||||||
|
CPViewControllerCachedCibs = [CPDictionary dictionary];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Convenience initializer calls -initWithCibName:bundle: with nil for both parameters.
|
||||||
|
*/
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
return [self initWithCibName:nil bundle:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithCibName:(CPString)aCibNameOrNil bundle:(CPBundle)aCibBundleOrNil
|
||||||
|
{
|
||||||
|
return [self initWithCibName:aCibNameOrNil bundle:aCibBundleOrNil externalNameTable:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithCibName:(CPString)aCibNameOrNil bundle:(CPBundle)aCibBundleOrNil owner:(id)anOwner
|
||||||
|
{
|
||||||
|
return [self initWithCibName:aCibNameOrNil
|
||||||
|
bundle:aCibBundleOrNil
|
||||||
|
externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
The designated initializer. If you subclass CPViewController, you must call the super implementation of this method, even if you aren't using a Cib.
|
||||||
|
In the specified Cib, the File's Owner proxy should have its class set to your view controller subclass, with the view outlet connected to the main view.
|
||||||
|
If you pass in a nil Cib name, then you must either call -setView: before -view is invoked, or override -loadView to set up your views.
|
||||||
|
|
||||||
|
@param cibNameOrNil The path to the cib to load for the root view or nil to programmatically create views.
|
||||||
|
@param cibBundleOrNil The bundle that the cib is located in or nil for the main bundle.
|
||||||
|
*/
|
||||||
|
- (id)initWithCibName:(CPString)aCibNameOrNil bundle:(CPBundle)aCibBundleOrNil externalNameTable:(CPDictionary)anExternalNameTable
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
// Don't load the cib until someone actually requests the view. The user may just be intending to use setView:.
|
||||||
|
_cibName = aCibNameOrNil;
|
||||||
|
_cibBundle = aCibBundleOrNil;
|
||||||
|
|
||||||
|
if (!_cibBundle)
|
||||||
|
{
|
||||||
|
var owner = [anExternalNameTable objectForKey:CPCibOwner];
|
||||||
|
|
||||||
|
_cibBundle = owner ? [CPBundle bundleForClass:[owner class]] : [CPBundle mainBundle];
|
||||||
|
}
|
||||||
|
|
||||||
|
_cibExternalNameTable = anExternalNameTable || [CPDictionary dictionaryWithObject:self forKey:CPCibOwner];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTitle:(CPString)aTitle
|
||||||
|
{
|
||||||
|
_title = aTitle;
|
||||||
|
|
||||||
|
if (self._navigationItem)
|
||||||
|
[_navigationItem setTitle:aTitle];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)title
|
||||||
|
{
|
||||||
|
return _title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Programmatically creates the view that the controller manages.
|
||||||
|
You should never call this method directly. The view controller calls this method when the view property is requested but is nil.
|
||||||
|
|
||||||
|
If you create your views manually, you must override this method and use it to create your view and assign it to the view property.
|
||||||
|
The default implementation for programmatic views is to create a plain view. You can invoke super to utilize this view.
|
||||||
|
|
||||||
|
If you use Interface Builder to create your views and initialize the view controllerŃthat is, you initialize the view using the
|
||||||
|
initWithCibName:bundle: methodŃthen you must not override this method. The consequences risk shattering the space-time continuum.
|
||||||
|
|
||||||
|
Note: The cib loading system is currently asynchronous.
|
||||||
|
*/
|
||||||
|
- (void)loadView
|
||||||
|
{
|
||||||
|
if (_view)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// check if a cib is already cached for the current _cibName
|
||||||
|
var cib = [CPViewControllerCachedCibs objectForKey:_cibName];
|
||||||
|
|
||||||
|
// If the cib isn't cached yet : fetch it and cache it
|
||||||
|
if (!cib)
|
||||||
|
{
|
||||||
|
cib = [[CPCib alloc] initWithContentsOfURL:[_cibBundle pathForResource:_cibName + @".cib"]];
|
||||||
|
[CPViewControllerCachedCibs setObject:cib forKey:_cibName];
|
||||||
|
}
|
||||||
|
|
||||||
|
[cib instantiateCibWithExternalNameTable:_cibExternalNameTable];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the view that the controller manages.
|
||||||
|
If this property is nil, the controller sends loadView to itself to create the view that it manages.
|
||||||
|
Subclasses should override the loadView method to create any custom views. The default value is nil.
|
||||||
|
*/
|
||||||
|
- (CPView)view
|
||||||
|
{
|
||||||
|
if (!_view)
|
||||||
|
{
|
||||||
|
var cibOwner = [_cibExternalNameTable objectForKey:CPCibOwner];
|
||||||
|
|
||||||
|
if ([cibOwner respondsToSelector:@selector(viewControllerWillLoadCib:)])
|
||||||
|
[cibOwner viewControllerWillLoadCib:self];
|
||||||
|
|
||||||
|
[self loadView];
|
||||||
|
|
||||||
|
if (_view === nil && [cibOwner isKindOfClass:[CPDocument class]])
|
||||||
|
[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:)])
|
||||||
|
[cibOwner viewControllerDidLoadCib:self];
|
||||||
|
|
||||||
|
[self viewDidLoad];
|
||||||
|
}
|
||||||
|
|
||||||
|
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 nib files.
|
||||||
|
*/
|
||||||
|
- (void)viewDidLoad
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Manually sets the view that the controller manages.
|
||||||
|
Setting to nil will cause -loadView to be called on all subsequent calls of -view.
|
||||||
|
|
||||||
|
@param aView The view this controller should represent.
|
||||||
|
*/
|
||||||
|
- (void)setView:(CPView)aView
|
||||||
|
{
|
||||||
|
_view = aView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPNavigationItem)navigationItem
|
||||||
|
{
|
||||||
|
var navigationItem = self._navigationItem;
|
||||||
|
|
||||||
|
if (!navigationItem)
|
||||||
|
navigationItem = [[CPNavigationItem alloc] initWithTitle:[self title]];
|
||||||
|
|
||||||
|
self._navigationItem = navigationItem;
|
||||||
|
|
||||||
|
return navigationItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewWillAppear:(BOOL)isAnimated
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewDidAppear:(BOOL)isAnimated
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewWillDisappear:(BOOL)isAnimated
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewDidDisappear:(BOOL)isAnimated
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
var CPViewControllerViewKey = @"CPViewControllerViewKey",
|
||||||
|
CPViewControllerTitleKey = @"CPViewControllerTitleKey",
|
||||||
|
CPViewControllerCibNameKey = @"CPViewControllerCibNameKey",
|
||||||
|
CPViewControllerBundleKey = @"CPViewControllerBundleKey";
|
||||||
|
|
||||||
|
@implementation CPViewController (CPCoding)
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Initializes the view controller by unarchiving data from a coder.
|
||||||
|
@param aCoder the coder from which the data will be unarchived
|
||||||
|
@return the initialized view controller
|
||||||
|
*/
|
||||||
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
self = [super initWithCoder:aCoder];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_view = [aCoder decodeObjectForKey:CPViewControllerViewKey];
|
||||||
|
_title = [aCoder decodeObjectForKey:CPViewControllerTitleKey];
|
||||||
|
_cibName = [aCoder decodeObjectForKey:CPViewControllerCibNameKey];
|
||||||
|
|
||||||
|
var bundlePath = [aCoder decodeObjectForKey:CPViewControllerBundleKey];
|
||||||
|
_cibBundle = bundlePath ? [CPBundle bundleWithPath:bundlePath] : [CPBundle mainBundle];
|
||||||
|
|
||||||
|
_cibExternalNameTable = [CPDictionary dictionaryWithObject:self forKey:CPCibOwner];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Archives the view controller to the provided coder.
|
||||||
|
@param aCoder the coder to which the view controller should be archived
|
||||||
|
*/
|
||||||
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
[super encodeWithCoder:aCoder];
|
||||||
|
|
||||||
|
[aCoder encodeObject:_view forKey:CPViewControllerViewKey];
|
||||||
|
[aCoder encodeObject:_title forKey:CPViewControllerTitleKey];
|
||||||
|
[aCoder encodeObject:_cibName forKey:CPViewControllerCibNameKey];
|
||||||
|
[aCoder encodeObject:[_cibBundle bundlePath] forKey:CPViewControllerBundleKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
+3
-2
@@ -150,8 +150,10 @@ CPWebViewScrollNative = 2;
|
|||||||
|
|
||||||
|
|
||||||
_frameView = [[CPView alloc] initWithFrame:[self bounds]];
|
_frameView = [[CPView alloc] initWithFrame:[self bounds]];
|
||||||
|
[_frameView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||||
|
|
||||||
_scrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
|
_scrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
|
||||||
|
[_scrollView setAutohidesScrollers:YES];
|
||||||
[_scrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
[_scrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||||
[_scrollView setDocumentView:_frameView];
|
[_scrollView setDocumentView:_frameView];
|
||||||
|
|
||||||
@@ -166,7 +168,6 @@ CPWebViewScrollNative = 2;
|
|||||||
- (void)setFrameSize:(CPSize)aSize
|
- (void)setFrameSize:(CPSize)aSize
|
||||||
{
|
{
|
||||||
[super setFrameSize:aSize];
|
[super setFrameSize:aSize];
|
||||||
|
|
||||||
[self _resizeWebFrame];
|
[self _resizeWebFrame];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +181,7 @@ CPWebViewScrollNative = 2;
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
[_frameView setFrameSize:[_scrollView bounds].size];
|
[_frameView setFrameSize:[_scrollView contentSize]];
|
||||||
|
|
||||||
// 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;
|
||||||
|
|||||||
+899
-330
File diff suppressed because it is too large
Load Diff
@@ -38,6 +38,11 @@ var _CPToolbarViewBackgroundColor = nil;
|
|||||||
return _CPToolbarViewBackgroundColor;
|
return _CPToolbarViewBackgroundColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setShowsResizeIndicator:(BOOL)shouldShowResizeIndicator
|
||||||
|
{
|
||||||
|
// We don't ever want to show the resize indicator.
|
||||||
|
}
|
||||||
|
|
||||||
- (void)tile
|
- (void)tile
|
||||||
{
|
{
|
||||||
[super tile];
|
[super tile];
|
||||||
@@ -66,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];
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
|
||||||
|
@import "_CPWindowView.j"
|
||||||
|
|
||||||
|
var _CPStandardWindowViewBodyBackgroundColor = nil;
|
||||||
|
|
||||||
|
@implementation _CPDocModalWindowView : _CPWindowView
|
||||||
|
{
|
||||||
|
CPView _bodyView;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CPColor)bodyBackgroundColor
|
||||||
|
{
|
||||||
|
if (!_CPStandardWindowViewBodyBackgroundColor)
|
||||||
|
_CPStandardWindowViewBodyBackgroundColor = [CPColor colorWithWhite:0.96 alpha:0.9];
|
||||||
|
|
||||||
|
return _CPStandardWindowViewBodyBackgroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithFrame:(CPRect)aFrame styleMask:(unsigned)aStyleMask
|
||||||
|
{
|
||||||
|
self = [super initWithFrame:aFrame styleMask:aStyleMask];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
var theClass = [self class],
|
||||||
|
bounds = [self bounds];
|
||||||
|
|
||||||
|
_bodyView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(bounds), CGRectGetHeight(bounds))];
|
||||||
|
|
||||||
|
[_bodyView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||||
|
[_bodyView setBackgroundColor:[theClass bodyBackgroundColor]];
|
||||||
|
[_bodyView setHitTests:NO];
|
||||||
|
|
||||||
|
[self addSubview:_bodyView];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||||
|
{
|
||||||
|
return aFrameRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGRect)frameRectForContentRect:(CGRect)aContentRect
|
||||||
|
{
|
||||||
|
return aContentRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -48,7 +48,7 @@ var HUD_TITLEBAR_HEIGHT = 26.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(6.0, 78.0)],
|
||||||
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground3.png"] size:CPSizeMake(6.0, 1.0)],
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground3.png"] size:CPSizeMake(6.0, 1.0)],
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground4.png"] size:CPSizeMake(1.0, 1.0)],
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground4.png"] size:CPSizeMake(5.0, 5.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(6.0, 1.0)],
|
||||||
|
|
||||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground6.png"] size:CPSizeMake(6.0, 6.0)],
|
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground6.png"] size:CPSizeMake(6.0, 6.0)],
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ var _CPTexturedWindowHeadGradientColor = nil,
|
|||||||
+ (CPColor)solidColor
|
+ (CPColor)solidColor
|
||||||
{
|
{
|
||||||
if (!_CPTexturedWindowHeadSolidColor)
|
if (!_CPTexturedWindowHeadSolidColor)
|
||||||
_CPTexturedWindowHeadSolidColor = [CPColor colorWithCalibratedRed:182.0 / 255.0 green:182.0 / 255.0 blue:182.0 / 255.0 alpha:1.0];
|
_CPTexturedWindowHeadSolidColor = [CPColor colorWithCalibratedRed:195.0 / 255.0 green:195.0 / 255.0 blue:195.0 / 255.0 alpha:1.0];
|
||||||
|
|
||||||
return _CPTexturedWindowHeadSolidColor;
|
return _CPTexturedWindowHeadSolidColor;
|
||||||
}
|
}
|
||||||
@@ -94,11 +94,15 @@ var _CPTexturedWindowHeadGradientColor = nil,
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var _CPStandardWindowViewBodyBackgroundColor = nil,
|
var _CPStandardWindowViewBodyBackgroundColor = nil,
|
||||||
_CPStandardWindowViewDividerBackgroundColor = nil,
|
_CPStandardWindowViewDividerBackgroundColor = nil,
|
||||||
_CPStandardWindowViewTitleBackgroundColor = nil,
|
_CPStandardWindowViewTitleBackgroundColor = nil,
|
||||||
_CPStandardWindowViewCloseButtonImage = nil,
|
_CPStandardWindowViewCloseButtonImage = nil,
|
||||||
_CPStandardWindowViewCloseButtonHighlightedImage = nil;
|
_CPStandardWindowViewCloseButtonHighlightedImage = nil,
|
||||||
|
_CPStandardWindowViewCloseButtonUnsavedImage = nil,
|
||||||
|
_CPStandardWindowViewCloseButtonUnsavedHighlightedImage = nil,
|
||||||
|
_CPStandardWindowViewMinimizeButtonImage = nil,
|
||||||
|
_CPStandardWindowViewMinimizeButtonHighlightedImage = nil;
|
||||||
|
|
||||||
var STANDARD_GRADIENT_HEIGHT = 41.0;
|
var STANDARD_GRADIENT_HEIGHT = 41.0;
|
||||||
STANDARD_TITLEBAR_HEIGHT = 25.0;
|
STANDARD_TITLEBAR_HEIGHT = 25.0;
|
||||||
@@ -112,6 +116,9 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
|
|||||||
|
|
||||||
CPTextField _titleField;
|
CPTextField _titleField;
|
||||||
CPButton _closeButton;
|
CPButton _closeButton;
|
||||||
|
CPButton _minimizeButton;
|
||||||
|
|
||||||
|
BOOL _isDocumentEdited;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CPColor)bodyBackgroundColor
|
+ (CPColor)bodyBackgroundColor
|
||||||
@@ -259,18 +266,38 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
|
|||||||
|
|
||||||
_CPStandardWindowViewCloseButtonImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/Standard/CPWindowStandardCloseButton.png"] size:CGSizeMake(16.0, 16.0)];
|
_CPStandardWindowViewCloseButtonImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/Standard/CPWindowStandardCloseButton.png"] size:CGSizeMake(16.0, 16.0)];
|
||||||
_CPStandardWindowViewCloseButtonHighlightedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/Standard/CPWindowStandardCloseButtonHighlighted.png"] size:CGSizeMake(16.0, 16.0)];
|
_CPStandardWindowViewCloseButtonHighlightedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/Standard/CPWindowStandardCloseButtonHighlighted.png"] size:CGSizeMake(16.0, 16.0)];
|
||||||
|
_CPStandardWindowViewCloseButtonUnsavedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/Standard/CPWindowStandardCloseButtonUnsaved.png"] size:CGSizeMake(16.0, 16.0)];
|
||||||
|
_CPStandardWindowViewCloseButtonUnsavedHighlightedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/Standard/CPWindowStandardCloseButtonUnsavedHighlighted.png"] size:CGSizeMake(16.0, 16.0)];
|
||||||
}
|
}
|
||||||
|
|
||||||
_closeButton = [[CPButton alloc] initWithFrame:CGRectMake(8.0, 7.0, 16.0, 16.0)];
|
_closeButton = [[CPButton alloc] initWithFrame:CGRectMake(8.0, 7.0, 16.0, 16.0)];
|
||||||
|
|
||||||
[_closeButton setBordered:NO];
|
[_closeButton setBordered:NO];
|
||||||
|
[self _updateCloseButton];
|
||||||
[_closeButton setImage:_CPStandardWindowViewCloseButtonImage];
|
|
||||||
[_closeButton setAlternateImage:_CPStandardWindowViewCloseButtonHighlightedImage];
|
|
||||||
|
|
||||||
[self addSubview:_closeButton];
|
[self addSubview:_closeButton];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_styleMask & CPMiniaturizableWindowMask && ![CPPlatform isBrowser])
|
||||||
|
{
|
||||||
|
if (!_CPStandardWindowViewMinimizeButtonImage)
|
||||||
|
{
|
||||||
|
var bundle = [CPBundle bundleForClass:[CPWindow class]];
|
||||||
|
|
||||||
|
_CPStandardWindowViewMinimizeButtonImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/Standard/CPWindowStandardMinimizeButton.png"] size:CGSizeMake(16.0, 16.0)];
|
||||||
|
_CPStandardWindowViewMinimizeButtonHighlightedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/Standard/CPWindowStandardMinimizeButtonHighlighted.png"] size:CGSizeMake(16.0, 16.0)];
|
||||||
|
}
|
||||||
|
|
||||||
|
_minimizeButton = [[CPButton alloc] initWithFrame:CGRectMake(27.0, 7.0, 16.0, 16.0)];
|
||||||
|
|
||||||
|
[_minimizeButton setBordered:NO];
|
||||||
|
|
||||||
|
[_minimizeButton setImage:_CPStandardWindowViewMinimizeButtonImage];
|
||||||
|
[_minimizeButton setAlternateImage:_CPStandardWindowViewMinimizeButtonHighlightedImage];
|
||||||
|
|
||||||
|
[self addSubview:_minimizeButton];
|
||||||
|
}
|
||||||
|
|
||||||
[self tile];
|
[self tile];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,6 +308,9 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
|
|||||||
{
|
{
|
||||||
[_closeButton setTarget:[self window]];
|
[_closeButton setTarget:[self window]];
|
||||||
[_closeButton setAction:@selector(performClose:)];
|
[_closeButton setAction:@selector(performClose:)];
|
||||||
|
|
||||||
|
[_minimizeButton setTarget:[self window]];
|
||||||
|
[_minimizeButton setAction:@selector(performMiniaturize:)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGSize)toolbarOffset
|
- (CGSize)toolbarOffset
|
||||||
@@ -303,7 +333,14 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
|
|||||||
|
|
||||||
[_bodyView setFrame:CGRectMake(0.0, dividerMaxY, width, CGRectGetHeight(bounds) - dividerMaxY)];
|
[_bodyView setFrame:CGRectMake(0.0, dividerMaxY, width, CGRectGetHeight(bounds) - dividerMaxY)];
|
||||||
|
|
||||||
[_titleField setFrame:CGRectMake(10.0, 3.0, width - 20.0, CGRectGetHeight([_titleField frame]))];
|
var leftOffset = 8;
|
||||||
|
|
||||||
|
if (_closeButton)
|
||||||
|
leftOffset += 19.0;
|
||||||
|
if (_minimizeButton)
|
||||||
|
leftOffset += 19.0;
|
||||||
|
|
||||||
|
[_titleField setFrame:CGRectMake(leftOffset, 5.0, width - leftOffset*2.0, CGRectGetHeight([_titleField frame]))];
|
||||||
|
|
||||||
[[theWindow contentView] setFrameOrigin:CGPointMake(0.0, CGRectGetMaxY([_dividerView frame]))];
|
[[theWindow contentView] setFrameOrigin:CGPointMake(0.0, CGRectGetMaxY([_dividerView frame]))];
|
||||||
}
|
}
|
||||||
@@ -334,6 +371,27 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
- (void)_updateCloseButton
|
||||||
|
{
|
||||||
|
if (_isDocumentEdited)
|
||||||
|
{
|
||||||
|
[_closeButton setImage:_CPStandardWindowViewCloseButtonUnsavedImage];
|
||||||
|
[_closeButton setAlternateImage:_CPStandardWindowViewCloseButtonUnsavedHighlightedImage];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[_closeButton setImage:_CPStandardWindowViewCloseButtonImage];
|
||||||
|
[_closeButton setAlternateImage:_CPStandardWindowViewCloseButtonHighlightedImage];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDocumentEdited:(BOOL)isEdited
|
||||||
|
{
|
||||||
|
_isDocumentEdited = isEdited;
|
||||||
|
[self _updateCloseButton];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setTitle:(CPString)aTitle
|
- (void)setTitle:(CPString)aTitle
|
||||||
{
|
{
|
||||||
[_titleField setStringValue:aTitle];
|
[_titleField setStringValue:aTitle];
|
||||||
|
|||||||
@@ -36,8 +36,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,15 +81,17 @@ 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();
|
||||||
|
|
||||||
[self setShowsResizeIndicator:!(_styleMask & CPBorderlessBridgeWindowMask) && (_styleMask & CPResizableWindowMask)];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setDocumentEdited:(BOOL)isEdited
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setTitle:(CPString)aTitle
|
- (void)setTitle:(CPString)aTitle
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -135,22 +139,38 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
|||||||
}
|
}
|
||||||
|
|
||||||
else if (type === CPLeftMouseDragged)
|
else if (type === CPLeftMouseDragged)
|
||||||
[theWindow setFrameSize:CGSizeMake(CGRectGetWidth(_resizeFrame) + location.x - CGRectGetMinX(_resizeFrame), CGRectGetHeight(_resizeFrame) + location.y - CGRectGetMinY(_resizeFrame))];
|
{
|
||||||
|
var newSize = CGSizeMake(CGRectGetWidth(_resizeFrame) + location.x - CGRectGetMinX(_resizeFrame), CGRectGetHeight(_resizeFrame) + location.y - CGRectGetMinY(_resizeFrame));
|
||||||
|
|
||||||
|
if (theWindow._isSheet && theWindow._parentView && (theWindow._frame.size.width !== newSize.width))
|
||||||
|
[theWindow._parentView _setAttachedSheetFrameOrigin];
|
||||||
|
|
||||||
|
[theWindow setFrameSize:newSize];
|
||||||
|
}
|
||||||
|
|
||||||
[CPApp setTarget:self selector:@selector(trackResizeWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
[CPApp setTarget:self selector:@selector(trackResizeWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGPoint)_pointWithinScreenFrame:(CGPoint)aPoint
|
- (CGPoint)_pointWithinScreenFrame:(CGPoint)aPoint
|
||||||
{
|
{
|
||||||
|
// FIXME: this is WRONG, all of this is WRONG
|
||||||
|
if (![CPPlatform isBrowser])
|
||||||
|
return aPoint;
|
||||||
|
|
||||||
var visibleFrame = _cachedScreenFrame;
|
var visibleFrame = _cachedScreenFrame;
|
||||||
|
|
||||||
if (!visibleFrame)
|
if (!visibleFrame)
|
||||||
visibleFrame = [[CPDOMWindowBridge sharedDOMWindowBridge] 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;
|
||||||
}
|
}
|
||||||
@@ -164,16 +184,18 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
|||||||
_cachedScreenFrame = nil;
|
_cachedScreenFrame = nil;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (type === CPLeftMouseDown)
|
else if (type === CPLeftMouseDown)
|
||||||
{
|
{
|
||||||
_mouseDraggedPoint = [[self window] convertBaseToBridge:[anEvent locationInWindow]];
|
_mouseDraggedPoint = [[self window] convertBaseToGlobal:[anEvent locationInWindow]];
|
||||||
_cachedScreenFrame = [[CPDOMWindowBridge sharedDOMWindowBridge] visibleFrame];
|
_cachedScreenFrame = [[CPPlatformWindow primaryPlatformWindow] visibleFrame];
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (type === CPLeftMouseDragged)
|
else if (type === CPLeftMouseDragged)
|
||||||
{
|
{
|
||||||
var theWindow = [self window],
|
var theWindow = [self window],
|
||||||
frame = [theWindow frame],
|
frame = [theWindow frame],
|
||||||
location = [theWindow convertBaseToBridge:[anEvent locationInWindow]],
|
location = [theWindow convertBaseToGlobal:[anEvent locationInWindow]],
|
||||||
origin = [self _pointWithinScreenFrame:CGPointMake(_CGRectGetMinX(frame) + (location.x - _mouseDraggedPoint.x),
|
origin = [self _pointWithinScreenFrame:CGPointMake(_CGRectGetMinX(frame) + (location.x - _mouseDraggedPoint.x),
|
||||||
_CGRectGetMinY(frame) + (location.y - _mouseDraggedPoint.y))];
|
_CGRectGetMinY(frame) + (location.y - _mouseDraggedPoint.y))];
|
||||||
|
|
||||||
@@ -207,7 +229,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPImage)showsResizeIndicator
|
- (BOOL)showsResizeIndicator
|
||||||
{
|
{
|
||||||
return _resizeIndicator !== nil;
|
return _resizeIndicator !== nil;
|
||||||
}
|
}
|
||||||
@@ -248,7 +270,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
|||||||
|
|
||||||
- (CGSize)toolbarOffset
|
- (CGSize)toolbarOffset
|
||||||
{
|
{
|
||||||
return CGSizeMakeZero();
|
return _toolbarOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPColor)toolbarLabelColor
|
- (CPColor)toolbarLabelColor
|
||||||
@@ -305,10 +327,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
|||||||
if (toolbarView)
|
if (toolbarView)
|
||||||
{
|
{
|
||||||
[toolbarView removeFromSuperview];
|
[toolbarView removeFromSuperview];
|
||||||
[toolbarView setLabelColor:[self toolbarLabelColor]];
|
[toolbarView FIXME_setIsHUD:_styleMask & CPHUDBackgroundWindowMask];
|
||||||
|
|
||||||
if ([self respondsToSelector:@selector(toolbarLabelShadowColor)])
|
|
||||||
[toolbarView setLabelShadowColor:[self toolbarLabelShadowColor]];
|
|
||||||
|
|
||||||
[self addSubview:toolbarView];
|
[self addSubview:toolbarView];
|
||||||
}
|
}
|
||||||
@@ -322,7 +341,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
|||||||
{
|
{
|
||||||
var contentRect = [self convertRect:[[theWindow contentView] frame] toView:nil];
|
var contentRect = [self convertRect:[[theWindow contentView] frame] toView:nil];
|
||||||
|
|
||||||
contentRect.origin = [theWindow convertBaseToBridge:contentRect.origin];
|
contentRect.origin = [theWindow convertBaseToGlobal:contentRect.origin];
|
||||||
|
|
||||||
[self setAutoresizesSubviews:NO];
|
[self setAutoresizesSubviews:NO];
|
||||||
[theWindow setFrame:[theWindow frameRectForContentRect:contentRect]];
|
[theWindow setFrame:[theWindow frameRectForContentRect:contentRect]];
|
||||||
|
|||||||
+190
-22
@@ -41,10 +41,24 @@
|
|||||||
*/
|
*/
|
||||||
@implementation CPWindowController : CPResponder
|
@implementation CPWindowController : CPResponder
|
||||||
{
|
{
|
||||||
id _owner;
|
CPWindow _window;
|
||||||
CPWindow _window;
|
|
||||||
CPDocument _document;
|
CPArray _documents;
|
||||||
CPString _windowCibName;
|
CPDocument _document;
|
||||||
|
BOOL _shouldCloseDocument;
|
||||||
|
BOOL _supportsMultipleDocuments;
|
||||||
|
|
||||||
|
id _cibOwner;
|
||||||
|
CPString _windowCibName;
|
||||||
|
CPString _windowCibPath;
|
||||||
|
|
||||||
|
CPViewController _viewController;
|
||||||
|
CPView _viewControllerContainerView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
return [self initWithWindow:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -59,8 +73,11 @@
|
|||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
[self setWindow:aWindow];
|
[self setWindow:aWindow];
|
||||||
|
[self setShouldCloseDocument:NO];
|
||||||
|
|
||||||
[self setNextResponder:CPApp];
|
[self setNextResponder:CPApp];
|
||||||
|
|
||||||
|
_documents = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -84,14 +101,25 @@
|
|||||||
*/
|
*/
|
||||||
- (id)initWithWindowCibName:(CPString)aWindowCibName owner:(id)anOwner
|
- (id)initWithWindowCibName:(CPString)aWindowCibName owner:(id)anOwner
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [self initWithWindow:nil];
|
||||||
|
|
||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_owner = anOwner;
|
_cibOwner = anOwner;
|
||||||
_windowCibName = aWindowCibName;
|
_windowCibName = aWindowCibName;
|
||||||
|
}
|
||||||
|
|
||||||
[self setNextResponder:CPApp];
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithWindowCibPath:(CPString)aWindowCibPath owner:(id)anOwner
|
||||||
|
{
|
||||||
|
self = [self initWithWindow:nil];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_cibOwner = anOwner;
|
||||||
|
_windowCibPath = aWindowCibPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -102,34 +130,33 @@
|
|||||||
*/
|
*/
|
||||||
- (void)loadWindow
|
- (void)loadWindow
|
||||||
{
|
{
|
||||||
[self windowWillLoad];
|
if (_window)
|
||||||
//FIXME: ACTUALLY LOAD WINDOW!!!
|
return;
|
||||||
[self setWindow:CPApp._keyWindow = [[CPWindow alloc] initWithContentRect:CPRectMakeZero() styleMask:CPBorderlessBridgeWindowMask|CPTitledWindowMask|CPClosableWindowMask|CPResizableWindowMask]];
|
|
||||||
|
|
||||||
[self windowDidLoad];
|
[[CPBundle bundleForClass:[_cibOwner class]] loadCibFile:[self windowCibPath] externalNameTable:[CPDictionary dictionaryWithObject:_cibOwner forKey:CPCibOwner]];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Shows the window.
|
Shows the window.
|
||||||
@param aSender the object requesting the show
|
@param aSender the object requesting the show
|
||||||
*/
|
*/
|
||||||
- (CFAction)showWindow:(id)aSender
|
- (@action)showWindow:(id)aSender
|
||||||
{
|
{
|
||||||
var theWindow = [self window];
|
var theWindow = [self window];
|
||||||
|
|
||||||
if ([theWindow respondsToSelector:@selector(becomesKeyOnlyIfNeeded)] && [theWindow becomesKeyOnlyIfNeeded])
|
if ([theWindow respondsToSelector:@selector(becomesKeyOnlyIfNeeded)] && [theWindow becomesKeyOnlyIfNeeded])
|
||||||
[theWindow orderFront:aSender];
|
[theWindow orderFront:aSender];
|
||||||
else
|
else
|
||||||
[theWindow makeKeyAndOrderFront:aSender];
|
[theWindow makeKeyAndOrderFront:aSender];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the window has been loaded. Specifically,
|
Returns \c YES if the window has been loaded. Specifically,
|
||||||
if loadWindow has been called.
|
if loadWindow has been called.
|
||||||
*/
|
*/
|
||||||
- (BOOL)isWindowLoaded
|
- (BOOL)isWindowLoaded
|
||||||
{
|
{
|
||||||
return _window;
|
return _window !== nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -138,7 +165,28 @@
|
|||||||
- (CPWindow)window
|
- (CPWindow)window
|
||||||
{
|
{
|
||||||
if (!_window)
|
if (!_window)
|
||||||
[self loadWindow];
|
{
|
||||||
|
[self windowWillLoad];
|
||||||
|
[_document windowControllerWillLoadCib:self];
|
||||||
|
|
||||||
|
[self loadWindow];
|
||||||
|
|
||||||
|
if (_window === nil && [_cibOwner isKindOfClass:[CPDocument class]])
|
||||||
|
[self setWindow:[_cibOwner valueForKey:@"window"]];
|
||||||
|
|
||||||
|
if (!_window)
|
||||||
|
{
|
||||||
|
var reason = [CPString stringWithFormat:@"Window for %@ could not be loaded from Cib or no window specified. \
|
||||||
|
Override loadWindow to load the window manually.", self];
|
||||||
|
|
||||||
|
[CPException raise:CPInternalInconsistencyException reason:reason];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self windowDidLoad];
|
||||||
|
[_document windowControllerDidLoadCib:self];
|
||||||
|
|
||||||
|
[self synchronizeWindowTitleWithDocumentName];
|
||||||
|
}
|
||||||
|
|
||||||
return _window;
|
return _window;
|
||||||
}
|
}
|
||||||
@@ -149,6 +197,8 @@
|
|||||||
*/
|
*/
|
||||||
- (void)setWindow:(CPWindow)aWindow
|
- (void)setWindow:(CPWindow)aWindow
|
||||||
{
|
{
|
||||||
|
[_window setWindowController:nil];
|
||||||
|
|
||||||
_window = aWindow;
|
_window = aWindow;
|
||||||
|
|
||||||
[_window setWindowController:self];
|
[_window setWindowController:self];
|
||||||
@@ -160,9 +210,6 @@
|
|||||||
*/
|
*/
|
||||||
- (void)windowDidLoad
|
- (void)windowDidLoad
|
||||||
{
|
{
|
||||||
[_document windowControllerDidLoadNib:self];
|
|
||||||
|
|
||||||
[self synchronizeWindowTitleWithDocumentName];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -170,7 +217,6 @@
|
|||||||
*/
|
*/
|
||||||
- (void)windowWillLoad
|
- (void)windowWillLoad
|
||||||
{
|
{
|
||||||
[_document windowControllerWillLoadNib:self];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -179,13 +225,16 @@
|
|||||||
*/
|
*/
|
||||||
- (void)setDocument:(CPDocument)aDocument
|
- (void)setDocument:(CPDocument)aDocument
|
||||||
{
|
{
|
||||||
if (_document == aDocument)
|
if (_document === aDocument)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||||
|
|
||||||
if (_document)
|
if (_document)
|
||||||
{
|
{
|
||||||
|
if (![self supportsMultipleDocuments])
|
||||||
|
[self removeDocument:_document];
|
||||||
|
|
||||||
[defaultCenter removeObserver:self
|
[defaultCenter removeObserver:self
|
||||||
name:CPDocumentWillSaveNotification
|
name:CPDocumentWillSaveNotification
|
||||||
object:_document];
|
object:_document];
|
||||||
@@ -203,6 +252,8 @@
|
|||||||
|
|
||||||
if (_document)
|
if (_document)
|
||||||
{
|
{
|
||||||
|
[self addDocument:_document];
|
||||||
|
|
||||||
[defaultCenter addObserver:self
|
[defaultCenter addObserver:self
|
||||||
selector:@selector(_documentWillSave:)
|
selector:@selector(_documentWillSave:)
|
||||||
name:CPDocumentWillSaveNotification
|
name:CPDocumentWillSaveNotification
|
||||||
@@ -221,9 +272,90 @@
|
|||||||
[self setDocumentEdited:[_document isDocumentEdited]];
|
[self setDocumentEdited:[_document isDocumentEdited]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var viewController = [_document viewControllerForWindowController:self];
|
||||||
|
|
||||||
|
if (viewController)
|
||||||
|
[self setViewController:viewController];
|
||||||
|
|
||||||
[self synchronizeWindowTitleWithDocumentName];
|
[self synchronizeWindowTitleWithDocumentName];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setSupportsMultipleDocuments:(BOOL)shouldSupportMultipleDocuments
|
||||||
|
{
|
||||||
|
_supportsMultipleDocuments = shouldSupportMultipleDocuments;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)supportsMultipleDocuments
|
||||||
|
{
|
||||||
|
return _supportsMultipleDocuments;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)addDocument:(CPDocument)aDocument
|
||||||
|
{
|
||||||
|
if (aDocument && ![_documents containsObject:aDocument])
|
||||||
|
[_documents addObject:aDocument];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeDocument:(CPDocument)aDocument
|
||||||
|
{
|
||||||
|
var index = [_documents indexOfObjectIdenticalTo:aDocument];
|
||||||
|
|
||||||
|
if (index === CPNotFound)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[_documents removeObjectAtIndex:index];
|
||||||
|
|
||||||
|
if (_document === aDocument && [_documents count])
|
||||||
|
[self setDocument:[_documents objectAtIndex:MIN(index, [_documents count] - 1)]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeDocumentAndCloseIfNecessary:(CPDocument)aDocument
|
||||||
|
{
|
||||||
|
[self removeDocument:aDocument];
|
||||||
|
|
||||||
|
if (![_documents count])
|
||||||
|
[self close];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPArray)documents
|
||||||
|
{
|
||||||
|
return _documents;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setViewControllerContainerView:(CPView)aView
|
||||||
|
{
|
||||||
|
_viewControllerContainerView = aView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewControllerContainerView
|
||||||
|
{
|
||||||
|
return _viewControllerContainerView;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPViewController)viewController
|
||||||
|
{
|
||||||
|
return _viewController;
|
||||||
|
}
|
||||||
|
|
||||||
/* @ignore */
|
/* @ignore */
|
||||||
- (void)_documentWillSave:(CPNotification)aNotification
|
- (void)_documentWillSave:(CPNotification)aNotification
|
||||||
{
|
{
|
||||||
@@ -252,13 +384,49 @@
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether the document has unsaved changes. The window can use this as a hint to
|
Sets whether the document has unsaved changes. The window can use this as a hint to
|
||||||
@param isEdited <code>YES</code> means the document has unsaved changes.
|
@param isEdited \c YES means the document has unsaved changes.
|
||||||
*/
|
*/
|
||||||
- (void)setDocumentEdited:(BOOL)isEdited
|
- (void)setDocumentEdited:(BOOL)isEdited
|
||||||
{
|
{
|
||||||
[[self window] setDocumentEdited:isEdited];
|
[[self window] setDocumentEdited:isEdited];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)close
|
||||||
|
{
|
||||||
|
[[self window] close];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setShouldCloseDocument:(BOOL)shouldCloseDocument
|
||||||
|
{
|
||||||
|
_shouldCloseDocument = shouldCloseDocument;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)shouldCloseDocument
|
||||||
|
{
|
||||||
|
return _shouldCloseDocument;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)owner
|
||||||
|
{
|
||||||
|
return _cibOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)windowCibName
|
||||||
|
{
|
||||||
|
if (_windowCibName)
|
||||||
|
return _windowCibName;
|
||||||
|
|
||||||
|
return [[_windowCibPath lastPathComponent] stringByDeletingPathExtension];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)windowCibPath
|
||||||
|
{
|
||||||
|
if (_windowCibPath)
|
||||||
|
return _windowCibPath;
|
||||||
|
|
||||||
|
return [[CPBundle bundleForClass:[_cibOwner class]] pathForResource:_windowCibName + @".cib"];
|
||||||
|
}
|
||||||
|
|
||||||
// Setting and Getting Window Attributes
|
// Setting and Getting Window Attributes
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
+28
-12
@@ -24,17 +24,20 @@
|
|||||||
@import <Foundation/CPURLConnection.j>
|
@import <Foundation/CPURLConnection.j>
|
||||||
@import <Foundation/CPURLRequest.j>
|
@import <Foundation/CPURLRequest.j>
|
||||||
|
|
||||||
|
@import "_CPCibClassSwapper.j"
|
||||||
@import "_CPCibCustomObject.j"
|
@import "_CPCibCustomObject.j"
|
||||||
@import "_CPCibCustomResource.j"
|
@import "_CPCibCustomResource.j"
|
||||||
@import "_CPCibCustomView.j"
|
@import "_CPCibCustomView.j"
|
||||||
@import "_CPCibKeyedUnarchiver.j"
|
@import "_CPCibKeyedUnarchiver.j"
|
||||||
@import "_CPCibObjectData.j"
|
@import "_CPCibObjectData.j"
|
||||||
|
@import "_CPCibProxyObject.j"
|
||||||
@import "_CPCibWindowTemplate.j"
|
@import "_CPCibWindowTemplate.j"
|
||||||
|
|
||||||
|
|
||||||
CPCibOwner = @"CPCibOwner",
|
CPCibOwner = @"CPCibOwner",
|
||||||
CPCibTopLevelObjects = @"CPCibTopLevelObjects",
|
CPCibTopLevelObjects = @"CPCibTopLevelObjects",
|
||||||
CPCibReplacementClasses = @"CPCibReplacementClasses";
|
CPCibReplacementClasses = @"CPCibReplacementClasses",
|
||||||
|
CPCibExternalObjects = @"CPCibExternalObjects";
|
||||||
|
|
||||||
var CPCibObjectDataKey = @"CPCibObjectDataKey";
|
var CPCibObjectDataKey = @"CPCibObjectDataKey";
|
||||||
|
|
||||||
@@ -57,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,6 +83,20 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey";
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (id)initWithCibNamed:(CPString)aName bundle:(CPBundle)aBundle
|
||||||
|
{
|
||||||
|
if (![aName hasSuffix:@".cib"])
|
||||||
|
aName = [aName stringByAppendingString:@".cib"];
|
||||||
|
|
||||||
|
// If aBundle is nil, use mainBundle, but ONLY for searching for the nib, not for resources later.
|
||||||
|
self = [self initWithContentsOfURL:[aBundle || [CPBundle mainBundle] pathForResource:aName]];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
_bundle = aBundle;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
- (id)initWithCibNamed:(CPString)aName bundle:(CPBundle)aBundle loadDelegate:(id)aLoadDelegate
|
- (id)initWithCibNamed:(CPString)aName bundle:(CPBundle)aBundle loadDelegate:(id)aLoadDelegate
|
||||||
{
|
{
|
||||||
if (![aName hasSuffix:@".cib"])
|
if (![aName hasSuffix:@".cib"])
|
||||||
@@ -124,6 +141,8 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey";
|
|||||||
[unarchiver setClass:[replacementClasses objectForKey:key] forClassName:key];
|
[unarchiver setClass:[replacementClasses objectForKey:key] forClassName:key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[unarchiver setExternalObjectsForProxyIdentifiers:[anExternalNameTable objectForKey:CPCibExternalObjects]];
|
||||||
|
|
||||||
var objectData = [unarchiver decodeObjectForKey:CPCibObjectDataKey];
|
var objectData = [unarchiver decodeObjectForKey:CPCibObjectDataKey];
|
||||||
|
|
||||||
if (!objectData || ![objectData isKindOfClass:[_CPCibObjectData class]])
|
if (!objectData || ![objectData isKindOfClass:[_CPCibObjectData class]])
|
||||||
@@ -135,14 +154,6 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey";
|
|||||||
[objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects];
|
[objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects];
|
||||||
[objectData awakeWithOwner:owner topLevelObjects:topLevelObjects];
|
[objectData awakeWithOwner:owner topLevelObjects:topLevelObjects];
|
||||||
|
|
||||||
var menu;
|
|
||||||
|
|
||||||
if ((menu = [objectData mainMenu]) != nil)
|
|
||||||
{
|
|
||||||
[CPApp setMainMenu:menu];
|
|
||||||
[CPMenu setMenuBarVisible:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display Visible Windows.
|
// Display Visible Windows.
|
||||||
[objectData displayVisibleWindows];
|
[objectData displayVisibleWindows];
|
||||||
|
|
||||||
@@ -160,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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* CPCibConnector.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Francisco Tolmasky.
|
||||||
|
* Copyright 2008, 280 North, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import <Foundation/CPObject.j>
|
||||||
|
@import <Foundation/CPKeyValueCoding.j>
|
||||||
|
|
||||||
|
|
||||||
|
var _CPCibConnectorSourceKey = @"_CPCibConnectorSourceKey",
|
||||||
|
_CPCibConnectorDestinationKey = @"_CPCibConnectorDestinationKey",
|
||||||
|
_CPCibConnectorLabelKey = @"_CPCibConnectorLabelKey";
|
||||||
|
|
||||||
|
@implementation CPCibConnector : CPObject
|
||||||
|
{
|
||||||
|
id _source @accessors(property=source);
|
||||||
|
id _destination @accessors(property=destination);
|
||||||
|
CPString _label @accessors(property=label);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)replaceObject:(id)anObject withObject:(id)anotherObject
|
||||||
|
{
|
||||||
|
if (_source === anObject)
|
||||||
|
_source = anotherObject;
|
||||||
|
|
||||||
|
if (_destination === anObject)
|
||||||
|
_destination = anotherObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)replaceObjects:(Object)replacementObjects
|
||||||
|
{
|
||||||
|
var replacement = replacementObjects[[_source UID]];
|
||||||
|
|
||||||
|
if (replacement !== undefined)
|
||||||
|
_source = replacement;
|
||||||
|
|
||||||
|
replacement = replacementObjects[[_destination UID]];
|
||||||
|
|
||||||
|
if (replacement !== undefined)
|
||||||
|
_destination = replacement;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation CPCibConnector (CPCoding)
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_source = [aCoder decodeObjectForKey:_CPCibConnectorSourceKey];
|
||||||
|
_destination = [aCoder decodeObjectForKey:_CPCibConnectorDestinationKey];
|
||||||
|
_label = [aCoder decodeObjectForKey:_CPCibConnectorLabelKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
[aCoder encodeObject:_source forKey:_CPCibConnectorSourceKey];
|
||||||
|
[aCoder encodeObject:_destination forKey:_CPCibConnectorDestinationKey];
|
||||||
|
[aCoder encodeObject:_label forKey:_CPCibConnectorLabelKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
// For backwards compatibility.
|
||||||
|
@implementation _CPCibConnector : CPCibConnector { } @end
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* CPCibControlConnector.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 "CPCibConnector.j"
|
||||||
|
|
||||||
|
|
||||||
|
@implementation CPCibControlConnector : CPCibConnector
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)establishConnection
|
||||||
|
{
|
||||||
|
var selectorName = _label,
|
||||||
|
selectorNameLength = [selectorName length];
|
||||||
|
|
||||||
|
if (selectorNameLength && selectorName.charAt(selectorNameLength - 1) !== ':')
|
||||||
|
selectorName += ':';
|
||||||
|
|
||||||
|
var selector = CPSelectorFromString(selectorName);
|
||||||
|
|
||||||
|
// Not having a selector is a fatal error.
|
||||||
|
if (!selector)
|
||||||
|
[CPException
|
||||||
|
raise:CPInvalidArgumentException
|
||||||
|
reason:@"-[" + [self className] + ' ' + _cmd + @"] selector " + selectorName + @" does not exist."];
|
||||||
|
|
||||||
|
// If the destination doesn't respond to this selector, warn but don't die.
|
||||||
|
if (_destination && ![_destination respondsToSelector:selector])
|
||||||
|
{
|
||||||
|
CPLog.warn(@"Could not connect the action " + selector + @" to target of class " + [_destination className]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not being able to set the action is a fatal error.
|
||||||
|
if ([_source respondsToSelector:@selector(setAction:)])
|
||||||
|
objj_msgSend(_source, @selector(setAction:), selector);
|
||||||
|
|
||||||
|
else
|
||||||
|
[CPException
|
||||||
|
raise:CPInvalidArgumentException
|
||||||
|
reason:@"-[" + [self className] + ' ' + _cmd + @"] " + [_source description] + " does not respond to setAction:"];
|
||||||
|
|
||||||
|
// Not being able to set the target is a fatal error.
|
||||||
|
if ([_source respondsToSelector:@selector(setTarget:)])
|
||||||
|
objj_msgSend(_source, @selector(setTarget:), _destination);
|
||||||
|
|
||||||
|
else
|
||||||
|
[CPException
|
||||||
|
raise:CPInvalidArgumentException
|
||||||
|
reason:@"-[" + [self className] + ' ' + _cmd + @"] " + [_source description] + " does not respond to setTarget:"];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPCibControlConnector : CPCibControlConnector { } @end
|
||||||
|
|
||||||
+69
-19
@@ -27,8 +27,6 @@
|
|||||||
|
|
||||||
var CPCibOwner = @"CPCibOwner";
|
var CPCibOwner = @"CPCibOwner";
|
||||||
|
|
||||||
var LoadInfoForCib = {};
|
|
||||||
|
|
||||||
@implementation CPObject (CPCibLoading)
|
@implementation CPObject (CPCibLoading)
|
||||||
|
|
||||||
- (void)awakeFromCib
|
- (void)awakeFromCib
|
||||||
@@ -39,15 +37,42 @@ var LoadInfoForCib = {};
|
|||||||
|
|
||||||
@implementation CPBundle (CPCibLoading)
|
@implementation CPBundle (CPCibLoading)
|
||||||
|
|
||||||
|
+ (void)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable
|
||||||
|
{
|
||||||
|
[[[CPCib alloc] initWithContentsOfURL:anAbsolutePath] instantiateCibWithExternalNameTable:aNameTable];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)loadCibNamed:(CPString)aName owner:(id)anOwner
|
||||||
|
{
|
||||||
|
if (![aName hasSuffix:@".cib"])
|
||||||
|
aName = [aName stringByAppendingString:@".cib"];
|
||||||
|
|
||||||
|
// Path is based solely on anOwner:
|
||||||
|
var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle],
|
||||||
|
path = [bundle pathForResource:aName];
|
||||||
|
|
||||||
|
[self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable
|
||||||
|
{
|
||||||
|
[[[CPCib alloc] initWithContentsOfURL:aFileName] instantiateCibWithExternalNameTable:aNameTable];
|
||||||
|
}
|
||||||
|
|
||||||
+ (void)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable loadDelegate:aDelegate
|
+ (void)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable loadDelegate:aDelegate
|
||||||
{
|
{
|
||||||
var cib = [[CPCib alloc] initWithContentsOfURL:anAbsolutePath loadDelegate:self];
|
[[CPCib alloc]
|
||||||
|
initWithContentsOfURL:anAbsolutePath
|
||||||
LoadInfoForCib[[cib hash]] = { loadDelegate:aDelegate, externalNameTable:aNameTable };
|
loadDelegate:[[_CPCibLoadDelegate alloc]
|
||||||
|
initWithLoadDelegate:aDelegate
|
||||||
|
externalNameTable:aNameTable]];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)loadCibNamed:(CPString)aName owner:(id)anOwner loadDelegate:(id)aDelegate
|
+ (void)loadCibNamed:(CPString)aName owner:(id)anOwner loadDelegate:(id)aDelegate
|
||||||
{
|
{
|
||||||
|
if (![aName hasSuffix:@".cib"])
|
||||||
|
aName = [aName stringByAppendingString:@".cib"];
|
||||||
|
|
||||||
// Path is based solely on anOwner:
|
// Path is based solely on anOwner:
|
||||||
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];
|
||||||
@@ -57,20 +82,45 @@ var LoadInfoForCib = {};
|
|||||||
|
|
||||||
- (void)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable loadDelegate:(id)aDelegate
|
- (void)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable loadDelegate:(id)aDelegate
|
||||||
{
|
{
|
||||||
var cib = [[CPCib alloc] initWithCibNamed:aFileName bundle:self loadDelegate:[self class]];
|
[[CPCib alloc]
|
||||||
|
initWithCibNamed:aFileName
|
||||||
LoadInfoForCib[[cib hash]] = { loadDelegate:aDelegate, externalNameTable:aNameTable };
|
bundle:self
|
||||||
}
|
loadDelegate:[[_CPCibLoadDelegate alloc]
|
||||||
|
initWithLoadDelegate:aDelegate
|
||||||
+ (void)cibDidFinishLoading:(CPCib)aCib
|
externalNameTable:aNameTable]];
|
||||||
{
|
}
|
||||||
var loadInfo = LoadInfoForCib[[aCib hash]];
|
|
||||||
|
@end
|
||||||
delete LoadInfoForCib[[aCib hash]];
|
|
||||||
|
@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
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* CPCibOutletConnector.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 "CPCibConnector.j"
|
||||||
|
|
||||||
|
|
||||||
|
@implementation CPCibOutletConnector : CPCibConnector
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)establishConnection
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
[_source setValue:_destination forKey:_label];
|
||||||
|
}
|
||||||
|
catch (anException)
|
||||||
|
{
|
||||||
|
if ([anException name] === CPUndefinedKeyException)
|
||||||
|
CPLog.warn(@"Could not connect the outlet " + _label + @" of target of class " + [_source className]);
|
||||||
|
|
||||||
|
else
|
||||||
|
throw anException;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation _CPCibOutletConnector : CPCibOutletConnector { } @end
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* _CPCibClassSwapper.j
|
||||||
|
* AppKit
|
||||||
|
*
|
||||||
|
* Created by Francisco Tolmasky.
|
||||||
|
* Copyright 2009, 280 North, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import <Foundation/CPObject.j>
|
||||||
|
@import <Foundation/CPString.j>
|
||||||
|
|
||||||
|
|
||||||
|
var _CPCibClassSwapperClassNameKey = @"_CPCibClassSwapperClassNameKey",
|
||||||
|
_CPCibClassSwapperOriginalClassNameKey = @"_CPCibClassSwapperOriginalClassNameKey";
|
||||||
|
|
||||||
|
@implementation _CPCibClassSwapper : CPObject
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)allocObjectWithCoder:(CPCoder)aCoder className:(CPString)aClassName
|
||||||
|
{
|
||||||
|
// FIXME: Also check class classForClassName:
|
||||||
|
var theClass = [aCoder classForClassName:aClassName];
|
||||||
|
|
||||||
|
if (!theClass)
|
||||||
|
{
|
||||||
|
theClass = objj_lookUpClass(aClassName);
|
||||||
|
|
||||||
|
if (!theClass)
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [theClass alloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)allocWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
if ([aCoder respondsToSelector:@selector(usesOriginalClasses)] && [aCoder usesOriginalClasses])
|
||||||
|
{
|
||||||
|
var theClassName = [aCoder decodeObjectForKey:_CPCibClassSwapperOriginalClassNameKey],
|
||||||
|
object = [self allocObjectWithCoder:aCoder className:theClassName];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var theClassName = [aCoder decodeObjectForKey:_CPCibClassSwapperClassNameKey],
|
||||||
|
object = [self allocObjectWithCoder:aCoder className:theClassName];
|
||||||
|
|
||||||
|
if (!object)
|
||||||
|
{
|
||||||
|
CPLog.error("Unable to find class " + theClassName + " in cib file.");
|
||||||
|
|
||||||
|
object = [self allocObjectWithCoder:aCoder className:[aCoder decodeObjectForKey:_CPCibClassSwapperOriginalClassNameKey]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!object)
|
||||||
|
[CPException raise:CPInvalidArgumentException reason:@"Unable to find class " + theClassName + " in cib file."];
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
|
|
||||||
@import <Foundation/CPObject.j>
|
|
||||||
@import <Foundation/CPKeyValueCoding.j>
|
|
||||||
|
|
||||||
|
|
||||||
var _CPCibConnectorSourceKey = @"_CPCibConnectorSourceKey",
|
|
||||||
_CPCibConnectorDestinationKey = @"_CPCibConnectorDestinationKey",
|
|
||||||
_CPCibConnectorLabelKey = @"_CPCibConnectorLabelKey";
|
|
||||||
|
|
||||||
@implementation _CPCibConnector : CPObject
|
|
||||||
{
|
|
||||||
id _source;
|
|
||||||
id _destination;
|
|
||||||
CPString _label;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)replaceObjects:(JSObject)replacementObjects
|
|
||||||
{
|
|
||||||
var replacement = replacementObjects[[_source hash]];
|
|
||||||
|
|
||||||
if (replacement !== undefined)
|
|
||||||
_source = replacement;
|
|
||||||
|
|
||||||
replacement = replacementObjects[[_destination hash]];
|
|
||||||
|
|
||||||
if (replacement !== undefined)
|
|
||||||
_destination = replacement;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation _CPCibConnector (CPCoding)
|
|
||||||
|
|
||||||
- (id)initWithCoder:(CPCoder)aCoder
|
|
||||||
{
|
|
||||||
self = [super init];
|
|
||||||
|
|
||||||
if (self)
|
|
||||||
{
|
|
||||||
_source = [aCoder decodeObjectForKey:_CPCibConnectorSourceKey];
|
|
||||||
_destination = [aCoder decodeObjectForKey:_CPCibConnectorDestinationKey];
|
|
||||||
_label = [aCoder decodeObjectForKey:_CPCibConnectorLabelKey];
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
|
||||||
{
|
|
||||||
[aCoder encodeObject:_source forKey:_CPCibConnectorSourceKey];
|
|
||||||
[aCoder encodeObject:_destination forKey:_CPCibConnectorDestinationKey];
|
|
||||||
[aCoder encodeObject:_label forKey:_CPCibConnectorLabelKey];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation _CPCibControlConnector : _CPCibConnector
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)establishConnection
|
|
||||||
{
|
|
||||||
var selectorName = _label;
|
|
||||||
|
|
||||||
if (![selectorName hasSuffix:@":"])
|
|
||||||
selectorName += ':';
|
|
||||||
|
|
||||||
var selector = CPSelectorFromString(selectorName);
|
|
||||||
|
|
||||||
if (!selector)
|
|
||||||
[CPException
|
|
||||||
raise:CPInvalidArgumentException
|
|
||||||
reason:@"-[" + [self className] + ' ' + _cmd + @"] selector " + selectorName + @" does not exist."];
|
|
||||||
|
|
||||||
if ([_source respondsToSelector:@selector(setAction:)])
|
|
||||||
objj_msgSend(_source, @selector(setAction:), selector);
|
|
||||||
|
|
||||||
else
|
|
||||||
[CPException
|
|
||||||
raise:CPInvalidArgumentException
|
|
||||||
reason:@"-[" + [self className] + ' ' + _cmd + @"] " + [_source description] + " does not respond to setAction:"];
|
|
||||||
|
|
||||||
if ([_source respondsToSelector:@selector(setTarget:)])
|
|
||||||
objj_msgSend(_source, @selector(setTarget:), _destination);
|
|
||||||
|
|
||||||
else
|
|
||||||
[CPException
|
|
||||||
raise:CPInvalidArgumentException
|
|
||||||
reason:@"-[" + [self className] + ' ' + _cmd + @"] " + [_source description] + " does not respond to setTarget:"];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation _CPCibOutletConnector : _CPCibConnector
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)establishConnection
|
|
||||||
{
|
|
||||||
[_source setValue:_destination forKey:_label];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -14,6 +14,11 @@ var _CPCibCustomObjectClassName = @"_CPCibCustomObjectClassName";
|
|||||||
return _className;
|
return _className;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setCustomClassName:(CPString)aClassName
|
||||||
|
{
|
||||||
|
_className = aClassName;
|
||||||
|
}
|
||||||
|
|
||||||
- (CPString)description
|
- (CPString)description
|
||||||
{
|
{
|
||||||
return [super description] + " (" + [self customClassName] + ')';
|
return [super description] + " (" + [self customClassName] + ')';
|
||||||
@@ -42,10 +47,21 @@ var _CPCibCustomObjectClassName = @"_CPCibCustomObjectClassName";
|
|||||||
{
|
{
|
||||||
var theClass = CPClassFromString(_className);
|
var theClass = CPClassFromString(_className);
|
||||||
|
|
||||||
#if DEBUG
|
// Hey this is us!
|
||||||
|
if (theClass === [self class])
|
||||||
|
{
|
||||||
|
_className = @"CPObject";
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
if (!theClass)
|
if (!theClass)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
CPLog("Unknown class \"" + _className + "\" in cib file");
|
CPLog("Unknown class \"" + _className + "\" in cib file");
|
||||||
#endif
|
#endif
|
||||||
|
theClass = [CPObject class];
|
||||||
|
}
|
||||||
|
|
||||||
if (theClass === [CPApplication class])
|
if (theClass === [CPApplication class])
|
||||||
return [CPApplication sharedApplication];
|
return [CPApplication sharedApplication];
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,17 @@
|
|||||||
return _className;
|
return _className;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setCustomClassName:(CPString)aClassName
|
||||||
|
{
|
||||||
|
if (_className === aClassName)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_className = aClassName;
|
||||||
|
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
var _CPCibCustomViewClassNameKey = @"_CPCibCustomViewClassNameKey";
|
var _CPCibCustomViewClassNameKey = @"_CPCibCustomViewClassNameKey";
|
||||||
@@ -58,16 +69,9 @@ var _CPCibCustomViewClassNameKey = @"_CPCibCustomViewClassNameKey";
|
|||||||
[aCoder encodeObject:_className forKey:_CPCibCustomViewClassNameKey];
|
[aCoder encodeObject:_className forKey:_CPCibCustomViewClassNameKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)drawRect:(CGRect)aRect
|
- (CPString)customClassName
|
||||||
{
|
{
|
||||||
var bounds = [self bounds],
|
return _className;
|
||||||
context = [[CPGraphicsContext currentContext] graphicsPort];
|
|
||||||
|
|
||||||
CGContextSetLineWidth(context, 1.0);
|
|
||||||
CGContextSetStrokeColor(context, [CPColor colorWithCalibratedRed:169.0 / 255.0 green:173.0 / 255.0 blue:178.0 / 255.0 alpha:1.0]);
|
|
||||||
CGContextStrokeRect(context, CGRectInset(CGRectIntegral(bounds), 0.5, 0.5));
|
|
||||||
CGContextSetFillColor(context, [CPColor colorWithCalibratedRed:224.0 / 255.0 green:236.0 / 255.0 blue:250.0 / 255.0 alpha:1.0]);
|
|
||||||
CGContextFillRect(context, CGRectInset(bounds, 2.0, 2.0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)_cibInstantiate
|
- (id)_cibInstantiate
|
||||||
@@ -99,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;
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,9 @@
|
|||||||
|
|
||||||
@implementation _CPCibKeyedUnarchiver : CPKeyedUnarchiver
|
@implementation _CPCibKeyedUnarchiver : CPKeyedUnarchiver
|
||||||
{
|
{
|
||||||
CPBundle _bundle;
|
CPBundle _bundle;
|
||||||
BOOL _awakenCustomResources;
|
BOOL _awakenCustomResources;
|
||||||
|
CPDictionary _externalObjectsForProxyIdentifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initForReadingWithData:(CPData)data bundle:(CPBundle)aBundle awakenCustomResources:(BOOL)shouldAwakenCustomResources
|
- (id)initForReadingWithData:(CPData)data bundle:(CPBundle)aBundle awakenCustomResources:(BOOL)shouldAwakenCustomResources
|
||||||
@@ -33,6 +34,16 @@
|
|||||||
return _awakenCustomResources;
|
return _awakenCustomResources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setExternalObjectsForProxyIdentifiers:(CPDictionary)externalObjectsForProxyIdentifiers
|
||||||
|
{
|
||||||
|
_externalObjectsForProxyIdentifiers = externalObjectsForProxyIdentifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)externalObjectForProxyIdentifier:(CPString)anIdentifier
|
||||||
|
{
|
||||||
|
return [_externalObjectsForProxyIdentifiers objectForKey:anIdentifier];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)replaceObjectAtUID:(int)aUID withObject:(id)anObject
|
- (void)replaceObjectAtUID:(int)aUID withObject:(id)anObject
|
||||||
{
|
{
|
||||||
_objects[aUID] = anObject;
|
_objects[aUID] = anObject;
|
||||||
|
|||||||
@@ -25,7 +25,9 @@
|
|||||||
@import <Foundation/CPString.j>
|
@import <Foundation/CPString.j>
|
||||||
|
|
||||||
@import "CPCib.j"
|
@import "CPCib.j"
|
||||||
@import "_CPCibConnector.j"
|
@import "CPCibConnector.j"
|
||||||
|
@import "CPCibControlConnector.j"
|
||||||
|
@import "CPCibOutletConnector.j"
|
||||||
|
|
||||||
|
|
||||||
@implementation _CPCibObjectData : CPObject
|
@implementation _CPCibObjectData : CPObject
|
||||||
@@ -98,28 +100,13 @@
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPMenu)mainMenu
|
|
||||||
{
|
|
||||||
var index = [_namesValues indexOfObjectIdenticalTo:"MainMenu"];
|
|
||||||
|
|
||||||
if (index === CPNotFound)
|
|
||||||
{
|
|
||||||
index = [_namesValues indexOfObjectIdenticalTo:"Main Menu"];
|
|
||||||
|
|
||||||
if (index === CPNotFound)
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _namesKeys[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)displayVisibleWindows
|
- (void)displayVisibleWindows
|
||||||
{
|
{
|
||||||
var object = nil,
|
var object = nil,
|
||||||
objectEnumerator = [_visibleWindows objectEnumerator];
|
objectEnumerator = [_visibleWindows objectEnumerator];
|
||||||
|
|
||||||
while (object = [objectEnumerator nextObject])
|
while (object = [objectEnumerator nextObject])
|
||||||
[_replacementObjects[[object hash]] makeKeyAndOrderFront:self];
|
[_replacementObjects[[object UID]] makeKeyAndOrderFront:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -242,7 +229,7 @@ var _CPCibObjectDataNamesKeysKey = @"_CPCibObjectDataNamesKeysKey
|
|||||||
|
|
||||||
if (instantiatedObject !== object)
|
if (instantiatedObject !== object)
|
||||||
{
|
{
|
||||||
_replacementObjects[[object hash]] = instantiatedObject;
|
_replacementObjects[[object UID]] = instantiatedObject;
|
||||||
|
|
||||||
if ([instantiatedObject isKindOfClass:[CPView class]])
|
if ([instantiatedObject isKindOfClass:[CPView class]])
|
||||||
{
|
{
|
||||||
@@ -266,7 +253,7 @@ var _CPCibObjectDataNamesKeysKey = @"_CPCibObjectDataNamesKeysKey
|
|||||||
|
|
||||||
- (void)establishConnectionsWithOwner:(id)anOwner topLevelObjects:(CPMutableArray)topLevelObjects
|
- (void)establishConnectionsWithOwner:(id)anOwner topLevelObjects:(CPMutableArray)topLevelObjects
|
||||||
{
|
{
|
||||||
_replacementObjects[[_fileOwner hash]] = anOwner;
|
_replacementObjects[[_fileOwner UID]] = anOwner;
|
||||||
|
|
||||||
var index = 0,
|
var index = 0,
|
||||||
count = _connections.length;
|
count = _connections.length;
|
||||||
@@ -287,7 +274,7 @@ var _CPCibObjectDataNamesKeysKey = @"_CPCibObjectDataNamesKeysKey
|
|||||||
while (count--)
|
while (count--)
|
||||||
{
|
{
|
||||||
var object = _objectsKeys[count],
|
var object = _objectsKeys[count],
|
||||||
instantiatedObject = _replacementObjects[[object hash]];
|
instantiatedObject = _replacementObjects[[object UID]];
|
||||||
|
|
||||||
if (instantiatedObject)
|
if (instantiatedObject)
|
||||||
object = instantiatedObject;
|
object = instantiatedObject;
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
|
|
||||||
|
@implementation _CPCibProxyObject : CPObject
|
||||||
|
{
|
||||||
|
CPString _identifier;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
var _CPCibProxyObjectIdentifierKey = @"CPIdentifier";
|
||||||
|
|
||||||
|
@implementation _CPCibProxyObject (CPCoding)
|
||||||
|
|
||||||
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
_identifier = [aCoder decodeObjectForKey:_CPCibProxyObjectIdentifierKey];
|
||||||
|
|
||||||
|
if ([aCoder respondsToSelector:@selector(externalObjectForProxyIdentifier:)])
|
||||||
|
return [aCoder externalObjectForProxyIdentifier:_identifier];
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||||
|
{
|
||||||
|
[aCoder encodeObject:_identifier forKey:_CPCibProxyObjectIdentifierKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -2,18 +2,19 @@
|
|||||||
@import <Foundation/CPObject.j>
|
@import <Foundation/CPObject.j>
|
||||||
|
|
||||||
|
|
||||||
var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey",
|
var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey",
|
||||||
_CPCibWindowTemplateMaxSizeKey = @"_CPCibWindowTemplateMaxSizeKey",
|
_CPCibWindowTemplateMaxSizeKey = @"_CPCibWindowTemplateMaxSizeKey",
|
||||||
|
|
||||||
_CPCibWindowTemplateViewClassKey = @"_CPCibWindowTemplateViewClassKey",
|
_CPCibWindowTemplateViewClassKey = @"_CPCibWindowTemplateViewClassKey",
|
||||||
_CPCibWindowTemplateWindowClassKey = @"_CPCibWindowTemplateWindowClassKey",
|
_CPCibWindowTemplateWindowClassKey = @"_CPCibWindowTemplateWindowClassKey",
|
||||||
|
|
||||||
_CPCibWindowTemplateWindowRectKey = @"_CPCibWindowTemplateWindowRectKey",
|
_CPCibWindowTemplateWindowRectKey = @"_CPCibWindowTemplateWindowRectKey",
|
||||||
_CPCibWindowTemplateWindowStyleMaskKey = @"_CPCibWindowTempatStyleMaskKey",
|
_CPCibWindowTemplateWindowStyleMaskKey = @"_CPCibWindowTempatStyleMaskKey",
|
||||||
_CPCibWindowTemplateWindowTitleKey = @"_CPCibWindowTemplateWindowTitleKey",
|
_CPCibWindowTemplateWindowTitleKey = @"_CPCibWindowTemplateWindowTitleKey",
|
||||||
_CPCibWindowTemplateWindowViewKey = @"_CPCibWindowTemplateWindowViewKey",
|
_CPCibWindowTemplateWindowViewKey = @"_CPCibWindowTemplateWindowViewKey",
|
||||||
|
|
||||||
_CPCibWindowTemplateWindowIsFullBridgeKey = @"_CPCibWindowTemplateWindowIsFullBridgeKey";
|
_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop = @"_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop";
|
||||||
|
_CPCibWindowTemplateWindowIsFullPlatformWindowKey = @"_CPCibWindowTemplateWindowIsFullPlatformWindowKey";
|
||||||
|
|
||||||
@implementation _CPCibWindowTemplate : CPObject
|
@implementation _CPCibWindowTemplate : CPObject
|
||||||
{
|
{
|
||||||
@@ -30,7 +31,27 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeK
|
|||||||
CPString _windowTitle;
|
CPString _windowTitle;
|
||||||
CPView _windowView;
|
CPView _windowView;
|
||||||
|
|
||||||
BOOL _windowIsFullBridge;
|
BOOL _windowAutorecalculatesKeyViewLoop;
|
||||||
|
BOOL _windowIsFullPlatformWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (self)
|
||||||
|
{
|
||||||
|
_windowClass = @"CPWindow";
|
||||||
|
_windowRect = CGRectMake(0.0, 0.0, 400.0, 200.0);
|
||||||
|
_windowStyleMask = CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask;
|
||||||
|
|
||||||
|
_windowTitle = @"Window";
|
||||||
|
_windowView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 400.0, 200.0)];
|
||||||
|
|
||||||
|
_windowIsFullPlatformWindow = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithCoder:(CPCoder)aCoder
|
- (id)initWithCoder:(CPCoder)aCoder
|
||||||
@@ -53,7 +74,8 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeK
|
|||||||
_windowTitle = [aCoder decodeObjectForKey:_CPCibWindowTemplateWindowTitleKey];
|
_windowTitle = [aCoder decodeObjectForKey:_CPCibWindowTemplateWindowTitleKey];
|
||||||
_windowView = [aCoder decodeObjectForKey:_CPCibWindowTemplateWindowViewKey];
|
_windowView = [aCoder decodeObjectForKey:_CPCibWindowTemplateWindowViewKey];
|
||||||
|
|
||||||
_windowIsFullBridge = [aCoder decodeObjectForKey:_CPCibWindowTemplateWindowIsFullBridgeKey];
|
_windowAutorecalculatesKeyViewLoop = !![aCoder decodeObjectForKey:_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop];
|
||||||
|
_windowIsFullPlatformWindow = !![aCoder decodeObjectForKey:_CPCibWindowTemplateWindowIsFullPlatformWindowKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -75,7 +97,22 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeK
|
|||||||
[aCoder encodeObject:_windowTitle forKey:_CPCibWindowTemplateWindowTitleKey];
|
[aCoder encodeObject:_windowTitle forKey:_CPCibWindowTemplateWindowTitleKey];
|
||||||
[aCoder encodeObject:_windowView forKey:_CPCibWindowTemplateWindowViewKey];
|
[aCoder encodeObject:_windowView forKey:_CPCibWindowTemplateWindowViewKey];
|
||||||
|
|
||||||
[aCoder encodeObject:_windowIsFullBridge forKey:_CPCibWindowTemplateWindowIsFullBridgeKey];
|
if (_windowAutorecalculatesKeyViewLoop)
|
||||||
|
[aCoder encodeObject:_windowAutorecalculatesKeyViewLoop forKey:_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop];
|
||||||
|
|
||||||
|
if (_windowIsFullPlatformWindow)
|
||||||
|
[aCoder encodeObject:_windowIsFullPlatformWindow forKey:_CPCibWindowTemplateWindowIsFullPlatformWindowKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CPString)customClassName
|
||||||
|
{
|
||||||
|
return _windowClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)setCustomClassName:(CPString)aClassName
|
||||||
|
{
|
||||||
|
_windowClass = aClassName;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CPString)windowClass
|
- (CPString)windowClass
|
||||||
@@ -97,9 +134,8 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeK
|
|||||||
[theWindow setMinSize:_minSize];
|
[theWindow setMinSize:_minSize];
|
||||||
if (_maxSize)
|
if (_maxSize)
|
||||||
[theWindow setMaxSize:_maxSize];
|
[theWindow setMaxSize:_maxSize];
|
||||||
[theWindow setLevel:CPFloatingWindowLevel];
|
|
||||||
|
|
||||||
//[result setHidesOnDeactivate:(_wtFlags&0x80000000)?YES:NO];
|
//[result setHidesOnDeactivate:(_wtFlags&0x80000000)?YES:NO];
|
||||||
[theWindow setTitle:_windowTitle];
|
[theWindow setTitle:_windowTitle];
|
||||||
|
|
||||||
// FIXME: we can't autoresize yet...
|
// FIXME: we can't autoresize yet...
|
||||||
@@ -114,7 +150,8 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeK
|
|||||||
[theWindow setToolbar:_viewClass];
|
[theWindow setToolbar:_viewClass];
|
||||||
}
|
}
|
||||||
|
|
||||||
[theWindow setFullBridge:_windowIsFullBridge];
|
[theWindow setAutorecalculatesKeyViewLoop:_windowAutorecalculatesKeyViewLoop];
|
||||||
|
[theWindow setFullBridge:_windowIsFullPlatformWindow];
|
||||||
|
|
||||||
return theWindow;
|
return theWindow;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,8 +54,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code>
|
Returns \c YES
|
||||||
@return <code>YES</code>
|
@return \c YES
|
||||||
*/
|
*/
|
||||||
- (void)shouldArchiveValueForKey:(CPString)aKey
|
- (void)shouldArchiveValueForKey:(CPString)aKey
|
||||||
{
|
{
|
||||||
@@ -63,8 +63,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>nil</code>
|
Returns \c nil
|
||||||
@return <code>nil</code>
|
@return \c nil
|
||||||
*/
|
*/
|
||||||
+ (id)defaultValueForKey:(CPString)aKey
|
+ (id)defaultValueForKey:(CPString)aKey
|
||||||
{
|
{
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Specifies whether this animation should be removed after it has completed.
|
Specifies whether this animation should be removed after it has completed.
|
||||||
@param <code>YES</code> means the animation should be removed
|
@param \c YES means the animation should be removed
|
||||||
*/
|
*/
|
||||||
- (void)setRemovedOnCompletion:(BOOL)isRemovedOnCompletion
|
- (void)setRemovedOnCompletion:(BOOL)isRemovedOnCompletion
|
||||||
{
|
{
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the animation is removed after completion
|
Returns \c YES if the animation is removed after completion
|
||||||
*/
|
*/
|
||||||
- (BOOL)removedOnCompletion
|
- (BOOL)removedOnCompletion
|
||||||
{
|
{
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the animation is removed after completion
|
Returns \c YES if the animation is removed after completion
|
||||||
*/
|
*/
|
||||||
- (BOOL)isRemovedOnCompletion
|
- (BOOL)isRemovedOnCompletion
|
||||||
{
|
{
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the animation's timing function. If <code>nil</code>, then it has a linear pacing.
|
Returns the animation's timing function. If \c nil, then it has a linear pacing.
|
||||||
*/
|
*/
|
||||||
- (CAMediaTimingFunction)timingFunction
|
- (CAMediaTimingFunction)timingFunction
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -56,12 +56,12 @@ var CALayerRegisteredRunLoopUpdates = nil;
|
|||||||
|
|
||||||
@delegate -(void)drawLayer:(CALayer)layer inContext:(CGContextRef)ctx;
|
@delegate -(void)drawLayer:(CALayer)layer inContext:(CGContextRef)ctx;
|
||||||
If the delegate implements this method, the CALayer will
|
If the delegate implements this method, the CALayer will
|
||||||
call this in place of its <code>drawInContext:</code>.
|
call this in place of its \c -drawInContext:.
|
||||||
@param layer the layer to draw for
|
@param layer the layer to draw for
|
||||||
@param ctx the context to draw on
|
@param ctx the context to draw on
|
||||||
|
|
||||||
@delegate -(void)displayLayer:(CALayer)layer;
|
@delegate -(void)displayLayer:(CALayer)layer;
|
||||||
The delegate can override the layer's <code>display</code> method
|
The delegate can override the layer's \c -display method
|
||||||
by implementing this method.
|
by implementing this method.
|
||||||
*/
|
*/
|
||||||
@implementation CALayer : CPObject
|
@implementation CALayer : CPObject
|
||||||
@@ -419,7 +419,7 @@ var CALayerRegisteredRunLoopUpdates = nil;
|
|||||||
// Providing Layer Content
|
// Providing Layer Content
|
||||||
/*!
|
/*!
|
||||||
Returns the CGImage contents of this layer.
|
Returns the CGImage contents of this layer.
|
||||||
The default contents are <code>nil</code>.
|
The default contents are \c nil.
|
||||||
*/
|
*/
|
||||||
- (CGImage)contents
|
- (CGImage)contents
|
||||||
{
|
{
|
||||||
@@ -547,7 +547,7 @@ var CALayerRegisteredRunLoopUpdates = nil;
|
|||||||
// Style Attributes
|
// Style Attributes
|
||||||
/*!
|
/*!
|
||||||
Returns the opacity of the layer. The value is between
|
Returns the opacity of the layer. The value is between
|
||||||
<code>0.0</code> (transparent) and <code>1.0</code> (opaque).
|
\c 0.0 (transparent) and \c 1.0 (opaque).
|
||||||
*/
|
*/
|
||||||
- (float)opacity
|
- (float)opacity
|
||||||
{
|
{
|
||||||
@@ -556,7 +556,7 @@ var CALayerRegisteredRunLoopUpdates = nil;
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets the opacity for the layer.
|
Sets the opacity for the layer.
|
||||||
@param anOpacity the new opacity (between <code>0.0</code> (transparent) and <code>1.0</code> (opaque)).
|
@param anOpacity the new opacity (between \c 0.0 (transparent) and \c 1.0 (opaque)).
|
||||||
*/
|
*/
|
||||||
- (void)setOpacity:(float)anOpacity
|
- (void)setOpacity:(float)anOpacity
|
||||||
{
|
{
|
||||||
@@ -571,7 +571,7 @@ var CALayerRegisteredRunLoopUpdates = nil;
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether the layer is hidden.
|
Sets whether the layer is hidden.
|
||||||
@param isHidden <code>YES</code> means the layer will be hidden. <code>NO</code> means the layer will be visible.
|
@param isHidden \c YES means the layer will be hidden. \c NO means the layer will be visible.
|
||||||
*/
|
*/
|
||||||
- (void)setHidden:(BOOL)isHidden
|
- (void)setHidden:(BOOL)isHidden
|
||||||
{
|
{
|
||||||
@@ -580,7 +580,7 @@ var CALayerRegisteredRunLoopUpdates = nil;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the layer is hidden.
|
Returns \c YES if the layer is hidden.
|
||||||
*/
|
*/
|
||||||
- (BOOL)hidden
|
- (BOOL)hidden
|
||||||
{
|
{
|
||||||
@@ -588,7 +588,7 @@ var CALayerRegisteredRunLoopUpdates = nil;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the layer is hidden.
|
Returns \c YES if the layer is hidden.
|
||||||
*/
|
*/
|
||||||
- (BOOL)isHidden
|
- (BOOL)isHidden
|
||||||
{
|
{
|
||||||
@@ -597,7 +597,7 @@ var CALayerRegisteredRunLoopUpdates = nil;
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether content that goes lies outside the bounds is hidden or visible.
|
Sets whether content that goes lies outside the bounds is hidden or visible.
|
||||||
@param masksToBounds <code>YES</code> hides the excess content. <code>NO</code> makes it visible.
|
@param masksToBounds \c YES hides the excess content. \c NO makes it visible.
|
||||||
*/
|
*/
|
||||||
- (void)setMasksToBounds:(BOOL)masksToBounds
|
- (void)setMasksToBounds:(BOOL)masksToBounds
|
||||||
{
|
{
|
||||||
@@ -724,7 +724,7 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
|
|||||||
Inserts a layer below another layer.
|
Inserts a layer below another layer.
|
||||||
@param aLayer the layer to insert
|
@param aLayer the layer to insert
|
||||||
@param aSublayer the layer to insert below
|
@param aSublayer the layer to insert below
|
||||||
@throws CALayerNotFoundException if <code>aSublayer</code> is not in the array of sublayers
|
@throws CALayerNotFoundException if \c aSublayer is not in the array of sublayers
|
||||||
*/
|
*/
|
||||||
- (void)insertSublayer:(CALayer)aLayer below:(CALayer)aSublayer
|
- (void)insertSublayer:(CALayer)aLayer below:(CALayer)aSublayer
|
||||||
{
|
{
|
||||||
@@ -737,7 +737,7 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
|
|||||||
Inserts a layer above another layer.
|
Inserts a layer above another layer.
|
||||||
@param aLayer the layer to insert
|
@param aLayer the layer to insert
|
||||||
@param aSublayer the layer to insert above
|
@param aSublayer the layer to insert above
|
||||||
@throws CALayerNotFoundException if <code>aSublayer</code> is not in the array of sublayers
|
@throws CALayerNotFoundException if \c aSublayer is not in the array of sublayers
|
||||||
*/
|
*/
|
||||||
- (void)insertSublayer:(CALayer)aLayer above:(CALayer)aSublayer
|
- (void)insertSublayer:(CALayer)aLayer above:(CALayer)aSublayer
|
||||||
{
|
{
|
||||||
@@ -777,11 +777,10 @@ 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 (hash in CALayerRegisteredRunLoopUpdates)
|
|
||||||
{
|
{
|
||||||
var layer = CALayerRegisteredRunLoopUpdates[hash],
|
var layer = CALayerRegisteredRunLoopUpdates[UID],
|
||||||
mask = layer._runLoopUpdateMask;
|
mask = layer._runLoopUpdateMask;
|
||||||
|
|
||||||
if (mask & CALayerDOMUpdateMask)
|
if (mask & CALayerDOMUpdateMask)
|
||||||
@@ -813,7 +812,7 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_runLoopUpdateMask |= anUpdateMask;
|
_runLoopUpdateMask |= anUpdateMask;
|
||||||
CALayerRegisteredRunLoopUpdates[[self hash]] = self;
|
CALayerRegisteredRunLoopUpdates[[self UID]] = self;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -834,7 +833,7 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Sets whether the layer needs to be redrawn when its bounds are changed.
|
Sets whether the layer needs to be redrawn when its bounds are changed.
|
||||||
@param needsDisplayOnBoundsChange <code>YES</code> means the display is redraw on a bounds change.
|
@param needsDisplayOnBoundsChange \c YES means the display is redraw on a bounds change.
|
||||||
*/
|
*/
|
||||||
- (void)setNeedsDisplayOnBoundsChange:(BOOL)needsDisplayOnBoundsChange
|
- (void)setNeedsDisplayOnBoundsChange:(BOOL)needsDisplayOnBoundsChange
|
||||||
{
|
{
|
||||||
@@ -842,7 +841,7 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the display should be redrawn on a bounds change.
|
Returns \c YES if the display should be redrawn on a bounds change.
|
||||||
*/
|
*/
|
||||||
- (BOOL)needsDisplayOnBoundsChange
|
- (BOOL)needsDisplayOnBoundsChange
|
||||||
{
|
{
|
||||||
@@ -906,7 +905,7 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
|
|||||||
|
|
||||||
// Hit Testing
|
// Hit Testing
|
||||||
/*!
|
/*!
|
||||||
Returns <code>YES</code> if the layer contains the point.
|
Returns \c YES if the layer contains the point.
|
||||||
@param aPoint the point to test
|
@param aPoint the point to test
|
||||||
*/
|
*/
|
||||||
- (BOOL)containsPoint:(CGPoint)aPoint
|
- (BOOL)containsPoint:(CGPoint)aPoint
|
||||||
@@ -917,7 +916,7 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
|
|||||||
/*!
|
/*!
|
||||||
Returns the farthest descendant of this layer that contains the specified point.
|
Returns the farthest descendant of this layer that contains the specified point.
|
||||||
@param aPoint the point to test
|
@param aPoint the point to test
|
||||||
@return the containing layer or <code>nil</code> if there was no hit.
|
@return the containing layer or \c nil if there was no hit.
|
||||||
*/
|
*/
|
||||||
- (CALayer)hitTest:(CGPoint)aPoint
|
- (CALayer)hitTest:(CGPoint)aPoint
|
||||||
{
|
{
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user