Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
099ee1e249 | ||
|
|
aba7fd5527 | ||
|
|
68c794bf9d | ||
|
|
ca9b3a7dbf | ||
|
|
4eba585286 | ||
|
|
4172ecfdf2 | ||
|
|
da80176935 | ||
|
|
f50802b85b | ||
|
|
5351bf7e12 | ||
|
|
96a038559e | ||
|
|
c321084990 | ||
|
|
e13d070439 | ||
|
|
1a8fc7f07f | ||
|
|
9ef95e1f68 | ||
|
|
28ed2f9bd0 | ||
|
|
93f51eaa42 | ||
|
|
7c807dd887 | ||
|
|
429b42d3e0 | ||
|
|
08f013171e | ||
|
|
d620032d0d | ||
|
|
3bc5605633 | ||
|
|
3a0068186a | ||
|
|
e19a782954 | ||
|
|
88783efa7b | ||
|
|
a249588f52 | ||
|
|
2951a83e73 | ||
|
|
b99ece088d | ||
|
|
ebd797d6d7 | ||
|
|
fa7a68f3f8 | ||
|
|
8167c46cfc | ||
|
|
9456810c7e | ||
|
|
79f2ec5d17 | ||
|
|
38a0a261c0 | ||
|
|
91eb23ba87 | ||
|
|
706129bcbd | ||
|
|
97b77e9b7b | ||
|
|
3b85a67faf | ||
|
|
f2571e6536 | ||
|
|
bec8a4b1c6 | ||
|
|
028fb03ef1 | ||
|
|
65aa08a9d9 | ||
|
|
22058a7a93 | ||
|
|
90514bd3cb | ||
|
|
bd7d258fcd | ||
|
|
c21e40e819 | ||
|
|
e0c8ae6335 | ||
|
|
e9d5d33cb2 | ||
|
|
0d9b49df85 | ||
|
|
db5e5d7da6 | ||
|
|
44236795b5 | ||
|
|
a26bca5dbe | ||
|
|
872b446695 | ||
|
|
2b0ed8234c | ||
|
|
39ec1cfd27 | ||
|
|
b7dcd24e11 | ||
|
|
5097030143 | ||
|
|
516fac037f | ||
|
|
1bf632a575 | ||
|
|
6137aa8637 | ||
|
|
4be4506ffc | ||
|
|
d3c368ba92 | ||
|
|
9b0d03b024 | ||
|
|
c21d2fd017 | ||
|
|
2940b5e787 | ||
|
|
cf18bcaaf9 | ||
|
|
c4eaf083b4 | ||
|
|
df6b592d11 | ||
|
|
109e8b1e33 | ||
|
|
85c88d7c93 | ||
|
|
d8e5fa3087 | ||
|
|
697a7b308a | ||
|
|
dcc031f23a | ||
|
|
061ea47953 | ||
|
|
f0e5161b7b | ||
|
|
eada36af26 | ||
|
|
a02c687df9 | ||
|
|
e636087f4a | ||
|
|
4876f77914 | ||
|
|
ed6bed9bf7 | ||
|
|
87cb2eb19d | ||
|
|
53334251b8 | ||
|
|
a069f2945b | ||
|
|
5a0e1d7bb3 | ||
|
|
ed1d77c86d | ||
|
|
74054442a2 | ||
|
|
59ef8329c0 | ||
|
|
20cffaa7fe | ||
|
|
ebeb1040e8 | ||
|
|
cdb919dea3 | ||
|
|
c509e6131a | ||
|
|
db6a4d7042 | ||
|
|
a32b5ea72b | ||
|
|
58a2fce110 | ||
|
|
3d9ae42dbf | ||
|
|
c4a16d10bc | ||
|
|
eeca40c6f0 | ||
|
|
2a031e82a4 | ||
|
|
0e6ce205ab | ||
|
|
9acbe0f2f8 | ||
|
|
3ee9c1a439 | ||
|
|
0eeff20af6 | ||
|
|
a1cf9f1cd4 | ||
|
|
3897f422fe | ||
|
|
9d785d1a3c | ||
|
|
66f818872c | ||
|
|
342bacb25c | ||
|
|
8e81be0319 | ||
|
|
3acfa142bc | ||
|
|
94a58c810e | ||
|
|
757a2bf400 | ||
|
|
b18fbd685b | ||
|
|
56b5a9ec22 | ||
|
|
70432f0198 | ||
|
|
0736f86f32 | ||
|
|
107d739489 | ||
|
|
32a86a911f | ||
|
|
9a32733f88 | ||
|
|
0f655e3264 | ||
|
|
55a4afa341 | ||
|
|
3b5aa1a2ab | ||
|
|
658e569251 | ||
|
|
4eacfd83d6 | ||
|
|
ad0fd0a34e | ||
|
|
1d8092e431 | ||
|
|
87cc62d1d8 | ||
|
|
a16388b57d | ||
|
|
98e54d2e09 | ||
|
|
bd02ec057c | ||
|
|
6ac804d37c | ||
|
|
4b764dc8b4 | ||
|
|
3a8ad56d4b | ||
|
|
f5bee48d98 | ||
|
|
24fbfbee60 | ||
|
|
a1bc5ad4d3 | ||
|
|
4aa3824a2a | ||
|
|
37d92c1182 | ||
|
|
a0eadc6c4a | ||
|
|
fdf672cf0a | ||
|
|
b8dacb1ffa | ||
|
|
81a99dd190 | ||
|
|
6a42d601c5 | ||
|
|
59ce74a3df | ||
|
|
eacee00fc8 | ||
|
|
fe70a5541e | ||
|
|
c9d4089b9a | ||
|
|
8fdb872605 | ||
|
|
8b28041cf0 | ||
|
|
4d3f8c3c8c | ||
|
|
f8cb4a15cb | ||
|
|
dd7d36da43 | ||
|
|
12201d38f3 | ||
|
|
3b4ad1d583 | ||
|
|
d44df8a9da | ||
|
|
ab88f72827 | ||
|
|
75a00e8c4a | ||
|
|
76c5500488 | ||
|
|
8cb7c05c88 | ||
|
|
e081dbf127 | ||
|
|
71e8f0201a | ||
|
|
c9ecb20b50 | ||
|
|
7dc213995c | ||
|
|
bea34a9b35 | ||
|
|
5ae405a89b | ||
|
|
66fcbe7871 | ||
|
|
b27a3cdbe5 | ||
|
|
9d7b822409 | ||
|
|
ab3f260757 | ||
|
|
b26b0a321b | ||
|
|
9536858599 | ||
|
|
c7d3ccb13a | ||
|
|
a081f98fd1 | ||
|
|
7096ea549e | ||
|
|
8e007985a1 | ||
|
|
e03e774113 | ||
|
|
7a41282912 | ||
|
|
c8f8c01d2f | ||
|
|
7f6db7bf98 | ||
|
|
e058efb622 | ||
|
|
c14643849f | ||
|
|
edd09ef06a | ||
|
|
d06fccf157 | ||
|
|
6bc3d49ba2 | ||
|
|
a8d8736899 | ||
|
|
b1e4a43cd3 | ||
|
|
eafbebcebb | ||
|
|
0c72c52ba2 | ||
|
|
e8194d9c2e | ||
|
|
f0e1b67197 | ||
|
|
7ba27cf617 | ||
|
|
c9f765645c | ||
|
|
5daa8cb289 | ||
|
|
789d832808 | ||
|
|
d7971322cb | ||
|
|
6ddeb167b3 | ||
|
|
c1be09c692 | ||
|
|
1c2a304ee5 | ||
|
|
1a51acf2fc | ||
|
|
47a5296f0b | ||
|
|
1189e8c849 | ||
|
|
ce2316a8ee | ||
|
|
ec9ddc0819 | ||
|
|
a5bd55dcac | ||
|
|
b0b1bd88a6 | ||
|
|
75d5619abd | ||
|
|
522a641690 | ||
|
|
b39f509263 | ||
|
|
1ea95bf6e0 | ||
|
|
08d690b65d | ||
|
|
80f5ab09f3 | ||
|
|
5c8f201a92 | ||
|
|
cf777d7f41 | ||
|
|
bb7876759a | ||
|
|
800d6498d6 | ||
|
|
0648b4279f | ||
|
|
1a73abe7c3 | ||
|
|
cce4f7883c | ||
|
|
3dff67e0b1 | ||
|
|
24326883ca | ||
|
|
a5854f129d | ||
|
|
052c07f3e3 | ||
|
|
9367566e61 | ||
|
|
107103bcbb | ||
|
|
20ae47971c | ||
|
|
d4ecb03d15 | ||
|
|
f4eb47519d | ||
|
|
e37bfeeb09 | ||
|
|
bb0972ba49 | ||
|
|
ddc5994869 | ||
|
|
2169ba35ad | ||
|
|
50b447b05d | ||
|
|
bc14ad6b9d | ||
|
|
ffa33788c4 | ||
|
|
23c9c6bf44 | ||
|
|
476c02976b | ||
|
|
6ac28e1a77 | ||
|
|
4ec7cea6c4 | ||
|
|
0036f329f5 | ||
|
|
15af54efda | ||
|
|
07966bb7fe | ||
|
|
e7d9b0503b | ||
|
|
072b43d178 | ||
|
|
281d2295ae | ||
|
|
79cf4370b4 | ||
|
|
6217fc8459 | ||
|
|
f1fd3d170a | ||
|
|
4e410f8a81 | ||
|
|
7a1b273d8d | ||
|
|
820531342d | ||
|
|
353db3277a | ||
|
|
82f37549ae | ||
|
|
09e1bd6bf1 | ||
|
|
44f3abf262 | ||
|
|
8c09af5013 | ||
|
|
0781e932c6 | ||
|
|
3cee00323c | ||
|
|
b1f6f3ddfa | ||
|
|
7147266ddf | ||
|
|
357212bff7 | ||
|
|
ed4fc3b20f | ||
|
|
7e8b71dd52 | ||
|
|
267f00bfe1 | ||
|
|
8f90dbce99 | ||
|
|
00485dba89 | ||
|
|
8fd4f5e4b6 | ||
|
|
e7e69b3fd4 | ||
|
|
2463c1dc05 | ||
|
|
bc590286f2 | ||
|
|
8c83816ec8 | ||
|
|
699069ce8f | ||
|
|
ec0cd22c1d | ||
|
|
8da3a8866d | ||
|
|
21f6fdff48 | ||
|
|
ed82a1fc87 | ||
|
|
1fa143453d | ||
|
|
1240bab7ed | ||
|
|
4af29d83d7 | ||
|
|
6aed29af91 | ||
|
|
37f1f50000 | ||
|
|
a93654c66b | ||
|
|
0d2dd94c81 | ||
|
|
c2f97e9aa3 | ||
|
|
e04bf6de95 | ||
|
|
38499c006a | ||
|
|
80cac38682 | ||
|
|
2b16d36aa2 | ||
|
|
dc9d49a12c | ||
|
|
03c81dfa9c | ||
|
|
b096e5dd0a | ||
|
|
7ae519145f | ||
|
|
592c3c1652 | ||
|
|
e940f294a6 | ||
|
|
759de8f45f | ||
|
|
c92c6c37f7 | ||
|
|
f425601043 | ||
|
|
68ba089a26 | ||
|
|
5ff7169546 | ||
|
|
7365a95b4d | ||
|
|
788427ec09 | ||
|
|
01ed8ad583 | ||
|
|
f516ba7a7d | ||
|
|
ab5603bd5a | ||
|
|
5c560e82b3 | ||
|
|
263a94af18 | ||
|
|
9d1cf360b6 | ||
|
|
60f664a5c2 | ||
|
|
a1c7aa7790 | ||
|
|
a29096ca5c | ||
|
|
0ef64f4091 | ||
|
|
945deeba60 | ||
|
|
aa775675b5 | ||
|
|
db76044880 | ||
|
|
edc58e358b | ||
|
|
1133efb3f1 | ||
|
|
d524accc98 | ||
|
|
543f91dd6e | ||
|
|
9848dabfa8 | ||
|
|
bc59efc3ba | ||
|
|
9af63ca32f | ||
|
|
eb8a566ae8 | ||
|
|
38eb3e489e | ||
|
|
97f7eaf499 | ||
|
|
d3356eea5c | ||
|
|
7a57bd73c3 | ||
|
|
b517c93190 | ||
|
|
7a9fded2e4 | ||
|
|
8ed2096de7 | ||
|
|
791a1eb130 | ||
|
|
9dab10ce19 | ||
|
|
fd95c2ced6 | ||
|
|
c32fef0eb9 | ||
|
|
c77b35c07b | ||
|
|
4303ea3584 | ||
|
|
ddb6f63ea7 | ||
|
|
06985a5b6c | ||
|
|
4841f209b3 | ||
|
|
7e6ed01dd2 | ||
|
|
b7e41894af | ||
|
|
5dfcfc32e7 | ||
|
|
fb74541796 | ||
|
|
2f7b29593e | ||
|
|
7ce6b1cfda | ||
|
|
7ad1d14d15 | ||
|
|
444c30e389 | ||
|
|
06fc31c33b | ||
|
|
4c58077cee | ||
|
|
25253942a6 | ||
|
|
4d75b47713 | ||
|
|
63c500c444 | ||
|
|
208c3fea35 | ||
|
|
3201b5921c | ||
|
|
e92a7825bf | ||
|
|
65b1fb2bae | ||
|
|
98df7e1eb8 | ||
|
|
86079af3b1 | ||
|
|
eeab0cf1b2 | ||
|
|
ac16b7ad0b | ||
|
|
e9b87d7acc | ||
|
|
b37893d9bb | ||
|
|
6f4ecdfbd9 | ||
|
|
697921b486 | ||
|
|
3c01d4aa8b | ||
|
|
a1eafdfbd8 | ||
|
|
2cfb171b38 | ||
|
|
2742e3d77b | ||
|
|
5488d8f633 | ||
|
|
35c7155983 | ||
|
|
b90a8a58fd | ||
|
|
85fa2011b2 | ||
|
|
063b05d964 | ||
|
|
ac90a0c0fb | ||
|
|
3efe33d2fb | ||
|
|
3e5ea97768 | ||
|
|
a970657312 | ||
|
|
240615c71b | ||
|
|
d3f4e205af | ||
|
|
cc63c239f6 | ||
|
|
4b82cae638 | ||
|
|
68c8d15ed4 | ||
|
|
021f5bb030 | ||
|
|
fc5d9a413d | ||
|
|
e09acb9208 | ||
|
|
2f57404c9c | ||
|
|
a29bdf0cf4 | ||
|
|
c29597689c | ||
|
|
797fbca6d4 | ||
|
|
6ed4b289d8 | ||
|
|
7dd07b2f5b | ||
|
|
b371fda0a5 | ||
|
|
3bdb11d804 | ||
|
|
199b777dcc | ||
|
|
70ccec2e82 | ||
|
|
a195624549 | ||
|
|
e417eba6bd | ||
|
|
210bb3e5c9 | ||
|
|
140ae354a1 | ||
|
|
2451b08306 | ||
|
|
04d33e772f | ||
|
|
3592fd8dae | ||
|
|
889e8d3b6e | ||
|
|
908fc67f96 | ||
|
|
c9a645285a | ||
|
|
3655724810 | ||
|
|
866047c116 | ||
|
|
8912d31bec | ||
|
|
1e65342814 | ||
|
|
c7ca352205 | ||
|
|
4b1ce8bc0b | ||
|
|
422e940bc7 | ||
|
|
76e2a2b8ca | ||
|
|
e3565bdc7d | ||
|
|
86f01cfaec | ||
|
|
6e4007adc0 | ||
|
|
8c6913c399 | ||
|
|
efdfd0db10 | ||
|
|
d6412eec58 | ||
|
|
53a6d2de83 | ||
|
|
7fe990e9f6 | ||
|
|
7b7ad0715b | ||
|
|
1a57d032b9 | ||
|
|
77bb169680 | ||
|
|
b424c19eee | ||
|
|
4d597069cf | ||
|
|
5afbdf7f20 | ||
|
|
33f558b221 | ||
|
|
b05d0dd1ec | ||
|
|
b2b305cc4b | ||
|
|
c5a9ee544c | ||
|
|
368d66f76e | ||
|
|
5aaae61b46 | ||
|
|
29fe50c2d7 | ||
|
|
d0c59ee253 | ||
|
|
d2e39238f4 | ||
|
|
4aec3f7466 | ||
|
|
c8991e07b9 | ||
|
|
48157db973 | ||
|
|
d070e5fce5 | ||
|
|
a8fae51ea8 | ||
|
|
2815d462be | ||
|
|
85f8ca9241 | ||
|
|
b5fb9e8c23 | ||
|
|
1addc002d3 | ||
|
|
e99e2660e9 | ||
|
|
03d1bb8bce | ||
|
|
5b00f7f2e8 | ||
|
|
97b7f0901e | ||
|
|
67b2671dad | ||
|
|
7886d49e65 | ||
|
|
e5284e9b43 | ||
|
|
c6403baa04 | ||
|
|
662b1ec696 | ||
|
|
9570e541d9 | ||
|
|
043df71185 | ||
|
|
8dab47f4da | ||
|
|
90d069df2b | ||
|
|
dcbe3ee650 | ||
|
|
e32489aba1 | ||
|
|
b619c0b793 | ||
|
|
fab61d14fa | ||
|
|
b4edc084f8 | ||
|
|
c7518d0c49 | ||
|
|
a40345c14d | ||
|
|
909471a5d7 | ||
|
|
38f7ea00c2 | ||
|
|
9f459f053e | ||
|
|
4195f3b8c6 | ||
|
|
4926824482 | ||
|
|
cb2f539cf7 | ||
|
|
7f31be7cb1 | ||
|
|
78b9c5b576 | ||
|
|
01e35efdbb | ||
|
|
bef1687b1f | ||
|
|
afa691376e | ||
|
|
be10bcf27a | ||
|
|
608cb86a4a | ||
|
|
88780ff0a9 | ||
|
|
a5e241afd7 | ||
|
|
28772d3254 | ||
|
|
d1f5c1eebc | ||
|
|
c77a282aaf | ||
|
|
7a1cd5c545 | ||
|
|
29ff54054e | ||
|
|
8e1bbe0132 | ||
|
|
a2b6585c0d | ||
|
|
aa452952a8 | ||
|
|
6ea4aa0a66 | ||
|
|
2462cd7b1d | ||
|
|
331e338c06 | ||
|
|
2b68f40872 | ||
|
|
2f7b3c306d | ||
|
|
eba5dbe654 | ||
|
|
9ae1f548bf | ||
|
|
d191255a84 | ||
|
|
9bf8824109 | ||
|
|
f773bd217c | ||
|
|
a5f0f0e3db | ||
|
|
6f6bfc667b | ||
|
|
0789f49b94 | ||
|
|
92c94eab8f | ||
|
|
9f06ed725e | ||
|
|
c45039fd70 | ||
|
|
8e203ec78e | ||
|
|
e32515e5cc | ||
|
|
2b77da821c | ||
|
|
f8404c7a97 | ||
|
|
156610ee07 | ||
|
|
fcaf672bf8 | ||
|
|
dd5d8fcdce | ||
|
|
e0c4f6455d | ||
|
|
dd5d7e9979 | ||
|
|
408baac91e | ||
|
|
f241142216 | ||
|
|
f0561844d8 | ||
|
|
bd6294b806 | ||
|
|
70f8e3a832 | ||
|
|
59b302acde | ||
|
|
f54f8dfec9 | ||
|
|
93135e7e81 | ||
|
|
b8026e19ba | ||
|
|
147d9282fb | ||
|
|
7c18b8bc5f | ||
|
|
2ccbf5d4e5 | ||
|
|
da6d8c86d1 | ||
|
|
78d997b404 | ||
|
|
89b23ef0d7 | ||
|
|
b958911c63 | ||
|
|
c6e5219f2e | ||
|
|
3bb450adbf | ||
|
|
a0f5257258 | ||
|
|
6520615bb0 | ||
|
|
4593212698 | ||
|
|
5363deb122 | ||
|
|
d5a651fc43 | ||
|
|
4740acbcc6 | ||
|
|
bfb2134329 | ||
|
|
ec83977fe1 | ||
|
|
98d08ff05d | ||
|
|
1eb6319b49 | ||
|
|
8f7e06f9d6 | ||
|
|
81e3abe10c | ||
|
|
edcee8934d | ||
|
|
d115d2ef47 | ||
|
|
d1dd725848 | ||
|
|
ebdba33082 | ||
|
|
918f6fbb8f | ||
|
|
28733ec592 | ||
|
|
916b9a399b | ||
|
|
3d62791477 | ||
|
|
64e6764015 | ||
|
|
cbed5c9cb1 | ||
|
|
0246d501e2 | ||
|
|
3d5b30ab9e | ||
|
|
4719578f10 | ||
|
|
fe370c7066 | ||
|
|
63d208bf20 | ||
|
|
5158540208 | ||
|
|
a69f7dc81a | ||
|
|
e848e161d4 | ||
|
|
3db61216e1 | ||
|
|
63b00186f4 | ||
|
|
110d4c478d | ||
|
|
49c29ded92 | ||
|
|
06670f2214 | ||
|
|
134bfec615 | ||
|
|
279326ffe1 | ||
|
|
ecb04e983e | ||
|
|
73b4c33f05 | ||
|
|
ad30f4dcbb | ||
|
|
0318587f80 | ||
|
|
2b6fddf26c | ||
|
|
da61da392b | ||
|
|
984b46ba07 | ||
|
|
1abce77b3a | ||
|
|
420606d8e8 | ||
|
|
80c8fd9794 | ||
|
|
1f479c3f20 | ||
|
|
0af89853d4 | ||
|
|
b5bb9c8ec3 | ||
|
|
ff13de9f75 | ||
|
|
47f40eb04b | ||
|
|
1ffc7ed6fb | ||
|
|
63710d5fae | ||
|
|
a2ef701d18 | ||
|
|
55e07536d9 | ||
|
|
fc81483371 | ||
|
|
e552b022ba | ||
|
|
af0a479f88 | ||
|
|
86a28d8cc1 | ||
|
|
3dd178a69d | ||
|
|
417334419a | ||
|
|
6c34bec51e | ||
|
|
c03b3c2d34 | ||
|
|
e97d4a8e72 | ||
|
|
24d0af3104 | ||
|
|
5790e99359 | ||
|
|
0d6c2c9890 | ||
|
|
cbabb544ab | ||
|
|
42220e057b | ||
|
|
c5df9c973f | ||
|
|
91509e7d36 | ||
|
|
b89aa9af0d | ||
|
|
4421b55613 | ||
|
|
75d9929483 | ||
|
|
7c78c2ef5d | ||
|
|
3758c86d20 | ||
|
|
ada547a79d | ||
|
|
445adcb47f | ||
|
|
4e9b975ca8 | ||
|
|
5d26066e02 | ||
|
|
de73d86684 | ||
|
|
d6244f090e | ||
|
|
aac09d8208 | ||
|
|
a127fc9ec3 | ||
|
|
551aa300ea | ||
|
|
485e59b5eb | ||
|
|
fdfcbf1da2 | ||
|
|
0f5eee0258 | ||
|
|
870492eb96 | ||
|
|
b50005049e | ||
|
|
0e890e19ea | ||
|
|
59aabc150c | ||
|
|
b159815349 | ||
|
|
1c44dc1052 | ||
|
|
bfe5afaddd | ||
|
|
64e907156c | ||
|
|
5d01ca428c | ||
|
|
4f7fbdc344 | ||
|
|
6fe49fbf8d | ||
|
|
c5f37e665b | ||
|
|
99180ba001 | ||
|
|
9377cf9128 | ||
|
|
e17d8ca302 | ||
|
|
acbaa1eec4 | ||
|
|
65b6ff6ecc | ||
|
|
df7aa30267 | ||
|
|
0f4aab926e | ||
|
|
7f3512d22c | ||
|
|
a6b5ed22b0 | ||
|
|
e843b31287 | ||
|
|
06a5aa45ba | ||
|
|
45a5eed62f | ||
|
|
188e27e931 | ||
|
|
f7a7f06c67 | ||
|
|
ed560ed489 | ||
|
|
186eb66f52 | ||
|
|
860f0d5846 | ||
|
|
4a7c2a96db | ||
|
|
0b09ada144 | ||
|
|
8b566f06f0 | ||
|
|
28d174d9d8 | ||
|
|
dd892f746d | ||
|
|
95b1b8b19d | ||
|
|
298b73ddfc | ||
|
|
4b9695ff50 | ||
|
|
a02b721944 | ||
|
|
f60a92d2c4 |
@@ -9,3 +9,4 @@ WebSite
|
||||
*.xcodeproj/*.perspectivev3
|
||||
xcuserdata/
|
||||
!*.xcodeproj/project.pbxproj
|
||||
*.xCodeSupport/
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
@import "CPCollectionViewItem.j"
|
||||
@import "CPColor.j"
|
||||
@import "CPColorPanel.j"
|
||||
@import "CPColorSpace.j"
|
||||
@import "CPColorWell.j"
|
||||
@import "CPCompatibility.j"
|
||||
@import "CPControl.j"
|
||||
@@ -55,6 +56,7 @@
|
||||
@import "CPFont.j"
|
||||
@import "CPFontManager.j"
|
||||
@import "CPGeometry.j"
|
||||
@import "CPGradient.j"
|
||||
@import "CPGraphics.j"
|
||||
@import "CPImage.j"
|
||||
@import "CPImageView.j"
|
||||
@@ -66,6 +68,7 @@
|
||||
@import "CPOutlineView.j"
|
||||
@import "CPPanel.j"
|
||||
@import "CPPasteboard.j"
|
||||
@import "CPPopover.j"
|
||||
@import "CPPopUpButton.j"
|
||||
@import "CPPredicateEditor.j"
|
||||
@import "CPPredicateEditorRowTemplate.j"
|
||||
@@ -98,5 +101,6 @@
|
||||
@import "CPViewAnimation.j"
|
||||
@import "CPViewController.j"
|
||||
@import "CPWebView.j"
|
||||
@import "CPWorkspace.j"
|
||||
@import "CPWindow.j"
|
||||
@import "CPWindowController.j"
|
||||
|
||||
@@ -117,7 +117,7 @@ CPCriticalAlertStyle = 2;
|
||||
*/
|
||||
+ (CPAlert)alertWithMessageText:(CPString)aMessage defaultButton:(CPString)defaultButtonTitle alternateButton:(CPString)alternateButtonTitle otherButton:(CPString)otherButtonTitle informativeTextWithFormat:(CPString)informativeText
|
||||
{
|
||||
var alert = [[CPAlert alloc] init];
|
||||
var alert = [[self alloc] init];
|
||||
|
||||
[alert setMessageText:aMessage];
|
||||
[alert addButtonWithTitle:defaultButtonTitle];
|
||||
@@ -142,7 +142,7 @@ CPCriticalAlertStyle = 2;
|
||||
*/
|
||||
+ (CPAlert)alertWithError:(CPString)anErrorMessage
|
||||
{
|
||||
var alert = [[CPAlert alloc] init];
|
||||
var alert = [[self alloc] init];
|
||||
|
||||
[alert setMessageText:anErrorMessage];
|
||||
[alert setAlertStyle:CPCriticalAlertStyle];
|
||||
@@ -371,8 +371,8 @@ CPCriticalAlertStyle = 2;
|
||||
[_informativeLabel setAlignment:[self currentValueForThemeAttribute:@"informative-text-alignment"]];
|
||||
[_informativeLabel setLineBreakMode:CPLineBreakByWordWrapping];
|
||||
|
||||
informativeLabelWidth = CGRectGetWidth([[_window contentView] frame]) - inset.left - inset.right,
|
||||
informativeLabelOriginY = [_messageLabel frameOrigin].y + [_messageLabel frameSize].height + defaultElementsMargin,
|
||||
informativeLabelWidth = CGRectGetWidth([[_window contentView] frame]) - inset.left - inset.right;
|
||||
informativeLabelOriginY = [_messageLabel frameOrigin].y + [_messageLabel frameSize].height + defaultElementsMargin;
|
||||
informativeLabelTextSize = [[_informativeLabel stringValue] sizeWithFont:[_informativeLabel font] inWidth:informativeLabelWidth];
|
||||
|
||||
[_informativeLabel setFrame:CGRectMake(inset.left, informativeLabelOriginY, informativeLabelTextSize.width, informativeLabelTextSize.height + sizeWithFontCorrection)];
|
||||
|
||||
@@ -306,6 +306,9 @@ ACTUAL_FRAME_RATE = 0;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)])
|
||||
return [_delegate animation:self valueForProgress:t];
|
||||
|
||||
if (_animationCurve == CPAnimationLinear)
|
||||
return t;
|
||||
|
||||
var c1 = [],
|
||||
c2 = [];
|
||||
|
||||
@@ -338,7 +338,7 @@ CPRunContinuesResponse = -1002;
|
||||
Copyright - Human readable copyright information.
|
||||
</pre>
|
||||
|
||||
If you choose not the include any of the above keys, they will default
|
||||
If you choose not the include any of the above keys, they will default
|
||||
to the following respective keys in your info.plist file.
|
||||
|
||||
<pre>
|
||||
@@ -1003,7 +1003,7 @@ CPRunContinuesResponse = -1002;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the arguments of your application.
|
||||
Sets the arguments of your application.
|
||||
That is, set the slash seperated values of an array as the window location hash.
|
||||
|
||||
For example if you pass an array:
|
||||
@@ -1166,12 +1166,12 @@ CPRunContinuesResponse = -1002;
|
||||
var _CPModalSessionMake = function(aWindow, aStopCode)
|
||||
{
|
||||
return { _window:aWindow, _state:CPRunContinuesResponse , _previous:nil };
|
||||
}
|
||||
};
|
||||
|
||||
var _CPEventListenerMake = function(anEventMask, aCallback)
|
||||
{
|
||||
return { _mask:anEventMask, _callback:aCallback };
|
||||
}
|
||||
};
|
||||
|
||||
// Make this a global for use in CPPlatformWindow+DOM.j.
|
||||
_CPRunModalLoop = function(anEvent)
|
||||
@@ -1183,7 +1183,7 @@ _CPRunModalLoop = function(anEvent)
|
||||
|
||||
if (theWindow == modalSession._window || [theWindow worksWhenModal])
|
||||
[theWindow sendEvent:anEvent];
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
Starts the GUI and Cappuccino frameworks. This function should be
|
||||
@@ -1340,8 +1340,8 @@ var _CPAppBootstrapperActions = nil;
|
||||
[editMenu addItem:undoMenuItem];
|
||||
[editMenu addItem:redoMenuItem];
|
||||
|
||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"]],
|
||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"]],
|
||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"]];
|
||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"]];
|
||||
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"v"]];
|
||||
|
||||
[editMenuItem setSubmenu:editMenu];
|
||||
|
||||
@@ -313,6 +313,8 @@
|
||||
|
||||
// Don't use [super setContent:] as that would fire the contentObject change.
|
||||
// We need to be in control of when notifications fire.
|
||||
// Note that if we have a contentArray binding, setting the content does /not/
|
||||
// cause a reverse binding set.
|
||||
_contentObject = value;
|
||||
|
||||
if (_clearsFilterPredicateOnInsertion && _filterPredicate != nil)
|
||||
@@ -562,8 +564,9 @@
|
||||
- (BOOL)setSelectionIndexes:(CPIndexSet)indexes
|
||||
{
|
||||
[self _selectionWillChange]
|
||||
[self __setSelectionIndexes:indexes];
|
||||
var r = [self __setSelectionIndexes:indexes avoidEmpty:NO];
|
||||
[self _selectionDidChange];
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -572,7 +575,7 @@
|
||||
*/
|
||||
- (BOOL)__setSelectionIndex:(int)theIndex
|
||||
{
|
||||
[self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:theIndex]];
|
||||
return [self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:theIndex]];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -581,28 +584,43 @@
|
||||
*/
|
||||
- (BOOL)__setSelectionIndexes:(CPIndexSet)indexes
|
||||
{
|
||||
if (!indexes)
|
||||
indexes = [CPIndexSet indexSet];
|
||||
[self __setSelectionIndexes:indexes avoidEmpty:_avoidsEmptySelection];
|
||||
}
|
||||
|
||||
if (![indexes count])
|
||||
- (BOOL)__setSelectionIndexes:(CPIndexSet)indexes avoidEmpty:(BOOL)avoidEmpty
|
||||
{
|
||||
var newIndexes = indexes;
|
||||
|
||||
if (!newIndexes)
|
||||
newIndexes = [CPIndexSet indexSet];
|
||||
|
||||
if (![newIndexes count])
|
||||
{
|
||||
if (_avoidsEmptySelection && [[self arrangedObjects] count])
|
||||
indexes = [CPIndexSet indexSetWithIndex:0];
|
||||
if (avoidEmpty && [[self arrangedObjects] count])
|
||||
newIndexes = [CPIndexSet indexSetWithIndex:0];
|
||||
}
|
||||
else
|
||||
{
|
||||
var objectsCount = [[self arrangedObjects] count];
|
||||
|
||||
// Don't trash the input - the caller might depend on it or we might have been
|
||||
// given _selectionIndexes as the input in which case the equality test below
|
||||
// would always succeed despite our change below.
|
||||
newIndexes = [newIndexes copy];
|
||||
|
||||
// Remove out of bounds indexes.
|
||||
[indexes removeIndexesInRange:CPMakeRange(objectsCount, [indexes lastIndex] + 1)];
|
||||
[newIndexes removeIndexesInRange:CPMakeRange(objectsCount, [newIndexes lastIndex] + 1)];
|
||||
// When avoiding empty selection and the deleted selection was at the bottom, select the last item.
|
||||
if (![indexes count] && _avoidsEmptySelection && objectsCount)
|
||||
indexes = [CPIndexSet indexSetWithIndex:objectsCount - 1];
|
||||
if (![newIndexes count] && avoidEmpty && objectsCount)
|
||||
newIndexes = [CPIndexSet indexSetWithIndex:objectsCount - 1];
|
||||
}
|
||||
|
||||
if ([_selectionIndexes isEqualToIndexSet:indexes])
|
||||
if ([_selectionIndexes isEqualToIndexSet:newIndexes])
|
||||
return NO;
|
||||
|
||||
_selectionIndexes = [indexes copy];
|
||||
// If we haven't already created our own index instance, make sure to copy it here so that
|
||||
// the copy the user sent in is decoupled from our internal copy.
|
||||
_selectionIndexes = indexes === newIndexes ? [indexes copy] : newIndexes;
|
||||
|
||||
// Push back the new selection to the model for selectionIndexes if we have one.
|
||||
// There won't be an infinite loop because of the equality check above.
|
||||
@@ -634,10 +652,11 @@
|
||||
[self willChangeValueForKey:@"selectionIndexes"];
|
||||
[self _selectionWillChange];
|
||||
|
||||
[self __setSelectedObjects:objects];
|
||||
var r = [self __setSelectedObjects:objects avoidEmpty:NO];
|
||||
|
||||
[self didChangeValueForKey:@"selectionIndexes"];
|
||||
[self _selectionDidChange];
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -645,6 +664,11 @@
|
||||
@ignore
|
||||
*/
|
||||
- (BOOL)__setSelectedObjects:(CPArray)objects
|
||||
{
|
||||
[self __setSelectedObjects:objects avoidEmpty:_avoidsEmptySelection];
|
||||
}
|
||||
|
||||
- (BOOL)__setSelectedObjects:(CPArray)objects avoidEmpty:(BOOL)avoidEmpty
|
||||
{
|
||||
var set = [CPIndexSet indexSet],
|
||||
count = [objects count],
|
||||
@@ -658,7 +682,7 @@
|
||||
[set addIndex:index];
|
||||
}
|
||||
|
||||
[self __setSelectionIndexes:set];
|
||||
[self __setSelectionIndexes:set avoidEmpty:avoidEmpty];
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -737,6 +761,10 @@
|
||||
*/
|
||||
_disableSetContent = YES;
|
||||
[_contentObject addObject:object];
|
||||
|
||||
// Allow handlesContentAsCompoundValue reverse sets to trigger.
|
||||
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
|
||||
|
||||
_disableSetContent = NO;
|
||||
|
||||
if (willClearPredicate)
|
||||
@@ -771,7 +799,8 @@
|
||||
}
|
||||
|
||||
/*!
|
||||
Adds an object at a given index to the receiver's collection.
|
||||
Adds an object at a given index in the receiver's arrangedObjects. Also add the object
|
||||
to the content collection (although at the end rather than the given index).
|
||||
|
||||
@param id anObject - The object to add to the collection.
|
||||
@param int anIndex - The index to insert the object at.
|
||||
@@ -781,8 +810,12 @@
|
||||
if (![self canAdd])
|
||||
return;
|
||||
|
||||
if (_clearsFilterPredicateOnInsertion)
|
||||
var willClearPredicate = NO;
|
||||
if (_clearsFilterPredicateOnInsertion && _filterPredicate)
|
||||
{
|
||||
[self willChangeValueForKey:@"filterPredicate"];
|
||||
willClearPredicate = YES;
|
||||
}
|
||||
|
||||
[self willChangeValueForKey:@"content"];
|
||||
|
||||
@@ -790,10 +823,17 @@
|
||||
See _disableSetContent explanation in addObject:.
|
||||
*/
|
||||
_disableSetContent = YES;
|
||||
[_contentObject insertObject:anObject atIndex:anIndex];
|
||||
|
||||
// The atArrangedObjectIndex: part of this method's name only refers to where the
|
||||
// object goes in arrangedObjects, not in the content array. So use addObject:,
|
||||
// not insertObject:atIndex: here for speed.
|
||||
[_contentObject addObject:anObject];
|
||||
// Allow handlesContentAsCompoundValue reverse sets to trigger.
|
||||
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
|
||||
|
||||
_disableSetContent = NO;
|
||||
|
||||
if (_clearsFilterPredicateOnInsertion)
|
||||
if (willClearPredicate)
|
||||
[self __setFilterPredicate:nil];
|
||||
|
||||
[[self arrangedObjects] insertObject:anObject atIndex:anIndex];
|
||||
@@ -809,7 +849,7 @@
|
||||
[self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:0]];
|
||||
|
||||
[self didChangeValueForKey:@"content"];
|
||||
if (_clearsFilterPredicateOnInsertion)
|
||||
if (willClearPredicate)
|
||||
[self didChangeValueForKey:@"filterPredicate"];
|
||||
}
|
||||
|
||||
@@ -820,26 +860,28 @@
|
||||
*/
|
||||
- (void)removeObject:(id)object
|
||||
{
|
||||
[self willChangeValueForKey:@"content"];
|
||||
[self willChangeValueForKey:@"content"];
|
||||
|
||||
/*
|
||||
See _disableSetContent explanation in addObject:.
|
||||
*/
|
||||
_disableSetContent = YES;
|
||||
[_contentObject removeObject:object];
|
||||
_disableSetContent = NO;
|
||||
// See _disableSetContent explanation in addObject:.
|
||||
_disableSetContent = YES;
|
||||
|
||||
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
|
||||
{
|
||||
[_contentObject removeObject:object];
|
||||
// Allow handlesContentAsCompoundValue reverse sets to trigger.
|
||||
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
|
||||
|
||||
_disableSetContent = NO;
|
||||
|
||||
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
|
||||
{
|
||||
// selectionIndexes change notification will be fired as a result of the
|
||||
// content change. Don't fire manually.
|
||||
var pos = [_arrangedObjects indexOfObject:object];
|
||||
|
||||
[_arrangedObjects removeObjectAtIndex:pos];
|
||||
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:-1];
|
||||
}
|
||||
}
|
||||
|
||||
[self didChangeValueForKey:@"content"];
|
||||
[self didChangeValueForKey:@"content"];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -875,16 +917,61 @@
|
||||
*/
|
||||
- (void)remove:(id)sender
|
||||
{
|
||||
[self removeObjects:[[self arrangedObjects] objectsAtIndexes:[self selectionIndexes]]];
|
||||
[self removeObjectsAtArrangedObjectIndexes:_selectionIndexes];
|
||||
}
|
||||
|
||||
/*!
|
||||
Removes the objects at the specified indexes in the controller's arranged objects from the content array.
|
||||
@param CPIndexSet indexes - indexes of the objects to remove.
|
||||
*/
|
||||
- (void)removeObjectsAtArrangedObjectIndexes:(CPIndexSet)indexes
|
||||
- (void)removeObjectsAtArrangedObjectIndexes:(CPIndexSet)anIndexSet
|
||||
{
|
||||
[self _removeObjects:[[self arrangedObjects] objectsAtIndexes:indexes]];
|
||||
[self willChangeValueForKey:@"content"];
|
||||
|
||||
/*
|
||||
See _disableSetContent explanation in addObject:.
|
||||
*/
|
||||
_disableSetContent = YES;
|
||||
|
||||
var arrangedObjects = [self arrangedObjects],
|
||||
index = [anIndexSet lastIndex],
|
||||
position = CPNotFound,
|
||||
newSelectionIndexes = [_selectionIndexes copy];
|
||||
|
||||
while (index !== CPNotFound)
|
||||
{
|
||||
var object = [arrangedObjects objectAtIndex:index];
|
||||
|
||||
// First try the simple case which should work if there are no sort descriptors.
|
||||
if ([_contentObject objectAtIndex:index] === object)
|
||||
[_contentObject removeObjectAtIndex:index];
|
||||
else
|
||||
{
|
||||
// Since we don't have a reverse mapping between the sorted order and the
|
||||
// unsorted one, we'll just simply have to remove an arbitrary pointer. It might
|
||||
// be the 'wrong' one - as in not the one the user selected - but the wrong
|
||||
// one is still just another pointer to the same object, so the user will not
|
||||
// be able to see any difference.
|
||||
contentIndex = [_contentObject indexOfObjectIdenticalTo:object];
|
||||
[_contentObject removeObjectAtIndex:contentIndex];
|
||||
}
|
||||
[arrangedObjects removeObjectAtIndex:index];
|
||||
|
||||
// Deselect this row if it was selected, and either way shift all selection indexes
|
||||
// following it up by 1.
|
||||
[newSelectionIndexes removeIndex:index];
|
||||
[newSelectionIndexes shiftIndexesStartingAtIndex:index by:-1];
|
||||
|
||||
index = [anIndexSet indexLessThanIndex:index];
|
||||
}
|
||||
// Allow handlesContentAsCompoundValue reverse sets to trigger.
|
||||
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
|
||||
_disableSetContent = NO;
|
||||
|
||||
// This will automatically handle the avoidsEmptySelection case.
|
||||
[self __setSelectionIndexes:newSelectionIndexes];
|
||||
|
||||
[self didChangeValueForKey:@"content"];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -904,6 +991,8 @@
|
||||
[contentArray addObject:[objects objectAtIndex:i]];
|
||||
|
||||
[self setContent:contentArray];
|
||||
// Allow handlesContentAsCompoundValue reverse sets to trigger.
|
||||
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -922,11 +1011,13 @@
|
||||
{
|
||||
[self willChangeValueForKey:@"content"];
|
||||
|
||||
/*
|
||||
See _disableSetContent explanation in addObject:.
|
||||
*/
|
||||
// See _disableSetContent explanation in addObject:.
|
||||
_disableSetContent = YES;
|
||||
|
||||
[_contentObject removeObjectsInArray:objects];
|
||||
// Allow handlesContentAsCompoundValue reverse sets to trigger.
|
||||
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
|
||||
|
||||
_disableSetContent = NO;
|
||||
|
||||
var arrangedObjects = [self arrangedObjects],
|
||||
@@ -985,12 +1076,76 @@
|
||||
var destination = [_info objectForKey:CPObservedObjectKey],
|
||||
keyPath = [_info objectForKey:CPObservedKeyPathKey],
|
||||
options = [_info objectForKey:CPOptionsKey],
|
||||
newValue = [destination mutableArrayValueForKeyPath:keyPath];
|
||||
isCompound = [self handlesContentAsCompoundValue],
|
||||
dotIndex = keyPath.lastIndexOf("."),
|
||||
firstPart = dotIndex !== CPNotFound ? keyPath.substring(0, dotIndex) : nil,
|
||||
isSelectionProxy = firstPart && [[destination valueForKeyPath:firstPart] isKindOfClass:CPControllerSelectionProxy];
|
||||
|
||||
if (!isCompound && !isSelectionProxy)
|
||||
{
|
||||
newValue = [destination mutableArrayValueForKeyPath:keyPath];
|
||||
}
|
||||
else
|
||||
{
|
||||
// 1. If handlesContentAsCompoundValue we cannot just set up a proxy.
|
||||
// Every read and every write must go through transformValue and
|
||||
// reverseTransformValue, and the resulting object cannot be described by
|
||||
// a key path.
|
||||
|
||||
// 2. If isSelectionProxy, we don't want to proxy a proxy - that's bad
|
||||
// for performance and won't work with markers.
|
||||
|
||||
newValue = [destination valueForKeyPath:keyPath];
|
||||
}
|
||||
|
||||
var isPlaceholder = CPIsControllerMarker(newValue);
|
||||
if (isPlaceholder)
|
||||
{
|
||||
if (newValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
||||
{
|
||||
[CPException raise:CPGenericException
|
||||
reason:@"can't transform non applicable key on: " + _source + " value: " + newValue];
|
||||
}
|
||||
|
||||
newValue = [self _placeholderForMarker:newValue];
|
||||
|
||||
// This seems to be what Cocoa does.
|
||||
if (!newValue)
|
||||
newValue = [CPMutableArray array];
|
||||
}
|
||||
else
|
||||
newValue = [self transformValue:newValue withOptions:options];
|
||||
|
||||
if (isCompound)
|
||||
{
|
||||
// Make sure we can edit our copy of the content. TODO In Cocoa, this copy
|
||||
// appears to be deferred until the array actually needs to be edited.
|
||||
newValue = [newValue mutableCopy];
|
||||
}
|
||||
|
||||
newValue = [self transformValue:newValue withOptions:options];
|
||||
[_source setValue:newValue forKey:aBinding];
|
||||
}
|
||||
|
||||
- (void)_contentArrayDidChange
|
||||
{
|
||||
// When handlesContentAsCompoundValue == YES, it is not sufficient to modify the content object
|
||||
// in place because what we are holding is an array 'unwrapped' from a compound value by
|
||||
// a value transformer. So when we modify it we need a reverse set and transform to create
|
||||
// a new compound value.
|
||||
//
|
||||
// (The Cocoa documentation on the subject is not very clear but after substantial
|
||||
// experimentation this seems both reasonable and compliant.)
|
||||
if ([self handlesContentAsCompoundValue])
|
||||
{
|
||||
var destination = [_info objectForKey:CPObservedObjectKey],
|
||||
keyPath = [_info objectForKey:CPObservedKeyPathKey];
|
||||
|
||||
[self suppressSpecificNotificationFromObject:destination keyPath:keyPath];
|
||||
[self reverseSetValueFor:@"contentArray"];
|
||||
[self unsuppressSpecificNotificationFromObject:destination keyPath:keyPath];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPArrayControllerAvoidsEmptySelection = @"CPArrayControllerAvoidsEmptySelection",
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
* Copyright 2009 280 North, Inc.
|
||||
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@@ -276,7 +275,7 @@ var DefaultLineWidth = 1.0;
|
||||
/*!
|
||||
Append the contents of a CPBezierPath object.
|
||||
*/
|
||||
- (void)appendBezierPath:(NSBezierPath *)other
|
||||
- (void)appendBezierPath:(CPBezierPath)other
|
||||
{
|
||||
CGPathAddPath(_path, nil, other._path);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,16 @@ CPLineBorder = 1;
|
||||
CPBezelBorder = 2;
|
||||
CPGrooveBorder = 3;
|
||||
|
||||
// CPTitlePosition
|
||||
CPNoTitle = 0;
|
||||
CPAboveTop = 1;
|
||||
CPAtTop = 2;
|
||||
CPBelowTop = 3;
|
||||
CPAboveBottom = 4;
|
||||
CPAtBottom = 5;
|
||||
CPBelowBottom = 6;
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPBox
|
||||
@@ -54,6 +64,10 @@ CPGrooveBorder = 3;
|
||||
|
||||
CPSize _contentMargin;
|
||||
CPView _contentView;
|
||||
|
||||
CPString _title @accessors(getter=title);
|
||||
int _titlePosition @accessors(getter=titlePosition);
|
||||
CPTextField _titleView;
|
||||
}
|
||||
|
||||
+ (id)boxEnclosingView:(CPView)aView
|
||||
@@ -61,6 +75,7 @@ CPGrooveBorder = 3;
|
||||
var box = [[self alloc] initWithFrame:CGRectMakeZero()],
|
||||
enclosingView = [aView superview];
|
||||
|
||||
[box setAutoresizingMask:[aView autoresizingMask]];
|
||||
[box setFrameFromContentFrame:[aView frame]];
|
||||
|
||||
[enclosingView replaceSubview:aView with:box];
|
||||
@@ -83,6 +98,9 @@ CPGrooveBorder = 3;
|
||||
_borderWidth = 1.0;
|
||||
_contentMargin = CGSizeMake(0.0, 0.0);
|
||||
|
||||
_titlePosition = CPNoTitle;
|
||||
_titleView = [CPTextField labelWithTitle:@""];
|
||||
|
||||
_contentView = [[CPView alloc] initWithFrame:[self bounds]];
|
||||
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
@@ -277,18 +295,100 @@ CPGrooveBorder = 3;
|
||||
|
||||
- (void)setFrameFromContentFrame:(CPRect)aRect
|
||||
{
|
||||
[self setFrame:CGRectInset(aRect, -(_contentMargin.width + _borderWidth), -(_contentMargin.height + _borderWidth))];
|
||||
var offset = [self _titleHeightOffset];
|
||||
|
||||
[self setFrame:CGRectInset(aRect, -(_contentMargin.width + _borderWidth), -(_contentMargin.height + offset[0] + _borderWidth))];
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)setTitle:(CPString)aTitle
|
||||
{
|
||||
if (aTitle == _title)
|
||||
return;
|
||||
|
||||
_title = aTitle;
|
||||
|
||||
[self _manageTitlePositioning];
|
||||
}
|
||||
|
||||
- (void)setTitlePosition:(int)aTitlePotisition
|
||||
{
|
||||
if (aTitlePotisition == _titlePosition)
|
||||
return;
|
||||
|
||||
_titlePosition = aTitlePotisition;
|
||||
|
||||
[self _manageTitlePositioning];
|
||||
}
|
||||
|
||||
- (void)_manageTitlePositioning
|
||||
{
|
||||
if (_titlePosition == CPNoTitle)
|
||||
{
|
||||
[_titleView removeFromSuperview];
|
||||
[self setNeedsDisplay:YES];
|
||||
return;
|
||||
}
|
||||
|
||||
[_titleView setStringValue:_title];
|
||||
[_titleView sizeToFit];
|
||||
[self addSubview:_titleView];
|
||||
|
||||
switch (_titlePosition)
|
||||
{
|
||||
case CPAtTop:
|
||||
case CPAboveTop:
|
||||
case CPBelowTop:
|
||||
[_titleView setFrameOrigin:CPPointMake(5.0, 0.0)];
|
||||
[_titleView setAutoresizingMask:CPViewNotSizable];
|
||||
break;
|
||||
|
||||
case CPAboveBottom:
|
||||
case CPAtBottom:
|
||||
case CPBelowBottom:
|
||||
var h = [_titleView frameSize].height;
|
||||
[_titleView setFrameOrigin:CPPointMake(5.0, [self frameSize].height - h)];
|
||||
[_titleView setAutoresizingMask:CPViewMinYMargin];
|
||||
break;
|
||||
}
|
||||
|
||||
[self sizeToFit];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)sizeToFit
|
||||
{
|
||||
var contentFrame = [_contentView frame];
|
||||
var contentFrame = [_contentView frame],
|
||||
offset = [self _titleHeightOffset];
|
||||
|
||||
if (!contentFrame)
|
||||
return;
|
||||
|
||||
[_contentView setAutoresizingMask:CPViewNotSizable];
|
||||
[self setFrameSize:CGSizeMake(contentFrame.size.width + _contentMargin.width * 2,
|
||||
contentFrame.size.height + _contentMargin.height * 2)];
|
||||
contentFrame.size.height + _contentMargin.height * 2 + offset[0])];
|
||||
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
[_contentView setFrameOrigin:CGPointMake(_contentMargin.width, _contentMargin.height)];
|
||||
[_contentView setFrameOrigin:CGPointMake(_contentMargin.width, _contentMargin.height + offset[1])];
|
||||
}
|
||||
|
||||
- (float)_titleHeightOffset
|
||||
{
|
||||
if (_titlePosition == CPNoTitle)
|
||||
return [0.0, 0.0];
|
||||
|
||||
switch (_titlePosition)
|
||||
{
|
||||
case CPAtTop:
|
||||
return [[_titleView frameSize].height, [_titleView frameSize].height];
|
||||
|
||||
case CPAtBottom:
|
||||
return [[_titleView frameSize].height, 0.0];
|
||||
|
||||
default:
|
||||
return [0.0, 0.0];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)drawRect:(CPRect)rect
|
||||
@@ -296,7 +396,7 @@ CPGrooveBorder = 3;
|
||||
if (_borderType === CPNoBorder)
|
||||
return;
|
||||
|
||||
var bounds = [self bounds];
|
||||
var bounds = CGRectMakeCopy([self bounds]);
|
||||
|
||||
switch (_boxType)
|
||||
{
|
||||
@@ -311,6 +411,16 @@ CPGrooveBorder = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_titlePosition == CPAtTop)
|
||||
{
|
||||
bounds.origin.y += [_titleView frameSize].height;
|
||||
bounds.size.height -= [_titleView frameSize].height;
|
||||
}
|
||||
if (_titlePosition == CPAtBottom)
|
||||
{
|
||||
bounds.size.height -= [_titleView frameSize].height;
|
||||
}
|
||||
|
||||
switch (_borderType)
|
||||
{
|
||||
case CPBezelBorder:
|
||||
@@ -385,7 +495,10 @@ var CPBoxTypeKey = @"CPBoxTypeKey",
|
||||
CPBoxFillColorKey = @"CPBoxFillColorKey",
|
||||
CPBoxCornerRadiusKey = @"CPBoxCornerRadiusKey",
|
||||
CPBoxBorderWidthKey = @"CPBoxBorderWidthKey",
|
||||
CPBoxContentMarginKey = @"CPBoxContentMarginKey";
|
||||
CPBoxContentMarginKey = @"CPBoxContentMarginKey",
|
||||
CPBoxTitle = @"CPBoxTitle",
|
||||
CPBoxTitlePosition = @"CPBoxTitlePosition",
|
||||
CPBoxTitleView = @"CPBoxTitleView";
|
||||
|
||||
@implementation CPBox (CPCoding)
|
||||
|
||||
@@ -406,10 +519,16 @@ var CPBoxTypeKey = @"CPBoxTypeKey",
|
||||
|
||||
_contentMargin = [aCoder decodeSizeForKey:CPBoxContentMarginKey];
|
||||
|
||||
_title = [aCoder decodeObjectForKey:CPBoxTitle];
|
||||
_titlePosition = [aCoder decodeIntForKey:CPBoxTitlePosition];
|
||||
_titleView = [aCoder decodeObjectForKey:CPBoxTitleView] || [CPTextField labelWithTitle:_title];
|
||||
|
||||
_contentView = [self subviews][0];
|
||||
|
||||
[self setAutoresizesSubviews:YES];
|
||||
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
[self _manageTitlePositioning];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -428,6 +547,10 @@ var CPBoxTypeKey = @"CPBoxTypeKey",
|
||||
[aCoder encodeFloat:_cornerRadius forKey:CPBoxCornerRadiusKey];
|
||||
[aCoder encodeFloat:_borderWidth forKey:CPBoxBorderWidthKey];
|
||||
|
||||
[aCoder encodeObject:_title forKey:CPBoxTitle];
|
||||
[aCoder encodeInt:_titlePosition forKey:CPBoxTitlePosition];
|
||||
[aCoder encodeObject:_titleView forKey:CPBoxTitleView];
|
||||
|
||||
[aCoder encodeSize:_contentMargin forKey:CPBoxContentMarginKey];
|
||||
}
|
||||
|
||||
|
||||
@@ -901,6 +901,12 @@ var _CPBrowserResizeControlBackgroundImage = nil;
|
||||
[_browser _column:_index clickedRow:[selectedIndexes count] === 1 ? [selectedIndexes firstIndex] : -1];
|
||||
}
|
||||
|
||||
- (void)tableViewSelectionDidChange:(CPNotification)aNotification
|
||||
{
|
||||
var selectedIndexes = [[aNotification object] selectedRowIndexes];
|
||||
[_browser selectRowIndexes:selectedIndexes inColumn:_index];
|
||||
}
|
||||
|
||||
- (id)childAtIndex:(unsigned)index
|
||||
{
|
||||
return [_delegate browser:_browser child:index ofItem:_item];
|
||||
|
||||
@@ -100,6 +100,16 @@ CPCheckBoxImageOffset = 4.0;
|
||||
{
|
||||
}
|
||||
|
||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
||||
{
|
||||
[super _updatePlaceholdersWithOptions:options];
|
||||
|
||||
[self _setPlaceholder:CPMixedState forMarker:CPMultipleValuesMarker isDefault:YES];
|
||||
[self _setPlaceholder:CPOffState forMarker:CPNoSelectionMarker isDefault:YES];
|
||||
[self _setPlaceholder:CPOffState forMarker:CPNotApplicableMarker isDefault:YES];
|
||||
[self _setPlaceholder:CPOffState forMarker:CPNullMarker isDefault:YES];
|
||||
}
|
||||
|
||||
- (void)setValueFor:(CPString)theBinding
|
||||
{
|
||||
var destination = [_info objectForKey:CPObservedObjectKey],
|
||||
@@ -110,24 +120,14 @@ CPCheckBoxImageOffset = 4.0;
|
||||
|
||||
if (isPlaceholder)
|
||||
{
|
||||
switch (newValue)
|
||||
if (newValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
||||
{
|
||||
case CPMultipleValuesMarker:
|
||||
newValue = CPMixedState;
|
||||
break;
|
||||
|
||||
case CPNoSelectionMarker:
|
||||
newValue = CPOffState;
|
||||
break;
|
||||
|
||||
case CPNotApplicableMarker:
|
||||
if ([options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
||||
[CPException raise:CPGenericException reason:@"can't transform non applicable key on: "+_source+" value: "+newValue];
|
||||
|
||||
newValue = CPOffState;
|
||||
break;
|
||||
[CPException raise:CPGenericException
|
||||
reason:@"can't transform non applicable key on: " + _source + " value: " + newValue];
|
||||
}
|
||||
|
||||
newValue = [self _placeholderForMarker:newValue];
|
||||
|
||||
if (newValue === CPMixedState)
|
||||
{
|
||||
[_source setAllowsMixedState:YES];
|
||||
|
||||
@@ -40,23 +40,23 @@
|
||||
|
||||
@par Delegate Methods
|
||||
|
||||
@delegate -(void)collectionViewDidChangeSelection:(CPCollectionView)collectionView;
|
||||
@delegate - (void)collectionViewDidChangeSelection:(CPCollectionView)collectionView;
|
||||
Called when the selection in the collection view has changed.
|
||||
@param collectionView the collection view who's selection changed
|
||||
|
||||
@delegate -(void)collectionView:(CPCollectionView)collectionView didDoubleClickOnItemAtIndex:(int)index;
|
||||
@delegate - (void)collectionView:(CPCollectionView)collectionView didDoubleClickOnItemAtIndex:(int)index;
|
||||
Called when the user double-clicks on an item in the collection view.
|
||||
@param collectionView the collection view that received the double-click
|
||||
@param index the index of the item that received the double-click
|
||||
|
||||
@delegate -(CPData)collectionView:(CPCollectionView)collectionView dataForItemsAtIndexes:(CPIndexSet)indices forType:(CPString)aType;
|
||||
@delegate - (CPData)collectionView:(CPCollectionView)collectionView dataForItemsAtIndexes:(CPIndexSet)indices forType:(CPString)aType;
|
||||
Invoked to obtain data for a set of indices.
|
||||
@param collectionView the collection view to obtain data for
|
||||
@param indices the indices to return data for
|
||||
@param aType the data type
|
||||
@return a data object containing the index items
|
||||
|
||||
@delegate -(CPArray)collectionView:(CPCollectionView)collectionView dragTypesForItemsAtIndexes:(CPIndexSet)indices;
|
||||
@delegate - (CPArray)collectionView:(CPCollectionView)collectionView dragTypesForItemsAtIndexes:(CPIndexSet)indices;
|
||||
Invoked to obtain the data types supported by the specified indices for placement on the pasteboard.
|
||||
@param collectionView the collection view the items reside in
|
||||
@param indices the indices to obtain drag types
|
||||
@@ -340,19 +340,21 @@
|
||||
*/
|
||||
- (void)setSelectionIndexes:(CPIndexSet)anIndexSet
|
||||
{
|
||||
if ([_selectionIndexes isEqual:anIndexSet] || !_isSelectable)
|
||||
if (!anIndexSet)
|
||||
anIndexSet = [CPIndexSet indexSet];
|
||||
if (!_isSelectable || [_selectionIndexes isEqual:anIndexSet])
|
||||
return;
|
||||
|
||||
var index = CPNotFound;
|
||||
|
||||
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
|
||||
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) !== CPNotFound)
|
||||
[_items[index] setSelected:NO];
|
||||
|
||||
_selectionIndexes = anIndexSet;
|
||||
|
||||
var index = CPNotFound;
|
||||
|
||||
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
|
||||
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) !== CPNotFound)
|
||||
[_items[index] setSelected:YES];
|
||||
|
||||
var binderClass = [[self class] _binderClassForBinding:@"selectionIndexes"];
|
||||
@@ -473,7 +475,7 @@
|
||||
}
|
||||
|
||||
var superview = [self superview],
|
||||
proposedHeight = y + itemSize.height + _verticalMargin;
|
||||
proposedHeight = y + itemSize.height + _verticalMargin;
|
||||
|
||||
if ([superview isKindOfClass:[CPClipView class]])
|
||||
{
|
||||
@@ -559,6 +561,8 @@
|
||||
*/
|
||||
- (void)setMinItemSize:(CGSize)aSize
|
||||
{
|
||||
if (aSize === nil || aSize === undefined)
|
||||
[CPException raise:CPInvalidArgumentException reason:"Invalid value provided for minimum size"];
|
||||
if (CGSizeEqualToSize(_minItemSize, aSize))
|
||||
return;
|
||||
|
||||
@@ -965,14 +969,15 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeK
|
||||
{
|
||||
[super awakeFromCib];
|
||||
|
||||
if (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()) || CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
|
||||
var prototypeView = [_itemPrototype view];
|
||||
if (prototypeView && (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()) || CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero())))
|
||||
{
|
||||
var item = _itemPrototype;
|
||||
|
||||
if (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()))
|
||||
_minItemSize = [[item view] frameSize];
|
||||
_minItemSize = [prototypeView frameSize];
|
||||
else if (CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
|
||||
_maxItemSize = [[item view] frameSize];
|
||||
_maxItemSize = [prototypeView frameSize];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
@import "CPCompatibility.j"
|
||||
@import "CPImage.j"
|
||||
|
||||
/// @cond IGNORE
|
||||
|
||||
var _redComponent = 0,
|
||||
_greenComponent = 1,
|
||||
@@ -54,6 +55,66 @@ var cachedBlackColor,
|
||||
cachedShadowColor,
|
||||
cachedClearColor;
|
||||
|
||||
/// @endcond
|
||||
|
||||
/*!
|
||||
Orientation to use with \c CPColorPattern for vertical patterns.
|
||||
*/
|
||||
CPColorPatternIsVertical = YES;
|
||||
|
||||
/*!
|
||||
Orientation to use with \c CPColorPattern for horizontal patterns.
|
||||
*/
|
||||
CPColorPatternIsHorizontal = NO;
|
||||
|
||||
/*!
|
||||
To create a simple color with a pattern image:
|
||||
|
||||
<code>CPColorWithImages(name, width, height{, bundle})</code>
|
||||
|
||||
To create a color with a three part pattern image:
|
||||
|
||||
<code>CPColorWithImages(slices{, orientation})</code>
|
||||
|
||||
where slices is an array of three [name, width, height{, bundle}] arrays,
|
||||
and orientation is \c CPColorPatternIsVertical or \ref CPColorPatternIsHorizontal.
|
||||
If orientatation is not passed, it defaults to \ref CPColorPatternIsHorizontal.
|
||||
|
||||
To create a color with a nine part pattern image:
|
||||
|
||||
<code>CPColorWithImages(slices);</code>
|
||||
|
||||
where slices is an array of nine [name, width, height{, bundle}] arrays.
|
||||
*/
|
||||
function CPColorWithImages()
|
||||
{
|
||||
if (arguments.length < 3)
|
||||
{
|
||||
var slices = arguments[0],
|
||||
imageSlices = [];
|
||||
|
||||
for (var i = 0; i < slices.length; ++i)
|
||||
{
|
||||
var slice = slices[i];
|
||||
|
||||
imageSlices.push(slice ? CPImageInBundle(slice[0], CGSizeMake(slice[1], slice[2]), slice[3]) : nil);
|
||||
}
|
||||
|
||||
if (imageSlices.length === 3)
|
||||
return [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:imageSlices isVertical:arguments[1] || CPColorPatternIsHorizontal]];
|
||||
else
|
||||
return [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:imageSlices]];
|
||||
}
|
||||
else if (arguments.length === 3 || arguments.length === 4)
|
||||
{
|
||||
return [CPColor colorWithPatternImage:CPImageInBundle(arguments[0], CGSizeMake(arguments[1], arguments[2]), arguments[3])];
|
||||
}
|
||||
else
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
|
||||
@@ -72,7 +133,7 @@ var cachedBlackColor,
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a color in the RGB color space, with an alpha value.
|
||||
Creates a color in the RGB colorspace, with an alpha value.
|
||||
Each component should be between the range of 0.0 to 1.0. For
|
||||
the alpha component, a value of 1.0 is opaque, and 0.0 means
|
||||
completely transparent.
|
||||
@@ -86,13 +147,13 @@ var cachedBlackColor,
|
||||
*/
|
||||
+ (CPColor)colorWithRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha
|
||||
{
|
||||
return [[CPColor alloc] _initWithRGBA:[red, green, blue, alpha]];
|
||||
return [[CPColor alloc] _initWithRGBA:[MAX(0.0, MIN(1.0, red)), MAX(0.0, MIN(1.0, green)), MAX(0.0, MIN(1.0, blue)), MAX(0.0, MIN(1.0, alpha))]];
|
||||
}
|
||||
|
||||
/*!
|
||||
@deprecated in favor of colorWithRed:green:blue:alpha:
|
||||
|
||||
Creates a color in the RGB color space, with an alpha value.
|
||||
Creates a color in the RGB colorspace, with an alpha value.
|
||||
Each component should be between the range of 0.0 to 1.0. For
|
||||
the alpha component, a value of 1.0 is opaque, and 0.0 means
|
||||
completely transparent.
|
||||
@@ -167,12 +228,12 @@ var cachedBlackColor,
|
||||
|
||||
switch (FLOOR(hue / 60))
|
||||
{
|
||||
case 0: return [CPColor colorWithCalibratedRed: b green: t blue: p alpha: alpha];
|
||||
case 1: return [CPColor colorWithCalibratedRed: q green: b blue: p alpha: alpha];
|
||||
case 2: return [CPColor colorWithCalibratedRed: p green: b blue: t alpha: alpha];
|
||||
case 3: return [CPColor colorWithCalibratedRed: p green: q blue: b alpha: alpha];
|
||||
case 4: return [CPColor colorWithCalibratedRed: t green: p blue: b alpha: alpha];
|
||||
case 5: return [CPColor colorWithCalibratedRed: b green: p blue: q alpha: alpha];
|
||||
case 0: return [CPColor colorWithCalibratedRed:b green:t blue:p alpha:alpha];
|
||||
case 1: return [CPColor colorWithCalibratedRed:q green:b blue:p alpha:alpha];
|
||||
case 2: return [CPColor colorWithCalibratedRed:p green:b blue:t alpha:alpha];
|
||||
case 3: return [CPColor colorWithCalibratedRed:p green:q blue:b alpha:alpha];
|
||||
case 4: return [CPColor colorWithCalibratedRed:t green:p blue:b alpha:alpha];
|
||||
case 5: return [CPColor colorWithCalibratedRed:b green:p blue:q alpha:alpha];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +253,17 @@ var cachedBlackColor,
|
||||
return rgba ? [[CPColor alloc] _initWithRGBA: rgba] : null;
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a color in the sRGB colorspace with the given components and alpha values.
|
||||
Values below 0.0 are treated as 0.0 and values above 1.0 are treated as 1.0.
|
||||
*/
|
||||
+ (CPColor)colorWithSRGBRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha
|
||||
{
|
||||
// TODO If Cappuccino is ported to a colorspace aware platform, this color should be in
|
||||
// sRGBColorSpace.
|
||||
return [self colorWithRed:red green:green blue:blue alpha:alpha];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a black color object. (RGBA=[0.0, 0.0, 0.0, 1.0])
|
||||
*/
|
||||
@@ -419,7 +491,9 @@ var cachedBlackColor,
|
||||
parts[3] ? parseFloat(parts[3], 10) : 1.0
|
||||
];
|
||||
|
||||
_cssString = aString;
|
||||
// We can't reuse aString as _cssString because the browser might not support the `rgba` syntax, and aString might
|
||||
// use it (issue #1413.)
|
||||
[self _initCSSStringFromComponents];
|
||||
|
||||
return self;
|
||||
}
|
||||
@@ -433,18 +507,23 @@ var cachedBlackColor,
|
||||
{
|
||||
_components = components;
|
||||
|
||||
var hasAlpha = CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0;
|
||||
|
||||
_cssString = (hasAlpha ? "rgba(" : "rgb(") +
|
||||
parseInt(_components[0] * 255.0) + ", " +
|
||||
parseInt(_components[1] * 255.0) + ", " +
|
||||
parseInt(_components[2] * 255.0) +
|
||||
(hasAlpha ? (", " + _components[3]) : "") + ")";
|
||||
[self _initCSSStringFromComponents];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_initCSSStringFromComponents
|
||||
{
|
||||
var hasAlpha = CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0;
|
||||
|
||||
_cssString = (hasAlpha ? "rgba(" : "rgb(") +
|
||||
parseInt(_components[0] * 255.0) + ", " +
|
||||
parseInt(_components[1] * 255.0) + ", " +
|
||||
parseInt(_components[2] * 255.0) +
|
||||
(hasAlpha ? (", " + _components[3]) : "") + ")";
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (id)_initWithPatternImage:(CPImage)anImage
|
||||
{
|
||||
@@ -633,7 +712,36 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
return [super description]+" "+[self cssString];
|
||||
var description = [super description],
|
||||
patternImage = [self patternImage];
|
||||
|
||||
if (!patternImage)
|
||||
return description + " " + [self cssString];
|
||||
|
||||
description += " {\n";
|
||||
|
||||
if ([patternImage isThreePartImage] || [patternImage isNinePartImage])
|
||||
{
|
||||
var slices = [patternImage imageSlices];
|
||||
|
||||
if ([patternImage isThreePartImage])
|
||||
description += " orientation: " + ([patternImage isVertical] ? "vertical" : "horizontal") + ",\n";
|
||||
|
||||
description += " patternImage (" + slices.length + " part): [\n";
|
||||
|
||||
for (var i = 0; i < slices.length; ++i)
|
||||
{
|
||||
var imgDescription = [slices[i] description];
|
||||
|
||||
description += imgDescription.replace(/^/mg, " ") + ",\n";
|
||||
}
|
||||
|
||||
description = description.substr(0, description.length - 2) + "\n ]\n}";
|
||||
}
|
||||
else
|
||||
description += [patternImage description].replace(/^/mg, " ") + "\n}";
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -678,8 +786,10 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
|
||||
|
||||
@end
|
||||
|
||||
/// @cond IGNORE
|
||||
var CPColorComponentsKey = @"CPColorComponentsKey",
|
||||
CPColorPatternImageKey = @"CPColorPatternImageKey";
|
||||
/// @endcond
|
||||
|
||||
@implementation CPColor (CPCoding)
|
||||
|
||||
@@ -710,13 +820,12 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
|
||||
@end
|
||||
|
||||
|
||||
/// @cond IGNORE
|
||||
var hexCharacters = "0123456789ABCDEF";
|
||||
|
||||
/*!
|
||||
Used for the CPColor \c +colorWithHexString: implementation
|
||||
@ignore
|
||||
@class CPColor
|
||||
@return an array of rgb components
|
||||
/*
|
||||
Used for the CPColor +colorWithHexString: implementation.
|
||||
Returns an array of rgb components.
|
||||
*/
|
||||
var hexToRGB = function(hex)
|
||||
{
|
||||
@@ -754,3 +863,5 @@ var byteToHex = function(n)
|
||||
return hexCharacters.charAt((n - n % 16) / 16) +
|
||||
hexCharacters.charAt(n % 16);
|
||||
};
|
||||
|
||||
/// @endcond
|
||||
|
||||
@@ -51,7 +51,7 @@ CPWheelColorPickerMode = 1;
|
||||
*/
|
||||
CPSliderColorPickerMode = 2;
|
||||
|
||||
CPColorPickerViewWidth = 265,
|
||||
CPColorPickerViewWidth = 265;
|
||||
CPColorPickerViewHeight = 370;
|
||||
|
||||
/*!
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* CPColorSpace.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Alexander Ljungberg.
|
||||
* Copyright 2012, SlevenBits Ltd.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
var sRGBColorSpace = nil;
|
||||
|
||||
/*!
|
||||
Represent color spaces.
|
||||
*/
|
||||
@implementation CPColorSpace : CPObject
|
||||
{
|
||||
CGColorSpace _cgColorSpace;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return an object representing the standard sRGB color space.
|
||||
*/
|
||||
+ (CPColorSpace)sRGBColorSpace
|
||||
{
|
||||
if (!sRGBColorSpace)
|
||||
sRGBColorSpace = [[self alloc] initWithCGColorSpace:CGColorSpaceCreateDeviceRGB()];
|
||||
return sRGBColorSpace;
|
||||
}
|
||||
|
||||
- (id)initWithCGColorSpace:(CGColorSpace)cgColorSpace
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_cgColorSpace = cgColorSpace;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return a Core Graphics color space representing the receiver.
|
||||
*/
|
||||
- (CGColorSpace)CGColorSpace
|
||||
{
|
||||
return _cgColorSpace;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -46,6 +46,22 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
CPView _wellView;
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
||||
{
|
||||
if (theBinding == CPValueBinding)
|
||||
return [CPColorWellValueBinder class];
|
||||
|
||||
return [super _binderClassForBinding:theBinding];
|
||||
}
|
||||
|
||||
- (void)_reverseSetBinding
|
||||
{
|
||||
var binderClass = [[self class] _binderClassForBinding:CPValueBinding],
|
||||
theBinding = [binderClass getBinding:CPValueBinding forObject:self];
|
||||
|
||||
[theBinding reverseSetValueFor:@"color"];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
@@ -262,6 +278,48 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPColorWellValueBinder : CPBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
||||
{
|
||||
var placeholderColor = [CPColor blueColor];
|
||||
|
||||
[self _setPlaceholder:placeholderColor forMarker:CPMultipleValuesMarker isDefault:YES];
|
||||
[self _setPlaceholder:placeholderColor forMarker:CPNoSelectionMarker isDefault:YES];
|
||||
[self _setPlaceholder:placeholderColor forMarker:CPNotApplicableMarker isDefault:YES];
|
||||
[self _setPlaceholder:placeholderColor forMarker:CPNullMarker isDefault:YES];
|
||||
}
|
||||
|
||||
- (void)setValueFor:(CPString)theBinding
|
||||
{
|
||||
var destination = [_info objectForKey:CPObservedObjectKey],
|
||||
keyPath = [_info objectForKey:CPObservedKeyPathKey],
|
||||
options = [_info objectForKey:CPOptionsKey],
|
||||
newValue = [destination valueForKeyPath:keyPath],
|
||||
isPlaceholder = CPIsControllerMarker(newValue);
|
||||
|
||||
if (isPlaceholder)
|
||||
{
|
||||
if (newValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
||||
{
|
||||
[CPException raise:CPGenericException
|
||||
reason:@"can't transform non applicable key on: " + _source + " value: " + newValue];
|
||||
}
|
||||
|
||||
newValue = [self _placeholderForMarker:newValue];
|
||||
}
|
||||
else
|
||||
{
|
||||
newValue = [self transformValue:newValue withOptions:options];
|
||||
}
|
||||
|
||||
[_source setColor:newValue];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPColorWellColorKey = "CPColorWellColorKey",
|
||||
CPColorWellBorderedKey = "CPColorWellBorderedKey";
|
||||
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#import "../Foundation/Ref.h"
|
||||
|
||||
@import "../Foundation/CPFormatter.j"
|
||||
@import "CPFont.j"
|
||||
@import "CPShadow.j"
|
||||
@import "CPView.j"
|
||||
@@ -82,6 +85,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
@implementation CPControl : CPView
|
||||
{
|
||||
id _value;
|
||||
CPFormatter _formatter @accessors(property=formatter);
|
||||
|
||||
// Target-Action Support
|
||||
id _target;
|
||||
@@ -221,10 +225,11 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
@param anAction the action to send
|
||||
@param anObject the object to which the action will be sent
|
||||
*/
|
||||
- (void)sendAction:(SEL)anAction to:(id)anObject
|
||||
- (BOOL)sendAction:(SEL)anAction to:(id)anObject
|
||||
{
|
||||
[self _reverseSetBinding];
|
||||
[CPApp sendAction:anAction to:anObject from:self];
|
||||
|
||||
return [CPApp sendAction:anAction to:anObject from:self];
|
||||
}
|
||||
|
||||
- (int)sendActionOn:(int)mask
|
||||
@@ -502,15 +507,46 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
*/
|
||||
- (CPString)stringValue
|
||||
{
|
||||
if (_formatter && _value !== undefined && _value !== nil)
|
||||
{
|
||||
var formattedValue = [self hasThemeState:CPThemeStateEditing] ? [_formatter editingStringForObjectValue:_value] : [_formatter stringForObjectValue:_value];
|
||||
|
||||
if (formattedValue !== nil && formattedValue !== undefined)
|
||||
return formattedValue;
|
||||
}
|
||||
|
||||
return (_value === undefined || _value === nil) ? "" : String(_value);
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the receiver's string value.
|
||||
*/
|
||||
- (void)setStringValue:(CPString)anObject
|
||||
- (void)setStringValue:(CPString)aString
|
||||
{
|
||||
[self setObjectValue:anObject];
|
||||
// Cocoa raises an invalid parameter assertion and returns if you pass nil.
|
||||
if (aString === nil || aString === undefined)
|
||||
{
|
||||
CPLog.warn("nil sent to CPControl -setStringValue");
|
||||
return;
|
||||
}
|
||||
|
||||
var value;
|
||||
|
||||
if (_formatter)
|
||||
{
|
||||
value = nil;
|
||||
|
||||
if ([_formatter getObjectValue:AT_REF(value) forString:aString errorDescription:nil] === NO)
|
||||
{
|
||||
// If the given string is non-empty and doesn't work, Cocoa tries an empty string.
|
||||
if (!aString || [_formatter getObjectValue:AT_REF(value) forString:@"" errorDescription:nil] === NO)
|
||||
value = undefined; // Means the value is invalid
|
||||
}
|
||||
}
|
||||
else
|
||||
value = aString;
|
||||
|
||||
[self setObjectValue:value];
|
||||
}
|
||||
|
||||
- (void)takeDoubleValueFrom:(id)sender
|
||||
@@ -526,21 +562,18 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
[self setFloatValue:[sender floatValue]];
|
||||
}
|
||||
|
||||
|
||||
- (void)takeIntegerValueFrom:(id)sender
|
||||
{
|
||||
if ([sender respondsToSelector:@selector(integerValue)])
|
||||
[self setIntegerValue:[sender integerValue]];
|
||||
}
|
||||
|
||||
|
||||
- (void)takeIntValueFrom:(id)sender
|
||||
{
|
||||
if ([sender respondsToSelector:@selector(intValue)])
|
||||
[self setIntValue:[sender intValue]];
|
||||
}
|
||||
|
||||
|
||||
- (void)takeObjectValueFrom:(id)sender
|
||||
{
|
||||
if ([sender respondsToSelector:@selector(objectValue)])
|
||||
@@ -882,7 +915,7 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
|
||||
if (_target !== nil)
|
||||
[aCoder encodeConditionalObject:_target forKey:CPControlTargetKey];
|
||||
|
||||
if (_action !== NULL)
|
||||
if (_action !== nil)
|
||||
[aCoder encodeObject:_action forKey:CPControlActionKey];
|
||||
|
||||
[aCoder encodeInt:_sendActionOn forKey:CPControlSendActionOnKey];
|
||||
|
||||
@@ -922,9 +922,9 @@ var CPDocumentUntitledCount = 0;
|
||||
var _CPReadSessionMake = function(aType, aDelegate, aDidReadSelector, aContextInfo)
|
||||
{
|
||||
return { fileType:aType, delegate:aDelegate, didReadSelector:aDidReadSelector, contextInfo:aContextInfo };
|
||||
}
|
||||
};
|
||||
|
||||
var _CPSaveSessionMake = function(anAbsoluteURL, aSaveOperation, aChangeCount, aDelegate, aDidSaveSelector, aContextInfo, aConnection)
|
||||
{
|
||||
return { absoluteURL:anAbsoluteURL, saveOperation:aSaveOperation, changeCount:aChangeCount, delegate:aDelegate, didSaveSelector:aDidSaveSelector, contextInfo:aContextInfo, connection:aConnection };
|
||||
}
|
||||
};
|
||||
|
||||
@@ -571,31 +571,27 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
if (_modifierFlags & (CPCommandKeyMask | CPControlKeyMask))
|
||||
return YES;
|
||||
|
||||
// Cocoa allows almost any key as a key equivalent unless the first responder is a
|
||||
// text field (presumably a subclass of NSText.)
|
||||
var firstResponderIsText = [[_window firstResponder] isKindOfClass:[CPTextField class]];
|
||||
|
||||
// Some keys are accepted as key equivalents even if the first responder is a text
|
||||
// field.
|
||||
for (var i = 0; i < characterCount; i++)
|
||||
{
|
||||
switch (_characters.charAt(i))
|
||||
var c = _characters.charAt(i);
|
||||
|
||||
if ((c >= CPUpArrowFunctionKey && c <= CPModeSwitchFunctionKey) ||
|
||||
c === CPEnterCharacter ||
|
||||
c === CPNewlineCharacter ||
|
||||
c === CPCarriageReturnCharacter ||
|
||||
c === CPEscapeFunctionKey)
|
||||
{
|
||||
case CPBackspaceCharacter:
|
||||
case CPDeleteCharacter:
|
||||
case CPDeleteFunctionKey:
|
||||
case CPTabCharacter:
|
||||
case CPCarriageReturnCharacter:
|
||||
case CPNewlineCharacter:
|
||||
case CPSpaceFunctionKey:
|
||||
case CPEscapeFunctionKey:
|
||||
case CPPageUpFunctionKey:
|
||||
case CPPageDownFunctionKey:
|
||||
case CPLeftArrowFunctionKey:
|
||||
case CPUpArrowFunctionKey:
|
||||
case CPRightArrowFunctionKey:
|
||||
case CPDownArrowFunctionKey:
|
||||
case CPEndFunctionKey:
|
||||
case CPHomeFunctionKey:
|
||||
return YES;
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
// FIXME: More cases?
|
||||
return NO;
|
||||
|
||||
return !firstResponderIsText;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -651,4 +647,3 @@ function _CPEventFromNativeMouseEvent(aNativeEvent, anEventType, aPoint, modifie
|
||||
|
||||
return aNativeEvent;
|
||||
}
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ var _CPFonts = {},
|
||||
*/
|
||||
+ (CPFont)fontWithName:(CPString)aName size:(float)aSize
|
||||
{
|
||||
return _CPCachedFont(aName, aSize, NO, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:NO italic:NO];
|
||||
return [CPFont fontWithName:aName size:aSize bold:NO italic:NO];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -154,7 +154,7 @@ var _CPFonts = {},
|
||||
*/
|
||||
+ (CPFont)fontWithName:(CPString)aName size:(float)aSize italic:(BOOL)italic
|
||||
{
|
||||
return _CPCachedFont(aName, aSize, NO, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:NO italic:italic];
|
||||
return [CPFont fontWithName:aName size:aSize bold:NO italic:italic];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -165,7 +165,7 @@ var _CPFonts = {},
|
||||
*/
|
||||
+ (CPFont)boldFontWithName:(CPString)aName size:(float)aSize
|
||||
{
|
||||
return _CPCachedFont(aName, aSize, YES, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:YES italic:NO];
|
||||
return [CPFont fontWithName:aName size:aSize bold:YES italic:NO];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -177,7 +177,7 @@ var _CPFonts = {},
|
||||
*/
|
||||
+ (CPFont)boldFontWithName:(CPString)aName size:(float)aSize italic:(BOOL)italic
|
||||
{
|
||||
return _CPCachedFont(aName, aSize, NO, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:YES italic:italic];
|
||||
return [CPFont fontWithName:aName size:aSize bold:YES italic:italic];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -187,7 +187,7 @@ var _CPFonts = {},
|
||||
*/
|
||||
+ (CPFont)systemFontOfSize:(CPSize)aSize
|
||||
{
|
||||
return _CPCachedFont(_CPFontSystemFontFace, aSize, NO, NO) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:NO italic:NO];
|
||||
return [CPFont fontWithName:_CPFontSystemFontFace size:aSize bold:NO italic:NO];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -197,15 +197,15 @@ var _CPFonts = {},
|
||||
*/
|
||||
+ (CPFont)boldSystemFontOfSize:(CPSize)aSize
|
||||
{
|
||||
return _CPCachedFont(_CPFontSystemFontFace, aSize, YES, NO) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:YES italic:NO];
|
||||
return [CPFont fontWithName:_CPFontSystemFontFace size:aSize bold:YES italic:NO];
|
||||
}
|
||||
|
||||
/* FIXME Font Descriptor
|
||||
@ignore
|
||||
*/
|
||||
- (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold
|
||||
+ (CPFont)fontWithName:(CPString)aName size:(float)aSize bold:(BOOL)bold italic:(BOOL)italic
|
||||
{
|
||||
return [self _initWithName:aName size:aSize bold:isBold italic:NO];
|
||||
return _CPCachedFont(aName, aSize, bold, italic) || [[CPFont alloc] _initWithName:aName size:aSize bold:bold italic:italic];
|
||||
}
|
||||
|
||||
- (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold italic:(BOOL)isItalic
|
||||
|
||||
@@ -143,7 +143,7 @@ var _CPFontDetectFontAvailable = function(font)
|
||||
if (_CPFontDetectCompareFonts(_CPFontDetectReferenceFonts[i], font))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
var _CPFontDetectCache = {};
|
||||
|
||||
@@ -165,7 +165,7 @@ var _CPFontDetectCompareFonts = function(fontA, fontB)
|
||||
bHeight = _CPFontDetectSpan.offsetHeight;
|
||||
|
||||
return (a.w != bWidth || a.h != bHeight);
|
||||
}
|
||||
};
|
||||
|
||||
// Test the candidate fonts pairwise until we find two that are different. Otherwise return the first.
|
||||
var _CPFontDetectPickTwoDifferentFonts = function(candidates)
|
||||
@@ -175,6 +175,6 @@ var _CPFontDetectPickTwoDifferentFonts = function(candidates)
|
||||
if (_CPFontDetectCompareFonts(candidates[i], candidates[j]))
|
||||
return [candidates[i], candidates[j]];
|
||||
return [candidates[0]];
|
||||
}
|
||||
};
|
||||
|
||||
[CPFontManager setFontManagerFactory:[CPFontManager class]];
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* CPGradient.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Alexander Ljungberg.
|
||||
* Copyright 2012, SlevenBits Ltd.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
CPGradientDrawsBeforeStartingLocation = kCGGradientDrawsBeforeStartLocation;
|
||||
CPGradientDrawsAfterEndingLocation = kCGGradientDrawsAfterEndLocation;
|
||||
|
||||
/*!
|
||||
A class for drawing linear and radial gradients with a convenient API.
|
||||
*/
|
||||
@implementation CPGradient : CPObject
|
||||
{
|
||||
CGGradient _gradient;
|
||||
}
|
||||
|
||||
- (id)initWithColors:(CPArray)someColors
|
||||
{
|
||||
var count = [someColors count];
|
||||
|
||||
if (count < 2)
|
||||
[CPException raise:CPInvalidArgumentException reason:@"at least 2 colors required"];
|
||||
|
||||
var distance = 1.0 / (count - 1),
|
||||
locations = [CPMutableArray array],
|
||||
location = 0.0;
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
[locations addObject:location];
|
||||
location += distance;
|
||||
}
|
||||
|
||||
return [self initWithColors:someColors atLocations:locations colorSpace:nil];
|
||||
}
|
||||
|
||||
- (id)initWithColors:(CPArray)someColors atLocations:(CPArray)someLocations colorSpace:(CPColorSpace)aColorSpace
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
var cgColors = [],
|
||||
count = [someColors count],
|
||||
colorSpace = [aColorSpace CGColorSpace] || CGColorSpaceCreateDeviceRGB;
|
||||
for (var i = 0; i < count; i++)
|
||||
cgColors.push(CGColorCreate(colorSpace, [someColors[i] components]));
|
||||
_gradient = CGGradientCreateWithColors(colorSpace, cgColors, someLocations);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)drawInRect:(CGRect)rect angle:(float)angle
|
||||
{
|
||||
var ctx = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
CGContextSaveGState(ctx);
|
||||
CGContextClipToRect(ctx, rect);
|
||||
CGContextAddRect(ctx, rect);
|
||||
|
||||
var startPoint,
|
||||
endPoint;
|
||||
|
||||
// Modulo of negative values doesn't work as expected in JS.
|
||||
angle = ((angle % 360.0) + 360.0) % 360.0;
|
||||
|
||||
if (angle < 90.0)
|
||||
startPoint = _CGPointMake(_CGRectGetMinX(rect), _CGRectGetMinY(rect));
|
||||
else if (angle < 180.0)
|
||||
startPoint = _CGPointMake(_CGRectGetMaxX(rect), _CGRectGetMinY(rect));
|
||||
else if (angle < 270.0)
|
||||
startPoint = _CGPointMake(_CGRectGetMaxX(rect), _CGRectGetMaxY(rect));
|
||||
else
|
||||
startPoint = _CGPointMake(_CGRectGetMinX(rect), _CGRectGetMaxY(rect));
|
||||
|
||||
// A line segment comes out of the starting point at the given angle, with the first colour
|
||||
// at the starting point and the last at the end. To do what drawInRect: is supposed to do
|
||||
// we want the opposite corner of the starting corner to just reach the final colour stop.
|
||||
// So when the angle isn't a right angle, the segment has to extend beyond the edge of the
|
||||
// rectangle just far enough. This is hard to describe without a picture but if we place
|
||||
// another line through the opposite corner at -90 degrees, it'll help form some triangles
|
||||
// from which we can derive this formula:
|
||||
//
|
||||
// length = cos(angle) * (rectWidth + rectHeight * tan(angle))
|
||||
//
|
||||
// This simplifies down to (in the first quadrant) rectWidth * cos(a) + rectHeight * sin(a).
|
||||
|
||||
var radians = PI * angle / 180.0,
|
||||
length = ABS(_CGRectGetWidth(rect) * COS(radians)) + ABS(_CGRectGetHeight(rect) * SIN(radians));
|
||||
|
||||
endPoint = _CGPointMake(startPoint.x + length * COS(radians),
|
||||
startPoint.y + length * SIN(radians));
|
||||
|
||||
[self drawFromPoint:startPoint toPoint:endPoint options:CPGradientDrawsBeforeStartingLocation | CPGradientDrawsAfterEndingLocation];
|
||||
CGContextRestoreGState(ctx);
|
||||
}
|
||||
|
||||
- (void)drawFromPoint:(NSPoint)startingPoint toPoint:(NSPoint)endingPoint options:(NSGradientDrawingOptions)options
|
||||
{
|
||||
var ctx = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
// TODO kCGGradientDrawsBeforeStartLocation and kCGGradientDrawsAfterEndLocation are not actually supported
|
||||
// by CGContextDrawLinearGradient yet.
|
||||
CGContextDrawLinearGradient(ctx, _gradient, startingPoint, endingPoint, options);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -86,4 +86,17 @@ var CPGraphicsContextCurrent = nil;
|
||||
return _graphicsPort;
|
||||
}
|
||||
|
||||
/*!
|
||||
(Not implemented. Always returns Cappuccino's default, `YES`.)
|
||||
|
||||
Return `isFlipped` of the receiver's focused view, unless no view is focused in which case the receiver's
|
||||
`flipped` flag, as set by `graphicsContextWithGraphicsPort:flipped:`, is returned.
|
||||
|
||||
Note: Cappuccino is flipped by default.
|
||||
*/
|
||||
- (BOOL)isFlipped
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -44,7 +44,8 @@ CPImageNameColorPanel = @"CPImageNameColorPanel";
|
||||
CPImageNameColorPanelHighlighted = @"CPImageNameColorPanelHighlighted";
|
||||
|
||||
var imagesForNames = { },
|
||||
AppKitImageForNames = { };
|
||||
AppKitImageForNames = { },
|
||||
ImageDescriptionFormat = "%s {\n filename: \"%s\",\n size: { width:%f, height:%f }\n}";
|
||||
|
||||
AppKitImageForNames[CPImageNameColorPanel] = CGSizeMake(26.0, 29.0);
|
||||
AppKitImageForNames[CPImageNameColorPanelHighlighted] = CGSizeMake(26.0, 29.0);
|
||||
@@ -280,7 +281,7 @@ function CPAppKitImage(aFilename, aSize)
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
[self _derefFromImage];
|
||||
}
|
||||
};
|
||||
|
||||
_image.onerror = function ()
|
||||
{
|
||||
@@ -292,7 +293,7 @@ function CPAppKitImage(aFilename, aSize)
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
[self _derefFromImage];
|
||||
}
|
||||
};
|
||||
|
||||
_image.onabort = function ()
|
||||
{
|
||||
@@ -304,7 +305,7 @@ function CPAppKitImage(aFilename, aSize)
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
[self _derefFromImage];
|
||||
}
|
||||
};
|
||||
|
||||
_image.src = _filename;
|
||||
|
||||
@@ -324,6 +325,24 @@ function CPAppKitImage(aFilename, aSize)
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
var filename = [self filename],
|
||||
size = [self size];
|
||||
|
||||
if (filename.indexOf("data:") === 0)
|
||||
{
|
||||
var index = filename.indexOf(",");
|
||||
|
||||
if (index > 0)
|
||||
filename = [CPString stringWithFormat:@"%s,%s...%s", filename.substr(0, index), filename.substr(index + 1, 10), filename.substr(filename.length - 10)];
|
||||
else
|
||||
filename = "data:<unknown type>";
|
||||
}
|
||||
|
||||
return [CPString stringWithFormat:ImageDescriptionFormat, [super description], filename, size.width, size.height];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)_derefFromImage
|
||||
{
|
||||
|
||||
@@ -41,15 +41,7 @@ CPImageAlignBottomLeft = 6;
|
||||
CPImageAlignBottomRight = 7;
|
||||
CPImageAlignRight = 8;
|
||||
|
||||
var CPImageViewShadowBackgroundColor = nil,
|
||||
CPImageViewEmptyPlaceholderImage = nil;
|
||||
|
||||
var LEFT_SHADOW_INSET = 3.0,
|
||||
RIGHT_SHADOW_INSET = 3.0,
|
||||
TOP_SHADOW_INSET = 3.0,
|
||||
BOTTOM_SHADOW_INSET = 5.0,
|
||||
VERTICAL_SHADOW_INSET = TOP_SHADOW_INSET + BOTTOM_SHADOW_INSET,
|
||||
HORIZONTAL_SHADOW_INSET = LEFT_SHADOW_INSET + RIGHT_SHADOW_INSET;
|
||||
var CPImageViewEmptyPlaceholderImage = nil;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -297,8 +289,8 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
imageScaling = [self currentValueForThemeAttribute:@"image-scaling"],
|
||||
x = 0.0,
|
||||
y = 0.0,
|
||||
insetWidth = (_hasShadow ? HORIZONTAL_SHADOW_INSET : 0.0),
|
||||
insetHeight = (_hasShadow ? VERTICAL_SHADOW_INSET : 0.0),
|
||||
insetWidth = (_hasShadow ? [_shadowView horizontalInset] : 0.0),
|
||||
insetHeight = (_hasShadow ? [_shadowView verticalInset] : 0.0),
|
||||
boundsWidth = _CGRectGetWidth(bounds),
|
||||
boundsHeight = _CGRectGetHeight(bounds),
|
||||
width = boundsWidth - insetWidth,
|
||||
@@ -406,7 +398,7 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
_imageRect = _CGRectMake(x, y, width, height);
|
||||
|
||||
if (_hasShadow)
|
||||
[_shadowView setFrame:_CGRectMake(x - LEFT_SHADOW_INSET, y - TOP_SHADOW_INSET, width + insetWidth, height + insetHeight)];
|
||||
[_shadowView setFrame:_CGRectMake(x - [_shadowView leftInset], y - [_shadowView topInset], width + insetWidth, height + insetHeight)];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
|
||||
@@ -39,6 +39,9 @@ var CPBindingOperationAnd = 0,
|
||||
{
|
||||
CPDictionary _info;
|
||||
id _source;
|
||||
|
||||
JSObject _suppressedNotifications;
|
||||
JSObject _placeholderForMarker;
|
||||
}
|
||||
|
||||
+ (void)exposeBinding:(CPString)aBinding forClass:(Class)aClass
|
||||
@@ -122,10 +125,14 @@ var CPBindingOperationAnd = 0,
|
||||
{
|
||||
_source = aSource;
|
||||
_info = [CPDictionary dictionaryWithObjects:[aDestination, aKeyPath] forKeys:[CPObservedObjectKey, CPObservedKeyPathKey]];
|
||||
_suppressedNotifications = {};
|
||||
_placeholderForMarker = {};
|
||||
|
||||
if (options)
|
||||
[_info setObject:options forKey:CPOptionsKey];
|
||||
|
||||
[self _updatePlaceholdersWithOptions:options];
|
||||
|
||||
[aDestination addObserver:self forKeyPath:aKeyPath options:CPKeyValueObservingOptionNew context:aBinding];
|
||||
|
||||
var bindings = [bindingsMap objectForKey:[_source UID]];
|
||||
@@ -169,6 +176,10 @@ var CPBindingOperationAnd = 0,
|
||||
if (!changes)
|
||||
return;
|
||||
|
||||
var objectSuppressions = _suppressedNotifications[[anObject UID]];
|
||||
if (objectSuppressions && objectSuppressions[aKeyPath])
|
||||
return;
|
||||
|
||||
[self setValueFor:context];
|
||||
}
|
||||
|
||||
@@ -197,14 +208,13 @@ var CPBindingOperationAnd = 0,
|
||||
if (valueTransformer)
|
||||
aValue = [valueTransformer transformedValue:aValue];
|
||||
|
||||
|
||||
if (aValue === undefined || aValue === nil || aValue === [CPNull null])
|
||||
aValue = [options objectForKey:CPNullPlaceholderBindingOption] || nil;
|
||||
|
||||
return aValue;
|
||||
}
|
||||
|
||||
- (id)reverseTransformValue:(id)aValue withOptions: (CPDictionary)options
|
||||
- (id)reverseTransformValue:(id)aValue withOptions:(CPDictionary)options
|
||||
{
|
||||
var valueTransformerName = [options objectForKey:CPValueTransformerNameBindingOption],
|
||||
valueTransformer;
|
||||
@@ -226,6 +236,80 @@ var CPBindingOperationAnd = 0,
|
||||
return [[options objectForKey:CPContinuouslyUpdatesValueBindingOption] boolValue];
|
||||
}
|
||||
|
||||
- (BOOL)handlesContentAsCompoundValue
|
||||
{
|
||||
var options = [_info objectForKey:CPOptionsKey];
|
||||
return [[options objectForKey:CPHandlesContentAsCompoundValueBindingOption] boolValue];
|
||||
}
|
||||
|
||||
/*!
|
||||
Use this to avoid reacting to the notifications coming out of a reverseTransformedValue:.
|
||||
*/
|
||||
- (void)suppressSpecificNotificationFromObject:(id)anObject keyPath:(CPString)aKeyPath
|
||||
{
|
||||
if (!anObject)
|
||||
return;
|
||||
|
||||
var uid = [anObject UID],
|
||||
objectSuppressions = _suppressedNotifications[uid];
|
||||
if (!objectSuppressions)
|
||||
_suppressedNotifications[uid] = objectSuppressions = {};
|
||||
|
||||
objectSuppressions[aKeyPath] = YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
Use this to cancel suppressSpecificNotificationFromObject:keyPath:.
|
||||
*/
|
||||
- (void)unsuppressSpecificNotificationFromObject:(id)anObject keyPath:(CPString)aKeyPath
|
||||
{
|
||||
if (!anObject)
|
||||
return;
|
||||
|
||||
var uid = [anObject UID],
|
||||
objectSuppressions = _suppressedNotifications[uid];
|
||||
if (!objectSuppressions)
|
||||
return;
|
||||
|
||||
delete objectSuppressions[aKeyPath];
|
||||
}
|
||||
|
||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
||||
{
|
||||
var count = [CPBinderPlaceholderMarkers count];
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var marker = CPBinderPlaceholderMarkers[count],
|
||||
optionName = CPBinderPlaceholderOptions[count],
|
||||
isExplicit = [options containsKey:optionName],
|
||||
placeholder = isExplicit ? [options objectForKey:optionName] : nil;
|
||||
[self _setPlaceholder:placeholder forMarker:marker isDefault:!isExplicit];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_placeholderForMarker:aMarker
|
||||
{
|
||||
var placeholder = _placeholderForMarker[aMarker];
|
||||
if (placeholder)
|
||||
return placeholder['value'];
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)_setPlaceholder:(id)aPlaceholder forMarker:(id)aMarker isDefault:(BOOL)isDefault
|
||||
{
|
||||
if (isDefault)
|
||||
{
|
||||
var existingPlaceholder = _placeholderForMarker[aMarker];
|
||||
|
||||
// Don't overwrite an explicitly set placeholder with a default.
|
||||
if (existingPlaceholder && !existingPlaceholder['isDefault'])
|
||||
return;
|
||||
}
|
||||
|
||||
_placeholderForMarker[aMarker] = { 'isDefault': isDefault, 'value': aPlaceholder };
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPObject (KeyValueBindingCreation)
|
||||
@@ -235,7 +319,6 @@ var CPBindingOperationAnd = 0,
|
||||
[CPBinder exposeBinding:aBinding forClass:[self class]];
|
||||
}
|
||||
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)theBinding
|
||||
{
|
||||
return [CPBinder class];
|
||||
@@ -267,10 +350,10 @@ var CPBindingOperationAnd = 0,
|
||||
- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options
|
||||
{
|
||||
if (!anObject || !aKeyPath)
|
||||
return CPLog.error("Invalid object or path on "+self+" for "+aBinding);
|
||||
return CPLog.error("Invalid object or path on " + self + " for " + aBinding);
|
||||
|
||||
//if (![[self exposedBindings] containsObject:aBinding])
|
||||
// CPLog.warn("No binding exposed on "+self+" for "+aBinding);
|
||||
// CPLog.warn("No binding exposed on " + self + " for " + aBinding);
|
||||
|
||||
var binderClass = [[self class] _binderClassForBinding:aBinding];
|
||||
|
||||
@@ -382,7 +465,7 @@ var resolveMultipleValues = function resolveMultipleValues(/*CPString*/key, /*CP
|
||||
}
|
||||
|
||||
return !operation;
|
||||
}
|
||||
};
|
||||
|
||||
var invokeAction = function invokeAction(/*CPString*/targetKey, /*CPString*/argumentKey, /*CPDictionary*/bindings)
|
||||
{
|
||||
@@ -419,7 +502,7 @@ var invokeAction = function invokeAction(/*CPString*/targetKey, /*CPString*/argu
|
||||
}
|
||||
|
||||
[invocation invoke];
|
||||
}
|
||||
};
|
||||
|
||||
// Keys in options dictionary
|
||||
|
||||
@@ -474,4 +557,8 @@ CPValueTransformerBindingOption = @"CPValueTransformer";
|
||||
CPIsControllerMarker = function(/*id*/anObject)
|
||||
{
|
||||
return anObject === CPMultipleValuesMarker || anObject === CPNoSelectionMarker || anObject === CPNotApplicableMarker || anObject === CPNullMarker;
|
||||
}
|
||||
};
|
||||
|
||||
var CPBinderPlaceholderMarkers = [CPMultipleValuesMarker, CPNoSelectionMarker, CPNotApplicableMarker, CPNullMarker],
|
||||
CPBinderPlaceholderOptions = [CPMultipleValuesPlaceholderBindingOption, CPNoSelectionPlaceholderBindingOption, CPNotApplicablePlaceholderBindingOption, CPNullPlaceholderBindingOption];
|
||||
|
||||
|
||||
@@ -149,9 +149,9 @@ var _CPLevelIndicatorBezelColor = nil,
|
||||
var filledColor = _CPLevelIndicatorSegmentNormalColor,
|
||||
value = [self doubleValue];
|
||||
|
||||
if (value < _criticalValue)
|
||||
if (value <= _criticalValue)
|
||||
filledColor = _CPLevelIndicatorSegmentCriticalColor;
|
||||
else if (value < _warningValue)
|
||||
else if (value <= _warningValue)
|
||||
filledColor = _CPLevelIndicatorSegmentWarningColor;
|
||||
|
||||
for (var i = 0; i < segmentCount; i++)
|
||||
@@ -223,6 +223,15 @@ var _CPLevelIndicatorBezelColor = nil,
|
||||
return _isEditable;
|
||||
}
|
||||
|
||||
- (CPView)hitTest:(CPPoint)aPoint
|
||||
{
|
||||
// Don't swallow clicks when displayed in a table.
|
||||
if (![self isEditable])
|
||||
return nil;
|
||||
|
||||
return [super hitTest:aPoint];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
if (![self isEditable] || ![self isEnabled])
|
||||
|
||||
@@ -352,8 +352,12 @@ var _CPMenuBarVisible = NO,
|
||||
while (count--)
|
||||
[_items[count] setMenu:nil];
|
||||
|
||||
_items = [CPMutableArray array];
|
||||
_highlightedIndex = CPNotFound;
|
||||
|
||||
// Because we are changing _items directly, be sure to notify KVO
|
||||
[self willChangeValueForKey:@"items"];
|
||||
_items = [CPMutableArray array];
|
||||
[self didChangeValueForKey:@"items"];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -622,11 +626,11 @@ var _CPMenuBarVisible = NO,
|
||||
var validator = [CPApp targetForAction:[item action] to:[item target] from:item];
|
||||
|
||||
if (!validator || ![validator respondsToSelector:[item action]])
|
||||
[item _setEnabled:NO];
|
||||
[item setEnabled:NO];
|
||||
else if ([validator respondsToSelector:@selector(validateMenuItem:)])
|
||||
[item _setEnabled:[validator validateMenuItem:item]];
|
||||
[item setEnabled:[validator validateMenuItem:item]];
|
||||
else if ([validator respondsToSelector:@selector(validateUserInterfaceItem:)])
|
||||
[item _setEnabled:[validator validateUserInterfaceItem:item]];
|
||||
[item setEnabled:[validator validateUserInterfaceItem:item]];
|
||||
}
|
||||
|
||||
[[_menuWindow _menuView] tile];
|
||||
@@ -711,10 +715,7 @@ var _CPMenuBarVisible = NO,
|
||||
if (aView && !theWindow)
|
||||
throw "In call to popUpMenuPositioningItem:atLocation:inView:callback:, view is not in any window.";
|
||||
|
||||
var delegate = [self delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
|
||||
[delegate menuWillOpen:self];
|
||||
[self _menuWillOpen];
|
||||
|
||||
// Convert location to global coordinates if not already in them.
|
||||
if (aView)
|
||||
@@ -802,10 +803,7 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
+ (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView withFont:(CPFont)aFont
|
||||
{
|
||||
var delegate = [aMenu delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
|
||||
[delegate menuWillOpen:aMenu];
|
||||
[aMenu _menuWillOpen];
|
||||
|
||||
if (!aFont)
|
||||
aFont = [CPFont systemFontOfSize:12.0];
|
||||
@@ -875,7 +873,15 @@ var _CPMenuBarVisible = NO,
|
||||
*/
|
||||
- (CPMenuItem)highlightedItem
|
||||
{
|
||||
return _highlightedIndex >= 0 ? _items[_highlightedIndex] : nil;
|
||||
if (_highlightedIndex < 0)
|
||||
return nil;
|
||||
|
||||
var highlightedItem = _items[_highlightedIndex];
|
||||
|
||||
if ([highlightedItem isSeparatorItem])
|
||||
return nil;
|
||||
|
||||
return highlightedItem;
|
||||
}
|
||||
|
||||
// Managing the Delegate
|
||||
@@ -890,6 +896,22 @@ var _CPMenuBarVisible = NO,
|
||||
return _delegate;
|
||||
}
|
||||
|
||||
- (void)_menuWillOpen
|
||||
{
|
||||
var delegate = [self delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
|
||||
[delegate menuWillOpen:self];
|
||||
}
|
||||
|
||||
- (void)_menuDidClose
|
||||
{
|
||||
var delegate = [self delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuDidClose:)])
|
||||
[delegate menuDidClose:self];
|
||||
}
|
||||
|
||||
// Handling Tracking
|
||||
/*!
|
||||
Cancels tracking.
|
||||
|
||||
@@ -257,7 +257,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
|
||||
items = [_menu itemArray],
|
||||
count = items.length;
|
||||
|
||||
for (index = 0; index < count; ++index)
|
||||
for (var index = 0; index < count; ++index)
|
||||
{
|
||||
var item = items[index],
|
||||
menuItemView = [item _menuItemView];
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
|
||||
_CPMenuManagerScrollingStateUp = -1,
|
||||
_CPMenuManagerScrollingStateDown = 1,
|
||||
_CPMenuManagerScrollingStateUp = -1;
|
||||
_CPMenuManagerScrollingStateDown = 1;
|
||||
_CPMenuManagerScrollingStateNone = 0;
|
||||
|
||||
var STICKY_TIME_INTERVAL = 500,
|
||||
@@ -11,6 +11,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
@implementation _CPMenuManager: CPObject
|
||||
{
|
||||
CPTimeInterval _startTime;
|
||||
BOOL _hasMouseGoneUpAfterStartedTracking;
|
||||
int _scrollingState;
|
||||
CGPoint _lastGlobalLocation;
|
||||
|
||||
@@ -60,6 +61,9 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
{
|
||||
var menu = [aMenuContainer menu];
|
||||
|
||||
if ([menu numberOfItems] <= 0)
|
||||
return;
|
||||
|
||||
CPApp._activeMenu = menu;
|
||||
|
||||
_startTime = [anEvent timestamp];//new Date();
|
||||
@@ -87,6 +91,8 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
return [self trackMenuBarButtonEvent:anEvent];
|
||||
}
|
||||
|
||||
_hasMouseGoneUpAfterStartedTracking = NO;
|
||||
|
||||
[self trackEvent:anEvent];
|
||||
}
|
||||
|
||||
@@ -99,7 +105,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
if (type === CPAppKitDefined)
|
||||
return [self completeTracking];
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPKeyDownMask | CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask | CPScrollWheelMask untilDate:nil inMode:nil dequeue:YES];
|
||||
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPKeyDownMask | CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPRightMouseUpMask | CPAppKitDefinedMask | CPScrollWheelMask untilDate:nil inMode:nil dequeue:YES];
|
||||
|
||||
if (type === CPKeyDown)
|
||||
{
|
||||
@@ -221,8 +227,20 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
[CPEvent startPeriodicEventsAfterDelay:0.0 withPeriod:0.04];
|
||||
}
|
||||
}
|
||||
else if (type === CPLeftMouseUp && ([anEvent timestamp] - _startTime > (STICKY_TIME_INTERVAL + [activeMenu numberOfItems] * 5)))
|
||||
[trackingMenu cancelTracking];
|
||||
else if (type === CPLeftMouseUp || type === CPRightMouseUp)
|
||||
{
|
||||
if (_hasMouseGoneUpAfterStartedTracking)
|
||||
{
|
||||
// Don't close the menu if the current item has a submenu
|
||||
// and did not override it's default action
|
||||
if ([activeItem action] === @selector(submenuAction:))
|
||||
return;
|
||||
|
||||
[trackingMenu cancelTracking];
|
||||
}
|
||||
else
|
||||
_hasMouseGoneUpAfterStartedTracking = YES;
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent previous selected menu items from opening by stopping the timer if a
|
||||
@@ -306,11 +324,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
|
||||
// Hide all submenus.
|
||||
[self showMenu:nil fromMenu:trackingMenu atPoint:nil];
|
||||
|
||||
var delegate = [trackingMenu delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuDidClose:)])
|
||||
[delegate menuDidClose:trackingMenu];
|
||||
[trackingMenu _menuDidClose];
|
||||
|
||||
if (_trackingCallback)
|
||||
_trackingCallback([self trackingMenuContainer], trackingMenu);
|
||||
@@ -379,6 +393,8 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
var count = _menuContainerStack.length,
|
||||
index = count;
|
||||
|
||||
[newMenu _menuWillOpen];
|
||||
|
||||
// Hide all menus up to the base menu...
|
||||
while (index--)
|
||||
{
|
||||
@@ -398,6 +414,8 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
|
||||
[_CPMenuWindow poolMenuWindow:menuContainer];
|
||||
[_menuContainerStack removeObjectAtIndex:index];
|
||||
|
||||
[menu _menuDidClose];
|
||||
}
|
||||
|
||||
if (!newMenu)
|
||||
|
||||
@@ -148,14 +148,6 @@ var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionary];
|
||||
@param isEnabled \c YES enables the item. \c NO disables it.
|
||||
*/
|
||||
- (void)setEnabled:(BOOL)isEnabled
|
||||
{
|
||||
if ([_menu autoenablesItems])
|
||||
return;
|
||||
|
||||
[self _setEnabled:isEnabled];
|
||||
}
|
||||
|
||||
- (void)_setEnabled:(BOOL)isEnabled
|
||||
{
|
||||
if (_isEnabled === isEnabled)
|
||||
return;
|
||||
@@ -496,6 +488,7 @@ CPOffState
|
||||
if (_submenu)
|
||||
{
|
||||
[_submenu setSupermenu:_menu];
|
||||
[_submenu setTitle:[self title]]
|
||||
|
||||
[self setTarget:_menu];
|
||||
[self setAction:@selector(submenuAction:)];
|
||||
|
||||
@@ -131,8 +131,8 @@
|
||||
|
||||
_contentObject = aContent;
|
||||
|
||||
[self didChangeValueForKey:@"contentObject"];
|
||||
[self _selectionDidChange];
|
||||
[self didChangeValueForKey:@"contentObject"];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -498,7 +498,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
return "<_CPObservableArray: "+[super description]+" >";
|
||||
return "<_CPObservableArray: " + [super description] + " >";
|
||||
}
|
||||
|
||||
- (id)initWithArray:(CPArray)anArray
|
||||
@@ -663,7 +663,8 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
|
||||
- (id)_controllerMarkerForValues:(CPArray)theValues
|
||||
{
|
||||
var count = [theValues count];
|
||||
var count = [theValues count],
|
||||
value;
|
||||
|
||||
if (!count)
|
||||
value = CPNoSelectionMarker;
|
||||
@@ -677,7 +678,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
{
|
||||
value = [theValues objectAtIndex:0];
|
||||
|
||||
for (var i = 0, count= [theValues count]; i < count && value != CPMultipleValuesMarker; i++)
|
||||
for (var i = 0, count = [theValues count]; i < count && value != CPMultipleValuesMarker; i++)
|
||||
{
|
||||
if (![value isEqual:[theValues objectAtIndex:i]])
|
||||
value = CPMultipleValuesMarker;
|
||||
@@ -693,8 +694,8 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
|
||||
- (id)valueForKeyPath:(CPString)theKeyPath
|
||||
{
|
||||
var values = [[_controller selectedObjects] valueForKeyPath:theKeyPath];
|
||||
value = [self _controllerMarkerForValues:values];
|
||||
var values = [[_controller selectedObjects] valueForKeyPath:theKeyPath],
|
||||
value = [self _controllerMarkerForValues:values];
|
||||
|
||||
[_cachedValues setObject:value forKey:theKeyPath];
|
||||
|
||||
@@ -710,6 +711,17 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
{
|
||||
[[_controller selectedObjects] setValue:theValue forKeyPath:theKeyPath];
|
||||
[_cachedValues removeObjectForKey:theKeyPath];
|
||||
|
||||
// Allow handlesContentAsCompoundValue to work, based on observation of Cocoa's
|
||||
// NSArrayController - when handlesContentAsCompoundValue and setValue:forKey:@"selection.X"
|
||||
// is called, the array controller causes the compound value to be rewritten if
|
||||
// handlesContentAsCompoundValue == YES. Note that
|
||||
// A) this doesn't use observation (observe: X is not visible in backtraces)
|
||||
// B) it only happens through the selection proxy and not on arrangedObject.X, content.X
|
||||
// or even selectedObjects.X.
|
||||
// FIXME The main code for this should somehow be in CPArrayController and also work
|
||||
// for table based row edits.
|
||||
[[CPBinder getBinding:@"contentArray" forObject:_controller] _contentArrayDidChange];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)theValue forKey:(CPString)theKeyPath
|
||||
|
||||
@@ -62,7 +62,7 @@ var CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_
|
||||
CPOutlineViewDelegate_outlineView_shouldReorderColumn_toColumn_ = 1 << 12,
|
||||
CPOutlineViewDelegate_outlineView_shouldSelectItem_ = 1 << 13,
|
||||
CPOutlineViewDelegate_outlineView_shouldSelectTableColumn_ = 1 << 14,
|
||||
CPOutlineViewDelegate_outlineView_shouldShowOutlineViewForItem_ = 1 << 15,
|
||||
CPOutlineViewDelegate_outlineView_shouldShowOutlineDisclosureControlForItem_ = 1 << 15,
|
||||
CPOutlineViewDelegate_outlineView_shouldShowViewExpansionForTableColumn_item_ = 1 << 16,
|
||||
CPOutlineViewDelegate_outlineView_shouldTrackView_forTableColumn_item_ = 1 << 17,
|
||||
CPOutlineViewDelegate_outlineView_shouldTypeSelectForEvent_withCurrentSearchString_ = 1 << 18,
|
||||
@@ -80,6 +80,10 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
CPOutlineViewCoalesceSelectionNotificationStateOn = 1,
|
||||
CPOutlineViewCoalesceSelectionNotificationStateDid = 2;
|
||||
|
||||
#define SELECTION_SHOULD_CHANGE(anOutlineView) (!((anOutlineView)._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_selectionShouldChangeInOutlineView_) || [(anOutlineView)._outlineViewDelegate selectionShouldChangeInOutlineView:(anOutlineView)])
|
||||
|
||||
#define SHOULD_SELECT_ITEM(anOutlineView, anItem) (!((anOutlineView)._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldSelectItem_) || [(anOutlineView)._outlineViewDelegate outlineView:(anOutlineView) shouldSelectItem:(anItem)])
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPOutlineView
|
||||
@@ -136,7 +140,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
_selectionHighlightStyle = CPTableViewSelectionHighlightStyleSourceList;
|
||||
|
||||
// The root item has weight "0", thus represents the weight solely of its descendants.
|
||||
_rootItemInfo = { isExpanded:YES, isExpandable:NO, level:-1, row:-1, children:[], weight:0 };
|
||||
_rootItemInfo = { isExpanded:YES, isExpandable:NO, shouldShowOutlineDisclosureControl:NO, level:-1, row:-1, children:[], weight:0 };
|
||||
|
||||
_itemsForRows = [];
|
||||
_itemInfosForItems = { };
|
||||
@@ -294,6 +298,19 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
return itemInfo.isExpandable;
|
||||
}
|
||||
|
||||
- (BOOL)_shouldShowOutlineDisclosureControlForItem:(id)anItem
|
||||
{
|
||||
if (!anItem)
|
||||
return YES;
|
||||
|
||||
var itemInfo = _itemInfosForItems[[anItem UID]];
|
||||
|
||||
if (!itemInfo)
|
||||
return YES;
|
||||
|
||||
return itemInfo.shouldShowOutlineDisclosureControl;
|
||||
}
|
||||
|
||||
/*!
|
||||
Used to find if an item is already expanded.
|
||||
|
||||
@@ -690,7 +707,8 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
*/
|
||||
- (CGRect)frameOfOutlineDisclosureControlAtRow:(CPInteger)aRow
|
||||
{
|
||||
if (![self isExpandable:[self itemAtRow:aRow]])
|
||||
var theItem = [self itemAtRow:aRow];
|
||||
if (![self isExpandable:theItem] || ![self _shouldShowOutlineDisclosureControlForItem:theItem])
|
||||
return _CGRectMakeZero();
|
||||
|
||||
var dataViewFrame = [self _frameOfOutlineDataViewAtRow:aRow],
|
||||
@@ -822,29 +840,24 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
name:CPOutlineViewSelectionIsChangingNotification
|
||||
object:self];
|
||||
|
||||
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemWillExpand:)])
|
||||
[defaultCenter
|
||||
removeObserver:_outlineViewDelegate
|
||||
name:CPOutlineViewItemWillExpandNotification
|
||||
object:self];
|
||||
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemDidExpand:)])
|
||||
[defaultCenter
|
||||
removeObserver:_outlineViewDelegate
|
||||
name:CPOutlineViewItemDidExpandNotification
|
||||
object:self];
|
||||
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemWillCollapse:)])
|
||||
[defaultCenter
|
||||
removeObserver:_outlineViewDelegate
|
||||
name:CPOutlineViewItemWillCollapseNotification
|
||||
object:self];
|
||||
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemDidCollapse:)])
|
||||
[defaultCenter
|
||||
removeObserver:_outlineViewDelegate
|
||||
@@ -870,7 +883,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
CPOutlineViewDelegate_outlineView_shouldReorderColumn_toColumn_ , @selector(outlineView:shouldReorderColumn:toColumn:),
|
||||
CPOutlineViewDelegate_outlineView_shouldSelectItem_ , @selector(outlineView:shouldSelectItem:),
|
||||
CPOutlineViewDelegate_outlineView_shouldSelectTableColumn_ , @selector(outlineView:shouldSelectTableColumn:),
|
||||
CPOutlineViewDelegate_outlineView_shouldShowOutlineViewForItem_ , @selector(outlineView:shouldShowOutlineViewForItem:),
|
||||
CPOutlineViewDelegate_outlineView_shouldShowOutlineDisclosureControlForItem_ , @selector(outlineView:shouldShowOutlineDisclosureControlForItem:),
|
||||
CPOutlineViewDelegate_outlineView_shouldShowViewExpansionForTableColumn_item_ , @selector(outlineView:shouldShowViewExpansionForTableColumn:item:),
|
||||
CPOutlineViewDelegate_outlineView_shouldTrackView_forTableColumn_item_ , @selector(outlineView:shouldTrackView:forTableColumn:item:),
|
||||
CPOutlineViewDelegate_outlineView_shouldTypeSelectForEvent_withCurrentSearchString_ , @selector(outlineView:shouldTypeSelectForEvent:withCurrentSearchString:),
|
||||
@@ -921,7 +934,6 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
name:CPOutlineViewSelectionIsChangingNotification
|
||||
object:self];
|
||||
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemWillExpand:)])
|
||||
[defaultCenter
|
||||
addObserver:_outlineViewDelegate
|
||||
@@ -984,7 +996,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
_disclosureControlData = nil;
|
||||
_disclosureControlQueue = [];
|
||||
|
||||
// fIXME: really?
|
||||
// FIXME: really?
|
||||
[self reloadData];
|
||||
}
|
||||
|
||||
@@ -1120,13 +1132,14 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
if (_dragHoverTimer)
|
||||
[_dragHoverTimer invalidate];
|
||||
|
||||
var autoExpandCallBack = function(){
|
||||
var autoExpandCallBack = function()
|
||||
{
|
||||
if (_dropItem)
|
||||
{
|
||||
[_dropOperationFeedbackView blink];
|
||||
[CPTimer scheduledTimerWithTimeInterval:.3 callback:objj_msgSend(self, "expandItem:", _dropItem) repeats:NO];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_dragHoverTimer = [CPTimer scheduledTimerWithTimeInterval:.8 callback:autoExpandCallBack repeats:NO];
|
||||
}
|
||||
@@ -1284,7 +1297,12 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
item = _itemsForRows[row],
|
||||
isExpandable = [self isExpandable:item];
|
||||
|
||||
if (!isExpandable)
|
||||
if (!isExpandable)
|
||||
continue;
|
||||
|
||||
var disclosureControlFrame = [self frameOfOutlineDisclosureControlAtRow:row];
|
||||
|
||||
if (_CGRectIsEmpty(disclosureControlFrame))
|
||||
continue;
|
||||
|
||||
var control = [self _dequeueDisclosureControl];
|
||||
@@ -1294,7 +1312,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
[control setState:[self isItemExpanded:item] ? CPOnState : CPOffState];
|
||||
var selector = [self isRowSelected:row] ? @"setThemeState:" : @"unsetThemeState:";
|
||||
[control performSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelected];
|
||||
[control setFrame:[self frameOfOutlineDisclosureControlAtRow:row]];
|
||||
[control setFrame:disclosureControlFrame];
|
||||
|
||||
[self addSubview:control];
|
||||
}
|
||||
@@ -1458,6 +1476,62 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
|
||||
}
|
||||
|
||||
- (void)keyDown:(CPEvent)anEvent
|
||||
{
|
||||
var character = [anEvent charactersIgnoringModifiers],
|
||||
modifierFlags = [anEvent modifierFlags];
|
||||
|
||||
// Check for the key events manually, as opposed to waiting for CPWindow to sent the actual action message
|
||||
// in _processKeyboardUIKey:, because we might not want to handle the arrow events.
|
||||
|
||||
if (character !== CPRightArrowFunctionKey && character !== CPLeftArrowFunctionKey)
|
||||
return [super keyDown:anEvent];
|
||||
|
||||
var rows = [self selectedRowIndexes],
|
||||
indexes = [],
|
||||
items = [];
|
||||
|
||||
[rows getIndexes:indexes maxCount:-1 inIndexRange:nil];
|
||||
|
||||
var i = 0,
|
||||
c = [indexes count];
|
||||
|
||||
for (; i < c; i++)
|
||||
items.push([self itemAtRow:indexes[i]]);
|
||||
|
||||
if (character === CPRightArrowFunctionKey)
|
||||
{
|
||||
for (var i = 0; i < c; i++)
|
||||
[self expandItem:items[i]];
|
||||
}
|
||||
else if (character === CPLeftArrowFunctionKey)
|
||||
{
|
||||
// When a single, collapsed item is selected and the left arrow key is pressed, the parent
|
||||
// should be selected if possible.
|
||||
if (c == 1)
|
||||
{
|
||||
var theItem = items[0];
|
||||
if (![self isItemExpanded:theItem])
|
||||
{
|
||||
var parent = [self parentForItem:theItem],
|
||||
shouldSelect = parent && SELECTION_SHOULD_CHANGE(self) && SHOULD_SELECT_ITEM(self, parent);
|
||||
if (shouldSelect)
|
||||
{
|
||||
var rowIndex = [self rowForItem:parent];
|
||||
[self selectRowIndexes:[CPIndexSet indexSetWithIndex:rowIndex] byExtendingSelection:NO];
|
||||
[self scrollRowToVisible:rowIndex];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < c; i++)
|
||||
[self collapseItem:items[i]];
|
||||
}
|
||||
|
||||
[super keyDown:anEvent];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever...
|
||||
@@ -1496,8 +1570,9 @@ var _reloadItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem)
|
||||
|
||||
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:newItem];
|
||||
itemInfo.isExpanded = itemInfo.isExpandable && itemInfo.isExpanded;
|
||||
itemInfo.shouldShowOutlineDisclosureControl = !(_implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldShowOutlineDisclosureControlForItem_) || [_outlineViewDelegate outlineView:self shouldShowOutlineDisclosureControlForItem:newItem];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever...
|
||||
var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem, /*BOOL*/ isIntermediate)
|
||||
@@ -1521,6 +1596,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
return [];
|
||||
|
||||
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:anItem];
|
||||
itemInfo.shouldShowOutlineDisclosureControl = !(_implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldShowOutlineDisclosureControlForItem_) || [_outlineViewDelegate outlineView:self shouldShowOutlineDisclosureControlForItem:anItem];
|
||||
|
||||
// If we were previously expanded, but now no longer expandable, "de-expand".
|
||||
// NOTE: we are *not* collapsing, thus no notification is posted.
|
||||
@@ -1551,7 +1627,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
|
||||
if (!childItemInfo)
|
||||
{
|
||||
childItemInfo = { isExpanded:NO, isExpandable:NO, children:[], weight:1 };
|
||||
childItemInfo = { isExpanded:NO, isExpandable:NO, shouldShowOutlineDisclosureControl:YES, children:[], weight:1 };
|
||||
itemInfosForItems[[childItem UID]] = childItemInfo;
|
||||
}
|
||||
|
||||
@@ -1602,7 +1678,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
}
|
||||
}//end of with
|
||||
return descendants;
|
||||
}
|
||||
};
|
||||
|
||||
@implementation _CPOutlineViewTableViewDataSource : CPObject
|
||||
{
|
||||
@@ -1754,9 +1830,9 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
var dataView = nil;
|
||||
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_))
|
||||
dataView = [_outlineView._outlineViewDelegate outlineView:_outlineView
|
||||
dataViewForTableColumn:theTableColumn
|
||||
item:[_outlineView itemAtRow:theRow]];
|
||||
dataView = [_outlineView._outlineViewDelegate outlineView:_outlineView
|
||||
dataViewForTableColumn:theTableColumn
|
||||
item:[_outlineView itemAtRow:theRow]];
|
||||
|
||||
if (!dataView)
|
||||
dataView = [theTableColumn dataViewForRow:theRow];
|
||||
@@ -1766,10 +1842,12 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
|
||||
- (BOOL)tableView:(CPTableView)theTableView shouldSelectRow:(int)theRow
|
||||
{
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldSelectItem_))
|
||||
return [_outlineView._outlineViewDelegate outlineView:_outlineView shouldSelectItem:[_outlineView itemAtRow:theRow]];
|
||||
return SHOULD_SELECT_ITEM(_outlineView, [_outlineView itemAtRow:theRow]);
|
||||
}
|
||||
|
||||
return YES;
|
||||
- (BOOL)selectionShouldChangeInTableView:(CPTableView)theTableView
|
||||
{
|
||||
return SELECTION_SHOULD_CHANGE(_outlineView);
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(CPTableView)aTableView shouldEditTableColumn:(CPTableColumn)aColumn row:(int)aRow
|
||||
@@ -1847,16 +1925,22 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
var bounds = [self bounds],
|
||||
context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
width = _CGRectGetWidth(bounds),
|
||||
height = _CGRectGetHeight(bounds);
|
||||
|
||||
CGContextBeginPath(context);
|
||||
|
||||
CGContextTranslateCTM(context, _CGRectGetWidth(bounds) / 2.0, _CGRectGetHeight(bounds) / 2.0);
|
||||
CGContextRotateCTM(context, _angle);
|
||||
CGContextTranslateCTM(context, -_CGRectGetWidth(bounds) / 2.0, -_CGRectGetHeight(bounds) / 2.0);
|
||||
if (_angle)
|
||||
{
|
||||
var centre = _CGPointMake(FLOOR(width / 2.0), FLOOR(height / 2.0));
|
||||
CGContextTranslateCTM(context, centre.x, centre.y);
|
||||
CGContextRotateCTM(context, _angle);
|
||||
CGContextTranslateCTM(context, -centre.x, -centre.y);
|
||||
}
|
||||
|
||||
// Center, but crisp.
|
||||
CGContextTranslateCTM(context, FLOOR((_CGRectGetWidth(bounds) - 9.0) / 2.0), FLOOR((_CGRectGetHeight(bounds) - 8.0) / 2.0));
|
||||
CGContextTranslateCTM(context, FLOOR((width - 9.0) / 2.0), FLOOR((height - 8.0) / 2.0));
|
||||
|
||||
CGContextMoveToPoint(context, 0.0, 0.0);
|
||||
CGContextAddLineToPoint(context, 9.0, 0.0);
|
||||
@@ -1869,20 +1953,14 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
[self hasThemeState:CPThemeStateHighlighted]));
|
||||
CGContextFillPath(context);
|
||||
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint(context, 0.0, 0.0);
|
||||
|
||||
CGContextAddLineToPoint(context, 4.5, 8.0);
|
||||
if (_angle === 0.0)
|
||||
{
|
||||
CGContextAddLineToPoint(context, 4.5, 8.0);
|
||||
CGContextAddLineToPoint(context, 9.0, 0.0);
|
||||
}
|
||||
|
||||
else
|
||||
CGContextAddLineToPoint(context, 4.5, 8.0);
|
||||
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithCalibratedWhite:1.0 alpha: 0.8]);
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithCalibratedWhite:1.0 alpha: 0.7]);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
@@ -1946,7 +2024,8 @@ var CPOutlineViewIndentationPerLevelKey = @"CPOutlineViewIndentationPerLevelKey"
|
||||
@end
|
||||
|
||||
|
||||
var colorForDisclosureTriangle = function(isSelected, isHighlighted) {
|
||||
var colorForDisclosureTriangle = function(isSelected, isHighlighted)
|
||||
{
|
||||
return isSelected
|
||||
? (isHighlighted
|
||||
? [CPColor colorWithCalibratedWhite:0.9 alpha: 1.0]
|
||||
@@ -1954,4 +2033,4 @@ var colorForDisclosureTriangle = function(isSelected, isHighlighted) {
|
||||
: (isHighlighted
|
||||
? [CPColor colorWithCalibratedWhite:0.4 alpha: 1.0]
|
||||
: [CPColor colorWithCalibratedWhite:0.5 alpha: 1.0]);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -86,7 +86,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
|
||||
[self setPullsDown:shouldPullDown];
|
||||
|
||||
var options = CPKeyValueObservingOptionNew |CPKeyValueObservingOptionOld;/* |CPKeyValueObservingOptionInitial;*/
|
||||
var options = CPKeyValueObservingOptionNew | CPKeyValueObservingOptionOld; // | CPKeyValueObservingOptionInitial;
|
||||
[self addObserver:self forKeyPath:@"menu.items" options:options context:nil];
|
||||
[self addObserver:self forKeyPath:@"_firstItem.changeCount" options:options context:nil];
|
||||
[self addObserver:self forKeyPath:@"selectedItem.changeCount" options:options context:nil];
|
||||
@@ -193,6 +193,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
- (void)removeAllItems
|
||||
{
|
||||
[[self menu] removeAllItems];
|
||||
[self synchronizeTitleAndSelectedItem];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -248,7 +249,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (int)selectedTag
|
||||
- (int)_selectedTag
|
||||
{
|
||||
return [[self selectedItem] tag];
|
||||
}
|
||||
@@ -775,6 +776,16 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
[[self selectedItem] setState:CPOffState];
|
||||
}
|
||||
|
||||
- (void)_reverseSetBinding
|
||||
{
|
||||
var binderClass = [[self class] _binderClassForBinding:CPSelectedIndexBinding],
|
||||
theBinding = [binderClass getBinding:CPSelectedIndexBinding forObject:self];
|
||||
|
||||
[theBinding reverseSetValueFor:@"objectValue"];
|
||||
|
||||
[super _reverseSetBinding];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var DEPRECATED_CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
|
||||
|
||||
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* CPPopover.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Antoine Mercadal.
|
||||
* Copyright 2011 Antoine Mercadal.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
@import "CPButton.j"
|
||||
@import "CPColor.j"
|
||||
@import "CPImage.j"
|
||||
@import "CPImageView.j"
|
||||
@import "CPResponder.j"
|
||||
@import "CPView.j"
|
||||
@import "_CPAttachedWindow.j"
|
||||
|
||||
|
||||
CPPopoverBehaviorApplicationDefined = 0;
|
||||
CPPopoverBehaviorTransient = 1;
|
||||
CPPopoverBehaviorSemitransient = 2;
|
||||
|
||||
var CPPopoverDelegate_popover_willShow_ = 1 << 0,
|
||||
CPPopoverDelegate_popover_didShow_ = 1 << 1,
|
||||
CPPopoverDelegate_popover_shouldClose_ = 1 << 2,
|
||||
CPPopoverDelegate_popover_willClose_ = 1 << 3,
|
||||
CPPopoverDelegate_popover_didClose_ = 1 << 4;
|
||||
|
||||
|
||||
/*! @ingroup appkit
|
||||
@class CPPopover
|
||||
|
||||
This class represent a widget that displays a attached
|
||||
view relative to another one.
|
||||
|
||||
Delegate can implement:
|
||||
|
||||
@code
|
||||
– popoverShouldClose:(CPPopover)aPopOver
|
||||
– popoverWillShow:(CPPopover)aPopOver
|
||||
– popoverDidShow:(CPPopover)aPopOver
|
||||
– popoverWillClose:(CPPopover)aPopOver
|
||||
– popoverDidClose:(CPPopover)aPopOver
|
||||
@endcode
|
||||
*/
|
||||
@implementation CPPopover : CPResponder
|
||||
{
|
||||
@outlet CPViewController _contentViewController @accessors(property=contentViewController);
|
||||
@outlet id _delegate @accessors(getter=delegate);
|
||||
|
||||
BOOL _animates @accessors(property=animates);
|
||||
int _appearance @accessors(property=appearance);
|
||||
int _behavior @accessors(getter=behavior);
|
||||
|
||||
_CPAttachedWindow _attachedWindow;
|
||||
BOOL _needsNewAttachedWindow;
|
||||
int _implementedDelegateMethods;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization
|
||||
|
||||
/*!
|
||||
Initialize the CPPopover witn default values
|
||||
|
||||
@returns anInitialized CPPopover
|
||||
*/
|
||||
- (CPPopover)init
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_animates = YES;
|
||||
_appearance = CPPopoverAppearanceMinimal;
|
||||
_behavior = CPPopoverBehaviorApplicationDefined;
|
||||
_needsNewAttachedWindow = YES;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Getters / Setters
|
||||
|
||||
/*!
|
||||
Returns the current rect of the popover
|
||||
|
||||
@return CGRect representing the frame of the popover
|
||||
*/
|
||||
- (CGRect)positioningRect
|
||||
{
|
||||
if (![_attachedWindow isVisible])
|
||||
return nil;
|
||||
return [_attachedWindow frame];
|
||||
}
|
||||
|
||||
/*! Sets the frame of the popover
|
||||
@param aRect the desired frame
|
||||
*/
|
||||
- (void)setPositioningRect:(CGRect)aRect
|
||||
{
|
||||
if (![_attachedWindow isVisible])
|
||||
return;
|
||||
[_attachedWindow setFrame:aRect];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the size of the popover's view
|
||||
|
||||
@return CGSize representing the size of the popover's view
|
||||
*/
|
||||
- (CGSize)contentSize
|
||||
{
|
||||
if (![_attachedWindow isVisible])
|
||||
return nil;
|
||||
return [[_contentViewController view] frameSize];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the size of of the popover's view
|
||||
|
||||
@param aSize the desired size
|
||||
*/
|
||||
- (void)setContentSize:(CPSize)aSize
|
||||
{
|
||||
[[_contentViewController view] setFrameSize:aSize];
|
||||
}
|
||||
|
||||
/*!
|
||||
Indicates if CPPopover is visible
|
||||
|
||||
@returns \c YES if visible
|
||||
*/
|
||||
- (BOOL)shown
|
||||
{
|
||||
return [_attachedWindow isVisible];
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the behaviour of the CPPopover. It can be:
|
||||
|
||||
- \c CPPopoverBehaviorTransient: the popover will close if another control outside the popover becomes the responder
|
||||
- \c CPPopoverBehaviorApplicationDefined: (DEFAULT) the application is responsible for closing the popover
|
||||
|
||||
@param aBehaviour the desired behaviour
|
||||
*/
|
||||
- (void)setBehaviour:(int)aBehaviour
|
||||
{
|
||||
if (_behavior == aBehaviour)
|
||||
return;
|
||||
|
||||
_behavior = aBehaviour;
|
||||
_needsNewAttachedWindow = YES;
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
{
|
||||
if (_delegate === aDelegate)
|
||||
return;
|
||||
|
||||
_delegate = aDelegate;
|
||||
_implementedDelegateMethods = 0;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(popoverWillShow:)])
|
||||
_implementedDelegateMethods |= CPPopoverDelegate_popover_willShow_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(popoverDidShow:)])
|
||||
_implementedDelegateMethods |= CPPopoverDelegate_popover_didShow_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(popoverShouldClose:)])
|
||||
_implementedDelegateMethods |= CPPopoverDelegate_popover_shouldClose_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(popoverWillClose:)])
|
||||
_implementedDelegateMethods |= CPPopoverDelegate_popover_willClose_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(popoverDidClose:)])
|
||||
_implementedDelegateMethods |= CPPopoverDelegate_popover_didClose_;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Positioning
|
||||
|
||||
/*!
|
||||
Show the popover
|
||||
|
||||
@param positioningRect if set, the popover will be positionned to a random rect relative to the window
|
||||
@param positioningView if set, the popover will be positioned relative to this view
|
||||
@param preferredEdge: \c CPRectEdge representing the preferred positioning.
|
||||
*/
|
||||
- (void)showRelativeToRect:(CGRect)positioningRect ofView:(CPView)positioningView preferredEdge:(CPRectEdge)preferredEdge
|
||||
{
|
||||
if (!_contentViewController)
|
||||
[CPException raise:CPInternalInconsistencyException reason:@"contentViewController must not be nil"];
|
||||
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_willShow_)
|
||||
[_delegate popoverWillShow:self];
|
||||
|
||||
if (!_attachedWindow || _needsNewAttachedWindow || [_attachedWindow isVisible])
|
||||
{
|
||||
var styleMask = (_behavior == CPPopoverBehaviorTransient) ? CPClosableOnBlurWindowMask : nil;
|
||||
_attachedWindow = [[_CPAttachedWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:styleMask];
|
||||
_needsNewAttachedWindow = NO;
|
||||
}
|
||||
|
||||
[_attachedWindow setAppearance:_appearance];
|
||||
[_attachedWindow setAnimates:_animates];
|
||||
[_attachedWindow setDelegate:self];
|
||||
[_attachedWindow setMovableByWindowBackground:NO];
|
||||
[_attachedWindow setFrame:[_attachedWindow frameRectForContentRect:[[_contentViewController view] frame]]];
|
||||
[_attachedWindow setContentView:[_contentViewController view]];
|
||||
|
||||
if (positioningRect)
|
||||
[_attachedWindow positionRelativeToRect:positioningRect preferredEdge:preferredEdge];
|
||||
else if (positioningView)
|
||||
[_attachedWindow positionRelativeToView:positioningView preferredEdge:preferredEdge];
|
||||
else
|
||||
[CPException raise:CPInvalidArgumentException reason:@"a value must be passed for positioningRect or positioningView"];
|
||||
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_didShow_)
|
||||
[_delegate popoverDidShow:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
Closes the popover
|
||||
*/
|
||||
- (void)close
|
||||
{
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_shouldClose_)
|
||||
if (![_delegate popoverShouldClose:self])
|
||||
return;
|
||||
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_willClose_)
|
||||
[_delegate popoverWillClose:self];
|
||||
|
||||
[_attachedWindow close];
|
||||
|
||||
// popoverDidClose will be sent from attachedWindowDidClose, since
|
||||
// the attached window will close asynchronously when animating.
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Action
|
||||
|
||||
/*!
|
||||
Close the popover
|
||||
|
||||
@param aSender the sender of the action
|
||||
*/
|
||||
- (IBAction)performClose:(id)aSender
|
||||
{
|
||||
[self close];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Delegates
|
||||
|
||||
/*! @ignore */
|
||||
- (BOOL)attachedWindowShouldClose:(_CPAttachedWindow)anAttachedWindow
|
||||
{
|
||||
[self close];
|
||||
|
||||
// We return NO, because we want the CPPopover to determine
|
||||
// if the attached window can be closed and to give us a chance
|
||||
// to send delegate messages.
|
||||
return NO;
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (void)attachedWindowDidClose:(_CPAttachedWindow)anAttachedWindow
|
||||
{
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_didClose_)
|
||||
[_delegate popoverDidClose:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPPopoverNeedsNewAttachedWindowKey = @"CPPopoverNeedsNewAttachedWindowKey",
|
||||
CPPopoverAppearanceKey = @"CPPopoverAppearanceKey",
|
||||
CPPopoverAnimatesKey = @"CPPopoverAnimatesKey",
|
||||
CPPopoverContentViewControllerKey = @"CPPopoverContentViewControllerKey",
|
||||
CPPopoverDelegateKey = @"CPPopoverDelegateKey",
|
||||
CPPopoverBehaviorKey = @"CPPopoverBehaviorKey";
|
||||
|
||||
@implementation CPPopover (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_needsNewAttachedWindow = [aCoder decodeBoolForKey:CPPopoverNeedsNewAttachedWindowKey];
|
||||
_appearance = [aCoder decodeIntForKey:CPPopoverAppearanceKey];
|
||||
_animates = [aCoder decodeBoolForKey:CPPopoverAnimatesKey];
|
||||
_contentViewController = [aCoder decodeObjectForKey:CPPopoverContentViewControllerKey];
|
||||
[self setDelegate:[aCoder decodeObjectForKey:CPPopoverDelegateKey]];
|
||||
[self setBehaviour:[aCoder decodeIntForKey:CPPopoverBehaviorKey]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeBool:_needsNewAttachedWindow forKey:CPPopoverNeedsNewAttachedWindowKey];
|
||||
[aCoder encodeInt:_appearance forKey:CPPopoverAppearanceKey];
|
||||
[aCoder encodeBool:_animates forKey:CPPopoverAnimatesKey];
|
||||
[aCoder encodeObject:_contentViewController forKey:CPPopoverContentViewControllerKey];
|
||||
[aCoder encodeObject:_delegate forKey:CPPopoverDelegateKey];
|
||||
[aCoder encodeInt:_behavior forKey:CPPopoverBehaviorKey];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -477,7 +477,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
||||
_doubleValue = [aCoder decodeObjectForKey:@"_doubleValue"];
|
||||
_controlSize = [aCoder decodeObjectForKey:@"_controlSize"];
|
||||
_isIndeterminate = [aCoder decodeObjectForKey:@"_isIndeterminate"];
|
||||
_style = [aCoder decodeObjectForKey:@"_style"];
|
||||
_style = [aCoder decodeIntForKey:@"_style"];
|
||||
_isAnimating = [aCoder decodeObjectForKey:@"_isAnimating"];
|
||||
_isDisplayedWhenStoppedSet = [aCoder decodeObjectForKey:@"_isDisplayedWhenStoppedSet"];
|
||||
_isDisplayedWhenStopped = [aCoder decodeObjectForKey:@"_isDisplayedWhenStopped"];
|
||||
@@ -495,7 +495,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
|
||||
[aCoder encodeObject:_doubleValue forKey:@"_doubleValue"];
|
||||
[aCoder encodeObject:_controlSize forKey:@"_controlSize"];
|
||||
[aCoder encodeObject:_isIndeterminate forKey:@"_isIndeterminate"];
|
||||
[aCoder encodeObject:_style forKey:@"_style"];
|
||||
[aCoder encodeInt:_style forKey:@"_style"];
|
||||
[aCoder encodeObject:_isAnimating forKey:@"_isAnimating"];
|
||||
[aCoder encodeObject:_isDisplayedWhenStoppedSet forKey:@"_isDisplayedWhenStoppedSet"];
|
||||
[aCoder encodeObject:_isDisplayedWhenStopped forKey:@"_isDisplayedWhenStopped"];
|
||||
|
||||
@@ -150,6 +150,14 @@ CPRadioImageOffset = 4.0;
|
||||
[_radioGroup _setSelectedRadio:self];
|
||||
}
|
||||
|
||||
- (void)sendAction:(SEL)anAction to:(id)anObject
|
||||
{
|
||||
[super sendAction:anAction to:anObject];
|
||||
|
||||
if (_radioGroup)
|
||||
[CPApp sendAction:[_radioGroup action] to:[_radioGroup target] from:_radioGroup];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
|
||||
@@ -220,8 +228,6 @@ var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
|
||||
|
||||
[_selectedRadio setState:CPOffState];
|
||||
_selectedRadio = aRadio;
|
||||
|
||||
[CPApp sendAction:_action to:_target from:self];
|
||||
}
|
||||
|
||||
- (CPRadio)selectedRadio
|
||||
|
||||
@@ -200,7 +200,7 @@
|
||||
if (isPopup)
|
||||
{
|
||||
itemArray = [[templateView itemArray] valueForKey:@"title"];
|
||||
itemsCount = [itemArray count],
|
||||
itemsCount = [itemArray count];
|
||||
menuIndex = 0;
|
||||
}
|
||||
|
||||
@@ -501,4 +501,4 @@ var CPPredicateTemplatesKey = @"CPPredicateTemplates";
|
||||
|
||||
@end
|
||||
|
||||
/*! @endcond */
|
||||
/*! @endcond */
|
||||
|
||||
@@ -20,17 +20,17 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
CPUndefinedAttributeType = 0,
|
||||
CPInteger16AttributeType = 100,
|
||||
CPInteger32AttributeType = 200,
|
||||
CPInteger64AttributeType = 300,
|
||||
CPDecimalAttributeType = 400,
|
||||
CPDoubleAttributeType = 500,
|
||||
CPFloatAttributeType = 600,
|
||||
CPStringAttributeType = 700,
|
||||
CPBooleanAttributeType = 800,
|
||||
CPDateAttributeType = 900,
|
||||
CPBinaryDataAttributeType = 1000,
|
||||
CPUndefinedAttributeType = 0;
|
||||
CPInteger16AttributeType = 100;
|
||||
CPInteger32AttributeType = 200;
|
||||
CPInteger64AttributeType = 300;
|
||||
CPDecimalAttributeType = 400;
|
||||
CPDoubleAttributeType = 500;
|
||||
CPFloatAttributeType = 600;
|
||||
CPStringAttributeType = 700;
|
||||
CPBooleanAttributeType = 800;
|
||||
CPDateAttributeType = 900;
|
||||
CPBinaryDataAttributeType = 1000;
|
||||
CPTransformableAttributeType = 1800;
|
||||
|
||||
@implementation CPPredicateEditorRowTemplate : CPObject
|
||||
@@ -785,4 +785,4 @@ var CPPredicateTemplateTypeKey = @"CPPredicateTemplateType",
|
||||
}
|
||||
|
||||
@end
|
||||
/*! @endcond */
|
||||
/*! @endcond */
|
||||
|
||||
@@ -16,12 +16,12 @@ var GRADIENT_NORMAL,
|
||||
{
|
||||
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
|
||||
{
|
||||
GRADIENT_NORMAL = "-webkit-gradient(linear, left top, left bottom, from(rgb(252, 252, 252)), to(rgb(223, 223, 223)))",
|
||||
GRADIENT_NORMAL = "-webkit-gradient(linear, left top, left bottom, from(rgb(252, 252, 252)), to(rgb(223, 223, 223)))";
|
||||
GRADIENT_HIGHLIGHTED = "-webkit-gradient(linear, left top, left bottom, from(rgb(223, 223, 223)), to(rgb(252, 252, 252)))";
|
||||
}
|
||||
else if (CPBrowserIsEngine(CPGeckoBrowserEngine))
|
||||
{
|
||||
GRADIENT_NORMAL = "-moz-linear-gradient(top, rgb(252, 252, 252), rgb(223, 223, 223))",
|
||||
GRADIENT_NORMAL = "-moz-linear-gradient(top, rgb(252, 252, 252), rgb(223, 223, 223))";
|
||||
GRADIENT_HIGHLIGHTED = "-moz-linear-gradient(top, rgb(223, 223, 223), rgb(252, 252, 252))";
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ var GRADIENT_NORMAL,
|
||||
style.border = "1px solid rgb(189, 189, 189)";
|
||||
style.filter = IE_FILTER;
|
||||
|
||||
[self setTextColor:[CPColor colorWithWhite:101/255 alpha:1]];
|
||||
[self setTextColor:[CPColor colorWithWhite:101 / 255 alpha:1]];
|
||||
[self setBordered:NO];
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2008, 280 North, Inc.
|
||||
*
|
||||
* Modified to match Lion style by Antoine Mercadal 2011
|
||||
* <antoine.mercadal@archipelproject.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
@@ -20,8 +23,9 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPControl.j"
|
||||
#include "../Foundation/Foundation.h"
|
||||
|
||||
@import "CPControl.j"
|
||||
|
||||
// CPScroller Constants
|
||||
CPScrollerNoPart = 0;
|
||||
@@ -54,6 +58,17 @@ NAMES_FOR_PARTS[CPScrollerKnobSlot] = @"knob-slot";
|
||||
NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
|
||||
|
||||
CPScrollerStyleLegacy = 0;
|
||||
CPScrollerStyleOverlay = 1;
|
||||
|
||||
CPScrollerKnobStyleDefault = 0;
|
||||
CPScrollerKnobStyleDark = 1;
|
||||
CPScrollerKnobStyleLight = 2;
|
||||
|
||||
CPThemeStateScrollViewLegacy = CPThemeState("scroller-style-legacy");
|
||||
CPThemeStateScrollerKnobLight = CPThemeState("scroller-knob-light");
|
||||
CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
|
||||
@implementation CPScroller : CPControl
|
||||
{
|
||||
CPControlSize _controlSize;
|
||||
@@ -68,8 +83,19 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
CPScrollerPart _trackingPart;
|
||||
float _trackingFloatValue;
|
||||
CGPoint _trackingStartPoint;
|
||||
|
||||
CPViewAnimation _animationScroller;
|
||||
|
||||
BOOL _allowFadingOut @accessors(getter=allowFadingOut);
|
||||
int _style;
|
||||
CPTimer _timerFadeOut;
|
||||
BOOL _isMouseOver;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Class methods
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return "scroller";
|
||||
@@ -78,49 +104,43 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithJSObject:{
|
||||
@"scroller-width": 15.0,
|
||||
@"knob-slot-color": [CPColor lightGrayColor],
|
||||
@"scroller-width": 7.0,
|
||||
@"knob-slot-color": [CPNull null],
|
||||
@"decrement-line-color": [CPNull null],
|
||||
@"increment-line-color": [CPNull null],
|
||||
@"knob-color": [CPColor grayColor],
|
||||
@"knob-color": [CPNull null],
|
||||
@"decrement-line-size":_CGSizeMakeZero(),
|
||||
@"increment-line-size":_CGSizeMakeZero(),
|
||||
@"track-inset":_CGInsetMakeZero(),
|
||||
@"knob-inset": _CGInsetMakeZero(),
|
||||
@"minimum-knob-length":21.0
|
||||
}]
|
||||
@"minimum-knob-length":21.0,
|
||||
@"track-border-overlay": 9.0
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
// Calculating Layout
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
+ (float)scrollerWidth
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_controlSize = CPRegularControlSize;
|
||||
_partRects = [];
|
||||
|
||||
[self setFloatValue:0.0];
|
||||
[self setKnobProportion:1.0];
|
||||
|
||||
_hitPart = CPScrollerNoPart;
|
||||
|
||||
[self _calculateIsVertical];
|
||||
}
|
||||
|
||||
return self;
|
||||
return [self scrollerWidthInStyle:CPScrollerStyleLegacy];
|
||||
}
|
||||
|
||||
// Determining CPScroller Size
|
||||
/*!
|
||||
Returns the CPScroller's width for a CPRegularControlSize.
|
||||
*/
|
||||
+ (float)scrollerWidth
|
||||
+ (float)scrollerWidthInStyle:(int)aStyle
|
||||
{
|
||||
return [[[CPScroller alloc] init] currentValueForThemeAttribute:@"scroller-width"];
|
||||
var scroller = [[self alloc] init];
|
||||
|
||||
if (aStyle == CPScrollerStyleLegacy)
|
||||
return [scroller valueForThemeAttribute:@"scroller-width" inState:CPThemeStateScrollViewLegacy];
|
||||
return [scroller currentValueForThemeAttribute:@"scroller-width"];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the CPScroller's overlay value.
|
||||
*/
|
||||
+ (float)scrollerOverlay
|
||||
{
|
||||
return [[[self alloc] init] currentValueForThemeAttribute:@"track-border-overlay"];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -132,6 +152,87 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
return [self scrollerWidth];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
_controlSize = CPRegularControlSize;
|
||||
_partRects = [];
|
||||
|
||||
[self setFloatValue:0.0];
|
||||
[self setKnobProportion:1.0];
|
||||
|
||||
_hitPart = CPScrollerNoPart;
|
||||
_allowFadingOut = YES;
|
||||
_isMouseOver = NO;
|
||||
_style = CPScrollerStyleOverlay;
|
||||
var paramAnimFadeOut = [CPDictionary dictionaryWithObjects:[self, CPViewAnimationFadeOutEffect]
|
||||
forKeys:[CPViewAnimationTargetKey, CPViewAnimationEffectKey]];
|
||||
|
||||
_animationScroller = [[CPViewAnimation alloc] initWithDuration:0.2 animationCurve:CPAnimationEaseInOut];
|
||||
[_animationScroller setViewAnimations:[paramAnimFadeOut]];
|
||||
[_animationScroller setDelegate:self];
|
||||
[self setAlphaValue:0.0];
|
||||
[self _calculateIsVertical];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Getters / Setters
|
||||
|
||||
/*!
|
||||
Returns the scroller's style
|
||||
*/
|
||||
- (void)style
|
||||
{
|
||||
return _style;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the scroller's control size
|
||||
@param aStyle the scroller style: CPScrollerStyleLegacy or CPScrollerStyleOverlay
|
||||
*/
|
||||
- (void)setStyle:(id)aStyle
|
||||
{
|
||||
if (_style != nil && _style === aStyle)
|
||||
return;
|
||||
|
||||
_style = aStyle;
|
||||
|
||||
if (_style === CPScrollerStyleLegacy)
|
||||
{
|
||||
[self fadeIn];
|
||||
[self setThemeState:CPThemeStateScrollViewLegacy];
|
||||
}
|
||||
else
|
||||
{
|
||||
_allowFadingOut = YES;
|
||||
[self unsetThemeState:CPThemeStateScrollViewLegacy];
|
||||
}
|
||||
|
||||
[self _adjustScrollerSize];
|
||||
}
|
||||
|
||||
- (void)setObjectValue:(id)aValue
|
||||
{
|
||||
[super setObjectValue:MIN(1.0, MAX(0.0, +aValue))];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the scroller's control size
|
||||
*/
|
||||
- (CPControlSize)controlSize
|
||||
{
|
||||
return _controlSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the scroller's size.
|
||||
@param aControlSize the scroller's size
|
||||
@@ -147,27 +248,6 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the scroller's control size
|
||||
*/
|
||||
- (CPControlSize)controlSize
|
||||
{
|
||||
return _controlSize;
|
||||
}
|
||||
|
||||
- (void)setObjectValue:(id)aValue
|
||||
{
|
||||
[super setObjectValue:MIN(1.0, MAX(0.0, +aValue))];
|
||||
}
|
||||
|
||||
- (void)setKnobProportion:(float)aProportion
|
||||
{
|
||||
_knobProportion = MIN(1.0, MAX(0.0001, aProportion));
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
/*!
|
||||
Return's the knob's proportion
|
||||
*/
|
||||
@@ -176,17 +256,50 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
return _knobProportion;
|
||||
}
|
||||
|
||||
- (id)currentValueForThemeAttribute:(CPString)anAttributeName
|
||||
/*!
|
||||
Set the knob's proportion
|
||||
@param aProportion the desired proportion
|
||||
*/
|
||||
- (void)setKnobProportion:(float)aProportion
|
||||
{
|
||||
var themeState = _themeState;
|
||||
if (!_IS_NUMERIC(aProportion))
|
||||
[CPException raise:CPInvalidArgumentException reason:"aProportion must be numeric"];
|
||||
|
||||
if (NAMES_FOR_PARTS[_hitPart] + "-color" !== anAttributeName)
|
||||
themeState &= ~CPThemeStateHighlighted;
|
||||
_knobProportion = MIN(1.0, MAX(0.0001, aProportion));
|
||||
|
||||
return [self valueForThemeAttribute:anAttributeName inState:themeState];
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
// Calculating Layout
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Privates
|
||||
|
||||
/*! @ignore */
|
||||
- (void)_adjustScrollerSize
|
||||
{
|
||||
var frame = [self frame],
|
||||
scrollerWidth = [self currentValueForThemeAttribute:@"scroller-width"];
|
||||
|
||||
if ([self isVertical] && CGRectGetWidth(frame) !== scrollerWidth)
|
||||
frame.size.width = scrollerWidth;
|
||||
|
||||
if (![self isVertical] && CGRectGetHeight(frame) !== scrollerWidth)
|
||||
frame.size.height = scrollerWidth;
|
||||
|
||||
[self setFrame:frame];
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (void)_performFadeOut:(CPTimer)aTimer
|
||||
{
|
||||
[self fadeOut];
|
||||
_timerFadeOut = nil;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Utilities
|
||||
|
||||
- (CGRect)rectForPart:(CPScrollerPart)aPart
|
||||
{
|
||||
@@ -208,6 +321,9 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
// The ordering of these tests is important. We check the knob and
|
||||
// page rects first since they may overlap with the arrows.
|
||||
|
||||
if (![self hasThemeState:CPThemeStateSelected])
|
||||
return CPScrollerNoPart;
|
||||
|
||||
if (CGRectContainsPoint([self rectForPart:CPScrollerKnob], aPoint))
|
||||
return CPScrollerKnob;
|
||||
|
||||
@@ -330,7 +446,35 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
return _usableParts;
|
||||
}
|
||||
|
||||
// Drawing the Parts
|
||||
/*!
|
||||
Display the scroller
|
||||
*/
|
||||
- (void)fadeIn
|
||||
{
|
||||
if (_isMouseOver && _knobProportion != 1.0)
|
||||
[self setThemeState:CPThemeStateSelected];
|
||||
|
||||
if (_timerFadeOut)
|
||||
[_timerFadeOut invalidate];
|
||||
|
||||
[self setAlphaValue:1.0];
|
||||
}
|
||||
|
||||
/*!
|
||||
Start the fade out anination
|
||||
*/
|
||||
- (void)fadeOut
|
||||
{
|
||||
if ([self hasThemeState:CPThemeStateScrollViewLegacy])
|
||||
return;
|
||||
|
||||
[_animationScroller startAnimation];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Drawing
|
||||
|
||||
/*!
|
||||
Draws the specified arrow and sets the highlight.
|
||||
@param anArrow the arrow to draw
|
||||
@@ -382,7 +526,8 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
[self checkSpaceForParts];
|
||||
|
||||
var index = 0,
|
||||
count = PARTS_ARRANGEMENT.length;
|
||||
count = PARTS_ARRANGEMENT.length,
|
||||
view;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
@@ -458,7 +603,8 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackKnob:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
if (type === CPLeftMouseDragged)
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -564,6 +710,20 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Overrides
|
||||
|
||||
- (id)currentValueForThemeAttribute:(CPString)anAttributeName
|
||||
{
|
||||
var themeState = _themeState;
|
||||
|
||||
if (NAMES_FOR_PARTS[_hitPart] + "-color" !== anAttributeName)
|
||||
themeState &= ~CPThemeStateHighlighted;
|
||||
|
||||
return [self valueForThemeAttribute:anAttributeName inState:themeState];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
if (![self isEnabled])
|
||||
@@ -582,10 +742,52 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(CPEvent)anEvent
|
||||
{
|
||||
[super mouseEntered:anEvent];
|
||||
|
||||
if (_timerFadeOut)
|
||||
[_timerFadeOut invalidate];
|
||||
|
||||
if (![self isEnabled])
|
||||
return;
|
||||
|
||||
_allowFadingOut = NO;
|
||||
_isMouseOver = YES;
|
||||
|
||||
if ([self alphaValue] > 0 && _knobProportion != 1.0)
|
||||
[self setThemeState:CPThemeStateSelected];
|
||||
}
|
||||
|
||||
- (void)mouseExited:(CPEvent)anEvent
|
||||
{
|
||||
[super mouseExited:anEvent];
|
||||
|
||||
if ([self isHidden] || ![self isEnabled] || !_isMouseOver)
|
||||
return;
|
||||
|
||||
_allowFadingOut = YES;
|
||||
_isMouseOver = NO;
|
||||
|
||||
if (_timerFadeOut)
|
||||
[_timerFadeOut invalidate];
|
||||
_timerFadeOut = [CPTimer scheduledTimerWithTimeInterval:1.2 target:self selector:@selector(_performFadeOut:) userInfo:nil repeats:NO];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Delegates
|
||||
|
||||
- (void)animationDidEnd:(CPAnimation)animation
|
||||
{
|
||||
[self unsetThemeState:CPThemeStateSelected];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPScrollerControlSizeKey = "CPScrollerControlSize",
|
||||
CPScrollerKnobProportionKey = "CPScrollerKnobProportion";
|
||||
var CPScrollerControlSizeKey = @"CPScrollerControlSize",
|
||||
CPScrollerKnobProportionKey = @"CPScrollerKnobProportion",
|
||||
CPScrollerStyleKey = @"CPScrollerStyleKey";
|
||||
|
||||
@implementation CPScroller (CPCoding)
|
||||
|
||||
@@ -605,20 +807,18 @@ var CPScrollerControlSizeKey = "CPScrollerControlSize",
|
||||
|
||||
_hitPart = CPScrollerNoPart;
|
||||
|
||||
_allowFadingOut = YES;
|
||||
_isMouseOver = NO;
|
||||
var paramAnimFadeOut = [CPDictionary dictionaryWithObjects:[self, CPViewAnimationFadeOutEffect]
|
||||
forKeys:[CPViewAnimationTargetKey, CPViewAnimationEffectKey]];
|
||||
_animationScroller = [[CPViewAnimation alloc] initWithDuration:0.2 animationCurve:CPAnimationEaseInOut];
|
||||
[_animationScroller setViewAnimations:[paramAnimFadeOut]];
|
||||
[_animationScroller setDelegate:self];
|
||||
[self setAlphaValue:0.0];
|
||||
|
||||
[self _calculateIsVertical];
|
||||
|
||||
// Adjust the size of the scroller if the size from cib
|
||||
// isn't equal to the scrollerWidth
|
||||
var frame = [self frame],
|
||||
scrollerWidth = [CPScroller scrollerWidth];
|
||||
|
||||
if ([self isVertical] && CGRectGetWidth(frame) !== scrollerWidth)
|
||||
frame.size.width = scrollerWidth;
|
||||
|
||||
if (![self isVertical] && CGRectGetHeight(frame) !== scrollerWidth)
|
||||
frame.size.height = scrollerWidth;
|
||||
|
||||
[self setFrame:frame];
|
||||
[self setStyle:[aCoder decodeIntForKey:CPScrollerStyleKey]];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -630,6 +830,7 @@ var CPScrollerControlSizeKey = "CPScrollerControlSize",
|
||||
|
||||
[aCoder encodeInt:_controlSize forKey:CPScrollerControlSizeKey];
|
||||
[aCoder encodeFloat:_knobProportion forKey:CPScrollerKnobProportionKey];
|
||||
[aCoder encodeInt:_style forKey:CPScrollerStyleKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -47,7 +47,6 @@ var LIGHT_LEFT_INSET = 3.0,
|
||||
/*!
|
||||
@ingroup appkit
|
||||
*/
|
||||
|
||||
@implementation CPShadowView : CPView
|
||||
{
|
||||
CPShadowWeight _weight;
|
||||
@@ -60,35 +59,33 @@ var LIGHT_LEFT_INSET = 3.0,
|
||||
|
||||
var bundle = [CPBundle bundleForClass:[self class]];
|
||||
|
||||
CPShadowViewLightBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTopLeft.png"] size:CGSizeMake(9.0, 9.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTop.png"] size:CGSizeMake(1.0, 9.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTopRight.png"] size:CGSizeMake(9.0, 9.0)],
|
||||
CPShadowViewLightBackgroundColor = CPColorWithImages([
|
||||
[@"CPShadowView/CPShadowViewLightTopLeft.png", 9.0, 9.0, bundle],
|
||||
[@"CPShadowView/CPShadowViewLightTop.png", 1.0, 9.0, bundle],
|
||||
[@"CPShadowView/CPShadowViewLightTopRight.png", 9.0, 9.0, bundle],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightLeft.png"] size:CGSizeMake(9.0, 1.0)],
|
||||
nil,
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightRight.png"] size:CGSizeMake(9.0, 1.0)],
|
||||
[@"CPShadowView/CPShadowViewLightLeft.png", 9.0, 1.0, bundle],
|
||||
nil,
|
||||
[@"CPShadowView/CPShadowViewLightRight.png", 9.0, 1.0, bundle],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottomLeft.png"] size:CGSizeMake(9.0, 9.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottom.png"] size:CGSizeMake(1.0, 9.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottomRight.png"] size:CGSizeMake(9.0, 9.0)]
|
||||
]]];
|
||||
[@"CPShadowView/CPShadowViewLightBottomLeft.png", 9.0, 9.0, bundle],
|
||||
[@"CPShadowView/CPShadowViewLightBottom.png", 1.0, 9.0, bundle],
|
||||
[@"CPShadowView/CPShadowViewLightBottomRight.png", 9.0, 9.0, bundle]
|
||||
]);
|
||||
|
||||
CPShadowViewHeavyBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTopLeft.png"] size:CGSizeMake(17.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTop.png"] size:CGSizeMake(1.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTopRight.png"] size:CGSizeMake(17.0, 17.0)],
|
||||
CPShadowViewHeavyBackgroundColor = CPColorWithImages([
|
||||
[@"CPShadowView/CPShadowViewHeavyTopLeft.png", 17.0, 17.0, bundle],
|
||||
[@"CPShadowView/CPShadowViewHeavyTop.png", 1.0, 17.0, bundle],
|
||||
[@"CPShadowView/CPShadowViewHeavyTopRight.png", 17.0, 17.0, bundle],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyLeft.png"] size:CGSizeMake(17.0, 1.0)],
|
||||
nil,
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyRight.png"] size:CGSizeMake(17.0, 1.0)],
|
||||
[@"CPShadowView/CPShadowViewHeavyLeft.png", 17.0, 1.0, bundle],
|
||||
nil,
|
||||
[@"CPShadowView/CPShadowViewHeavyRight.png", 17.0, 1.0, bundle],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottomLeft.png"] size:CGSizeMake(17.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottom.png"] size:CGSizeMake(1.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottomRight.png"] size:CGSizeMake(17.0, 17.0)]
|
||||
]]];
|
||||
[@"CPShadowView/CPShadowViewHeavyBottomLeft.png", 17.0, 17.0, bundle],
|
||||
[@"CPShadowView/CPShadowViewHeavyBottom.png", 1.0, 17.0, bundle],
|
||||
[@"CPShadowView/CPShadowViewHeavyBottomRight.png", 17.0, 17.0, bundle]
|
||||
]);
|
||||
}
|
||||
|
||||
+ (id)shadowViewEnclosingView:(CPView)aView
|
||||
@@ -98,20 +95,24 @@ var LIGHT_LEFT_INSET = 3.0,
|
||||
|
||||
+ (id)shadowViewEnclosingView:(CPView)aView withWeight:(CPShadowWeight)aWeight
|
||||
{
|
||||
var shadowView = [[CPShadowView alloc] initWithFrame:[aView frame]];
|
||||
[shadowView setWeight:aWeight];
|
||||
var shadowView = [[self alloc] initWithFrame:[aView frame]];
|
||||
|
||||
var size = [shadowView frame].size,
|
||||
width = size.width - [shadowView leftInset] - [shadowView rightInset],
|
||||
height = size.height - [shadowView topInset] - [shadowView bottomInset],
|
||||
enclosingView = [aView superview];
|
||||
if (shadowView)
|
||||
{
|
||||
[shadowView setWeight:aWeight];
|
||||
|
||||
[shadowView setHitTests:[aView hitTests]];
|
||||
[shadowView setAutoresizingMask:[aView autoresizingMask]];
|
||||
[aView removeFromSuperview];
|
||||
[shadowView addSubview:aView];
|
||||
[aView setFrame:CGRectMake([shadowView leftInset], [shadowView topInset], width, height)]
|
||||
[enclosingView addSubview:shadowView];
|
||||
var size = [shadowView frame].size,
|
||||
width = size.width - [shadowView leftInset] - [shadowView rightInset],
|
||||
height = size.height - [shadowView topInset] - [shadowView bottomInset],
|
||||
enclosingView = [aView superview];
|
||||
|
||||
[shadowView setHitTests:[aView hitTests]];
|
||||
[shadowView setAutoresizingMask:[aView autoresizingMask]];
|
||||
[aView removeFromSuperview];
|
||||
[shadowView addSubview:aView];
|
||||
[aView setFrame:CGRectMake([shadowView leftInset], [shadowView topInset], width, height)]
|
||||
[enclosingView addSubview:shadowView];
|
||||
}
|
||||
|
||||
return shadowView;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ CPSoundPlayBackStatePause = 2;
|
||||
CPString _name @accessors(property=name);
|
||||
id _delegate @accessors(property=delegate);
|
||||
|
||||
BOOL _playRequestBeforeLoad;
|
||||
HTMLAudioElement _audioTag;
|
||||
int _loadStatus;
|
||||
int _playBackStatus;
|
||||
@@ -61,6 +62,7 @@ CPSoundPlayBackStatePause = 2;
|
||||
_loops = NO;
|
||||
_audioTag = document.createElement("audio");
|
||||
_audioTag.preload = YES;
|
||||
_playRequestBeforeLoad = NO;
|
||||
|
||||
_audioTag.addEventListener("canplay", function()
|
||||
{
|
||||
@@ -138,6 +140,12 @@ CPSoundPlayBackStatePause = 2;
|
||||
- (void)_soundDidload
|
||||
{
|
||||
_loadStatus = CPSoundLoadStateCanBePlayed;
|
||||
|
||||
if (_playRequestBeforeLoad)
|
||||
{
|
||||
_playRequestBeforeLoad = NO;
|
||||
[self play];
|
||||
}
|
||||
}
|
||||
|
||||
/*! @ignore
|
||||
@@ -167,6 +175,12 @@ CPSoundPlayBackStatePause = 2;
|
||||
*/
|
||||
- (BOOL)play
|
||||
{
|
||||
if (_loadStatus === CPSoundLoadStateLoading)
|
||||
{
|
||||
_playRequestBeforeLoad = YES;
|
||||
return YES;
|
||||
}
|
||||
|
||||
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|
||||
|| (_playBackStatus === CPSoundPlayBackStatePlay))
|
||||
return NO;
|
||||
|
||||
@@ -20,16 +20,43 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "../Foundation/Foundation.h"
|
||||
|
||||
@import "CPButtonBar.j"
|
||||
@import "CPImage.j"
|
||||
@import "CPView.j"
|
||||
|
||||
#define SPLIT_VIEW_MAYBE_POST_WILL_RESIZE() \
|
||||
if ((_suppressResizeNotificationsMask & DidPostWillResizeNotification) === 0) \
|
||||
{ \
|
||||
[self _postNotificationWillResize]; \
|
||||
_suppressResizeNotificationsMask |= DidPostWillResizeNotification; \
|
||||
}
|
||||
|
||||
#define SPLIT_VIEW_MAYBE_POST_DID_RESIZE() \
|
||||
if ((_suppressResizeNotificationsMask & ShouldSuppressResizeNotifications) !== 0) \
|
||||
_suppressResizeNotificationsMask |= DidSuppressResizeNotification; \
|
||||
else \
|
||||
[self _postNotificationDidResize];
|
||||
|
||||
#define SPLIT_VIEW_DID_SUPPRESS_RESIZE_NOTIFICATION() \
|
||||
((_suppressResizeNotificationsMask & DidSuppressResizeNotification) !== 0)
|
||||
|
||||
#define SPLIT_VIEW_SUPPRESS_RESIZE_NOTIFICATIONS(shouldSuppress) \
|
||||
if (shouldSuppress) \
|
||||
_suppressResizeNotificationsMask |= ShouldSuppressResizeNotifications; \
|
||||
else \
|
||||
_suppressResizeNotificationsMask = 0;
|
||||
|
||||
CPSplitViewDidResizeSubviewsNotification = @"CPSplitViewDidResizeSubviewsNotification";
|
||||
CPSplitViewWillResizeSubviewsNotification = @"CPSplitViewWillResizeSubviewsNotification";
|
||||
|
||||
var CPSplitViewHorizontalImage = nil,
|
||||
CPSplitViewVerticalImage = nil;
|
||||
CPSplitViewVerticalImage = nil,
|
||||
|
||||
ShouldSuppressResizeNotifications = 1,
|
||||
DidPostWillResizeNotification = 1 << 1,
|
||||
DidSuppressResizeNotification = 1 << 2;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -45,24 +72,29 @@ var CPSplitViewHorizontalImage = nil,
|
||||
|
||||
@implementation CPSplitView : CPView
|
||||
{
|
||||
id _delegate;
|
||||
BOOL _isVertical;
|
||||
BOOL _isPaneSplitter;
|
||||
id _delegate;
|
||||
BOOL _isVertical;
|
||||
BOOL _isPaneSplitter;
|
||||
|
||||
int _currentDivider;
|
||||
float _initialOffset;
|
||||
float _preCollapsePosition;
|
||||
int _currentDivider;
|
||||
float _initialOffset;
|
||||
CPDictionary _preCollapsePositions;
|
||||
|
||||
CPString _originComponent;
|
||||
CPString _sizeComponent;
|
||||
CPString _originComponent;
|
||||
CPString _sizeComponent;
|
||||
|
||||
CPArray _DOMDividerElements;
|
||||
CPString _dividerImagePath;
|
||||
int _drawingDivider;
|
||||
CPArray _DOMDividerElements;
|
||||
CPString _dividerImagePath;
|
||||
int _drawingDivider;
|
||||
|
||||
BOOL _needsResizeSubviews;
|
||||
CPString _autosaveName;
|
||||
BOOL _shouldAutosave;
|
||||
BOOL _needsRestoreFromAutosave;
|
||||
|
||||
CPArray _buttonBars;
|
||||
BOOL _needsResizeSubviews;
|
||||
int _suppressResizeNotificationsMask;
|
||||
|
||||
CPArray _buttonBars;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
@@ -93,11 +125,15 @@ var CPSplitViewHorizontalImage = nil,
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
_suppressResizeNotificationsMask = 0;
|
||||
_preCollapsePositions = [CPMutableDictionary new];
|
||||
_currentDivider = CPNotFound;
|
||||
|
||||
_DOMDividerElements = [];
|
||||
_buttonBars = [];
|
||||
|
||||
_shouldAutosave = YES;
|
||||
|
||||
[self _setVertical:YES];
|
||||
}
|
||||
|
||||
@@ -412,7 +448,6 @@ var CPSplitViewHorizontalImage = nil,
|
||||
{
|
||||
_currentDivider = CPNotFound;
|
||||
[self _updateResizeCursor:anEvent];
|
||||
[self _postNotificationDidResize];
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -436,7 +471,8 @@ var CPSplitViewHorizontalImage = nil,
|
||||
[_delegate respondsToSelector:@selector(splitView:shouldCollapseSubview:forDoubleClickOnDividerAtIndex:)])
|
||||
{
|
||||
var minPosition = [self minPossiblePositionOfDividerAtIndex:i],
|
||||
maxPosition = [self maxPossiblePositionOfDividerAtIndex:i];
|
||||
maxPosition = [self maxPossiblePositionOfDividerAtIndex:i],
|
||||
_preCollapsePosition = [_preCollapsePositions objectForKey:"" + i] || 0;
|
||||
|
||||
if ([_delegate splitView:self canCollapseSubview:_subviews[i]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i] forDoubleClickOnDividerAtIndex:i])
|
||||
{
|
||||
@@ -526,20 +562,34 @@ var CPSplitViewHorizontalImage = nil,
|
||||
// If we are currently tracking, keep the resize cursor active even outside of hit areas.
|
||||
if (_currentDivider === i || (_currentDivider == CPNotFound && [self cursorAtPoint:point hitDividerAtIndex:i]))
|
||||
{
|
||||
var frame = [_subviews[i] frame],
|
||||
size = frame.size[_sizeComponent],
|
||||
startPosition = frame.origin[_originComponent] + size,
|
||||
var frameA = [_subviews[i] frame],
|
||||
sizeA = frameA.size[_sizeComponent],
|
||||
startPosition = frameA.origin[_originComponent] + sizeA,
|
||||
frameB = [_subviews[i + 1] frame],
|
||||
sizeB = frameB.size[_sizeComponent],
|
||||
canShrink = [self _realPositionForPosition:startPosition - 1 ofDividerAtIndex:i] < startPosition,
|
||||
canGrow = [self _realPositionForPosition:startPosition + 1 ofDividerAtIndex:i] > startPosition,
|
||||
cursor = [CPCursor arrowCursor];
|
||||
|
||||
if (size === 0)
|
||||
if (sizeA === 0)
|
||||
canGrow = YES; // Subview is collapsed.
|
||||
else if (!canShrink &&
|
||||
[_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)] &&
|
||||
[_delegate splitView:self canCollapseSubview:_subviews[i]])
|
||||
canShrink = YES; // Subview is collapsible.
|
||||
|
||||
if (sizeB === 0)
|
||||
{
|
||||
// Right/lower subview is collapsed.
|
||||
canGrow = NO;
|
||||
// It's safe to assume it can always be uncollapsed.
|
||||
canShrink = YES;
|
||||
}
|
||||
else if (!canGrow &&
|
||||
[_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)] &&
|
||||
[_delegate splitView:self canCollapseSubview:_subviews[i + 1]])
|
||||
canGrow = YES; // Right/lower subview is collapsible.
|
||||
|
||||
if (_isVertical && canShrink && canGrow)
|
||||
cursor = [CPCursor resizeLeftRightCursor];
|
||||
else if (_isVertical && canShrink)
|
||||
@@ -597,7 +647,15 @@ var CPSplitViewHorizontalImage = nil,
|
||||
{
|
||||
// not sure where this should override other positions?
|
||||
if ([_delegate respondsToSelector:@selector(splitView:constrainSplitPosition:ofSubviewAt:)])
|
||||
position = [_delegate splitView:self constrainSplitPosition:position ofSubviewAt:dividerIndex];
|
||||
{
|
||||
var proposedPosition = [_delegate splitView:self constrainSplitPosition:position ofSubviewAt:dividerIndex];
|
||||
|
||||
// Silently ignore bad positions which could result from odd delegate responses. We don't want these
|
||||
// bad results to go into the system and cause havoc with frame sizes as the split view tries to resize
|
||||
// its subviews.
|
||||
if (_IS_NUMERIC(proposedPosition))
|
||||
position = proposedPosition;
|
||||
}
|
||||
|
||||
var proposedMax = [self maxPossiblePositionOfDividerAtIndex:dividerIndex],
|
||||
proposedMin = [self minPossiblePositionOfDividerAtIndex:dividerIndex],
|
||||
@@ -605,18 +663,33 @@ var CPSplitViewHorizontalImage = nil,
|
||||
actualMin = proposedMin;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitView:constrainMinCoordinate:ofSubviewAt:)])
|
||||
actualMin = [_delegate splitView:self constrainMinCoordinate:proposedMin ofSubviewAt:dividerIndex];
|
||||
{
|
||||
var proposedActualMin = [_delegate splitView:self constrainMinCoordinate:proposedMin ofSubviewAt:dividerIndex];
|
||||
if (_IS_NUMERIC(proposedActualMin))
|
||||
actualMin = proposedActualMin;
|
||||
}
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitView:constrainMaxCoordinate:ofSubviewAt:)])
|
||||
actualMax = [_delegate splitView:self constrainMaxCoordinate:proposedMax ofSubviewAt:dividerIndex];
|
||||
{
|
||||
var proposedActualMax = [_delegate splitView:self constrainMaxCoordinate:proposedMax ofSubviewAt:dividerIndex];
|
||||
if (_IS_NUMERIC(proposedActualMax))
|
||||
actualMax = proposedActualMax;
|
||||
}
|
||||
|
||||
var viewA = _subviews[dividerIndex],
|
||||
viewB = _subviews[dividerIndex + 1],
|
||||
realPosition = MAX(MIN(position, actualMax), actualMin);
|
||||
|
||||
if (position < proposedMin + (actualMin - proposedMin) / 2)
|
||||
// Is this position past the halfway point to collapse?
|
||||
if (position < proposedMin + (actualMin - proposedMin) / 2)
|
||||
if ([_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)])
|
||||
if ([_delegate splitView:self canCollapseSubview:viewA])
|
||||
realPosition = proposedMin;
|
||||
// We can also collapse to the right.
|
||||
if (position > proposedMax - (proposedMax - actualMax) / 2)
|
||||
if ([_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)])
|
||||
if ([_delegate splitView:self canCollapseSubview:viewB])
|
||||
realPosition = proposedMax;
|
||||
|
||||
return realPosition;
|
||||
}
|
||||
@@ -628,6 +701,7 @@ var CPSplitViewHorizontalImage = nil,
|
||||
*/
|
||||
- (void)setPosition:(float)position ofDividerAtIndex:(int)dividerIndex
|
||||
{
|
||||
SPLIT_VIEW_SUPPRESS_RESIZE_NOTIFICATIONS(YES);
|
||||
[self _adjustSubviewsWithCalculatedSize];
|
||||
|
||||
var realPosition = [self _realPositionForPosition:position ofDividerAtIndex:dividerIndex];
|
||||
@@ -635,32 +709,59 @@ var CPSplitViewHorizontalImage = nil,
|
||||
var viewA = _subviews[dividerIndex],
|
||||
frameA = [viewA frame],
|
||||
viewB = _subviews[dividerIndex + 1],
|
||||
frameB = [viewB frame];
|
||||
|
||||
_preCollapsePosition = 0;
|
||||
frameB = [viewB frame],
|
||||
_preCollapsePosition = 0;
|
||||
|
||||
var preSize = frameA.size[_sizeComponent];
|
||||
frameA.size[_sizeComponent] = realPosition - frameA.origin[_originComponent];
|
||||
if (preSize !== 0 && frameA.size[_sizeComponent] === 0)
|
||||
_preCollapsePosition = preSize;
|
||||
[_subviews[dividerIndex] setFrame:frameA];
|
||||
if (preSize !== frameA.size[_sizeComponent])
|
||||
{
|
||||
SPLIT_VIEW_MAYBE_POST_WILL_RESIZE();
|
||||
[_subviews[dividerIndex] setFrame:frameA];
|
||||
SPLIT_VIEW_MAYBE_POST_DID_RESIZE();
|
||||
}
|
||||
|
||||
preSize = frameB.size[_sizeComponent];
|
||||
var preOrigin = frameB.origin[_originComponent];
|
||||
frameB.size[_sizeComponent] = frameB.origin[_originComponent] + frameB.size[_sizeComponent] - realPosition - [self dividerThickness];
|
||||
if (preSize !== 0 && frameB.size[_sizeComponent] === 0)
|
||||
_preCollapsePosition = preSize;
|
||||
_preCollapsePosition = frameB.origin[_originComponent];
|
||||
frameB.origin[_originComponent] = realPosition + [self dividerThickness];
|
||||
[_subviews[dividerIndex + 1] setFrame:frameB];
|
||||
if (preSize !== frameB.size[_sizeComponent] || preOrigin !== frameB.origin[_originComponent])
|
||||
{
|
||||
SPLIT_VIEW_MAYBE_POST_WILL_RESIZE();
|
||||
[_subviews[dividerIndex + 1] setFrame:frameB];
|
||||
SPLIT_VIEW_MAYBE_POST_DID_RESIZE();
|
||||
}
|
||||
|
||||
if (_preCollapsePosition)
|
||||
[_preCollapsePositions setObject:_preCollapsePosition forKey:"" + dividerIndex];
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
if (SPLIT_VIEW_DID_SUPPRESS_RESIZE_NOTIFICATION())
|
||||
[self _postNotificationDidResize];
|
||||
SPLIT_VIEW_SUPPRESS_RESIZE_NOTIFICATIONS(NO);
|
||||
}
|
||||
|
||||
- (void)setFrameSize:(CGSize)aSize
|
||||
{
|
||||
[self _adjustSubviewsWithCalculatedSize];
|
||||
if (_needsRestoreFromAutosave)
|
||||
_shouldAutosave = NO;
|
||||
else
|
||||
[self _adjustSubviewsWithCalculatedSize];
|
||||
|
||||
[super setFrameSize:aSize];
|
||||
|
||||
if (_needsRestoreFromAutosave)
|
||||
{
|
||||
_needsRestoreFromAutosave = NO;
|
||||
[self _restoreFromAutosave];
|
||||
_shouldAutosave = YES;
|
||||
}
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
@@ -672,67 +773,100 @@ var CPSplitViewHorizontalImage = nil,
|
||||
return;
|
||||
}
|
||||
|
||||
var count = [_subviews count];
|
||||
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
SPLIT_VIEW_MAYBE_POST_WILL_RESIZE();
|
||||
[self _postNotificationWillResize];
|
||||
|
||||
var index = 0,
|
||||
count = [_subviews count],
|
||||
bounds = [self bounds],
|
||||
boundsSize = bounds.size[_sizeComponent],
|
||||
dividerThickness = [self dividerThickness],
|
||||
totalDividers = count - 1,
|
||||
totalSizableSpace = 0,
|
||||
nonSizableSpace = 0,
|
||||
lastSizableIndex = -1,
|
||||
oldFlexibleSpace = 0,
|
||||
totalSizablePanes = 0,
|
||||
isVertical = [self isVertical];
|
||||
isSizableMap = {},
|
||||
viewSizes = [],
|
||||
delegateRespondsToShouldAdjust = [_delegate respondsToSelector:@selector(splitView:shouldAdjustSizeOfSubview:)];
|
||||
|
||||
// What we want to do is to preserve non resizable sizes first, and then to preserve the ratio of size to available
|
||||
// non fixed space for every other subview. E.g. assume fixed space was 20 pixels initially, view 1 was 20 and
|
||||
// view 2 was 30 pixels, for a total of 70 pixels. Then the new total size becomes 140 pixels. Now we want the fixed
|
||||
// space to still be 20 pixels, view 1 to be 48 pixels and view 2 to be 72 pixels. This way the relative size of
|
||||
// view 1 to view 2 remains the same - view 1 was 66% of view 2 initially and after the resize view 1 is still
|
||||
// 66% of view 2's size.
|
||||
//
|
||||
// For this calculation, we can consider the dividers themselves to also be fixed size areas - they should remain
|
||||
// the same size before and after.
|
||||
|
||||
// How much flexible size do we have in pre-resize pixels?
|
||||
for (index = 0; index < count; ++index)
|
||||
{
|
||||
var view = _subviews[index],
|
||||
isSizable = isVertical ? [view autoresizingMask] & CPViewWidthSizable : [view autoresizingMask] & CPViewHeightSizable;
|
||||
isSizable = !delegateRespondsToShouldAdjust || [_delegate splitView:self shouldAdjustSizeOfSubview:view],
|
||||
size = [view frame].size[_sizeComponent];
|
||||
|
||||
isSizableMap[index] = isSizable;
|
||||
|
||||
viewSizes.push(size);
|
||||
if (isSizable)
|
||||
{
|
||||
totalSizableSpace += [view frame].size[_sizeComponent];
|
||||
lastSizableIndex = index;
|
||||
oldFlexibleSpace += size;
|
||||
totalSizablePanes++;
|
||||
}
|
||||
}
|
||||
|
||||
if (totalSizablePanes === count)
|
||||
totalSizableSpace = 0;
|
||||
// nonSizableSpace is the number of fixed pixels in pre-resize terms and the desired number post-resize.
|
||||
var nonSizableSpace = oldSize[_sizeComponent] - oldFlexibleSpace,
|
||||
newFlexibleSpace = boundsSize - nonSizableSpace,
|
||||
remainingFixedPixelsToRemove = 0;
|
||||
|
||||
var nonSizableSpace = totalSizableSpace ? bounds.size[_sizeComponent] - totalSizableSpace : 0,
|
||||
remainingFlexibleSpace = bounds.size[_sizeComponent] - oldSize[_sizeComponent],
|
||||
oldDimension = (oldSize[_sizeComponent] - totalDividers * dividerThickness - nonSizableSpace),
|
||||
ratio = oldDimension <= 0 ? 0 : (bounds.size[_sizeComponent] - totalDividers * dividerThickness - nonSizableSpace) / oldDimension;
|
||||
if (newFlexibleSpace < 0)
|
||||
{
|
||||
remainingFixedPixelsToRemove = -newFlexibleSpace;
|
||||
newFlexibleSpace = 0;
|
||||
}
|
||||
|
||||
var remainingFixedPanes = count - totalSizablePanes;
|
||||
for (index = 0; index < count; ++index)
|
||||
{
|
||||
var view = _subviews[index],
|
||||
viewFrame = CGRectMakeCopy(bounds),
|
||||
isSizable = isVertical ? [view autoresizingMask] & CPViewWidthSizable : [view autoresizingMask] & CPViewHeightSizable;
|
||||
isSizable = isSizableMap[index],
|
||||
targetSize = 0;
|
||||
|
||||
// The last area must take up exactly the remaining space, fixed or not.
|
||||
if (index + 1 === count)
|
||||
viewFrame.size[_sizeComponent] = bounds.size[_sizeComponent] - viewFrame.origin[_originComponent];
|
||||
|
||||
else if (totalSizableSpace && isSizable && lastSizableIndex === index)
|
||||
viewFrame.size[_sizeComponent] = MAX(0, ROUND([view frame].size[_sizeComponent] + remainingFlexibleSpace))
|
||||
|
||||
else if (isSizable || !totalSizableSpace)
|
||||
targetSize = boundsSize - viewFrame.origin[_originComponent];
|
||||
// Try to keep fixed size areas the same size.
|
||||
else if (!isSizable)
|
||||
{
|
||||
viewFrame.size[_sizeComponent] = MAX(0, ROUND(ratio * [view frame].size[_sizeComponent]));
|
||||
remainingFlexibleSpace -= (viewFrame.size[_sizeComponent] - [view frame].size[_sizeComponent]);
|
||||
var removedFixedPixels = MIN(remainingFixedPixelsToRemove / remainingFixedPanes, viewSizes[index]);
|
||||
targetSize = viewSizes[index] - removedFixedPixels;
|
||||
remainingFixedPixelsToRemove -= removedFixedPixels;
|
||||
remainingFixedPanes--;
|
||||
}
|
||||
// (new size / flexible size available) == (old size / old flexible size available)
|
||||
else if (oldFlexibleSpace > 0)
|
||||
targetSize = newFlexibleSpace * viewSizes[index] / oldFlexibleSpace;
|
||||
// oldFlexibleSpace <= 0 so all flexible areas were crushed. When we get space, allocate it evenly.
|
||||
// totalSizablePanes cannot be 0 since isSizable.
|
||||
else
|
||||
targetSize = newFlexibleSpace / totalSizablePanes;
|
||||
|
||||
else if (totalSizableSpace && !isSizable)
|
||||
viewFrame.size[_sizeComponent] = [view frame].size[_sizeComponent];
|
||||
targetSize = MAX(0, ROUND(targetSize));
|
||||
|
||||
bounds.origin[_originComponent] += viewFrame.size[_sizeComponent] + dividerThickness;
|
||||
viewFrame.size[_sizeComponent] = targetSize;
|
||||
|
||||
[view setFrame:viewFrame];
|
||||
|
||||
bounds.origin[_originComponent] += targetSize + dividerThickness;
|
||||
}
|
||||
|
||||
[self _postNotificationDidResize];
|
||||
SPLIT_VIEW_MAYBE_POST_DID_RESIZE();
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -749,6 +883,11 @@ Notifies the delegate when the subviews will be resized.
|
||||
- (void)splitViewWillResizeSubviews:(CPNotification)aNotification;
|
||||
@endcode
|
||||
|
||||
Allows the delegate to specify which of the CPSplitView's subviews should adjust if the window is resized.
|
||||
@code
|
||||
- (BOOL)splitView:(CPSplitView)aSplitView shouldAdjustSizeOfSubview:(CPView)aSubView
|
||||
@endcode
|
||||
|
||||
Lets the delegate specify a different rect for which the user can drag the splitView divider.
|
||||
@code
|
||||
- (CGRect)splitView:(CPSplitView)aSplitView effectiveRect:(CGRect)aRect forDrawnRect:(CGRect)aDrawnRect ofDividerAtIndex:(int)aDividerIndex;
|
||||
@@ -831,6 +970,7 @@ The sum of the views and the sum of the dividers should be equal to the size of
|
||||
@param CPButtonBar - The supplied button bar.
|
||||
@param unsigned int - The divider index the button bar will be assigned to.
|
||||
*/
|
||||
// FIXME Should be renamed to setButtonBar:ofDividerAtIndex:.
|
||||
- (void)setButtonBar:(CPButtonBar)aButtonBar forDividerAtIndex:(unsigned)dividerIndex
|
||||
{
|
||||
if (!aButtonBar)
|
||||
@@ -867,15 +1007,125 @@ The sum of the views and the sum of the dividers should be equal to the size of
|
||||
|
||||
- (void)_postNotificationDidResize
|
||||
{
|
||||
[self _autosave];
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPSplitViewDidResizeSubviewsNotification object:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the name under which the split view divider positions is automatically saved to CPUserDefaults.
|
||||
|
||||
@param autosaveName the name to save under or nil to not save
|
||||
*/
|
||||
- (void)setAutosaveName:(CPString)autosaveName
|
||||
{
|
||||
if (_autosaveName == autosaveName)
|
||||
return;
|
||||
_autosaveName = autosaveName;
|
||||
}
|
||||
|
||||
/*!
|
||||
Get the name under which the split view divider position is automatically saved to CPUserDefaults.
|
||||
|
||||
@return the name to save under or nil if no auto save is active
|
||||
*/
|
||||
- (CPString)autosaveName
|
||||
{
|
||||
return _autosaveName;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (void)_autosave
|
||||
{
|
||||
if (!_shouldAutosave || !autosaveName)
|
||||
return;
|
||||
|
||||
var userDefaults = [CPUserDefaults standardUserDefaults],
|
||||
autosaveName = [self _framesKeyForAutosaveName:[self autosaveName]],
|
||||
autosavePrecollapseName = [self _precollapseKeyForAutosaveName:[self autosaveName]],
|
||||
count = [_subviews count],
|
||||
positions = [CPMutableArray new],
|
||||
preCollapseArray = [CPMutableArray new];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var frame = [_subviews[i] frame];
|
||||
[positions addObject:CPStringFromRect(frame)];
|
||||
[preCollapseArray addObject:[_preCollapsePositions objectForKey:"" + i]];
|
||||
}
|
||||
|
||||
[userDefaults setObject:positions forKey:autosaveName];
|
||||
[userDefaults setObject:preCollapseArray forKey:autosavePrecollapseName];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (void)_restoreFromAutosave
|
||||
{
|
||||
if (!_autosaveName)
|
||||
return;
|
||||
|
||||
var autosaveName = [self _framesKeyForAutosaveName:[self autosaveName]],
|
||||
autosavePrecollapseName = [self _precollapseKeyForAutosaveName:[self autosaveName]],
|
||||
userDefaults = [CPUserDefaults standardUserDefaults],
|
||||
frames = [userDefaults objectForKey:autosaveName],
|
||||
preCollapseArray = [userDefaults objectForKey:autosavePrecollapseName];
|
||||
|
||||
if (frames)
|
||||
{
|
||||
var dividerThickness = [self dividerThickness],
|
||||
position = 0;
|
||||
|
||||
_shouldAutosave = NO;
|
||||
for (var i = 0, count = [frames count] - 1; i < count; i++)
|
||||
{
|
||||
var frame = CPRectFromString(frames[i]);
|
||||
position += frame.size[_sizeComponent];
|
||||
|
||||
[self setPosition:position ofDividerAtIndex:i];
|
||||
|
||||
position += dividerThickness;
|
||||
}
|
||||
_shouldAutosave = YES;
|
||||
}
|
||||
|
||||
if (preCollapseArray)
|
||||
{
|
||||
_preCollapsePositions = [CPMutableDictionary new];
|
||||
for (var i = 0, count = [preCollapseArray count]; i < count; i++)
|
||||
[_preCollapsePositions setObject:preCollapseArray[i] forKey:i + ""];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (CPString)_framesKeyForAutosaveName:(CPString)theAutosaveName
|
||||
{
|
||||
if (!theAutosaveName)
|
||||
return nil;
|
||||
return @"CPSplitView Subview Frames " + theAutosaveName;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (CPString)_precollapseKeyForAutosaveName:(CPString)theAutosaveName
|
||||
{
|
||||
if (!theAutosaveName)
|
||||
return nil;
|
||||
return @"CPSplitView Subview Precollapse Positions " + theAutosaveName;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
|
||||
CPSplitViewIsVerticalKey = "CPSplitViewIsVerticalKey",
|
||||
CPSplitViewIsPaneSplitterKey = "CPSplitViewIsPaneSplitterKey",
|
||||
CPSplitViewButtonBarsKey = "CPSplitViewButtonBarsKey";
|
||||
CPSplitViewButtonBarsKey = "CPSplitViewButtonBarsKey",
|
||||
CPSplitViewAutosaveNameKey = "CPSplitViewAutosaveNameKey";
|
||||
|
||||
@implementation CPSplitView (CPCoding)
|
||||
|
||||
@@ -889,7 +1139,11 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
|
||||
|
||||
if (self)
|
||||
{
|
||||
_suppressResizeNotificationsMask = 0;
|
||||
_preCollapsePositions = [CPMutableDictionary new];
|
||||
|
||||
_currentDivider = CPNotFound;
|
||||
_shouldAutosave = YES;
|
||||
|
||||
_DOMDividerElements = [];
|
||||
|
||||
@@ -899,6 +1153,13 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
|
||||
|
||||
_isPaneSplitter = [aCoder decodeBoolForKey:CPSplitViewIsPaneSplitterKey];
|
||||
[self _setVertical:[aCoder decodeBoolForKey:CPSplitViewIsVerticalKey]];
|
||||
|
||||
[self setAutosaveName:[aCoder decodeObjectForKey:CPSplitViewAutosaveNameKey]];
|
||||
|
||||
// We have to wait until we know our frame size before restoring, or the frame resize later will throw
|
||||
// away the restored size.
|
||||
if (_autosaveName)
|
||||
_needsRestoreFromAutosave = YES;
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -919,6 +1180,8 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
|
||||
|
||||
[aCoder encodeBool:_isVertical forKey:CPSplitViewIsVerticalKey];
|
||||
[aCoder encodeBool:_isPaneSplitter forKey:CPSplitViewIsPaneSplitterKey];
|
||||
|
||||
[aCoder encodeObject:_autosaveName forKey:CPSplitViewAutosaveNameKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -25,15 +25,16 @@
|
||||
@import <AppKit/CPTextField.j>
|
||||
|
||||
|
||||
var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
|
||||
/*! CPStepper is an implementation of Cocoa NSStepper.
|
||||
/*!
|
||||
CPStepper is an implementation of Cocoa NSStepper.
|
||||
|
||||
This control display a two part button that can be used to increase or decrease a value with a given interval.
|
||||
This control displays a two part button that can be used to increase or decrease a value with a given interval.
|
||||
*/
|
||||
@implementation CPStepper: CPControl
|
||||
{
|
||||
BOOL _valueWraps @accessors(property=valueWraps);
|
||||
BOOL _autorepeat @accessors(getter=autorepeat);
|
||||
int _increment @accessors(property=increment);
|
||||
int _maxValue @accessors(property=maxValue);
|
||||
int _minValue @accessors(property=minValue);
|
||||
@@ -45,7 +46,8 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
#pragma mark -
|
||||
#pragma mark Initialization
|
||||
|
||||
/*! Initializes a CPStepper with given values
|
||||
/*!
|
||||
Initializes a CPStepper with given values.
|
||||
@param aValue the initial value of the CPStepper
|
||||
@param minValue the minimal acceptable value of the stepper
|
||||
@param maxValue the maximal acceptable value of the stepper
|
||||
@@ -53,7 +55,7 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
*/
|
||||
+ (CPStepper)stepperWithInitialValue:(float)aValue minValue:(float)aMinValue maxValue:(float)aMaxValue
|
||||
{
|
||||
var stepper = [[CPStepper alloc] initWithFrame:CPRectMake(0, 0, 19, 25)];
|
||||
var stepper = [[CPStepper alloc] initWithFrame:_CGRectMake(0, 0, 19, 25)];
|
||||
[stepper setDoubleValue:aValue];
|
||||
[stepper setMinValue:aMinValue];
|
||||
[stepper setMaxValue:aMaxValue];
|
||||
@@ -61,10 +63,12 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
return stepper;
|
||||
}
|
||||
|
||||
/*! Initializes a CPStepper with default values:
|
||||
/*!
|
||||
Initializes a CPStepper with default values:
|
||||
- minValue = 0.0
|
||||
- maxValue = 59.0
|
||||
- value = 0.0
|
||||
|
||||
@return Initialized CPStepper
|
||||
*/
|
||||
+ (CPStepper)stepper
|
||||
@@ -72,7 +76,8 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
return [CPStepper stepperWithInitialValue:0.0 minValue:0.0 maxValue:59.0];
|
||||
}
|
||||
|
||||
/*! Initializes the CPStepper
|
||||
/*!
|
||||
Initializes a CPStepper.
|
||||
@param aFrame the frame of the control
|
||||
@return initialized CPStepper
|
||||
*/
|
||||
@@ -84,33 +89,43 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
_minValue = 0.0;
|
||||
_increment = 1.0;
|
||||
_valueWraps = YES;
|
||||
_autorepeat = YES;
|
||||
|
||||
[self setDoubleValue:0.0];
|
||||
|
||||
_buttonUp = [[CPButton alloc] initWithFrame:CPRectMake(aFrame.size.width - CPStepperButtonsSize.width, 0, CPStepperButtonsSize.width, CPStepperButtonsSize.height)];
|
||||
[_buttonUp setContinuous:YES];
|
||||
[_buttonUp setTarget:self];
|
||||
[_buttonUp setAction:@selector(_buttonDidClick:)];
|
||||
[_buttonUp setAutoresizingMask:CPViewNotSizable];
|
||||
[self addSubview:_buttonUp];
|
||||
|
||||
_buttonDown = [[CPButton alloc] initWithFrame:CPRectMake(aFrame.size.width - CPStepperButtonsSize.width, CPStepperButtonsSize.height, CPStepperButtonsSize.width, CPStepperButtonsSize.height - 1)];
|
||||
[_buttonDown setContinuous:YES];
|
||||
[_buttonDown setTarget:self];
|
||||
[_buttonDown setAction:@selector(_buttonDidClick:)];
|
||||
[_buttonDown setAutoresizingMask:CPViewNotSizable];
|
||||
[self addSubview:_buttonDown];
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self _init];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_buttonUp = [[CPButton alloc] initWithFrame:_CGRectMakeZero()];
|
||||
[_buttonUp setContinuous:_autorepeat];
|
||||
[_buttonUp setTarget:self];
|
||||
[_buttonUp setAction:@selector(_buttonDidClick:)];
|
||||
[_buttonUp setAutoresizingMask:CPViewNotSizable];
|
||||
[self addSubview:_buttonUp];
|
||||
|
||||
_buttonDown = [[CPButton alloc] initWithFrame:_CGRectMakeZero()];
|
||||
[_buttonDown setContinuous:_autorepeat];
|
||||
[_buttonDown setTarget:self];
|
||||
[_buttonDown setAction:@selector(_buttonDidClick:)];
|
||||
[_buttonDown setAutoresizingMask:CPViewNotSizable];
|
||||
|
||||
[self setContinuous:_autorepeat];
|
||||
[self addSubview:_buttonDown];
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Superclass overrides
|
||||
|
||||
/*! set if the CPStepper is enabled or not
|
||||
/*!
|
||||
Set if the CPStepper is enabled or not.
|
||||
@param shouldEnabled BOOL that define if stepper is enabled or not.
|
||||
*/
|
||||
- (void)setEnabled:(BOOL)shouldEnabled
|
||||
@@ -121,19 +136,30 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
[_buttonDown setEnabled:shouldEnabled];
|
||||
}
|
||||
|
||||
/*! set the frame of the CPStepper and check if width is not smaller than theme min-size
|
||||
@param aFrame the frame
|
||||
*/
|
||||
|
||||
- (void)setFrame:(CGRect)aFrame
|
||||
{
|
||||
if (aFrame.size.width >= CGRectGetWidth(aFrame))
|
||||
[super setFrame:aFrame];
|
||||
var upSize = [self valueForThemeAttribute:@"up-button-size"],
|
||||
downSize = [self valueForThemeAttribute:@"down-button-size"],
|
||||
minSize = _CGSizeMake(upSize.width, upSize.height + downSize.height),
|
||||
frame = _CGRectMakeCopy(aFrame);
|
||||
|
||||
frame.size.width = Math.max(minSize.width, frame.size.width);
|
||||
frame.size.height = Math.max(minSize.height, frame.size.height);
|
||||
[super setFrame:frame];
|
||||
}
|
||||
|
||||
/*! @ignore
|
||||
*/
|
||||
/*! @ignore */
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
var aFrame = [self frame],
|
||||
upSize = [self valueForThemeAttribute:@"up-button-size"],
|
||||
downSize = [self valueForThemeAttribute:@"down-button-size"],
|
||||
upFrame = _CGRectMake(aFrame.size.width - upSize.width, 0, upSize.width, upSize.height),
|
||||
downFrame = _CGRectMake(aFrame.size.width - downSize.width, upSize.height, downSize.width, downSize.height);
|
||||
[_buttonUp setFrame:upFrame];
|
||||
[_buttonDown setFrame:downFrame];
|
||||
|
||||
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:CPThemeStateBordered] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered];
|
||||
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:CPThemeStateBordered | CPThemeStateDisabled] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateDisabled];
|
||||
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:CPThemeStateBordered | CPThemeStateHighlighted] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateHighlighted];
|
||||
@@ -142,16 +168,23 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inState:CPThemeStateBordered | CPThemeStateHighlighted] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateHighlighted];
|
||||
}
|
||||
|
||||
/*! set if CPStepper should autorepeat
|
||||
/*!
|
||||
Set if CPStepper should autorepeat.
|
||||
@param shouldAutoRepeat if YES, the first mouse down does one increment (decrement) and, after each delay of 0.5 seconds
|
||||
*/
|
||||
- (void)setAutorepeat:(BOOL)shouldAutoRepeat
|
||||
{
|
||||
[_buttonUp setContinuous:shouldAutoRepeat];
|
||||
[_buttonDown setContinuous:shouldAutoRepeat];
|
||||
if (shouldAutoRepeat !== _autorepeat)
|
||||
{
|
||||
[_buttonUp setContinuous:shouldAutoRepeat];
|
||||
[_buttonDown setContinuous:shouldAutoRepeat];
|
||||
}
|
||||
|
||||
[self setContinuous:shouldAutoRepeat];
|
||||
}
|
||||
|
||||
/*! set the current value of the stepper
|
||||
/*!
|
||||
Set the current value of the stepper.
|
||||
@param aValue a float containing the value
|
||||
*/
|
||||
- (void)setDoubleValue:(float)aValue
|
||||
@@ -167,8 +200,7 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
#pragma mark -
|
||||
#pragma mark Actions
|
||||
|
||||
/*! @ignore
|
||||
*/
|
||||
/*! @ignore */
|
||||
- (IBAction)_buttonDidClick:(id)aSender
|
||||
{
|
||||
if (![self isEnabled])
|
||||
@@ -183,7 +215,8 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
[self sendAction:_action to:_target];
|
||||
}
|
||||
|
||||
/*! @perform a programatic click on up button
|
||||
/*!
|
||||
Perform a programatic click on up button.
|
||||
@param aSender sender of the action
|
||||
*/
|
||||
- (IBAction)performClickUp:(id)aSender
|
||||
@@ -191,7 +224,8 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
[_buttonUp performClick:aSender];
|
||||
}
|
||||
|
||||
/*! @perform a programatic click on down button
|
||||
/*!
|
||||
Perform a programatic click on down button.
|
||||
@param aSender sender of the action
|
||||
*/
|
||||
- (IBAction)performClickDown:(id)aSender
|
||||
@@ -210,25 +244,33 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null]]
|
||||
forKeys:[@"bezel-color-up-button", @"bezel-color-down-button"]];
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null], _CGSizeMakeZero(), _CGSizeMakeZero()]
|
||||
forKeys:[@"bezel-color-up-button", @"bezel-color-down-button", @"up-button-size", @"down-button-size"]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPStepperMinValue = @"CPStepperMinValue",
|
||||
CPStepperMaxValue = @"CPStepperMaxValue",
|
||||
CPStepperValueWraps = @"CPStepperValueWraps",
|
||||
CPStepperAutorepeat = @"CPStepperAutorepeat",
|
||||
CPStepperIncrement = @"CPStepperIncrement";
|
||||
|
||||
@implementation CPStepper (CPCodingCompliance)
|
||||
@implementation CPStepper (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
{
|
||||
_maxValue = [aCoder decodeObjectForKey:@"_maxValue"];
|
||||
_minValue = [aCoder decodeObjectForKey:@"_minValue"];
|
||||
_increment = [aCoder decodeObjectForKey:@"_increment"];
|
||||
_buttonUp = [aCoder decodeObjectForKey:@"_buttonUp"];
|
||||
_buttonDown = [aCoder decodeObjectForKey:@"_buttonDown"];
|
||||
_increment = [aCoder decodeIntForKey:CPStepperIncrement];
|
||||
_minValue = [aCoder decodeIntForKey:CPStepperMinValue] || 0;
|
||||
_maxValue = [aCoder decodeIntForKey:CPStepperMaxValue] || 0;
|
||||
_valueWraps = [aCoder decodeBoolForKey:CPStepperValueWraps] || NO;
|
||||
_autorepeat = [aCoder decodeBoolForKey:CPStepperAutorepeat] || NO;
|
||||
|
||||
[self _init];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -236,11 +278,16 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeObject:_maxValue forKey:@"_maxValue"];
|
||||
[aCoder encodeObject:_minValue forKey:@"_minValue"];
|
||||
[aCoder encodeObject:_increment forKey:@"_increment"];
|
||||
[aCoder encodeObject:_buttonUp forKey:@"_buttonUp"];
|
||||
[aCoder encodeObject:_buttonDown forKey:@"_buttonDown"];
|
||||
[aCoder encodeInt:_increment forKey:CPStepperIncrement];
|
||||
|
||||
if (_minValue)
|
||||
[aCoder encodeInt:_minValue forKey:CPStepperMinValue];
|
||||
if (_maxValue)
|
||||
[aCoder encodeInt:_maxValue forKey:CPStepperMaxValue];
|
||||
if (_valueWraps)
|
||||
[aCoder encodeBool:_valueWraps forKey:CPStepperValueWraps];
|
||||
if (_autorepeat)
|
||||
[aCoder encodeBool:_autorepeat forKey:CPStepperAutorepeat];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,3 +1,25 @@
|
||||
/*
|
||||
* CPTabView.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Derek Hammer.
|
||||
* Copyright 2010, Derek Hammer.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPBox.j"
|
||||
@import "CPSegmentedControl.j"
|
||||
@import "CPTabViewItem.j"
|
||||
@@ -45,7 +67,6 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
_items = [CPArray array];
|
||||
_selectedIndex = CPNotFound;
|
||||
|
||||
[self _init];
|
||||
[self setTabViewType:CPTopTabsBezelBorder];
|
||||
@@ -56,6 +77,8 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_selectedIndex = CPNotFound;
|
||||
|
||||
_tabs = [[CPSegmentedControl alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
|
||||
[_tabs setHitTests:NO];
|
||||
|
||||
@@ -252,8 +275,6 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)selectTabViewItemAtIndex:(unsigned)anIndex
|
||||
{
|
||||
var aTabViewItem = [_items objectAtIndex:anIndex];
|
||||
|
||||
if (anIndex === _selectedIndex)
|
||||
return;
|
||||
|
||||
@@ -278,7 +299,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (CPTabViewItem)selectedTabViewItem
|
||||
{
|
||||
return [_items objectAtIndex:_selectedIndex];
|
||||
if (_selectedIndex != CPNotFound)
|
||||
return [_items objectAtIndex:_selectedIndex];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Modifying the font
|
||||
@@ -428,8 +452,12 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
- (void)_setSelectedIndex:(CPNumber)index
|
||||
{
|
||||
_selectedIndex = index;
|
||||
[self _setContentViewForItem:[_items objectAtIndex:_selectedIndex]];
|
||||
}
|
||||
|
||||
[_box setContentView:[[_items objectAtIndex:_selectedIndex] view]];
|
||||
- (void)_setContentViewForItem:(CPTabViewItem)anItem
|
||||
{
|
||||
[_box setContentView:[anItem view]];
|
||||
}
|
||||
|
||||
- (void)_updateItems
|
||||
@@ -469,17 +497,17 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
||||
[_tabs setFont:_font];
|
||||
|
||||
_items = [aCoder decodeObjectForKey:CPTabViewItemsKey];
|
||||
[_items makeObjectsPerformSelector:@selector(_setTabView:) withObject:self];
|
||||
|
||||
[self _updateItems];
|
||||
[self _repositionTabs];
|
||||
|
||||
var selected = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
|
||||
[self setDelegate:[aCoder decodeObjectForKey:CPTabViewDelegateKey]];
|
||||
|
||||
var selected = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
|
||||
if (selected)
|
||||
[self selectTabViewItem:selected];
|
||||
|
||||
[self setDelegate:[aCoder decodeObjectForKey:CPTabViewDelegateKey]];
|
||||
|
||||
[self setTabViewType:[aCoder decodeIntForKey:CPTabViewTypeKey]];
|
||||
}
|
||||
|
||||
@@ -491,7 +519,10 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeObject:_items forKey:CPTabViewItemsKey];
|
||||
[aCoder encodeObject:[self selectedTabViewItem] forKey:CPTabViewSelectedItemKey];
|
||||
|
||||
var selected = [self selectedTabViewItem];
|
||||
if (selected)
|
||||
[aCoder encodeObject:selected forKey:CPTabViewSelectedItemKey];
|
||||
|
||||
[aCoder encodeInt:_type forKey:CPTabViewTypeKey];
|
||||
[aCoder encodeObject:_font forKey:CPTabViewFontKey];
|
||||
|
||||
@@ -132,7 +132,13 @@ CPPressedTab = 2;
|
||||
*/
|
||||
- (void)setView:(CPView)aView
|
||||
{
|
||||
if (_view == aView)
|
||||
return;
|
||||
|
||||
_view = aView;
|
||||
|
||||
if ([_tabView selectedTabViewItem] == self)
|
||||
[_tabView _setContentViewForItem:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
@@ -132,7 +132,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
{
|
||||
var min = [self minWidth],
|
||||
max = [self maxWidth],
|
||||
newWidth = MIN(MAX(width, min), max);
|
||||
newWidth = ROUND(MIN(MAX(width, min), max));
|
||||
|
||||
[self setWidth:newWidth];
|
||||
|
||||
@@ -594,7 +594,22 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
[super bind:aBinding toObject:anObject withKeyPath:aKeyPath options:options];
|
||||
|
||||
if (![aBinding isEqual:@"someListOfExceptedBindings(notAcceptedBindings)"])
|
||||
[[self tableView] _establishBindingsIfUnbound:anObject];
|
||||
{
|
||||
// Bind the table to the array controller this column is bound to.
|
||||
// Note that anObject might not be the array controller. E.g. the keypath could be something like
|
||||
// somePathTo.anArrayController.arrangedObjects.aKey. Cocoa doesn't support this but it is consistent
|
||||
// and it makes sense.
|
||||
var acIndex = aKeyPath.lastIndexOf("arrangedObjects."),
|
||||
arrayController = anObject;
|
||||
|
||||
if (acIndex > 1)
|
||||
{
|
||||
var firstPart = aKeyPath.substring(0, acIndex - 1);
|
||||
arrayController = [anObject valueForKeyPath:firstPart];
|
||||
}
|
||||
|
||||
[[self tableView] _establishBindingsIfUnbound:arrayController];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -719,7 +734,6 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
||||
[self setIdentifier:[aCoder decodeObjectForKey:CPTableColumnIdentifierKey]];
|
||||
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
|
||||
[self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
|
||||
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
|
||||
|
||||
_resizingMask = [aCoder decodeIntForKey:CPTableColumnResizingMaskKey];
|
||||
_isHidden = [aCoder decodeBoolForKey:CPTableColumnIsHiddenKey];
|
||||
|
||||
@@ -643,7 +643,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
columnMaxX = _CGRectGetMaxX(columnToStroke);
|
||||
|
||||
CGContextMoveToPoint(context, FLOOR(columnMaxX) - 0.5, ROUND(_CGRectGetMinY(columnToStroke)));
|
||||
CGContextAddLineToPoint(context, FLOOR(columnMaxX) - 0.5, ROUND(_CGRectGetMaxY(columnToStroke)));
|
||||
CGContextAddLineToPoint(context, FLOOR(columnMaxX) - 0.5, ROUND(_CGRectGetMaxY(columnToStroke)) - 1.0);
|
||||
}
|
||||
CGContextClosePath(context);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
@@ -87,9 +87,9 @@ CPTableViewSelectionHighlightStyleNone = -1;
|
||||
CPTableViewSelectionHighlightStyleRegular = 0;
|
||||
CPTableViewSelectionHighlightStyleSourceList = 1;
|
||||
|
||||
CPTableViewGridNone = 0;
|
||||
CPTableViewSolidVerticalGridLineMask = 1 << 0;
|
||||
CPTableViewSolidHorizontalGridLineMask = 1 << 1;
|
||||
CPTableViewGridNone = 0;
|
||||
CPTableViewSolidVerticalGridLineMask = 1 << 0;
|
||||
CPTableViewSolidHorizontalGridLineMask = 1 << 1;
|
||||
|
||||
CPTableViewNoColumnAutoresizing = 0;
|
||||
CPTableViewUniformColumnAutoresizingStyle = 1; // FIX ME: This is FUBAR
|
||||
@@ -509,6 +509,11 @@ NOT YET IMPLEMENTED
|
||||
_objectValues = { };
|
||||
_cachedRowHeights = [];
|
||||
|
||||
// Otherwise, if we have a row marked as group with a
|
||||
// index greater than the new number or rows
|
||||
// it keeps the the graphical group style.
|
||||
[_groupRows removeAllIndexes];
|
||||
|
||||
// This updates the size too.
|
||||
[self noteNumberOfRowsChanged];
|
||||
|
||||
@@ -678,6 +683,7 @@ NOT YET IMPLEMENTED
|
||||
*/
|
||||
- (void)setRowHeight:(unsigned)aRowHeight
|
||||
{
|
||||
// Accept row heights such as "0".
|
||||
aRowHeight = +aRowHeight;
|
||||
|
||||
if (_rowHeight === aRowHeight)
|
||||
@@ -763,10 +769,6 @@ NOT YET IMPLEMENTED
|
||||
*/
|
||||
- (void)setSelectionHighlightStyle:(unsigned)aSelectionHighlightStyle
|
||||
{
|
||||
//early return for IE.
|
||||
if (aSelectionHighlightStyle == CPTableViewSelectionHighlightStyleSourceList && !CPFeatureIsCompatible(CPHTMLCanvasFeature))
|
||||
return;
|
||||
|
||||
_selectionHighlightStyle = aSelectionHighlightStyle;
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
@@ -953,6 +955,7 @@ NOT YET IMPLEMENTED
|
||||
*/
|
||||
- (void)_moveColumn:(unsigned)fromIndex toColumn:(unsigned)toIndex
|
||||
{
|
||||
// Convert parameters such as "0" to 0.
|
||||
fromIndex = +fromIndex;
|
||||
toIndex = +toIndex;
|
||||
|
||||
@@ -1510,6 +1513,8 @@ NOT YET IMPLEMENTED
|
||||
|
||||
if ([scrollView isKindOfClass:[CPScrollView class]] && [scrollView documentView] === self)
|
||||
[scrollView _updateCornerAndHeaderView];
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
// Complexity:
|
||||
@@ -1561,6 +1566,7 @@ NOT YET IMPLEMENTED
|
||||
*/
|
||||
- (CGRect)rectOfColumn:(CPInteger)aColumnIndex
|
||||
{
|
||||
// Convert e.g. "0" to 0.
|
||||
aColumnIndex = +aColumnIndex;
|
||||
|
||||
if (aColumnIndex < 0 || aColumnIndex >= NUMBER_OF_COLUMNS())
|
||||
@@ -1790,7 +1796,7 @@ NOT YET IMPLEMENTED
|
||||
{
|
||||
if (_implementedDelegateMethods & CPTableViewDelegate_tableView_heightOfRow_)
|
||||
{
|
||||
return idx = [_cachedRowHeights indexOfObject:aPoint
|
||||
return [_cachedRowHeights indexOfObject:aPoint
|
||||
inSortedRange:nil
|
||||
options:0
|
||||
usingComparator:function(aPoint, rowCache)
|
||||
@@ -1984,7 +1990,7 @@ NOT YET IMPLEMENTED
|
||||
// so we should size the last resized to fit
|
||||
|
||||
// find the last visisble column
|
||||
while (count-- && [_tableColumns[count] isHidden]) ;
|
||||
while (count-- && [_tableColumns[count] isHidden]);
|
||||
|
||||
// find the max x, but subtract a single pixel since the spacing isn't applicable here.
|
||||
var delta = superviewWidth - _CGRectGetMaxX([self rectOfColumn:count]) - ([self intercellSpacing].width || 1),
|
||||
@@ -2770,7 +2776,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
|
||||
*/
|
||||
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes atPoint:(CGPoint)mouseDownPoint
|
||||
{
|
||||
return YES;
|
||||
return [rowIndexes count] > 0 && [self numberOfRows] > 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -3044,7 +3050,6 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
|
||||
return _sortDescriptors;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
@@ -3425,7 +3430,6 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
|
||||
[aTableColumn setDataView:dataView];
|
||||
}
|
||||
|
||||
|
||||
return [aTableColumn _newDataViewForRow:aRow];
|
||||
}
|
||||
|
||||
@@ -3497,8 +3501,20 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
|
||||
{
|
||||
[super setNeedsDisplay:aFlag];
|
||||
[_tableDrawView setNeedsDisplay:aFlag];
|
||||
|
||||
[[self headerView] setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (void)setNeedsLayout
|
||||
{
|
||||
[super setNeedsLayout];
|
||||
[[self headerView] setNeedsLayout];
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
@@ -3544,16 +3560,16 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
|
||||
}
|
||||
|
||||
var exposedRows = [self _unboundedRowsInRect:aRect],
|
||||
firstRow = FLOOR(exposedRows.location / colorCount) * colorCount,
|
||||
lastRow = CPMaxRange(exposedRows),
|
||||
colorIndex = 0,
|
||||
groupRowRects = [],
|
||||
row = exposedRows.location;
|
||||
groupRowRects = [];
|
||||
|
||||
//loop through each color so we only draw once for each color
|
||||
while (colorIndex < colorCount)
|
||||
{
|
||||
CGContextBeginPath(context);
|
||||
for (var row = colorIndex; row <= lastRow; row += colorCount)
|
||||
for (var row = firstRow + colorIndex; row <= lastRow; row += colorCount)
|
||||
{
|
||||
// if it's not a group row draw it otherwise we draw it later
|
||||
if (![_groupRows containsIndex:row])
|
||||
@@ -3685,7 +3701,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
var drawGradient = (_selectionHighlightStyle === CPTableViewSelectionHighlightStyleSourceList && [_selectedRowIndexes count] >= 1),
|
||||
var drawGradient = (CPFeatureIsCompatible(CPHTMLCanvasFeature) && _selectionHighlightStyle === CPTableViewSelectionHighlightStyleSourceList && [_selectedRowIndexes count] >= 1),
|
||||
deltaHeight = 0.5 * (_gridStyleMask & CPTableViewSolidHorizontalGridLineMask);
|
||||
|
||||
CGContextBeginPath(context);
|
||||
@@ -3705,7 +3721,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
|
||||
{
|
||||
var topGroupLineColor = [CPColor colorWithCalibratedWhite:212.0 / 255.0 alpha:1.0],
|
||||
bottomGroupLineColor = [CPColor colorWithCalibratedWhite:185.0 / 255.0 alpha:1.0],
|
||||
gradientGroupColor = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [212.0 / 255.0, 212.0 / 255.0, 212.0 / 255.0,1.0, 197.0 / 255.0, 197.0 / 255.0, 197.0 / 255.0,1.0], [0,1], 2);
|
||||
gradientGroupColor = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [212.0 / 255.0, 212.0 / 255.0, 212.0 / 255.0, 1.0, 197.0 / 255.0, 197.0 / 255.0, 197.0 / 255.0, 1.0], [0, 1], 2);
|
||||
}
|
||||
|
||||
while (count--)
|
||||
@@ -3812,7 +3828,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
|
||||
*/
|
||||
- (void)_drawGroupRowsForRects:(CPArray)rects
|
||||
{
|
||||
if (_selectionHighlightStyle === CPTableViewSelectionHighlightStyleSourceList || !rects.length)
|
||||
if ((CPFeatureIsCompatible(CPHTMLCanvasFeature) && _selectionHighlightStyle === CPTableViewSelectionHighlightStyleSourceList) || !rects.length)
|
||||
return;
|
||||
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
@@ -3823,8 +3839,8 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
|
||||
var gradientCache = [self selectionGradientColors],
|
||||
topLineColor = [CPColor colorWithHexString:"d3d3d3"],
|
||||
bottomLineColor = [CPColor colorWithHexString:"bebebd"],
|
||||
gradientColor = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [220.0 / 255.0, 220.0 / 255.0, 220.0 / 255.0,1.0,
|
||||
199.0 / 255.0, 199.0 / 255.0, 199.0 / 255.0,1.0], [0,1], 2),
|
||||
gradientColor = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [220.0 / 255.0, 220.0 / 255.0, 220.0 / 255.0, 1.0,
|
||||
199.0 / 255.0, 199.0 / 255.0, 199.0 / 255.0, 1.0], [0, 1], 2),
|
||||
drawGradient = YES;
|
||||
|
||||
while (i--)
|
||||
@@ -3972,7 +3988,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
|
||||
{
|
||||
var row = [self rowAtPoint:aPoint];
|
||||
|
||||
//if the user clicks outside a row then deselect everything
|
||||
// If the user clicks outside a row then deselect everything.
|
||||
if (row < 0 && _allowsEmptySelection)
|
||||
[self selectRowIndexes:[CPIndexSet indexSet] byExtendingSelection:NO];
|
||||
|
||||
@@ -4609,7 +4625,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
|
||||
}
|
||||
_wasSelectionBroken = true;
|
||||
}
|
||||
else if (_wasSelectionBroken && ((shouldGoUpward && i !== [selectedIndexes firstIndex]) || (!shouldGoUpward && i !== [selectedIndexes lastindex])))
|
||||
else if (_wasSelectionBroken && ((shouldGoUpward && i !== [selectedIndexes firstIndex]) || (!shouldGoUpward && i !== [selectedIndexes lastIndex])))
|
||||
{
|
||||
shouldGoUpward ? i = [selectedIndexes firstIndex] - 1 : i = [selectedIndexes lastIndex];
|
||||
_wasSelectionBroken = false;
|
||||
@@ -4637,19 +4653,19 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
|
||||
while (![_delegate tableView:self shouldSelectRow:i] && (i < [self numberOfRows] || i > 0))
|
||||
shouldGoUpward ? i-- : i++; //check to see if the row can be selected if it can't be then see if the next row can be selected
|
||||
|
||||
//if the index still can be selected after the loop then just return
|
||||
if (![_delegate tableView:self shouldSelectRow:i])
|
||||
return;
|
||||
// If the index still can be selected after the loop then just return.
|
||||
if (![_delegate tableView:self shouldSelectRow:i])
|
||||
return;
|
||||
}
|
||||
|
||||
// if we go upward and see that this row is already selected we should deselect the row below
|
||||
if ([selectedIndexes containsIndex:i] && extend)
|
||||
// If we go upward and see that this row is already selected we should deselect the row below.
|
||||
if (extend && [selectedIndexes containsIndex:i])
|
||||
{
|
||||
// the row we're on is the last to be selected
|
||||
// The row we're on is the last to be selected.
|
||||
var differedLastSelectedRow = i;
|
||||
|
||||
// no remove the one before/after it
|
||||
shouldGoUpward ? i++ : i--;
|
||||
shouldGoUpward ? i++ : i--;
|
||||
|
||||
[selectedIndexes removeIndex:i];
|
||||
|
||||
@@ -4661,7 +4677,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
|
||||
if ([selectedIndexes containsIndex:i])
|
||||
{
|
||||
i = shouldGoUpward ? [selectedIndexes firstIndex] -1 : [selectedIndexes lastIndex] + 1;
|
||||
i = MIN(MAX(i,0), [self numberOfRows] - 1);
|
||||
i = MIN(MAX(i, 0), [self numberOfRows] - 1);
|
||||
}
|
||||
|
||||
[selectedIndexes addIndex:i];
|
||||
@@ -4938,15 +4954,17 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey",
|
||||
|
||||
isBlinking = YES;
|
||||
|
||||
var showCallback = function() {
|
||||
var showCallback = function()
|
||||
{
|
||||
objj_msgSend(self, "setHidden:", NO)
|
||||
isBlinking = NO;
|
||||
}
|
||||
};
|
||||
|
||||
var hideCallback = function() {
|
||||
var hideCallback = function()
|
||||
{
|
||||
objj_msgSend(self, "setHidden:", YES)
|
||||
isBlinking = YES;
|
||||
}
|
||||
};
|
||||
|
||||
objj_msgSend(self, "setHidden:", YES);
|
||||
[CPTimer scheduledTimerWithTimeInterval:0.1 callback:showCallback repeats:NO];
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/*
|
||||
* CPTextField.j
|
||||
* AppKit
|
||||
@@ -21,13 +20,15 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#import "../Foundation/Ref.h"
|
||||
|
||||
@import "CPControl.j"
|
||||
@import "CPStringDrawing.j"
|
||||
@import "CPCompatibility.j"
|
||||
@import "_CPImageAndTextView.j"
|
||||
|
||||
|
||||
CPTextFieldSquareBezel = 0; /*! A textfield bezel with a squared corners. */
|
||||
CPTextFieldSquareBezel = 0; /*! A textfield bezel with squared corners. */
|
||||
CPTextFieldRoundedBezel = 1; /*! A textfield bezel with rounded corners. */
|
||||
|
||||
CPTextFieldDidFocusNotification = @"CPTextFieldDidFocusNotification";
|
||||
@@ -83,12 +84,11 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
CPColor _textFieldBackgroundColor;
|
||||
|
||||
id _placeholderString;
|
||||
CPString _placeholderString;
|
||||
CPString _stringValue;
|
||||
|
||||
id _delegate;
|
||||
|
||||
CPString _textDidChangeValue;
|
||||
|
||||
// NS-style Display Properties
|
||||
CPTextFieldBezelStyle _bezelStyle;
|
||||
BOOL _isBordered;
|
||||
@@ -202,14 +202,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
CPTextFieldInputDidBlur = YES;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
CPTextFieldHandleBlur = function(anEvent)
|
||||
{
|
||||
CPTextFieldInputOwner = nil;
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
};
|
||||
|
||||
//FIXME make this not onblur
|
||||
CPTextFieldDOMInputElement.onblur = CPTextFieldBlurFunction;
|
||||
@@ -481,17 +481,17 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[self setNeedsLayout];
|
||||
|
||||
_isEditing = NO;
|
||||
_stringValue = [self stringValue];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var string = [self stringValue],
|
||||
element = [self _inputElement],
|
||||
var element = [self _inputElement],
|
||||
font = [self currentValueForThemeAttribute:@"font"];
|
||||
|
||||
// generate the font metric
|
||||
[font _getMetrics];
|
||||
|
||||
element.value = string;
|
||||
element.value = _stringValue;
|
||||
element.style.color = [[self currentValueForThemeAttribute:@"text-color"] cssString];
|
||||
element.style.font = [font cssString];
|
||||
element.style.zIndex = 1000;
|
||||
@@ -548,8 +548,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
CPTextFieldInputOwner = self;
|
||||
}, 0.0);
|
||||
|
||||
element.value = [self stringValue];
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
CPTextFieldInputIsActive = YES;
|
||||
@@ -572,17 +570,39 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
{
|
||||
[self unsetThemeState:CPThemeStateEditing];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var element = [self _inputElement],
|
||||
newValue = element.value,
|
||||
error = @"";
|
||||
|
||||
if (newValue !== _stringValue)
|
||||
{
|
||||
[self _setStringValue:newValue];
|
||||
}
|
||||
|
||||
// If there is a formatter, always give it a chance to reject the resignation,
|
||||
// even if the value has not changed.
|
||||
if ([self _valueIsValid:newValue] === NO)
|
||||
{
|
||||
[self setThemeState:CPThemeStateEditing];
|
||||
element.focus();
|
||||
return NO;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Cache the formatted string
|
||||
_stringValue = [self stringValue];
|
||||
|
||||
_willBecomeFirstResponderByClick = NO;
|
||||
|
||||
[self _updatePlaceholderState];
|
||||
|
||||
[self setNeedsLayout];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var element = [self _inputElement];
|
||||
|
||||
if ([self stringValue] !== element.value)
|
||||
[self _setStringValue:element.value];
|
||||
|
||||
CPTextFieldInputResigning = YES;
|
||||
|
||||
if (CPTextFieldInputIsActive)
|
||||
@@ -610,7 +630,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
#endif
|
||||
|
||||
//post CPControlTextDidEndEditingNotification
|
||||
// post CPControlTextDidEndEditingNotification
|
||||
if (_isEditing)
|
||||
{
|
||||
_isEditing = NO;
|
||||
@@ -625,6 +645,28 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)_valueIsValid:(CPString)aValue
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var error = @"";
|
||||
|
||||
if ([self _setStringValue:aValue isNewValue:NO errorDescription:AT_REF(error)] === NO)
|
||||
{
|
||||
var acceptInvalidValue = NO;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(control:didFailToFormatString:errorDescription:)])
|
||||
acceptInvalidValue = [_delegate control:self didFailToFormatString:[self _inputElement] errorDescription:error];
|
||||
|
||||
if (acceptInvalidValue === NO)
|
||||
return NO;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
Text fields require panels to become key window, so this returns \c YES.
|
||||
*/
|
||||
@@ -685,11 +727,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (void)keyUp:(CPEvent)anEvent
|
||||
{
|
||||
var oldValue = [self stringValue];
|
||||
[self _setStringValue:[self _inputElement].value];
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
if (oldValue !== [self stringValue])
|
||||
var newValue = [self _inputElement].value;
|
||||
|
||||
if (newValue !== _stringValue)
|
||||
{
|
||||
[self _setStringValue:newValue];
|
||||
|
||||
if (!_isEditing)
|
||||
{
|
||||
_isEditing = YES;
|
||||
@@ -699,14 +744,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
}
|
||||
|
||||
- (void)keyDown:(CPEvent)anEvent
|
||||
{
|
||||
if ([anEvent _couldBeKeyEquivalent] && [self performKeyEquivalent:anEvent])
|
||||
return;
|
||||
|
||||
// CPTextField uses an HTML input element to take the input so we need to
|
||||
// propagate the dom event so the element is updated. This has to be done
|
||||
// before interpretKeyEvents: though so individual commands have a chance
|
||||
@@ -735,45 +779,60 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (void)insertNewline:(id)sender
|
||||
{
|
||||
if (_isEditing)
|
||||
var newValue = [self _inputElement].value;
|
||||
|
||||
if (newValue !== _stringValue)
|
||||
{
|
||||
_isEditing = NO;
|
||||
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
|
||||
[self _setStringValue:newValue];
|
||||
}
|
||||
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
[self selectText:nil];
|
||||
if ([self _valueIsValid:_stringValue])
|
||||
{
|
||||
// If _isEditing == YES then the target action can also be called via
|
||||
// resignFirstResponder, and it is possible that the target action
|
||||
// itself will change this textfield's responder status, so start by
|
||||
// setting the _isEditing flag to NO to prevent the target action being
|
||||
// called twice (once below and once from resignFirstResponder).
|
||||
if (_isEditing)
|
||||
{
|
||||
_isEditing = NO;
|
||||
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
|
||||
}
|
||||
|
||||
// If there is no target action, or the sendAction call returns
|
||||
// success.
|
||||
if (![self action] || [self sendAction:[self action] to:[self target]])
|
||||
{
|
||||
[self selectAll:nil];
|
||||
}
|
||||
}
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
|
||||
}
|
||||
|
||||
- (void)insertNewlineIgnoringFieldEditor:(id)sender
|
||||
{
|
||||
var oldValue = [self stringValue];
|
||||
|
||||
[self _inputElement].value += CPNewlineCharacter;
|
||||
[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 _insertCharacterIgnoringFieldEditor:CPNewlineCharacter];
|
||||
}
|
||||
|
||||
- (void)insertTabIgnoringFieldEditor:(id)sender
|
||||
{
|
||||
var oldValue = [self stringValue];
|
||||
[self _insertCharacterIgnoringFieldEditor:CPTabCharacter];
|
||||
}
|
||||
|
||||
[self _inputElement].value += CPTabCharacter;
|
||||
[self _setStringValue:[self _inputElement].value];
|
||||
- (void)_insertCharacterIgnoringFieldEditor:(CPString)aCharacter
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
if (oldValue !== [self stringValue])
|
||||
var oldValue = _stringValue,
|
||||
range = [self selectedRange],
|
||||
element = [self _inputElement];
|
||||
|
||||
element.value = [element.value stringByReplacingCharactersInRange:[self selectedRange] withString:aCharacter];
|
||||
[self _setStringValue:element.value];
|
||||
|
||||
// NOTE: _stringValue is now the current input element value
|
||||
if (oldValue !== _stringValue)
|
||||
{
|
||||
if (!_isEditing)
|
||||
{
|
||||
@@ -783,6 +842,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)textDidBlur:(CPNotification)note
|
||||
@@ -813,15 +874,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[super textDidChange:note];
|
||||
}
|
||||
|
||||
- (void)sendAction:(SEL)anAction to:(id)anObject
|
||||
{
|
||||
[self _reverseSetBinding];
|
||||
|
||||
[CPApp sendAction:anAction to:anObject from:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the string the text field.
|
||||
Returns the string in the text field.
|
||||
*/
|
||||
- (id)objectValue
|
||||
{
|
||||
@@ -830,24 +884,84 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
/*
|
||||
@ignore
|
||||
Sets the internal string value without updating the value in the input element
|
||||
Sets the internal string value without updating the value in the input element.
|
||||
This should only be invoked when the underlying text element's value has changed.
|
||||
*/
|
||||
- (void)_setStringValue:(id)aValue
|
||||
- (BOOL)_setStringValue:(CPString)aValue
|
||||
{
|
||||
[self willChangeValueForKey:@"objectValue"];
|
||||
[super setObjectValue:String(aValue)];
|
||||
[self _updatePlaceholderState];
|
||||
[self didChangeValueForKey:@"objectValue"];
|
||||
return [self _setStringValue:aValue isNewValue:YES errorDescription:nil];
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
Sets the internal string value without updating the value in the input element.
|
||||
If there is a formatter and formatting fails, returns NO. Otherwise returns YES.
|
||||
*/
|
||||
- (BOOL)_setStringValue:(CPString)aValue isNewValue:(BOOL)isNewValue errorDescription:(CPStringRef)anError
|
||||
{
|
||||
_stringValue = aValue;
|
||||
|
||||
var objectValue = aValue,
|
||||
formatter = [self formatter],
|
||||
result = YES;
|
||||
|
||||
if (formatter)
|
||||
{
|
||||
var object = nil;
|
||||
|
||||
if ([formatter getObjectValue:AT_REF(object) forString:aValue errorDescription:anError])
|
||||
objectValue = object;
|
||||
else
|
||||
{
|
||||
objectValue = undefined; // Mark the value as invalid
|
||||
result = NO;
|
||||
}
|
||||
|
||||
isNewValue |= objectValue !== [super objectValue];
|
||||
}
|
||||
|
||||
if (isNewValue)
|
||||
{
|
||||
[self willChangeValueForKey:@"objectValue"];
|
||||
[super setObjectValue:objectValue];
|
||||
[self _updatePlaceholderState];
|
||||
[self didChangeValueForKey:@"objectValue"];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)setObjectValue:(id)aValue
|
||||
{
|
||||
[super setObjectValue:aValue];
|
||||
|
||||
var formatter = [self formatter];
|
||||
|
||||
if (formatter)
|
||||
{
|
||||
// If there is a formatter, make sure the object value can be formatted successfully
|
||||
var formattedString = [self hasThemeState:CPThemeStateEditing] ? [formatter editingStringForObjectValue:aValue] : [formatter stringForObjectValue:aValue];
|
||||
|
||||
if (formattedString === nil)
|
||||
{
|
||||
var value = nil;
|
||||
|
||||
// Formatting failed, get an "empty" object by formatting an empty string.
|
||||
// If that fails, the value is undefined.
|
||||
if ([formatter getObjectValue:AT_REF(value) forString:@"" errorDescription:nil] === NO)
|
||||
value = undefined;
|
||||
|
||||
[super setObjectValue:value];
|
||||
}
|
||||
}
|
||||
|
||||
_stringValue = [self stringValue];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
if (CPTextFieldInputOwner === self || [[self window] firstResponder] === self)
|
||||
[self _inputElement].value = aValue;
|
||||
[self _inputElement].value = _stringValue;
|
||||
|
||||
#endif
|
||||
|
||||
[self _updatePlaceholderState];
|
||||
@@ -855,9 +969,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (void)_updatePlaceholderState
|
||||
{
|
||||
var string = [self stringValue];
|
||||
|
||||
if ((!string || string.length === 0) && ![self hasThemeState:CPThemeStateEditing])
|
||||
if ((!_stringValue || _stringValue.length === 0) && ![self hasThemeState:CPThemeStateEditing])
|
||||
[self setThemeState:CPTextFieldStatePlaceholder];
|
||||
else
|
||||
[self unsetThemeState:CPTextFieldStatePlaceholder];
|
||||
@@ -910,7 +1022,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
However, since you don't know how tall it needs to be if you change the font, sizeToFit will still be
|
||||
useful for making the textfield an appropriate height.
|
||||
*/
|
||||
|
||||
- (void)sizeToFit
|
||||
{
|
||||
[self setFrameSize:[self _minimumFrameSize]];
|
||||
@@ -923,7 +1034,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
minSize = [self currentValueForThemeAttribute:@"min-size"],
|
||||
maxSize = [self currentValueForThemeAttribute:@"max-size"],
|
||||
lineBreakMode = [self lineBreakMode],
|
||||
text = ([self stringValue] || @" "),
|
||||
text = (_stringValue || @" "),
|
||||
textSize = _CGSizeMakeCopy(frameSize),
|
||||
font = [self currentValueForThemeAttribute:@"font"];
|
||||
|
||||
@@ -994,8 +1105,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return;
|
||||
|
||||
var pasteboard = [CPPasteboard generalPasteboard],
|
||||
stringValue = [self stringValue],
|
||||
stringForPasting = [stringValue substringWithRange:selectedRange];
|
||||
stringForPasting = [_stringValue substringWithRange:selectedRange];
|
||||
|
||||
[pasteboard declareTypes:[CPStringPboardType] owner:nil];
|
||||
[pasteboard setString:stringForPasting forType:CPStringPboardType];
|
||||
@@ -1025,9 +1135,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[self deleteBackward:sender];
|
||||
|
||||
var selectedRange = [self selectedRange],
|
||||
stringValue = [self stringValue],
|
||||
pasteString = [pasteboard stringForType:CPStringPboardType],
|
||||
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
|
||||
newValue = [_stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
|
||||
|
||||
[self setStringValue:newValue];
|
||||
[self setSelectedRange:CPMakeRange(selectedRange.location + pasteString.length, 0)];
|
||||
@@ -1041,6 +1150,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
if ([[self window] firstResponder] !== self)
|
||||
return CPMakeRange(0, 0);
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
// we wrap this in try catch because firefox will throw an exception in certain instances
|
||||
try
|
||||
{
|
||||
@@ -1067,6 +1178,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
// fall through to the return
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return CPMakeRange(0, 0);
|
||||
}
|
||||
|
||||
@@ -1075,6 +1188,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
if (![[self window] firstResponder] === self)
|
||||
return;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var inputElement = [self _inputElement];
|
||||
|
||||
try
|
||||
@@ -1103,6 +1218,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
catch (e)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)selectAll:(id)sender
|
||||
@@ -1120,8 +1237,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
selectedRange.location += 1;
|
||||
selectedRange.length -= 1;
|
||||
|
||||
var stringValue = [self stringValue],
|
||||
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
|
||||
var newValue = [_stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
|
||||
|
||||
[self setStringValue:newValue];
|
||||
[self setSelectedRange:CPMakeRange(selectedRange.location, 0)];
|
||||
@@ -1274,7 +1390,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
string = [self placeholderString];
|
||||
else
|
||||
{
|
||||
string = [self stringValue];
|
||||
string = _stringValue;
|
||||
|
||||
if ([self isSecure])
|
||||
string = secureStringForString(string);
|
||||
@@ -1317,7 +1433,7 @@ var secureStringForString = function(aString)
|
||||
return "";
|
||||
|
||||
return Array(aString.length + 1).join(CPSecureTextFieldCharacter);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
|
||||
@@ -1387,6 +1503,16 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
|
||||
{
|
||||
}
|
||||
|
||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
||||
{
|
||||
[super _updatePlaceholdersWithOptions:options];
|
||||
|
||||
[self _setPlaceholder:@"Multiple Values" forMarker:CPMultipleValuesMarker isDefault:YES];
|
||||
[self _setPlaceholder:@"No Selection" forMarker:CPNoSelectionMarker isDefault:YES];
|
||||
[self _setPlaceholder:@"Not Applicable" forMarker:CPNotApplicableMarker isDefault:YES];
|
||||
[self _setPlaceholder:@"" forMarker:CPNullMarker isDefault:YES];
|
||||
}
|
||||
|
||||
- (void)setValueFor:(CPString)theBinding
|
||||
{
|
||||
var destination = [_info objectForKey:CPObservedObjectKey],
|
||||
@@ -1397,29 +1523,14 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
|
||||
|
||||
if (isPlaceholder)
|
||||
{
|
||||
switch (newValue)
|
||||
if (newValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
||||
{
|
||||
case CPMultipleValuesMarker:
|
||||
newValue = [options objectForKey:CPMultipleValuesPlaceholderBindingOption] || @"Multiple Values";
|
||||
break;
|
||||
|
||||
case CPNoSelectionMarker:
|
||||
newValue = [options objectForKey:CPNoSelectionPlaceholderBindingOption] || @"No Selection";
|
||||
break;
|
||||
|
||||
case CPNotApplicableMarker:
|
||||
if ([options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
||||
[CPException raise:CPGenericException
|
||||
reason:@"can't transform non applicable key on: "+_source+" value: "+newValue];
|
||||
|
||||
newValue = [options objectForKey:CPNotApplicablePlaceholderBindingOption] || @"Not Applicable";
|
||||
break;
|
||||
|
||||
case CPNullMarker:
|
||||
newValue = [options objectForKey:CPNullPlaceholderBindingOption] || @"";
|
||||
break;
|
||||
[CPException raise:CPGenericException
|
||||
reason:@"can't transform non applicable key on: " + _source + " value: " + newValue];
|
||||
}
|
||||
|
||||
newValue = [self _placeholderForMarker:newValue];
|
||||
|
||||
[_source setPlaceholderString:newValue];
|
||||
[_source setObjectValue:nil];
|
||||
}
|
||||
|
||||
@@ -579,6 +579,7 @@ CPThemeStateCircular = CPThemeState("circular");
|
||||
_cache = {};
|
||||
|
||||
_name = [aCoder decodeObjectForKey:@"name"];
|
||||
_defaultValue = [aCoder decodeObjectForKey:@"defaultValue"];
|
||||
_values = [CPDictionary dictionary];
|
||||
|
||||
if ([aCoder containsValueForKey:@"value"])
|
||||
@@ -611,6 +612,7 @@ CPThemeStateCircular = CPThemeState("circular");
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeObject:_name forKey:@"name"];
|
||||
[aCoder encodeObject:_defaultValue forKey:@"defaultValue"];
|
||||
|
||||
var keys = [_values allKeys],
|
||||
count = keys.length;
|
||||
@@ -666,7 +668,7 @@ var numberOfOnes = function(aNumber)
|
||||
cachedNumberOfOnes[slot] = count;
|
||||
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
numberOfOnes.displayName = "numberOfOnes";
|
||||
|
||||
|
||||
@@ -97,61 +97,66 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
{
|
||||
if (self = [super initWithFrame:frame])
|
||||
{
|
||||
_selectedRange = CPMakeRange(0, 0);
|
||||
|
||||
_tokenScrollView = [[CPScrollView alloc] initWithFrame:CGRectMakeZero()];
|
||||
[_tokenScrollView setHasHorizontalScroller:NO];
|
||||
[_tokenScrollView setHasVerticalScroller:NO];
|
||||
[_tokenScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
var contentView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
[contentView setAutoresizingMask:CPViewWidthSizable];
|
||||
[_tokenScrollView setDocumentView:contentView];
|
||||
|
||||
[self addSubview:_tokenScrollView];
|
||||
|
||||
_tokenIndex = 0;
|
||||
|
||||
_cachedCompletions = [];
|
||||
_completionDelay = [CPTokenField defaultCompletionDelay];
|
||||
|
||||
_tokenizingCharacterSet = [[self class] defaultTokenizingCharacterSet];
|
||||
|
||||
_autocompleteContainer = [[CPView alloc] initWithFrame:CPRectMake(0.0, 0.0, frame.size.width, 92.0)];
|
||||
[_autocompleteContainer setBackgroundColor:[_CPMenuWindow backgroundColorForBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle]];
|
||||
|
||||
_autocompleteScrollView = [[CPScrollView alloc] initWithFrame:CPRectMake(1.0, 1.0, frame.size.width - 2.0, 90.0)];
|
||||
[_autocompleteScrollView setAutohidesScrollers:YES];
|
||||
[_autocompleteScrollView setHasHorizontalScroller:NO];
|
||||
[_autocompleteContainer addSubview:_autocompleteScrollView];
|
||||
|
||||
_autocompleteView = [[CPTableView alloc] initWithFrame:CPRectMakeZero()];
|
||||
|
||||
var tableColumn = [[CPTableColumn alloc] initWithIdentifier:CPTokenFieldTableColumnIdentifier];
|
||||
[tableColumn setResizingMask:CPTableColumnAutoresizingMask];
|
||||
[_autocompleteView addTableColumn:tableColumn];
|
||||
|
||||
[_autocompleteView setDataSource:self];
|
||||
[_autocompleteView setDelegate:self];
|
||||
[_autocompleteView setAllowsMultipleSelection:NO];
|
||||
[_autocompleteView setHeaderView:nil];
|
||||
[_autocompleteView setCornerView:nil];
|
||||
[_autocompleteView setRowHeight:30.0];
|
||||
[_autocompleteView setGridStyleMask:CPTableViewSolidHorizontalGridLineMask];
|
||||
[_autocompleteView setBackgroundColor:[CPColor clearColor]];
|
||||
[_autocompleteView setGridColor:[CPColor colorWithRed:242.0 / 255.0 green:243.0 / 255.0 blue:245.0 / 255.0 alpha:1.0]];
|
||||
|
||||
[_autocompleteScrollView setDocumentView:_autocompleteView];
|
||||
|
||||
[self setBezeled:YES];
|
||||
|
||||
[self _init];
|
||||
|
||||
[self setObjectValue:[]];
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_selectedRange = CPMakeRange(0, 0);
|
||||
|
||||
var frame = [self frame];
|
||||
|
||||
_tokenScrollView = [[CPScrollView alloc] initWithFrame:CGRectMakeZero()];
|
||||
[_tokenScrollView setHasHorizontalScroller:NO];
|
||||
[_tokenScrollView setHasVerticalScroller:NO];
|
||||
[_tokenScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
var contentView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
[contentView setAutoresizingMask:CPViewWidthSizable];
|
||||
[_tokenScrollView setDocumentView:contentView];
|
||||
|
||||
[self addSubview:_tokenScrollView];
|
||||
|
||||
_cachedCompletions = [];
|
||||
|
||||
_autocompleteContainer = [[CPView alloc] initWithFrame:CPRectMake(0.0, 0.0, frame.size.width, 92.0)];
|
||||
[_autocompleteContainer setBackgroundColor:[_CPMenuWindow backgroundColorForBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle]];
|
||||
|
||||
_autocompleteScrollView = [[CPScrollView alloc] initWithFrame:CPRectMake(1.0, 1.0, frame.size.width - 2.0, 90.0)];
|
||||
[_autocompleteScrollView setAutohidesScrollers:YES];
|
||||
[_autocompleteScrollView setHasHorizontalScroller:NO];
|
||||
[_autocompleteContainer addSubview:_autocompleteScrollView];
|
||||
|
||||
_autocompleteView = [[CPTableView alloc] initWithFrame:CPRectMakeZero()];
|
||||
|
||||
var tableColumn = [[CPTableColumn alloc] initWithIdentifier:CPTokenFieldTableColumnIdentifier];
|
||||
[tableColumn setResizingMask:CPTableColumnAutoresizingMask];
|
||||
[_autocompleteView addTableColumn:tableColumn];
|
||||
|
||||
[_autocompleteView setDataSource:self];
|
||||
[_autocompleteView setDelegate:self];
|
||||
[_autocompleteView setAllowsMultipleSelection:NO];
|
||||
[_autocompleteView setHeaderView:nil];
|
||||
[_autocompleteView setCornerView:nil];
|
||||
[_autocompleteView setRowHeight:30.0];
|
||||
[_autocompleteView setGridStyleMask:CPTableViewSolidHorizontalGridLineMask];
|
||||
[_autocompleteView setBackgroundColor:[CPColor clearColor]];
|
||||
[_autocompleteView setGridColor:[CPColor colorWithRed:242.0 / 255.0 green:243.0 / 255.0 blue:245.0 / 255.0 alpha:1.0]];
|
||||
|
||||
[_autocompleteScrollView setDocumentView:_autocompleteView];
|
||||
}
|
||||
|
||||
// ===============
|
||||
// = CONVENIENCE =
|
||||
// ===============
|
||||
@@ -159,7 +164,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
{
|
||||
var indexOfSelectedItem = 0;
|
||||
|
||||
_cachedCompletions = [self tokenField:self completionsForSubstring:[self _inputElement].value indexOfToken:_tokenIndex indexOfSelectedItem:indexOfSelectedItem];
|
||||
_cachedCompletions = [self tokenField:self completionsForSubstring:[self _inputElement].value indexOfToken:0 indexOfSelectedItem:indexOfSelectedItem];
|
||||
|
||||
[_autocompleteView selectRowIndexes:[CPIndexSet indexSetWithIndex:indexOfSelectedItem] byExtendingSelection:NO];
|
||||
[_autocompleteView reloadData];
|
||||
@@ -167,19 +172,20 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
|
||||
- (void)_autocompleteWithDOMEvent:(JSObject)DOMEvent
|
||||
{
|
||||
if (!_cachedCompletions || ![self hasThemeState:CPThemeStateAutoCompleting])
|
||||
if (![self _inputElement].value && (!_cachedCompletions || ![self hasThemeState:CPThemeStateAutoCompleting]))
|
||||
return;
|
||||
|
||||
[self _hideCompletions];
|
||||
|
||||
var token = _cachedCompletions[[_autocompleteView selectedRow]],
|
||||
var token = _cachedCompletions ? _cachedCompletions[[_autocompleteView selectedRow]] : nil,
|
||||
shouldRemoveLastObject = token !== @"" && [self _inputElement].value !== @"";
|
||||
|
||||
if (!token)
|
||||
token = [self _inputElement].value;
|
||||
|
||||
// Make sure the user typed an actual token to prevent the previous token from being emptied
|
||||
// If the input area is empty, we want to fallback to the normal behavior, resigning first responder or select the next or previous key view
|
||||
// If the input area is empty, we want to fall back to the normal behavior, resigning first
|
||||
// responder or selecting the next or previous key view.
|
||||
if (!token || token === @"")
|
||||
{
|
||||
if (DOMEvent && DOMEvent.keyCode === CPTabKeyCode)
|
||||
@@ -194,7 +200,6 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var objectValue = [self objectValue];
|
||||
|
||||
// Remove the uncompleted token and add the token string.
|
||||
@@ -202,10 +207,25 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
if (shouldRemoveLastObject)
|
||||
[objectValue removeObjectAtIndex:_selectedRange.location];
|
||||
|
||||
[objectValue insertObject:token atIndex:_selectedRange.location];
|
||||
// Give the delegate a chance to confirm, replace or add to the list of tokens being added.
|
||||
var delegateApprovedObjects = [self tokenField:self shouldAddObjects:[CPArray arrayWithObject:token] atIndex:_selectedRange.location],
|
||||
delegateApprovedObjectsCount = [delegateApprovedObjects count];
|
||||
if (delegateApprovedObjects)
|
||||
{
|
||||
for (var i = 0; i < delegateApprovedObjectsCount; i++)
|
||||
{
|
||||
[objectValue insertObject:[delegateApprovedObjects objectAtIndex:i] atIndex:_selectedRange.location + i];
|
||||
}
|
||||
}
|
||||
|
||||
// Put the cursor after the last inserted token.
|
||||
var location = _selectedRange.location;
|
||||
|
||||
[self setObjectValue:objectValue];
|
||||
_selectedRange = CPMakeRange(location + 1, 0);
|
||||
|
||||
if (delegateApprovedObjectsCount)
|
||||
location += delegateApprovedObjectsCount;
|
||||
_selectedRange = CPMakeRange(location, 0);
|
||||
|
||||
[self _inputElement].value = @"";
|
||||
[self setNeedsLayout];
|
||||
@@ -250,8 +270,13 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
var indexOfToken = [[self _tokens] indexOfObject:token],
|
||||
objectValue = [self objectValue];
|
||||
|
||||
// If the token was selected, deselect it for selection preservation.
|
||||
[self _deselectToken:token];
|
||||
// If the selection was to the right of the deleted token, move it to the left. If the deleted token was
|
||||
// selected, deselect it.
|
||||
if (indexOfToken < _selectedRange.location)
|
||||
_selectedRange.location--;
|
||||
else
|
||||
[self _deselectToken:token];
|
||||
|
||||
// Preserve selection.
|
||||
var selection = CPCopyRange(_selectedRange);
|
||||
[objectValue removeObjectAtIndex:indexOfToken];
|
||||
@@ -291,6 +316,14 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
[self _controlTextDidChange];
|
||||
}
|
||||
|
||||
- (void)_updatePlaceholderState
|
||||
{
|
||||
if (([[self _tokens] count] === 0) && ![self hasThemeState:CPThemeStateEditing])
|
||||
[self setThemeState:CPTextFieldStatePlaceholder];
|
||||
else
|
||||
[self unsetThemeState:CPTextFieldStatePlaceholder];
|
||||
}
|
||||
|
||||
// =============
|
||||
// = RESPONDER =
|
||||
// =============
|
||||
@@ -575,14 +608,16 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// ========
|
||||
// = VIEW =
|
||||
// ========
|
||||
- (void)viewDidMoveToWindow
|
||||
{
|
||||
[[[self window] contentView] addSubview:_autocompleteContainer];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
_autocompleteContainer._DOMElement.style.zIndex = 1000; // Anything else doesn't seem to work
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)removeFromSuperview
|
||||
@@ -625,7 +660,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
CPTokenFieldInputDidBlur = YES;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
CPTokenFieldKeyDownFunction = function(aDOMEvent)
|
||||
{
|
||||
@@ -779,7 +814,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
CPTokenFieldKeyPressFunction = function(aDOMEvent)
|
||||
{
|
||||
@@ -809,7 +844,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
// Force immediate layout in case word wrapping is now necessary.
|
||||
[owner setNeedsLayout];
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
};
|
||||
|
||||
CPTokenFieldKeyUpFunction = function()
|
||||
{
|
||||
@@ -822,14 +857,14 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
[self setNeedsLayout];
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
};
|
||||
|
||||
CPTokenFieldHandleBlur = function(anEvent)
|
||||
{
|
||||
CPTokenFieldInputOwner = nil;
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
};
|
||||
|
||||
if (document.attachEvent)
|
||||
{
|
||||
@@ -991,7 +1026,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
offset.x += width + spaceBetweenTokens.width;
|
||||
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
var placeEditor = function(useRemainingWidth)
|
||||
{
|
||||
@@ -1018,7 +1053,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
// When editing, always scroll to the cursor.
|
||||
if (_selectedRange.length == 0)
|
||||
[[_tokenScrollView documentView] scrollRectToVisible:inputFrame];
|
||||
}
|
||||
};
|
||||
|
||||
for (var i = 0, count = [tokens count]; i < count; i++)
|
||||
{
|
||||
@@ -1123,7 +1158,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(tokenField:completionsForSubstring:indexOfToken:indexOfSelectedItem:)])
|
||||
{
|
||||
return [[self delegate] tokenField:tokenField completionsForSubstring:substring indexOfToken:_tokenIndex indexOfSelectedItem:selectedIndex];
|
||||
return [[self delegate] tokenField:tokenField completionsForSubstring:substring indexOfToken:tokenIndex indexOfSelectedItem:selectedIndex];
|
||||
}
|
||||
|
||||
return [];
|
||||
@@ -1149,7 +1184,19 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
// // return an array of represented objects you want to add.
|
||||
// // If you want to reject the add, return an empty array.
|
||||
// // returning nil will cause an error.
|
||||
// - (NSArray *)tokenField:(NSTokenField *)tokenField shouldAddObjects:(NSArray *)tokens atIndex:(NSUInteger)index;
|
||||
- (CPArray)tokenField:(CPTokenField)tokenField shouldAddObjects:(CPArray)tokens atIndex:(int)index
|
||||
{
|
||||
var delegate = [self delegate];
|
||||
if ([delegate respondsToSelector:@selector(tokenField:shouldAddObjects:atIndex:)])
|
||||
{
|
||||
var approvedObjects = [delegate tokenField:tokenField shouldAddObjects:tokens atIndex:index];
|
||||
if (approvedObjects !== nil)
|
||||
return approvedObjects;
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
//
|
||||
// // If you return nil or don't implement these delegate methods, we will assume
|
||||
// // editing string = display string = represented object
|
||||
@@ -1292,3 +1339,37 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPTokenFieldTokenizingCharacterSetKey = "CPTokenFieldTokenizingCharacterSetKey",
|
||||
CPTokenFieldCompletionDelayKey = "CPTokenFieldCompletionDelay";
|
||||
|
||||
@implementation CPTokenField (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_tokenizingCharacterSet = [aCoder decodeObjectForKey:CPTokenFieldTokenizingCharacterSetKey] || [[self class] defaultTokenizingCharacterSet];
|
||||
_completionDelay = [aCoder decodeDoubleForKey:CPTokenFieldCompletionDelayKey] || [[self class] defaultCompletionDelay];
|
||||
|
||||
[self _init];
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeInt:_tokenizingCharacterSet forKey:CPTokenFieldTokenizingCharacterSetKey];
|
||||
[aCoder encodeDouble:_completionDelay forKey:CPTokenFieldCompletionDelayKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -50,9 +50,17 @@ CPToolbarDisplayModeIconOnly = 2;
|
||||
*/
|
||||
CPToolbarDisplayModeLabelOnly = 3;
|
||||
|
||||
|
||||
CPToolbarSizeModeDefault = 0;
|
||||
CPToolbarSizeModeRegular = 1;
|
||||
CPToolbarSizeModeSmall = 2;
|
||||
|
||||
var CPToolbarsByIdentifier = nil,
|
||||
CPToolbarConfigurationsByIdentifier = nil;
|
||||
|
||||
var TOOLBAR_REGULAR_HEIGHT = 59.0,
|
||||
TOOLBAR_SMALL_HEIGHT = 46.0;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPToolbar
|
||||
@@ -87,6 +95,7 @@ var CPToolbarsByIdentifier = nil,
|
||||
BOOL _showsBaselineSeparator;
|
||||
BOOL _allowsUserCustomization;
|
||||
BOOL _isVisible;
|
||||
int _sizeMode @accessors(property=sizeMode);
|
||||
|
||||
id _delegate;
|
||||
|
||||
@@ -148,6 +157,7 @@ var CPToolbarsByIdentifier = nil,
|
||||
|
||||
_identifier = anIdentifier;
|
||||
_isVisible = YES;
|
||||
_sizeMode = CPToolbarSizeModeDefault;
|
||||
|
||||
[CPToolbar _addToolbar:self forIdentifier:_identifier];
|
||||
}
|
||||
@@ -202,6 +212,16 @@ var CPToolbarsByIdentifier = nil,
|
||||
[_window _noteToolbarChanged];
|
||||
}
|
||||
|
||||
- (void)setSizeMode:(CPToolbarSizeMode)aSize
|
||||
{
|
||||
if (aSize === _sizeMode)
|
||||
return;
|
||||
_sizeMode = aSize;
|
||||
|
||||
[[self _toolbarView] setFrame:[self _toolbarViewFrame]];
|
||||
[_window _noteToolbarChanged];
|
||||
}
|
||||
|
||||
- (CPWindow)_window
|
||||
{
|
||||
return _window;
|
||||
@@ -232,12 +252,17 @@ var CPToolbarsByIdentifier = nil,
|
||||
|
||||
}
|
||||
|
||||
- (CGRect)_toolbarViewFrame
|
||||
{
|
||||
return CPRectMake(0.0, 0.0, 1200.0, _sizeMode != CPToolbarSizeModeSmall ? TOOLBAR_REGULAR_HEIGHT : TOOLBAR_SMALL_HEIGHT);
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (CPView)_toolbarView
|
||||
{
|
||||
if (!_toolbarView)
|
||||
{
|
||||
_toolbarView = [[_CPToolbarView alloc] initWithFrame:CPRectMake(0.0, 0.0, 1200.0, 59.0)];
|
||||
_toolbarView = [[_CPToolbarView alloc] initWithFrame:[self _toolbarViewFrame]];
|
||||
|
||||
[_toolbarView setToolbar:self];
|
||||
[_toolbarView setAutoresizingMask:CPViewWidthSizable];
|
||||
@@ -427,7 +452,8 @@ var CPToolbarIdentifierKey = @"CPToolbarIdentifierKey",
|
||||
CPToolbarIdentifiedItemsKey = @"CPToolbarIdentifiedItemsKey",
|
||||
CPToolbarDefaultItemsKey = @"CPToolbarDefaultItemsKey",
|
||||
CPToolbarAllowedItemsKey = @"CPToolbarAllowedItemsKey",
|
||||
CPToolbarSelectableItemsKey = @"CPToolbarSelectableItemsKey";
|
||||
CPToolbarSelectableItemsKey = @"CPToolbarSelectableItemsKey",
|
||||
CPToolbarSizeModeKey = @"CPToolbarSizeModeKey";
|
||||
|
||||
@implementation CPToolbar (CPCoding)
|
||||
|
||||
@@ -446,6 +472,7 @@ var CPToolbarIdentifierKey = @"CPToolbarIdentifierKey",
|
||||
_showsBaselineSeparator = [aCoder decodeBoolForKey:CPToolbarShowsBaselineSeparatorKey];
|
||||
_allowsUserCustomization = [aCoder decodeBoolForKey:CPToolbarAllowsUserCustomizationKey];
|
||||
_isVisible = [aCoder decodeBoolForKey:CPToolbarIsVisibleKey];
|
||||
_sizeMode = [aCoder decodeIntForKey:CPToolbarSizeModeKey];
|
||||
|
||||
_identifiedItems = [aCoder decodeObjectForKey:CPToolbarIdentifiedItemsKey];
|
||||
_defaultItems = [aCoder decodeObjectForKey:CPToolbarDefaultItemsKey];
|
||||
@@ -492,6 +519,7 @@ var CPToolbarIdentifierKey = @"CPToolbarIdentifierKey",
|
||||
[aCoder encodeBool:_showsBaselineSeparator forKey:CPToolbarShowsBaselineSeparatorKey];
|
||||
[aCoder encodeBool:_allowsUserCustomization forKey:CPToolbarAllowsUserCustomizationKey];
|
||||
[aCoder encodeBool:_isVisible forKey:CPToolbarIsVisibleKey];
|
||||
[aCoder encodeInt:_sizeMode forKey:CPToolbarSizeModeKey]
|
||||
|
||||
[aCoder encodeObject:_identifiedItems forKey:CPToolbarIdentifiedItemsKey];
|
||||
[aCoder encodeObject:_defaultItems forKey:CPToolbarDefaultItemsKey];
|
||||
@@ -515,7 +543,7 @@ var TOOLBAR_TOP_MARGIN = 5.0,
|
||||
var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
{
|
||||
return { index:anIndex, view:aView, label:aLabel, minWidth:aMinWidth };
|
||||
}
|
||||
};
|
||||
|
||||
/* @ignore */
|
||||
@implementation _CPToolbarView : CPView
|
||||
@@ -547,7 +575,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
_CPToolbarViewExtraItemsImage = [[CPImage alloc] initWithContentsOfFile: [bundle pathForResource:"_CPToolbarView/_CPToolbarViewExtraItemsImage.png"] size: CPSizeMake(10.0, 15.0)];
|
||||
_CPToolbarViewExtraItemsImage = [[CPImage alloc] initWithContentsOfFile: [bundle pathForResource:"_CPToolbarView/_CPToolbarViewExtraItemsImage.png"] size:CPSizeMake(10.0, 15.0)];
|
||||
|
||||
_CPToolbarViewExtraItemsAlternateImage = [[CPImage alloc] initWithContentsOfFile: [bundle pathForResource:"_CPToolbarView/_CPToolbarViewExtraItemsAlternateImage.png"] size:CGSizeMake(10.0, 15.0)];
|
||||
}
|
||||
@@ -876,7 +904,7 @@ var _CPToolbarItemVisibilityPriorityCompare = function(lhs, rhs)
|
||||
return CPOrderedAscending;
|
||||
|
||||
return CPOrderedDescending;
|
||||
}
|
||||
};
|
||||
|
||||
var TOP_MARGIN = 5.0,
|
||||
LABEL_MARGIN = 2.0;
|
||||
@@ -1015,7 +1043,7 @@ var TOP_MARGIN = 5.0,
|
||||
_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);
|
||||
_maxSize = CGSizeMake(MAX(_labelSize.width, maxSize.width), 100000000.0);
|
||||
|
||||
[_toolbar tile];
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ var CPUserDefaultsControllerSharedKey = "CPUserDefaultsControllerSharedKey";
|
||||
var keys = [_cachedValues allKeys],
|
||||
keysCount = [keys count];
|
||||
|
||||
while(keysCount--)
|
||||
while (keysCount--)
|
||||
{
|
||||
var key = keys[keysCount];
|
||||
[self willChangeValueForKey:key];
|
||||
@@ -194,7 +194,7 @@ var CPUserDefaultsControllerSharedKey = "CPUserDefaultsControllerSharedKey";
|
||||
var keys = [_cachedValues allKeys],
|
||||
keysCount = [keys count];
|
||||
|
||||
while(keysCount--)
|
||||
while (keysCount--)
|
||||
{
|
||||
var key = keys[keysCount];
|
||||
[[_controller defaults] setObject:[_cachedValues objectForKey:key] forKey:key];
|
||||
@@ -207,7 +207,7 @@ var CPUserDefaultsControllerSharedKey = "CPUserDefaultsControllerSharedKey";
|
||||
keys = [_cachedValues allKeys],
|
||||
keysCount = [keys count];
|
||||
|
||||
while(keysCount--)
|
||||
while (keysCount--)
|
||||
{
|
||||
var key = keys[keysCount];
|
||||
[self willChangeValueForKey:key];
|
||||
@@ -229,7 +229,7 @@ var CPUserDefaultsControllerSharedKey = "CPUserDefaultsControllerSharedKey";
|
||||
keys = [_cachedValues allKeys],
|
||||
keysCount = [keys count];
|
||||
|
||||
while(keysCount--)
|
||||
while (keysCount--)
|
||||
{
|
||||
var key = keys[keysCount],
|
||||
value = [_cachedValues objectForKey:key],
|
||||
@@ -250,7 +250,7 @@ var CPUserDefaultsControllerSharedKey = "CPUserDefaultsControllerSharedKey";
|
||||
keys = [_cachedValues allKeys],
|
||||
keysCount = [keys count];
|
||||
|
||||
while(keysCount--)
|
||||
while (keysCount--)
|
||||
{
|
||||
var key = keys[keysCount],
|
||||
value = [_cachedValues objectForKey:key],
|
||||
|
||||
@@ -141,6 +141,7 @@ var CPViewFlags = { },
|
||||
BOOL _postsFrameChangedNotifications;
|
||||
BOOL _postsBoundsChangedNotifications;
|
||||
BOOL _inhibitFrameAndBoundsChangedNotifications;
|
||||
BOOL _inLiveResize;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
DOMElement _DOMElement;
|
||||
@@ -291,6 +292,9 @@ var CPViewFlags = { },
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, _CGRectGetMinX(aFrame), _CGRectGetMinY(aFrame));
|
||||
CPDOMDisplayServerSetStyleSize(_DOMElement, width, height);
|
||||
|
||||
if (typeof(appkit_tag_dom_elements) !== "undefined" && !!appkit_tag_dom_elements)
|
||||
_DOMElement.setAttribute("data-cappuccino-view", [self className]);
|
||||
|
||||
_DOMImageParts = [];
|
||||
_DOMImageSizes = [];
|
||||
#endif
|
||||
@@ -848,11 +852,17 @@ var CPViewFlags = { },
|
||||
|
||||
if (_backgroundType === BackgroundVerticalThreePartImage)
|
||||
{
|
||||
// Make sure to repeat the top and bottom pieces horizontally if they're not the exact width needed.
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[0], size.width, _DOMImageSizes[0].height);
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], size.width, size.height - _DOMImageSizes[0].height - _DOMImageSizes[2].height);
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[2], size.width, _DOMImageSizes[2].height);
|
||||
}
|
||||
else if (_backgroundType === BackgroundHorizontalThreePartImage)
|
||||
{
|
||||
// Make sure to repeat the left and right pieces vertically if they're not the exact height needed.
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[0], _DOMImageSizes[0].width, size.height);
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], size.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, size.height);
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[2], _DOMImageSizes[2].width, size.height);
|
||||
}
|
||||
else if (_backgroundType === BackgroundNinePartImage)
|
||||
{
|
||||
@@ -1539,7 +1549,10 @@ var CPViewFlags = { },
|
||||
}
|
||||
else if (_backgroundType == BackgroundVerticalThreePartImage)
|
||||
{
|
||||
// Make sure to repeat the top and bottom pieces horizontally if they're not the exact width needed.
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[0], frameSize.width, _DOMImageSizes[0].height);
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], frameSize.width, frameSize.height - _DOMImageSizes[0].height - _DOMImageSizes[2].height);
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[2], frameSize.width, _DOMImageSizes[2].height);
|
||||
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0);
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, 0.0, _DOMImageSizes[0].height);
|
||||
@@ -1547,7 +1560,10 @@ var CPViewFlags = { },
|
||||
}
|
||||
else if (_backgroundType == BackgroundHorizontalThreePartImage)
|
||||
{
|
||||
// Make sure to repeat the left and right pieces vertically if they're not the exact height needed.
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[0], _DOMImageSizes[0].width, frameSize.height);
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], frameSize.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, frameSize.height);
|
||||
CPDOMDisplayServerSetStyleSize(_DOMImageParts[2], _DOMImageSizes[2].width, frameSize.height);
|
||||
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0);
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, _DOMImageSizes[0].width, 0.0);
|
||||
@@ -2128,6 +2144,43 @@ setBoundsOrigin:
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Return yes if the receiver is in a live-resize operation.
|
||||
*/
|
||||
- (BOOL)inLiveResize
|
||||
{
|
||||
return _inLiveResize;
|
||||
}
|
||||
|
||||
/*!
|
||||
Not implemented.
|
||||
|
||||
A view will be sent this message before a window begins a resize operation. The
|
||||
receiver might choose to simplify its drawing operations during a live resize
|
||||
for speed.
|
||||
|
||||
Subclasses should call super.
|
||||
*/
|
||||
- (void)viewWillStartLiveResize
|
||||
{
|
||||
_inLiveResize = YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
Not implemented.
|
||||
|
||||
A view will be sent this message after a window finishes a resize operation. The
|
||||
receiver which simplified its drawing operations in viewWillStartLiveResize might
|
||||
stop doing so now. Note the view might no longer be in a window, so use
|
||||
[self setNeedsDisplay:YES] if a final non-simplified redraw is required.
|
||||
|
||||
Subclasses should call super.
|
||||
*/
|
||||
- (void)viewDidEndLiveResize
|
||||
{
|
||||
_inLiveResize = NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPView (KeyView)
|
||||
@@ -2543,6 +2596,50 @@ setBoundsOrigin:
|
||||
return (_themeAttributes && _themeAttributes[aName] !== undefined);
|
||||
}
|
||||
|
||||
/*!
|
||||
Registers theme values encoded in an array at runtime. The format of the data in the array
|
||||
is the same as that used by ThemeDescriptors.j, with the exception that you need to use
|
||||
CPColorWithImages() in place of PatternColor(). For more information see the comments
|
||||
at the top of ThemeDescriptors.j.
|
||||
|
||||
@param themeValues array of theme values
|
||||
*/
|
||||
- (void)registerThemeValues:(CPArray)themeValues
|
||||
{
|
||||
for (var i = 0; i < themeValues.length; ++i)
|
||||
{
|
||||
var attributeValueState = themeValues[i],
|
||||
attribute = attributeValueState[0],
|
||||
value = attributeValueState[1],
|
||||
state = attributeValueState[2];
|
||||
|
||||
if (state)
|
||||
[self setValue:value forThemeAttribute:attribute inState:state];
|
||||
else
|
||||
[self setValue:value forThemeAttribute:attribute];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Registers theme values encoded in an array at runtime. The format of the data in the array
|
||||
is the same as that used by ThemeDescriptors.j, with the exception that you need to use
|
||||
CPColorWithImages() in place of PatternColor(). The values in \c inheritedValues are
|
||||
registered first, then those in \c themeValues override/augment the inherited values.
|
||||
For more information see the comments at the top of ThemeDescriptors.j.
|
||||
|
||||
@param themeValues array of base theme values
|
||||
@param inheritedValues array of overridden/additional theme values
|
||||
*/
|
||||
- (void)registerThemeValues:(CPArray)themeValues inherit:(CPArray)inheritedValues
|
||||
{
|
||||
// Register inherited values first, then override those with the subtheme values.
|
||||
if (inheritedValues)
|
||||
[self registerThemeValues:inheritedValues];
|
||||
|
||||
if (themeValues)
|
||||
[self registerThemeValues:themeValues];
|
||||
}
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aViewName
|
||||
{
|
||||
return nil;
|
||||
@@ -2799,7 +2896,7 @@ var _CPViewFullScreenModeStateMake = function(aView)
|
||||
var superview = aView._superview;
|
||||
|
||||
return { autoresizingMask:aView._autoresizingMask, frame:CGRectMakeCopy(aView._frame), index:(superview ? [superview._subviews indexOfObjectIdenticalTo:aView] : 0), superview:superview };
|
||||
}
|
||||
};
|
||||
|
||||
var _CPViewGetTransform = function(/*CPView*/ fromView, /*CPView */ toView)
|
||||
{
|
||||
@@ -2896,4 +2993,4 @@ var _CPViewGetTransform = function(/*CPView*/ fromView, /*CPView */ toView)
|
||||
}*/
|
||||
|
||||
return transform;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -111,7 +111,8 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
|
||||
view = [self _targetView:dictionary],
|
||||
startFrame = [self _startFrame:dictionary],
|
||||
endFrame = [self _endFrame:dictionary],
|
||||
differenceFrame = _CGRectMakeZero();
|
||||
differenceFrame = _CGRectMakeZero(),
|
||||
value = [super currentValue];
|
||||
|
||||
differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x;
|
||||
differenceFrame.origin.y = endFrame.origin.y - startFrame.origin.y;
|
||||
@@ -119,19 +120,19 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
|
||||
differenceFrame.size.height = endFrame.size.height - startFrame.size.height;
|
||||
|
||||
var intermediateFrame = _CGRectMakeZero();
|
||||
intermediateFrame.origin.x = startFrame.origin.x + differenceFrame.origin.x * progress;
|
||||
intermediateFrame.origin.y = startFrame.origin.y + differenceFrame.origin.y * progress;
|
||||
intermediateFrame.size.width = startFrame.size.width + differenceFrame.size.width * progress;
|
||||
intermediateFrame.size.height = startFrame.size.height + differenceFrame.size.height * progress;
|
||||
intermediateFrame.origin.x = startFrame.origin.x + differenceFrame.origin.x * value;
|
||||
intermediateFrame.origin.y = startFrame.origin.y + differenceFrame.origin.y * value;
|
||||
intermediateFrame.size.width = startFrame.size.width + differenceFrame.size.width * value;
|
||||
intermediateFrame.size.height = startFrame.size.height + differenceFrame.size.height * value;
|
||||
|
||||
[view setFrame:intermediateFrame];
|
||||
|
||||
// Update the view's alpha value
|
||||
var effect = [self _effect:dictionary];
|
||||
if (effect === CPViewAnimationFadeInEffect)
|
||||
[view setAlphaValue:1.0 * progress];
|
||||
[view setAlphaValue:1.0 * value];
|
||||
else if (effect === CPViewAnimationFadeOutEffect)
|
||||
[view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * progress];
|
||||
[view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * value];
|
||||
|
||||
if (progress === 1.0)
|
||||
[self _targetView:view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0];
|
||||
|
||||
@@ -66,6 +66,7 @@ var CPViewControllerCachedCibs;
|
||||
{
|
||||
CPView _view @accessors(property=view);
|
||||
BOOL _isLoading;
|
||||
BOOL _isLazy;
|
||||
|
||||
id _representedObject @accessors(property=representedObject);
|
||||
CPString _title @accessors(property=title);
|
||||
@@ -124,6 +125,7 @@ var CPViewControllerCachedCibs;
|
||||
_cibExternalNameTable = anExternalNameTable || [CPDictionary dictionaryWithObject:self forKey:CPCibOwner];
|
||||
|
||||
_isLoading = NO;
|
||||
_isLazy = NO;
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -136,12 +138,12 @@ var CPViewControllerCachedCibs;
|
||||
|
||||
If you create your views manually, you must override this method and use
|
||||
it to create your view and assign it to the view property. The default
|
||||
implementation for programmatic views is to create a plain view. You can
|
||||
invoke super to utilize this view.
|
||||
implementation for programmatic views is to create a plain, zero width & height
|
||||
view. You can invoke super to utilize this view.
|
||||
|
||||
If you use Interface Builder to create your views, you initialize the view
|
||||
using the initWithCibName:bundle: method then you must not override this
|
||||
method. The consequences risk shattering the space-time continuum.
|
||||
If you use Interface Builder to create your views, and you initialize the
|
||||
controller using the initWithCibName:bundle: methods, then you MUST NOT override
|
||||
this method. The consequences risk shattering the space-time continuum.
|
||||
|
||||
Note: The cib loading system is currently synchronous.
|
||||
*/
|
||||
@@ -150,17 +152,22 @@ var CPViewControllerCachedCibs;
|
||||
if (_view)
|
||||
return;
|
||||
|
||||
// check if a cib is already cached for the current _cibName
|
||||
var cib = [CPViewControllerCachedCibs objectForKey:_cibName];
|
||||
|
||||
if (!cib)
|
||||
if (_cibName)
|
||||
{
|
||||
// if the cib isn't cached yet : fetch it and cache it
|
||||
cib = [[CPCib alloc] initWithContentsOfURL:[_cibBundle pathForResource:_cibName + @".cib"]];
|
||||
[CPViewControllerCachedCibs setObject:cib forKey:_cibName];
|
||||
}
|
||||
// check if a cib is already cached for the current _cibName
|
||||
var cib = [CPViewControllerCachedCibs objectForKey:_cibName];
|
||||
|
||||
[cib instantiateCibWithExternalNameTable:_cibExternalNameTable];
|
||||
if (!cib)
|
||||
{
|
||||
// if the cib isn't cached yet : fetch it and cache it
|
||||
cib = [[CPCib alloc] initWithCibNamed:_cibName bundle:_cibBundle];
|
||||
[CPViewControllerCachedCibs setObject:cib forKey:_cibName];
|
||||
}
|
||||
|
||||
[cib instantiateCibWithExternalNameTable:_cibExternalNameTable];
|
||||
}
|
||||
else
|
||||
_view = [CPView new];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -199,6 +206,11 @@ var CPViewControllerCachedCibs;
|
||||
_isLoading = NO;
|
||||
[self viewDidLoad];
|
||||
}
|
||||
else if (_isLazy)
|
||||
{
|
||||
_isLazy = NO;
|
||||
[self viewDidLoad];
|
||||
}
|
||||
|
||||
return _view;
|
||||
}
|
||||
@@ -208,9 +220,9 @@ var CPViewControllerCachedCibs;
|
||||
This method is called after the view controller has loaded its associated views into memory.
|
||||
|
||||
This method is called regardless of whether the views were stored in a nib
|
||||
file or created programmatically in the loadView method. This method is
|
||||
most commonly used to perform additional initialization steps on views
|
||||
that are loaded from cib files.
|
||||
file or created programmatically in the loadView method, but NOT when setView
|
||||
is invoked. This method is most commonly used to perform additional initialization
|
||||
steps on views that are loaded from cib files.
|
||||
*/
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
@@ -228,13 +240,7 @@ var CPViewControllerCachedCibs;
|
||||
*/
|
||||
- (void)setView:(CPView)aView
|
||||
{
|
||||
var viewWasLoaded = !_view;
|
||||
|
||||
_view = aView;
|
||||
|
||||
// Make sure the viewDidLoad method is called if the view is set directly
|
||||
if (!_isLoading && viewWasLoaded)
|
||||
[self viewDidLoad];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -266,6 +272,7 @@ var CPViewControllerViewKey = @"CPViewControllerViewKey",
|
||||
_cibBundle = bundlePath ? [CPBundle bundleWithPath:bundlePath] : [CPBundle mainBundle];
|
||||
|
||||
_cibExternalNameTable = [CPDictionary dictionaryWithObject:self forKey:CPCibOwner];
|
||||
_isLazy = YES;
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
@@ -199,7 +199,7 @@ CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
_ignoreLoadEnd = NO;
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
};
|
||||
|
||||
if (_iframe.addEventListener)
|
||||
_iframe.addEventListener("load", _loadCallback, false);
|
||||
@@ -830,7 +830,7 @@ CPWebViewAppKitScrollMaxPollCount = 3;
|
||||
- (@action)reload:(id)sender
|
||||
{
|
||||
// If we're displaying pure HTML, redisplay it.
|
||||
if(!_url && (_html !== nil))
|
||||
if (!_url && (_html !== nil))
|
||||
[self loadHTMLString:_html];
|
||||
else
|
||||
[self _loadMainFrameURL];
|
||||
|
||||
@@ -271,6 +271,7 @@ var CPWindowActionMessageKeys = [
|
||||
BOOL _isAnimating;
|
||||
BOOL _hasShadow;
|
||||
BOOL _isMovableByWindowBackground;
|
||||
BOOL _isMovable;
|
||||
unsigned _shadowStyle;
|
||||
BOOL _showsResizeIndicator;
|
||||
|
||||
@@ -404,6 +405,7 @@ CPTexturedBackgroundWindowMask
|
||||
_registeredDraggedTypesArray = [];
|
||||
_isSheet = NO;
|
||||
_acceptsMouseMovedEvents = YES;
|
||||
_isMovable = YES;
|
||||
|
||||
// Set up our window number.
|
||||
_windowNumber = [CPApp._windows count];
|
||||
@@ -426,6 +428,7 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
// Create a generic content view.
|
||||
[self setContentView:[[CPView alloc] initWithFrame:CGRectMakeZero()]];
|
||||
[self setInitialFirstResponder:[self contentView]];
|
||||
|
||||
_firstResponder = self;
|
||||
|
||||
@@ -452,6 +455,7 @@ CPTexturedBackgroundWindowMask
|
||||
if (aStyleMask & CPBorderlessBridgeWindowMask)
|
||||
[self setFullPlatformWindow:YES];
|
||||
|
||||
_autorecalculatesKeyViewLoop = NO;
|
||||
_defaultButtonEnabled = YES;
|
||||
_keyViewLoopIsDirty = YES;
|
||||
|
||||
@@ -480,6 +484,7 @@ CPTexturedBackgroundWindowMask
|
||||
[self close];
|
||||
|
||||
_platformWindow = aPlatformWindow;
|
||||
[_platformWindow _setTitle:_title window:self];
|
||||
|
||||
if (wasVisible)
|
||||
[self orderFront:self];
|
||||
@@ -511,6 +516,10 @@ CPTexturedBackgroundWindowMask
|
||||
- (void)awakeFromCib
|
||||
{
|
||||
_keyViewLoopIsDirty = ![self _hasKeyViewLoop];
|
||||
// If no key view loop has been specified by hand, and we are not intending to auto recalculate,
|
||||
// set up a default key view loop.
|
||||
if (_keyViewLoopIsDirty && ![self autorecalculatesKeyViewLoop])
|
||||
[self recalculateKeyViewLoop];
|
||||
}
|
||||
|
||||
- (void)_setWindowView:(CPView)aWindowView
|
||||
@@ -949,6 +958,12 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
var bounds = CGRectMake(0.0, 0.0, CGRectGetWidth(_frame), CGRectGetHeight(_frame));
|
||||
|
||||
// During init the initial first responder is set to the contentView
|
||||
// if it hasn't changed in the mean time we need to update that reference
|
||||
// to the new contentView
|
||||
if ([self initialFirstResponder] === _contentView)
|
||||
[self setInitialFirstResponder:aView];
|
||||
|
||||
_contentView = aView;
|
||||
[_contentView setFrame:[self contentRectForFrameRect:bounds]];
|
||||
|
||||
@@ -1273,17 +1288,17 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
- (BOOL)acceptsFirstResponder
|
||||
{
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (id)initialFirstResponder
|
||||
- (CPView)initialFirstResponder
|
||||
{
|
||||
return _initialFirstResponder;
|
||||
}
|
||||
|
||||
- (void)setInitialFirstResponder:(id)aResponder
|
||||
- (void)setInitialFirstResponder:(CPView)aView
|
||||
{
|
||||
_initialFirstResponder = aResponder;
|
||||
_initialFirstResponder = aView;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1359,6 +1374,7 @@ CPTexturedBackgroundWindowMask
|
||||
_title = aTitle;
|
||||
|
||||
[_windowView setTitle:aTitle];
|
||||
[_platformWindow _setTitle:_title window:self];
|
||||
|
||||
[self _synchronizeMenuBarTitleWithWindowTitle];
|
||||
}
|
||||
@@ -1429,6 +1445,23 @@ CPTexturedBackgroundWindowMask
|
||||
return _isMovableByWindowBackground;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets whether the window can be moved.
|
||||
@param shouldBeMovable \c YES makes the window movable.
|
||||
*/
|
||||
- (void)setMovable:(BOOL)shouldBeMovable
|
||||
{
|
||||
_isMovable = shouldBeMovable;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns \c YES if the window can be moved.
|
||||
*/
|
||||
- (void)isMovable
|
||||
{
|
||||
return _isMovable;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the window location to be the center of the screen
|
||||
*/
|
||||
@@ -2472,9 +2505,7 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
_autorecalculatesKeyViewLoop = shouldRecalculate;
|
||||
|
||||
if (_keyViewLoopIsDirty)
|
||||
[self recalculateKeyViewLoop];
|
||||
else if (_autorecalculatesKeyViewLoop)
|
||||
if (_autorecalculatesKeyViewLoop)
|
||||
[self _dirtyKeyViewLoop];
|
||||
}
|
||||
|
||||
@@ -2485,30 +2516,70 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
- (void)selectNextKeyView:(id)sender
|
||||
{
|
||||
if (_keyViewLoopIsDirty && [self autorecalculatesKeyViewLoop])
|
||||
[self recalculateKeyViewLoop];
|
||||
|
||||
var nextValidKeyView = nil;
|
||||
|
||||
if ([_firstResponder isKindOfClass:[CPView class]])
|
||||
[self selectKeyViewFollowingView:_firstResponder];
|
||||
nextValidKeyView = [_firstResponder nextValidKeyView];
|
||||
|
||||
if (!nextValidKeyView)
|
||||
{
|
||||
var initialFirstResponder = [self initialFirstResponder];
|
||||
|
||||
if ([initialFirstResponder acceptsFirstResponder])
|
||||
nextValidKeyView = initialFirstResponder;
|
||||
else
|
||||
nextValidKeyView = [initialFirstResponder nextValidKeyView];
|
||||
}
|
||||
|
||||
[self makeFirstResponder:nextValidKeyView];
|
||||
}
|
||||
|
||||
- (void)selectPreviousKeyView:(id)sender
|
||||
{
|
||||
if (_keyViewLoopIsDirty && [self autorecalculatesKeyViewLoop])
|
||||
[self recalculateKeyViewLoop];
|
||||
|
||||
var previousValidKeyView = nil;
|
||||
|
||||
if ([_firstResponder isKindOfClass:[CPView class]])
|
||||
[self selectKeyViewPrecedingView:_firstResponder];
|
||||
previousValidKeyView = [_firstResponder previousValidKeyView];
|
||||
|
||||
if (!previousValidKeyView)
|
||||
{
|
||||
var initialFirstResponder = [self initialFirstResponder];
|
||||
|
||||
if ([initialFirstResponder acceptsFirstResponder])
|
||||
previousValidKeyView = initialFirstResponder;
|
||||
else
|
||||
previousValidKeyView = [initialFirstResponder previousValidKeyView];
|
||||
}
|
||||
|
||||
[self makeFirstResponder:previousValidKeyView];
|
||||
}
|
||||
|
||||
- (void)selectKeyViewFollowingView:(CPView)aView
|
||||
{
|
||||
if (_keyViewLoopIsDirty)
|
||||
if (_keyViewLoopIsDirty && [self autorecalculatesKeyViewLoop])
|
||||
[self recalculateKeyViewLoop];
|
||||
|
||||
[self makeFirstResponder:[aView nextValidKeyView]];
|
||||
var nextValidKeyView = [aView nextValidKeyView];
|
||||
|
||||
if ([nextValidKeyView isKindOfClass:[CPView class]])
|
||||
[self makeFirstResponder:nextValidKeyView];
|
||||
}
|
||||
|
||||
- (void)selectKeyViewPrecedingView:(CPView)aView
|
||||
{
|
||||
if (_keyViewLoopIsDirty)
|
||||
if (_keyViewLoopIsDirty && [self autorecalculatesKeyViewLoop])
|
||||
[self recalculateKeyViewLoop];
|
||||
|
||||
[self makeFirstResponder:[aView previousValidKeyView]];
|
||||
var previousValidKeyView = [aView previousValidKeyView];
|
||||
|
||||
if ([previousValidKeyView isKindOfClass:[CPView class]])
|
||||
[self makeFirstResponder:previousValidKeyView];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -2596,14 +2667,16 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
var allViews = function(aWindow)
|
||||
{
|
||||
var views = [[aWindow contentView] subviews],
|
||||
index = 0;
|
||||
var views = [CPArray arrayWithObject:[aWindow contentView]];
|
||||
|
||||
[views addObjectsFromArray:[[aWindow contentView] subviews]];
|
||||
|
||||
var index = 0;
|
||||
for (; index < views.length; ++index)
|
||||
views = views.concat([views[index] subviews]);
|
||||
|
||||
return views;
|
||||
}
|
||||
};
|
||||
|
||||
var keyViewComparator = function(lhs, rhs, context)
|
||||
{
|
||||
@@ -2634,7 +2707,7 @@ var keyViewComparator = function(lhs, rhs, context)
|
||||
return CPOrderedSame;
|
||||
|
||||
return CPOrderedDescending;
|
||||
}
|
||||
};
|
||||
|
||||
@implementation CPWindow (MenuBar)
|
||||
|
||||
@@ -2858,7 +2931,7 @@ var keyViewComparator = function(lhs, rhs, context)
|
||||
var interpolate = function(fromValue, toValue, progress)
|
||||
{
|
||||
return fromValue + (toValue - fromValue) * progress;
|
||||
}
|
||||
};
|
||||
|
||||
/* @ignore */
|
||||
@implementation _CPWindowFrameAnimation : CPAnimation
|
||||
@@ -2928,5 +3001,6 @@ CPCustomWindowShadowStyle = 3;
|
||||
@import "_CPHUDWindowView.j"
|
||||
@import "_CPBorderlessWindowView.j"
|
||||
@import "_CPBorderlessBridgeWindowView.j"
|
||||
@import "_CPAttachedWindowView.j"
|
||||
@import "CPDragServer.j"
|
||||
@import "CPView.j"
|
||||
|
||||
@@ -0,0 +1,388 @@
|
||||
/*
|
||||
* _CPAttachedWindowView.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Antoine Mercadal
|
||||
* Copyright 2011 <primalmotion@archipelproject.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "_CPWindowView.j"
|
||||
|
||||
#define ALIGN_STROKE(point) (FLOOR(point) === (point) ? (point) + halfStrokeWidth : (point))
|
||||
#define ALIGN_COORD(point) (FLOOR(point))
|
||||
|
||||
var _CPAttachedWindowViewDefaultCursorSize = CGSizeMake(16, 10);
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
|
||||
A custom CPWindowView that manages a border and cursor
|
||||
*/
|
||||
@implementation _CPAttachedWindowView : _CPWindowView
|
||||
{
|
||||
BOOL _mouseDownPressed @accessors(getter=isMouseDownPressed, setter=setMouseDownPressed:);
|
||||
float _arrowOffsetX @accessors(property=arrowOffsetX);
|
||||
float _arrowOffsetY @accessors(property=arrowOffsetY);
|
||||
int _appearance @accessors(property=appearance);
|
||||
unsigned _preferredEdge @accessors(property=preferredEdge);
|
||||
|
||||
CGSize _cursorSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
Compute the contentView frame from a given window frame
|
||||
|
||||
@param aFrameRect the window frame
|
||||
*/
|
||||
- (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
{
|
||||
var contentRect = CGRectMakeCopy(aFrameRect);
|
||||
|
||||
// @todo change border art and remove this pixel perfect adaptation
|
||||
// return CGRectInset(contentRect, 20, 20);
|
||||
|
||||
contentRect.origin.x += 18;
|
||||
contentRect.origin.y += 17;
|
||||
contentRect.size.width -= 35;
|
||||
contentRect.size.height -= 37;
|
||||
|
||||
return contentRect;
|
||||
}
|
||||
|
||||
/*!
|
||||
Compute the window frame from a given contentView frame
|
||||
|
||||
@param aContentRect the contentView frame
|
||||
*/
|
||||
+ (CGRect)frameRectForContentRect:(CGRect)aContentRect
|
||||
{
|
||||
var frameRect = CGRectMakeCopy(aContentRect);
|
||||
|
||||
// @todo change border art and remove this pixel perfect adaptation
|
||||
//return CGRectOffset(frameRect, 20, 20);
|
||||
|
||||
frameRect.origin.x -= 18;
|
||||
frameRect.origin.y -= 17;
|
||||
frameRect.size.width += 35;
|
||||
frameRect.size.height += 37;
|
||||
return frameRect;
|
||||
}
|
||||
|
||||
/*!
|
||||
Initialize the _CPWindowView
|
||||
*/
|
||||
- (id)initWithFrame:(CGRect)aFrame styleMask:(unsigned)aStyleMask
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame styleMask:aStyleMask])
|
||||
{
|
||||
_arrowOffsetX = 0.0;
|
||||
_arrowOffsetY = 0.0;
|
||||
|
||||
// @TODO: make this themable
|
||||
_appearance = CPPopoverAppearanceMinimal;
|
||||
_cursorSize = CGSizeMakeCopy(_CPAttachedWindowViewDefaultCursorSize);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Hide the cursor
|
||||
*/
|
||||
- (void)hideCursor
|
||||
{
|
||||
_cursorSize = CGSizeMakeZero();
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
Show the cursor
|
||||
*/
|
||||
- (void)showCursor
|
||||
{
|
||||
_cursorSize = CGSizeMakeCopy(_CPAttachedWindowViewDefaultCursorSize);
|
||||
[self setNeedsDisplay:YES];
|
||||
_mouseDownPressed = NO;
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw the view
|
||||
*/
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
[super drawRect:aRect];
|
||||
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
radius = 5,
|
||||
arrowWidth = _cursorSize.width,
|
||||
arrowHeight = _cursorSize.height,
|
||||
strokeWidth = 1,
|
||||
halfStrokeWidth = strokeWidth / 2.0,
|
||||
strokeColor,
|
||||
shadowColor = [[CPColor blackColor] colorWithAlphaComponent:.2],
|
||||
shadowSize = CGSizeMake(0, 6),
|
||||
shadowBlur = 15,
|
||||
gradient,
|
||||
frame = [self bounds];
|
||||
|
||||
if (_appearance == CPPopoverAppearanceMinimal)
|
||||
{
|
||||
gradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [(254.0 / 255), (254.0 / 255), (254.0 / 255), 0.93,
|
||||
(231.0 / 255), (231.0 / 255), (231.0 / 255), 0.93], [0,1], 2);
|
||||
strokeColor = [CPColor colorWithHexString:@"B8B8B8"];
|
||||
}
|
||||
else
|
||||
{
|
||||
gradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [(38.0 / 255), (38.0 / 255), (38.0 / 255), 0.93,
|
||||
(18.0 / 255), (18.0 / 255), (18.0 / 255), 0.93], [0,1], 2);
|
||||
strokeColor = [CPColor colorWithHexString:@"222222"];
|
||||
}
|
||||
|
||||
// fix rect to take care of stroke and shadow
|
||||
frame.origin.x += halfStrokeWidth + shadowBlur;
|
||||
frame.origin.y += halfStrokeWidth + (shadowBlur + shadowSize.height / 2);
|
||||
frame.size.width -= strokeWidth + (shadowBlur * 2);
|
||||
frame.size.height -= strokeWidth + (shadowBlur * 2 + shadowSize.height);
|
||||
|
||||
CGContextSetStrokeColor(context, strokeColor);
|
||||
CGContextSetLineWidth(context, strokeWidth);
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetShadowWithColor(context, shadowSize, shadowBlur, shadowColor);
|
||||
CGContextDrawLinearGradient(context, gradient, CGPointMake(CGRectGetMidX(frame), 0.0), CGPointMake(CGRectGetMidX(frame), frame.size.height), 0);
|
||||
|
||||
var xMin = _CGRectGetMinX(frame),
|
||||
xMax = _CGRectGetMaxX(frame),
|
||||
yMin = _CGRectGetMinY(frame),
|
||||
yMax = _CGRectGetMaxY(frame),
|
||||
arrowMinX = ALIGN_COORD(xMin + radius + strokeWidth),
|
||||
arrowMaxX = ALIGN_COORD(xMax - radius - strokeWidth),
|
||||
arrowMinY = ALIGN_COORD(yMin + radius + strokeWidth),
|
||||
arrowMaxY = ALIGN_COORD(yMax - radius + strokeWidth),
|
||||
arrowAnchor = CGPointMakeZero(),
|
||||
arrowStart = CGPointMakeZero(),
|
||||
pt = CGPointMakeZero();
|
||||
|
||||
// draw!
|
||||
switch (_preferredEdge)
|
||||
{
|
||||
case CPMinXEdge:
|
||||
case CPMaxXEdge:
|
||||
// origin nw
|
||||
pt.x = ALIGN_COORD(xMin + radius);
|
||||
pt.y = yMin;
|
||||
CGContextMoveToPoint(context, pt.x, pt.y);
|
||||
|
||||
// ne
|
||||
pt.x = ALIGN_COORD(xMax - radius);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, xMax, yMin, xMax, ALIGN_COORD(yMin + radius));
|
||||
|
||||
if (_preferredEdge === CPMinXEdge)
|
||||
{
|
||||
// arrow CPMinXEdge
|
||||
arrowAnchor.x = ALIGN_STROKE(xMax);
|
||||
arrowAnchor.y = ALIGN_COORD((frame.size.height / 2) + yMin + _arrowOffsetY);
|
||||
|
||||
// to top edge
|
||||
pt.y = ALIGN_COORD(arrowAnchor.y - (arrowWidth / 2));
|
||||
|
||||
// adjust starting point to not go beyond the corner
|
||||
if (pt.y <= arrowMinY)
|
||||
pt.y = arrowMinY;
|
||||
else if ((pt.y + arrowWidth) > arrowMaxY)
|
||||
pt.y = arrowMaxY - arrowWidth;
|
||||
|
||||
pt.x = arrowAnchor.x;
|
||||
arrowStart = CGPointMakeCopy(pt);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
|
||||
// top edge -> point
|
||||
pt.x = ALIGN_STROKE(arrowAnchor.x + arrowHeight);
|
||||
pt.y = arrowAnchor.y;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
|
||||
// point -> bottom edge
|
||||
pt.x = arrowAnchor.x;
|
||||
pt.y = ALIGN_COORD(arrowStart.y + arrowWidth);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
}
|
||||
|
||||
// se
|
||||
pt.x = xMax;
|
||||
pt.y = ALIGN_COORD(yMax - radius);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, pt.x, yMax, ALIGN_COORD(xMax - radius), yMax);
|
||||
|
||||
// sw
|
||||
pt.x = ALIGN_COORD(xMin + radius);
|
||||
pt.y = yMax;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, xMin, pt.y, xMin, ALIGN_COORD(yMax - radius));
|
||||
|
||||
if (_preferredEdge === CPMaxXEdge)
|
||||
{
|
||||
// arrow CPMaxXEdge
|
||||
arrowAnchor.x = ALIGN_STROKE(xMin);
|
||||
arrowAnchor.y = ALIGN_COORD((frame.size.height / 2) + yMin + _arrowOffsetY);
|
||||
|
||||
// to bottom edge
|
||||
pt.y = ALIGN_COORD(arrowAnchor.y + (arrowWidth / 2));
|
||||
|
||||
// adjust starting point to not go beyond the corner
|
||||
if ((pt.y - arrowWidth) < arrowMinY)
|
||||
pt.y = arrowMinY + arrowWidth;
|
||||
else if (pt.y > arrowMaxY)
|
||||
pt.y = arrowMaxY;
|
||||
|
||||
pt.x = arrowAnchor.x;
|
||||
arrowStart = CGPointMakeCopy(pt);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
|
||||
// bottom edge -> point
|
||||
pt.x = ALIGN_STROKE(arrowAnchor.x - arrowHeight);
|
||||
pt.y = arrowAnchor.y;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
|
||||
// point -> top edge
|
||||
pt.x = arrowAnchor.x;
|
||||
pt.y = ALIGN_COORD(arrowStart.y - arrowWidth);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
}
|
||||
|
||||
// nw
|
||||
pt.x = xMin;
|
||||
pt.y = ALIGN_COORD(yMin + radius);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, pt.x, yMin, ALIGN_COORD(xMin + radius), yMin);
|
||||
break;
|
||||
|
||||
case CPMaxYEdge:
|
||||
case CPMinYEdge:
|
||||
// origin sw
|
||||
pt.x = xMin;
|
||||
pt.y = ALIGN_COORD(yMax - radius);
|
||||
CGContextMoveToPoint(context, pt.x, pt.y);
|
||||
|
||||
// nw
|
||||
pt.y = ALIGN_COORD(yMin + radius);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, pt.x, yMin, ALIGN_COORD(xMin + radius), yMin);
|
||||
|
||||
if (_preferredEdge === CPMaxYEdge)
|
||||
{
|
||||
// arrow CPMaxYEdge
|
||||
arrowAnchor.x = ALIGN_COORD((frame.size.width / 2) + xMin + _arrowOffsetX);
|
||||
arrowAnchor.y = ALIGN_STROKE(yMin + _arrowOffsetY);
|
||||
|
||||
// to left edge
|
||||
pt.x = ALIGN_COORD(arrowAnchor.x - (arrowWidth / 2));
|
||||
|
||||
// adjust starting point to not go beyond the corner
|
||||
if (pt.x < arrowMinX)
|
||||
pt.x = arrowMinX;
|
||||
else if ((pt.x + arrowWidth) > arrowMaxX)
|
||||
pt.x = arrowMaxX - arrowWidth;
|
||||
|
||||
pt.y = arrowAnchor.y;
|
||||
arrowStart = CGPointMakeCopy(pt);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
|
||||
// left edge -> point
|
||||
pt.x = arrowAnchor.x;
|
||||
pt.y = ALIGN_STROKE(arrowAnchor.y - arrowHeight);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
|
||||
// point -> right edge
|
||||
pt.x = ALIGN_COORD(arrowStart.x + arrowWidth);
|
||||
pt.y = arrowAnchor.y;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
}
|
||||
|
||||
// ne
|
||||
pt.x = ALIGN_COORD(xMax - radius);
|
||||
pt.y = yMin;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, xMax, pt.y, xMax, ALIGN_COORD(yMin + radius));
|
||||
|
||||
// se
|
||||
pt.x = xMax;
|
||||
pt.y = ALIGN_COORD(yMax - radius);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, pt.x, yMax, ALIGN_COORD(xMax - radius), yMax);
|
||||
|
||||
if (_preferredEdge === CPMinYEdge)
|
||||
{
|
||||
// arrow CPMinYEdge
|
||||
arrowAnchor.x = ALIGN_COORD((frame.size.width / 2) + xMin + _arrowOffsetX);
|
||||
arrowAnchor.y = ALIGN_STROKE(yMax + _arrowOffsetY);
|
||||
|
||||
// to right edge
|
||||
pt.x = ALIGN_COORD(arrowAnchor.x + (arrowWidth / 2));
|
||||
|
||||
// adjust starting point to not go beyond the corner
|
||||
if ((pt.x - arrowWidth) < arrowMinX)
|
||||
pt.x = arrowMinX + arrowWidth;
|
||||
else if (pt.x > arrowMaxX)
|
||||
pt.x = arrowMaxX;
|
||||
|
||||
pt.y = arrowAnchor.y;
|
||||
arrowStart = CGPointMakeCopy(pt);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
|
||||
// right edge -> point
|
||||
pt.x = arrowAnchor.x;
|
||||
pt.y = ALIGN_STROKE(arrowAnchor.y + arrowHeight);
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
|
||||
// point -> left edge
|
||||
pt.x = ALIGN_COORD(arrowStart.x - arrowWidth);
|
||||
pt.y = arrowAnchor.y;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
}
|
||||
|
||||
// sw
|
||||
pt.x = ALIGN_COORD(xMin + radius);
|
||||
pt.y = yMax;
|
||||
CGContextAddLineToPoint(context, pt.x, pt.y);
|
||||
CGContextAddCurveToPoint(context, pt.x, pt.y, xMin, pt.y, xMin, ALIGN_COORD(yMax - radius));
|
||||
break;
|
||||
|
||||
default:
|
||||
// no computed edge means standard rounded rect
|
||||
CGContextAddPath(context, CGPathWithRoundedRectangleInRect(frame, radius, radius, YES, YES, YES, YES));
|
||||
}
|
||||
|
||||
CGContextClosePath(context);
|
||||
|
||||
//Draw it
|
||||
CGContextStrokePath(context);
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
_mouseDownPressed = YES;
|
||||
[super mouseDown:anEvent];
|
||||
}
|
||||
|
||||
- (void)mouseUp:(CPEvent)anEvent
|
||||
{
|
||||
_mouseDownPressed = NO;
|
||||
[super mouseUp:anEvent];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -33,7 +33,14 @@ var _CPToolbarViewBackgroundColor = nil;
|
||||
+ (CPColor)toolbarBackgroundColor
|
||||
{
|
||||
if (!_CPToolbarViewBackgroundColor)
|
||||
_CPToolbarViewBackgroundColor = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[_CPBorderlessBridgeWindowView class]] pathForResource:@"_CPToolbarView/_CPToolbarViewBackground.png"] size:CGSizeMake(1.0, 59.0)]];
|
||||
{
|
||||
var bundle = [CPBundle bundleForClass:[_CPBorderlessBridgeWindowView class]];
|
||||
_CPToolbarViewBackgroundColor = CPColorWithImages([
|
||||
["_CPToolbarView/toolbar-background-top.png", 1, 1, bundle],
|
||||
["_CPToolbarView/toolbar-background-center.png", 1, 57.0, bundle],
|
||||
["_CPToolbarView/toolbar-background-bottom.png", 1, 1, bundle],
|
||||
], CPColorPatternIsVertical);
|
||||
}
|
||||
|
||||
return _CPToolbarViewBackgroundColor;
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ var HUD_TITLEBAR_HEIGHT = 26.0;
|
||||
|
||||
if ([[[self window] toolbar] isVisible])
|
||||
{
|
||||
toolbarHeight = CGRectGetHeight([[self toolbarView] frame]);
|
||||
var toolbarHeight = CGRectGetHeight([[self toolbarView] frame]);
|
||||
|
||||
contentRect.origin.y += toolbarHeight;
|
||||
contentRect.size.height -= toolbarHeight;
|
||||
|
||||
@@ -181,7 +181,7 @@ var STANDARD_GRADIENT_HEIGHT = 41.0,
|
||||
|
||||
if ([theToolbar isVisible])
|
||||
{
|
||||
toolbarHeight = CGRectGetHeight([[theToolbar _toolbarView] frame]);
|
||||
var toolbarHeight = CGRectGetHeight([[theToolbar _toolbarView] frame]);
|
||||
|
||||
contentRect.origin.y += toolbarHeight;
|
||||
contentRect.size.height -= toolbarHeight;
|
||||
|
||||
@@ -27,15 +27,31 @@
|
||||
{
|
||||
BOOL _mouseDownPressed @accessors(getter=isMouseDownPressed, setter=setMouseDownPressed:);
|
||||
unsigned _gravity @accessors(property=gravity);
|
||||
|
||||
CPColor _backgroundColor;
|
||||
CPColor _strokeColor;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Class methods
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return @"tooltip";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[[CPColor colorWithHexString:@"E3E3E3"],
|
||||
[CPColor colorWithHexString:@"FFFFCA"],
|
||||
2.0,
|
||||
1.0,
|
||||
[CPColor blackColor]]
|
||||
forKeys:[@"stroke-color",
|
||||
@"background-color",
|
||||
@"border-radius",
|
||||
@"stroke-width",
|
||||
@"color"]];
|
||||
}
|
||||
|
||||
/*! compute the contentView frame from a given window frame
|
||||
@param aFrameRect the window frame
|
||||
*/
|
||||
@@ -67,21 +83,6 @@
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization
|
||||
|
||||
- (id)initWithFrame:(CPRect)aFrame styleMask:(unsigned)aStyleMask
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame styleMask:aStyleMask])
|
||||
{
|
||||
_strokeColor = [CPColor colorWithHexString:@"E3E3E3"];
|
||||
_backgroundColor = [CPColor colorWithHexString:@"FFFFCA"];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark drawing
|
||||
|
||||
@@ -90,11 +91,13 @@
|
||||
[super drawRect:aRect];
|
||||
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
radius = 2,
|
||||
strokeWidth = 1;
|
||||
radius = [self currentValueForThemeAttribute:@"border-radius"],
|
||||
strokeWidth = [self currentValueForThemeAttribute:@"stroke-width"],
|
||||
strokeColor = [self currentValueForThemeAttribute:@"stroke-color"],
|
||||
bgColor = [self currentValueForThemeAttribute:@"background-color"];
|
||||
|
||||
CGContextSetStrokeColor(context, _strokeColor);
|
||||
CGContextSetFillColor(context, _backgroundColor);
|
||||
CGContextSetStrokeColor(context, strokeColor);
|
||||
CGContextSetFillColor(context, bgColor);
|
||||
CGContextSetLineWidth(context, strokeWidth);
|
||||
CGContextBeginPath(context);
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
||||
return [self trackResizeWithEvent:anEvent];
|
||||
}
|
||||
|
||||
if ([theWindow isMovableByWindowBackground])
|
||||
if ([theWindow isMovable] && [theWindow isMovableByWindowBackground])
|
||||
[self trackMoveWithEvent:anEvent];
|
||||
|
||||
else
|
||||
@@ -174,6 +174,9 @@ var _CPWindowViewResizeIndicatorImage = nil;
|
||||
|
||||
- (void)trackMoveWithEvent:(CPEvent)anEvent
|
||||
{
|
||||
if (![[self window] isMovable])
|
||||
return;
|
||||
|
||||
var type = [anEvent type];
|
||||
|
||||
if (type === CPLeftMouseUp)
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* CPWorkspace.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Alexander Ljungberg.
|
||||
* Copyright 2012, SlevenBits Ltd.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
var SharedWorkspace = nil;
|
||||
|
||||
|
||||
@implementation CPWorkspace : CPObject
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
+ (CPWorkspace)sharedWorkspace
|
||||
{
|
||||
if (!SharedWorkspace)
|
||||
SharedWorkspace = [CPWorkspace new];
|
||||
|
||||
return SharedWorkspace;
|
||||
}
|
||||
|
||||
- (BOOL)openFile:(CPString)fullPath
|
||||
{
|
||||
var url = [CPURL URLWithString:fullPath];
|
||||
return [self openURL:url];
|
||||
}
|
||||
|
||||
- (BOOL)openURL:(CPURL)url
|
||||
{
|
||||
if (!url || ![url absoluteURL])
|
||||
return NO;
|
||||
window.open([url absoluteURL]);
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -34,9 +34,9 @@
|
||||
@import "_CPCibWindowTemplate.j"
|
||||
|
||||
|
||||
CPCibOwner = @"CPCibOwner",
|
||||
CPCibTopLevelObjects = @"CPCibTopLevelObjects",
|
||||
CPCibReplacementClasses = @"CPCibReplacementClasses",
|
||||
CPCibOwner = @"CPCibOwner";
|
||||
CPCibTopLevelObjects = @"CPCibTopLevelObjects";
|
||||
CPCibReplacementClasses = @"CPCibReplacementClasses";
|
||||
CPCibExternalObjects = @"CPCibExternalObjects";
|
||||
|
||||
var CPCibObjectDataKey = @"CPCibObjectDataKey";
|
||||
|
||||
@@ -125,14 +125,13 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemp
|
||||
|
||||
- (id)_cibInstantiate
|
||||
{
|
||||
var windowClass = CPClassFromString([self windowClass]);
|
||||
var windowClass = CPClassFromString([self windowClass]),
|
||||
theWindow = [[windowClass alloc] initWithContentRect:_windowRect styleMask:_windowStyleMask];
|
||||
|
||||
/* if (!windowClass)
|
||||
[NSException raise:NSInvalidArgumentException format:@"Unable to locate NSWindow class %@, using NSWindow",_windowClass];
|
||||
class=[NSWindow class];*/
|
||||
|
||||
var theWindow = [[windowClass alloc] initWithContentRect:_windowRect styleMask:_windowStyleMask];
|
||||
|
||||
if (_minSize)
|
||||
[theWindow setMinSize:_minSize];
|
||||
if (_maxSize)
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
function CABackingStoreGetContext(aBackingStore)
|
||||
{
|
||||
return aBackingStore.context;
|
||||
}
|
||||
};
|
||||
|
||||
if (CPFeatureIsCompatible(CPHTMLCanvasFeature))
|
||||
{
|
||||
@@ -42,7 +42,7 @@ CABackingStoreCreate = function()
|
||||
|
||||
// FIXME: Consolidate drawImage to support this.
|
||||
return { context:DOMElement.getContext("2d"), buffer:DOMElement, _image:DOMElement };
|
||||
}
|
||||
};
|
||||
|
||||
CABackingStoreSetSize = function(aBackingStore, aSize)
|
||||
{
|
||||
@@ -52,7 +52,8 @@ CABackingStoreSetSize = function(aBackingStore, aSize)
|
||||
buffer.height = aSize.height;
|
||||
buffer.style.width = PIXEL(aSize.width);
|
||||
buffer.style.height = PIXEL(aSize.height);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -64,10 +65,10 @@ CABackingStoreCreate = function()
|
||||
context.buffer = "";
|
||||
|
||||
return { context:context };
|
||||
}
|
||||
};
|
||||
|
||||
CABackingStoreSetSize = function(aBackingStore, aSize)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ function CGColorCreateCopy(aColor)
|
||||
*/
|
||||
function CGColorCreateGenericGray(gray, alpha)
|
||||
{
|
||||
return CGColorCreate(CGColorSpaceCreateDeviceRGB(), [gray,gray,gray, alpha]);
|
||||
return CGColorCreate(CGColorSpaceCreateDeviceRGB(), [gray, gray, gray, alpha]);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -137,7 +137,7 @@ function CGColorCreateGenericRGB(red, green, blue, alpha)
|
||||
*/
|
||||
function CGColorCreateGenericCMYK(cyan, magenta, yellow, black, alpha)
|
||||
{
|
||||
return CGColorCreate(CGColorSpaceCreateDeviceCMYK(),
|
||||
return CGColorCreate(CGColorSpaceCreateDeviceCMYK(),
|
||||
[cyan, magenta, yellow, black, alpha]);
|
||||
}
|
||||
|
||||
@@ -150,7 +150,8 @@ function CGColorCreateGenericCMYK(cyan, magenta, yellow, black, alpha)
|
||||
*/
|
||||
function CGColorCreateCopyWithAlpha(aColor, anAlpha)
|
||||
{
|
||||
if ( !aColor ) return aColor; // Avoid error null pointer in next line
|
||||
if (!aColor)
|
||||
return aColor; // Avoid error null pointer in next line
|
||||
|
||||
var components = aColor.components.slice();
|
||||
|
||||
|
||||
@@ -358,7 +358,7 @@ if (CPFeatureIsCompatible(CPJavaScriptCanvasTransformFeature))
|
||||
CGContextConcatCTM = function(aContext, anAffineTransform)
|
||||
{
|
||||
aContext.transform(anAffineTransform.a, anAffineTransform.b, anAffineTransform.c, anAffineTransform.d, anAffineTransform.tx, anAffineTransform.ty);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
else
|
||||
@@ -428,7 +428,7 @@ CGContextConcatCTM = function(aContext, anAffineTransform)
|
||||
CGContextScaleCTM(aContext, sx, sy);
|
||||
if (a2 != 0.0)
|
||||
CGContextRotateCTM(aContext, a2);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -29,16 +29,16 @@ kCGGradientDrawsAfterEndLocation = 1 << 1;
|
||||
|
||||
function CGGradientCreateWithColorComponents(aColorSpace, components, locations, count)
|
||||
{
|
||||
if ( locations === undefined || locations === NULL )
|
||||
if (locations === undefined || locations === NULL)
|
||||
{
|
||||
var num_of_colors = components.length / 4,
|
||||
locations = [];
|
||||
for ( var idx = 0; idx < num_of_colors; idx++ )
|
||||
for (var idx = 0; idx < num_of_colors; idx++)
|
||||
locations.push( idx / (num_of_colors - 1) );
|
||||
}
|
||||
|
||||
if ( count === undefined || count === NULL)
|
||||
var count = locations.length;
|
||||
if (count === undefined || count === NULL)
|
||||
count = locations.length;
|
||||
|
||||
var colors = [];
|
||||
|
||||
|
||||
@@ -42,7 +42,16 @@
|
||||
#include "DOM/CPPlatformString.j"
|
||||
#else
|
||||
@implementation CPPlatformString : CPBasePlatformString
|
||||
|
||||
+ (CGSize)sizeOfString:(CPString)aString withFont:(CPFont)aFont forWidth:(float)aWidth
|
||||
{
|
||||
return _CGSizeMakeZero();
|
||||
}
|
||||
|
||||
+ (CPDictionary)metricsOfFont:(CPFont)aFont
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjectsAndKeys:0, @"ascender", 0, @"descender", 0, @"lineHeight"];
|
||||
}
|
||||
|
||||
@end
|
||||
#endif
|
||||
|
||||
@@ -32,6 +32,7 @@ var PrimaryPlatformWindow = NULL;
|
||||
CPInteger _level;
|
||||
BOOL _hasShadow;
|
||||
unsigned _shadowStyle;
|
||||
CPString _title;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
DOMWindow _DOMWindow;
|
||||
@@ -258,6 +259,22 @@ var PrimaryPlatformWindow = NULL;
|
||||
return [CPPlatform isBrowser];
|
||||
}
|
||||
|
||||
- (void)_setTitle:(CPString)aTitle window:(CPWindow)aWindow
|
||||
{
|
||||
_title = aTitle;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
if (_DOMWindow && _DOMWindow.document
|
||||
&& (aWindow === [CPApp mainWindow] || [aWindow platformWindow] !== [CPPlatformWindow primaryPlatformWindow]))
|
||||
_DOMWindow.document.title = _title;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (CPString)title
|
||||
{
|
||||
return _title;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#if PLATFORM(BROWSER)
|
||||
|
||||
@@ -49,7 +49,7 @@ var screenNeedsInitialization = NO,
|
||||
window.onunload = function()
|
||||
{
|
||||
[CPApp terminate:nil];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+ (BOOL)isBrowser
|
||||
|
||||
@@ -534,13 +534,15 @@ var ModifierKeyCodes = [
|
||||
if (_DOMWindow)
|
||||
return _DOMWindow.focus();
|
||||
|
||||
_DOMWindow = window.open("", "_blank", "menubar=no,location=no,resizable=yes,scrollbars=no,status=no,left=" + _CGRectGetMinX(_contentRect) + ",top=" + _CGRectGetMinY(_contentRect) + ",width=" + _CGRectGetWidth(_contentRect) + ",height=" + _CGRectGetHeight(_contentRect));
|
||||
_DOMWindow = window.open("about:blank", "_blank", "menubar=no,location=no,resizable=yes,scrollbars=no,status=no,left=" + _CGRectGetMinX(_contentRect) + ",top=" + _CGRectGetMinY(_contentRect) + ",width=" + _CGRectGetWidth(_contentRect) + ",height=" + _CGRectGetHeight(_contentRect));
|
||||
|
||||
[PlatformWindows addObject:self];
|
||||
|
||||
// FIXME: cpSetFrame?
|
||||
_DOMWindow.document.write("<!DOCTYPE html><html lang='en'><head></head><body style='background-color:transparent;'></body></html>");
|
||||
_DOMWindow.document.close();
|
||||
if (self != [CPPlatformWindow primaryPlatformWindow])
|
||||
_DOMWindow.document.title = _title;
|
||||
|
||||
if (![CPPlatform isBrowser])
|
||||
{
|
||||
@@ -706,7 +708,8 @@ var ModifierKeyCodes = [
|
||||
var characters;
|
||||
|
||||
// Handle key codes for which String.fromCharCode won't work.
|
||||
if (aDOMEvent.which === 0 || aDOMEvent.charCode === 0)
|
||||
// Refs #1036: In Internet Explorer, both 'which' and 'charCode' are undefined for special keys.
|
||||
if (aDOMEvent.which === 0 || aDOMEvent.charCode === 0 || (aDOMEvent.which === undefined && aDOMEvent.charCode === undefined))
|
||||
characters = KeyCodesToUnicodeMap[_keyCode];
|
||||
|
||||
if (!characters)
|
||||
@@ -1565,7 +1568,7 @@ var _CPEventFromNativeMouseEvent = function(aNativeEvent, anEventType, aPoint, m
|
||||
aNativeEvent._eventNumber = anEventNumber;
|
||||
aNativeEvent._clickCount = aClickCount;
|
||||
aNativeEvent._pressure = aPressure;
|
||||
if((anEventType == CPLeftMouseDragged) || (anEventType == CPRightMouseDragged) || (anEventType == CPMouseMoved))
|
||||
if ((anEventType == CPLeftMouseDragged) || (anEventType == CPRightMouseDragged) || (anEventType == CPMouseMoved))
|
||||
{
|
||||
aNativeEvent._deltaX = aPoint.x - aMouseDragStart.x;
|
||||
aNativeEvent._deltaY = aPoint.y - aMouseDragStart.y;
|
||||
@@ -1578,7 +1581,7 @@ var _CPEventFromNativeMouseEvent = function(aNativeEvent, anEventType, aPoint, m
|
||||
|
||||
|
||||
return aNativeEvent;
|
||||
}
|
||||
};
|
||||
|
||||
var CLICK_SPACE_DELTA = 5.0,
|
||||
CLICK_TIME_DELTA = (typeof document != "undefined" && document.addEventListener) ? 350.0 : 1000.0;
|
||||
@@ -1593,7 +1596,7 @@ var CPDOMEventGetClickCount = function(aComparisonEvent, aTimestamp, aLocation)
|
||||
return (aTimestamp - [aComparisonEvent timestamp] < CLICK_TIME_DELTA &&
|
||||
ABS(comparisonLocation.x - aLocation.x) < CLICK_SPACE_DELTA &&
|
||||
ABS(comparisonLocation.y - aLocation.y) < CLICK_SPACE_DELTA) ? [aComparisonEvent clickCount] + 1 : 1;
|
||||
}
|
||||
};
|
||||
|
||||
var CPDOMEventStop = function(aDOMEvent, aPlatformWindow)
|
||||
{
|
||||
@@ -1613,7 +1616,7 @@ var CPDOMEventStop = function(aDOMEvent, aPlatformWindow)
|
||||
aPlatformWindow._DOMFocusElement.focus();
|
||||
aPlatformWindow._DOMFocusElement.blur();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function CPWindowObjectList()
|
||||
{
|
||||
|
||||
@@ -229,4 +229,4 @@ CPKeyCodes.isCharacterKey = function(keyCode)
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
Before Width: | Height: | Size: 185 B |
|
After Width: | Height: | Size: 108 B |
|
After Width: | Height: | Size: 193 B |
|
After Width: | Height: | Size: 109 B |
|
Before Width: | Height: | Size: 161 B |
|
Before Width: | Height: | Size: 146 B After Width: | Height: | Size: 123 B |
|
After Width: | Height: | Size: 120 B |
|
After Width: | Height: | Size: 162 B |
|
After Width: | Height: | Size: 155 B |
|
Before Width: | Height: | Size: 154 B |
|
Before Width: | Height: | Size: 436 B |
|
Before Width: | Height: | Size: 452 B |
|
Before Width: | Height: | Size: 444 B After Width: | Height: | Size: 205 B |
|
After Width: | Height: | Size: 122 B |
|
After Width: | Height: | Size: 158 B |
|
After Width: | Height: | Size: 157 B |
|
Before Width: | Height: | Size: 460 B After Width: | Height: | Size: 208 B |
|
After Width: | Height: | Size: 147 B |
|
After Width: | Height: | Size: 147 B |
|
After Width: | Height: | Size: 185 B |
|
After Width: | Height: | Size: 179 B |
|
Before Width: | Height: | Size: 145 B |