mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-09-09 20:27:13 +00:00
Compare commits
2319
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb56955fff | ||
|
|
cbb7cc93e9 | ||
|
|
8b608c5cce | ||
|
|
163fb14d0e | ||
|
|
e4f87bd805 | ||
|
|
864c7d96f1 | ||
|
|
e35e87fb05 | ||
|
|
3246bdbc8b | ||
|
|
710bb5fe1c | ||
|
|
53a52da709 | ||
|
|
4afbfc6e57 | ||
|
|
f7aa9efe13 | ||
|
|
1fce0ee551 | ||
|
|
ee695f9000 | ||
|
|
8f99ebb577 | ||
|
|
5bfafaf241 | ||
|
|
64e1a2ce4b | ||
|
|
27883c5beb | ||
|
|
2772725fe3 | ||
|
|
3f58a64827 | ||
|
|
cb37c7d218 | ||
|
|
45d951071f | ||
|
|
2ac60684fa | ||
|
|
af71742110 | ||
|
|
1adf27427a | ||
|
|
082f78eefa | ||
|
|
a8a9ec0023 | ||
|
|
df4f945bc6 | ||
|
|
ad756a5b86 | ||
|
|
2ca99ba669 | ||
|
|
6443575114 | ||
|
|
52a51d81f1 | ||
|
|
7d20b06e52 | ||
|
|
ad9d8a7200 | ||
|
|
44da699343 | ||
|
|
0a542f9be9 | ||
|
|
8f1601ca55 | ||
|
|
ff0ce164da | ||
|
|
3650c38aa9 | ||
|
|
61d97338e2 | ||
|
|
e27bb4de50 | ||
|
|
4462d8bf22 | ||
|
|
f23a8ac928 | ||
|
|
9e1750ee13 | ||
|
|
5cd284cb36 | ||
|
|
5ea58430fe | ||
|
|
acfbda0d91 | ||
|
|
437e5a62f1 | ||
|
|
bbb5aea77d | ||
|
|
b5d04f84e7 | ||
|
|
93b12eb14f | ||
|
|
0aa67c4cf2 | ||
|
|
1c1affac5c | ||
|
|
0919797edc | ||
|
|
94ac8fd837 | ||
|
|
ecc82b5b51 | ||
|
|
add021fd67 | ||
|
|
2daf309d7d | ||
|
|
20be4a40ea | ||
|
|
7de91da87a | ||
|
|
b8b48b533b | ||
|
|
535f981739 | ||
|
|
0404ac0395 | ||
|
|
f961625f03 | ||
|
|
7909bae065 | ||
|
|
7e6e117b17 | ||
|
|
314e64d7b1 | ||
|
|
77eb6b358f | ||
|
|
25f86e2542 | ||
|
|
8bc0461463 | ||
|
|
c9dd1ea71d | ||
|
|
85d3529bc3 | ||
|
|
3aac8bb072 | ||
|
|
e9a7e21aca | ||
|
|
fc0e4da33c | ||
|
|
ef3c1315dd | ||
|
|
5c12890faf | ||
|
|
c4fd5e0999 | ||
|
|
d3c56d635d | ||
|
|
c53cb49034 | ||
|
|
d38463c5d9 | ||
|
|
bc4b424f0e | ||
|
|
6bd4f3b7b4 | ||
|
|
d91d83f115 | ||
|
|
584b6ab219 | ||
|
|
04b155dbfb | ||
|
|
ddc5488db7 | ||
|
|
5c6906d5fd | ||
|
|
56fee5d286 | ||
|
|
c4dcab04b6 | ||
|
|
8dd9a96769 | ||
|
|
6864015af6 | ||
|
|
ebaa60e929 | ||
|
|
ac9962c624 | ||
|
|
ccd1773643 | ||
|
|
ac970ff768 | ||
|
|
53ff45425d | ||
|
|
de435c741f | ||
|
|
1dc9a44aec | ||
|
|
0206379315 | ||
|
|
c39adbbbc5 | ||
|
|
061a15d4f7 | ||
|
|
7c2518f027 | ||
|
|
a07459454b | ||
|
|
752f9d2694 | ||
|
|
0a180f9e20 | ||
|
|
6fff2e1c2f | ||
|
|
4266900d2e | ||
|
|
a2a1d84bc0 | ||
|
|
7648c562f1 | ||
|
|
403fd30926 | ||
|
|
17ccddf541 | ||
|
|
c24366fcec | ||
|
|
9a258a6265 | ||
|
|
4542ccbdc2 | ||
|
|
41d8ad2b86 | ||
|
|
a3a2ee118e | ||
|
|
f285efc277 | ||
|
|
fbaf87ec6c | ||
|
|
a005a468a7 | ||
|
|
c8d01549ba | ||
|
|
23af4505dd | ||
|
|
53cb6a5b3e | ||
|
|
765384ace1 | ||
|
|
d39e3e2f69 | ||
|
|
d75124066e | ||
|
|
f4400876da | ||
|
|
c222c5127f | ||
|
|
90d04956e6 | ||
|
|
5d3b918339 | ||
|
|
eba0091764 | ||
|
|
7999cbbea3 | ||
|
|
cee7987b35 | ||
|
|
d475c08024 | ||
|
|
d78f83ae49 | ||
|
|
df694f01e7 | ||
|
|
f5d9cbb11b | ||
|
|
d802588abe | ||
|
|
927d6d2fc6 | ||
|
|
bab7595078 | ||
|
|
1ea9a6c57f | ||
|
|
f479d415d8 | ||
|
|
f41e7be726 | ||
|
|
c1fe28124f | ||
|
|
01a1e506e4 | ||
|
|
e61aebb55d | ||
|
|
bae5bafc62 | ||
|
|
be6cb266de | ||
|
|
6f72edc2d9 | ||
|
|
29f66bdfed | ||
|
|
c1c6f5682c | ||
|
|
a8a74a0246 | ||
|
|
f9b867c3eb | ||
|
|
6c07f9a048 | ||
|
|
573e0acafa | ||
|
|
530c664967 | ||
|
|
12c29c8387 | ||
|
|
6c7f61d90f | ||
|
|
eb6d8d0bb3 | ||
|
|
ef462973c7 | ||
|
|
aa7e49cfde | ||
|
|
186048676a | ||
|
|
0f40721cff | ||
|
|
3799dd92fd | ||
|
|
9ea1a2b1de | ||
|
|
d8b27d122e | ||
|
|
15c3a6eae4 | ||
|
|
4fcc90d53e | ||
|
|
2619a50976 | ||
|
|
de116c95d4 | ||
|
|
47594c9b07 | ||
|
|
1b9098b564 | ||
|
|
b0306eac87 | ||
|
|
125e813d25 | ||
|
|
8e0d4a70f2 | ||
|
|
0556fc68b0 | ||
|
|
e9e2313159 | ||
|
|
dbb2f03a43 | ||
|
|
ed0dc2d887 | ||
|
|
0a93f2d0b0 | ||
|
|
fd581cd65c | ||
|
|
36702bc971 | ||
|
|
0fc3eb38f1 | ||
|
|
73c8e945e9 | ||
|
|
b8420303ba | ||
|
|
532bfcf937 | ||
|
|
f6d892023e | ||
|
|
7f2977f4af | ||
|
|
e246a2753b | ||
|
|
6d06a26c31 | ||
|
|
7cda21b60f | ||
|
|
1db740039b | ||
|
|
df462774aa | ||
|
|
f55fa789c4 | ||
|
|
488541f26e | ||
|
|
b404b1cf50 | ||
|
|
69370aa806 | ||
|
|
b3ddd85b09 | ||
|
|
033221fd01 | ||
|
|
1201fa38a8 | ||
|
|
32059c376e | ||
|
|
511d393c78 | ||
|
|
237601cf29 | ||
|
|
928f14872e | ||
|
|
c6a9adf96c | ||
|
|
cdd00e0bd4 | ||
|
|
2503d13402 | ||
|
|
2d97970d24 | ||
|
|
d8945e53ba | ||
|
|
f18012d07b | ||
|
|
104f8603b9 | ||
|
|
19bb083030 | ||
|
|
ae575a19a0 | ||
|
|
5f94d0a5c2 | ||
|
|
f2fe1a7c17 | ||
|
|
618e6a1604 | ||
|
|
cef294513a | ||
|
|
8550abadef | ||
|
|
25c8b2d631 | ||
|
|
e7b690205e | ||
|
|
2403f8833a | ||
|
|
9f25743b4d | ||
|
|
f1c76f65cf | ||
|
|
7b39533410 | ||
|
|
1fe9c39dd5 | ||
|
|
2b7be2e3f1 | ||
|
|
1ee9a3f279 | ||
|
|
679acfb239 | ||
|
|
3c7ab4b49b | ||
|
|
3f062e1c0a | ||
|
|
0a497d8c3f | ||
|
|
462351f485 | ||
|
|
c4cbb631a9 | ||
|
|
76f2d15b1b | ||
|
|
5d63865ae5 | ||
|
|
ad7c88fb45 | ||
|
|
1af3877758 | ||
|
|
146ce3b12b | ||
|
|
bf67721ac4 | ||
|
|
436f736a8e | ||
|
|
1446e90dd9 | ||
|
|
54716c03d1 | ||
|
|
fad5e97e0a | ||
|
|
8cf79590c5 | ||
|
|
c6aafac6c8 | ||
|
|
94a5995197 | ||
|
|
74081dc981 | ||
|
|
7a593b13a7 | ||
|
|
25dc38b2b1 | ||
|
|
403b12f7b7 | ||
|
|
cd223be88a | ||
|
|
a6a3fca1e7 | ||
|
|
63815eb5c2 | ||
|
|
4444264830 | ||
|
|
255f91f7ca | ||
|
|
700207d29b | ||
|
|
72d96e9a3b | ||
|
|
a55b6de1b4 | ||
|
|
9faac05666 | ||
|
|
7bf408aba0 | ||
|
|
70ee391b33 | ||
|
|
f5eb1158db | ||
|
|
81916d0f45 | ||
|
|
76d77cc244 | ||
|
|
03dccbe613 | ||
|
|
1ccec65619 | ||
|
|
b78e9062a1 | ||
|
|
dc87354702 | ||
|
|
033e8583db | ||
|
|
d46b51fa9a | ||
|
|
dd1dfdcfeb | ||
|
|
c0233c803d | ||
|
|
1fa8c88f6b | ||
|
|
195b109a36 | ||
|
|
994ac3fc8e | ||
|
|
a8ec5cf5e9 | ||
|
|
b4263aa3ec | ||
|
|
6456809a72 | ||
|
|
024c0a3186 | ||
|
|
560b1d48bc | ||
|
|
bb2d860807 | ||
|
|
6f1c0fa4a8 | ||
|
|
35808e7bde | ||
|
|
1b4eeb35b3 | ||
|
|
cee032bbc9 | ||
|
|
9547b70743 | ||
|
|
5df8939d84 | ||
|
|
0b9c689273 | ||
|
|
ac193cd97a | ||
|
|
7355a60f16 | ||
|
|
fb6f6325b5 | ||
|
|
0f767d9dfc | ||
|
|
d1addcab91 | ||
|
|
7a02cd794b | ||
|
|
258cd9209f | ||
|
|
700f6022d9 | ||
|
|
a0f6b815e8 | ||
|
|
54477b8b8f | ||
|
|
6183f8d4e9 | ||
|
|
d98e247665 | ||
|
|
d0cd976246 | ||
|
|
15f6f6a90a | ||
|
|
f18074bf49 | ||
|
|
3f64b74453 | ||
|
|
1c86256f83 | ||
|
|
98105ad4dc | ||
|
|
6bf2d6c1ab | ||
|
|
cebd51aac1 | ||
|
|
42b8b3aa75 | ||
|
|
c0eaf79d25 | ||
|
|
fb2fe3eb63 | ||
|
|
184d63f7eb | ||
|
|
14ebd58c96 | ||
|
|
3edddb8e91 | ||
|
|
d2340dff1a | ||
|
|
d30c6aec7d | ||
|
|
4854b3e08f | ||
|
|
facc748090 | ||
|
|
5c71612e34 | ||
|
|
f00a5fbaf4 | ||
|
|
34769da9cc | ||
|
|
458e6ed531 | ||
|
|
05814e9351 | ||
|
|
b6c0b1b396 | ||
|
|
1a299d85b6 | ||
|
|
1816274ebe | ||
|
|
b02e4c5308 | ||
|
|
12ed42e163 | ||
|
|
6c9c135062 | ||
|
|
6aea0160df | ||
|
|
30edd9e8dd | ||
|
|
7734402e8e | ||
|
|
ace1332ca5 | ||
|
|
baa313e8f8 | ||
|
|
3d9aa24f3c | ||
|
|
c287d457d6 | ||
|
|
7537b27a58 | ||
|
|
1f560c92fc | ||
|
|
74cd11c763 | ||
|
|
ee7d89331b | ||
|
|
5b51077823 | ||
|
|
d2f94d1945 | ||
|
|
0170a099bb | ||
|
|
2b893d0ea1 | ||
|
|
a08da57cbb | ||
|
|
a313fe5a86 | ||
|
|
544de699f6 | ||
|
|
d9d35b7f50 | ||
|
|
7dbec00f0e | ||
|
|
51b9b40c7e | ||
|
|
b2383a084a | ||
|
|
61848c5e24 | ||
|
|
60b2f7d243 | ||
|
|
d2a5e126ae | ||
|
|
9d7d8ddde9 | ||
|
|
249ebeb4aa | ||
|
|
378c14d790 | ||
|
|
30c1093c2f | ||
|
|
b966c8cb0b | ||
|
|
38cddf029b | ||
|
|
6652a27781 | ||
|
|
08b067cfc5 | ||
|
|
4959b84b4c | ||
|
|
d42562fdcb | ||
|
|
1e0aacd811 | ||
|
|
329469fe84 | ||
|
|
93b0c5a7e5 | ||
|
|
9e456fd315 | ||
|
|
8203c71b03 | ||
|
|
80d1e9a9a7 | ||
|
|
3c27e57b19 | ||
|
|
b46b2f048d | ||
|
|
8d403f579c | ||
|
|
12b274ab43 | ||
|
|
986cccb800 | ||
|
|
5da8728d6c | ||
|
|
66c9a1e90a | ||
|
|
a1925e1d0b | ||
|
|
da0910b1e5 | ||
|
|
8dbbe34dfc | ||
|
|
947d552509 | ||
|
|
037bc4ea2b | ||
|
|
cfbef141d8 | ||
|
|
410ad0dc09 | ||
|
|
3d9b42f0c2 | ||
|
|
eeea21c882 | ||
|
|
d94e5480c9 | ||
|
|
a5c8e87e6d | ||
|
|
08f74201b6 | ||
|
|
3a25c683b6 | ||
|
|
fb43f8bf1a | ||
|
|
bf082600c3 | ||
|
|
7596c66703 | ||
|
|
e1bcf6c47e | ||
|
|
ef1d6c78ac | ||
|
|
f36406af08 | ||
|
|
4b7d215d9d | ||
|
|
e09f12dc0b | ||
|
|
efa7406741 | ||
|
|
5a2181c064 | ||
|
|
dda81b12da | ||
|
|
c4bf67d133 | ||
|
|
f355c8679d | ||
|
|
095864de39 | ||
|
|
0eb196e852 | ||
|
|
62e5d8d841 | ||
|
|
2f82fb842d | ||
|
|
f9fa6abbad | ||
|
|
4b55a69150 | ||
|
|
42e12fae24 | ||
|
|
2f55d5130a | ||
|
|
cd4b47b397 | ||
|
|
126cba1e94 | ||
|
|
e4e894fa54 | ||
|
|
65f701d459 | ||
|
|
c2b7cc7964 | ||
|
|
969d1dff2a | ||
|
|
e0fab808b9 | ||
|
|
77031d7082 | ||
|
|
5a0f7ea706 | ||
|
|
9d041c4b62 | ||
|
|
ec4d29c327 | ||
|
|
5f8d8988e3 | ||
|
|
a31912f710 | ||
|
|
e0d42962e7 | ||
|
|
47688bf016 | ||
|
|
39a695959d | ||
|
|
71d45a67b7 | ||
|
|
8dc1369ba3 | ||
|
|
1206654d98 | ||
|
|
1492763d0c | ||
|
|
285fafc464 | ||
|
|
b15cc59b95 | ||
|
|
55cfe31dfe | ||
|
|
dafa6e0310 | ||
|
|
4befe17cab | ||
|
|
2217b560cb | ||
|
|
39d01a1da8 | ||
|
|
4e14ad7821 | ||
|
|
aee5a2cbe4 | ||
|
|
de2d5aec1a | ||
|
|
bea03de562 | ||
|
|
0aeccbb02c | ||
|
|
4e11152e76 | ||
|
|
5059028e8a | ||
|
|
070e6cf848 | ||
|
|
4187fe7261 | ||
|
|
bdec147874 | ||
|
|
189fc76dad | ||
|
|
c0a68005d4 | ||
|
|
8187e4cdc2 | ||
|
|
cc98fd4167 | ||
|
|
422e014eff | ||
|
|
dd4e044608 | ||
|
|
13fad1ca47 | ||
|
|
70aaa29016 | ||
|
|
7dcec9afcf | ||
|
|
608642fc25 | ||
|
|
dd62c08b09 | ||
|
|
315fc21eca | ||
|
|
8cfd3aeda9 | ||
|
|
6061323c36 | ||
|
|
17da8b04bf | ||
|
|
3a948406d5 | ||
|
|
91c52f8ec8 | ||
|
|
6076bbb554 | ||
|
|
f70d3359c4 | ||
|
|
2dbfbe36c3 | ||
|
|
a25bd03566 | ||
|
|
109da1c2cc | ||
|
|
9a48e25bb1 | ||
|
|
a3ade200a9 | ||
|
|
eb1901f03d | ||
|
|
f8c7cdfc28 | ||
|
|
ea58d84b55 | ||
|
|
1360caaa81 | ||
|
|
315a7b9e6a | ||
|
|
79311d107b | ||
|
|
77435fcbd7 | ||
|
|
4395c07648 | ||
|
|
f9cc77382a | ||
|
|
e4fce08eff | ||
|
|
47196cbc55 | ||
|
|
c0bf301434 | ||
|
|
f6671f8561 | ||
|
|
26aab2961b | ||
|
|
c233abe3a4 | ||
|
|
beb3646bef | ||
|
|
eb8330a420 | ||
|
|
7f3c2176f8 | ||
|
|
1d0fdd68f4 | ||
|
|
b26c78828e | ||
|
|
85648c7f11 | ||
|
|
8588f446aa | ||
|
|
d723c5c1c7 | ||
|
|
7897f2489c | ||
|
|
86e2e0a2c3 | ||
|
|
e2349019a3 | ||
|
|
e485044cfb | ||
|
|
72d80e2857 | ||
|
|
79a4733698 | ||
|
|
c64e1daa99 | ||
|
|
d6b4933b05 | ||
|
|
bcf9cee0f8 | ||
|
|
a2960a7997 | ||
|
|
dac9874895 | ||
|
|
a4d374ecb6 | ||
|
|
3e56c8ed8b | ||
|
|
f4c11d14e7 | ||
|
|
dde805931d | ||
|
|
fedc721432 | ||
|
|
b09cb24804 | ||
|
|
80bfeb1a29 | ||
|
|
63ad51a637 | ||
|
|
5ee6232bfc | ||
|
|
b7d399faf7 | ||
|
|
28691bb8a0 | ||
|
|
fd61f35f78 | ||
|
|
0505b59781 | ||
|
|
a3601e5167 | ||
|
|
99f63ab64d | ||
|
|
bb2a9fe180 | ||
|
|
e9c7c7ee4c | ||
|
|
ff7d4f237a | ||
|
|
8bf9f8057e | ||
|
|
27b0f531d7 | ||
|
|
01e96d3086 | ||
|
|
95e7a7c8eb | ||
|
|
bbc2f4766e | ||
|
|
12dde5154f | ||
|
|
5bc3609ad7 | ||
|
|
5c1cdea3c6 | ||
|
|
3da5b3a278 | ||
|
|
9f6460ddae | ||
|
|
f1dcf85d7b | ||
|
|
7b78edf38f | ||
|
|
4a726a0c75 | ||
|
|
5afa7e9fc3 | ||
|
|
75c102f304 | ||
|
|
68f3c10055 | ||
|
|
e9aeda2a34 | ||
|
|
45c7a110b6 | ||
|
|
e438e6aedb | ||
|
|
8dd888bcbd | ||
|
|
5f12291ac4 | ||
|
|
e206d78a52 | ||
|
|
d94a82b0a7 | ||
|
|
3bee3d1701 | ||
|
|
631352e1ef | ||
|
|
f2d5dee49e | ||
|
|
2d578c7cd9 | ||
|
|
b07ff100d1 | ||
|
|
b0c10b2248 | ||
|
|
7b8249442d | ||
|
|
8221339318 | ||
|
|
b773af96b8 | ||
|
|
dbc7808c70 | ||
|
|
77c5000f16 | ||
|
|
56928b6ca0 | ||
|
|
8178dfe7bd | ||
|
|
0db6c667c6 | ||
|
|
2b0a642827 | ||
|
|
f71c0f8cb8 | ||
|
|
3782372f65 | ||
|
|
9e35e42030 | ||
|
|
7a8195e54c | ||
|
|
b50ee28693 | ||
|
|
e134f910aa | ||
|
|
17eb6e47eb | ||
|
|
82ce626d8a | ||
|
|
e063ff5e54 | ||
|
|
5aa98966bc | ||
|
|
fca2746a82 | ||
|
|
7faffc2de7 | ||
|
|
86a8a9dc85 | ||
|
|
c13a0c1c26 | ||
|
|
6ce3c070b8 | ||
|
|
e1cb11da22 | ||
|
|
c628ea34b7 | ||
|
|
33b7c726f6 | ||
|
|
6f3fd424e1 | ||
|
|
b048ce9c8e | ||
|
|
6a1040d659 | ||
|
|
fc05c28231 | ||
|
|
5d165bc6df | ||
|
|
c139b5eabb | ||
|
|
d6dd0e551d | ||
|
|
a84a7bb7c3 | ||
|
|
7195ae6e46 | ||
|
|
3c70b2f033 | ||
|
|
c46340a830 | ||
|
|
8d703b1459 | ||
|
|
f1145ef169 | ||
|
|
a28f9ceeba | ||
|
|
1927bb4798 | ||
|
|
d4c77f9786 | ||
|
|
021f8d0331 | ||
|
|
e7d25550ee | ||
|
|
8227276437 | ||
|
|
38ef76bcdc | ||
|
|
7faa0f60b4 | ||
|
|
faebbb2b8a | ||
|
|
bc9beb1e87 | ||
|
|
f161f723d7 | ||
|
|
6c94550de3 | ||
|
|
b39a45781a | ||
|
|
9273c9ee10 | ||
|
|
e6285914b0 | ||
|
|
7d2eb83a1b | ||
|
|
7e622f1153 | ||
|
|
9b30a634b1 | ||
|
|
e897d2ef81 | ||
|
|
f5b177dda8 | ||
|
|
5f51b5d565 | ||
|
|
8d7753fb40 | ||
|
|
4c6f5744d8 | ||
|
|
43eb2932ba | ||
|
|
59de0e7a4a | ||
|
|
7b204cf910 | ||
|
|
b587a19a0f | ||
|
|
e58420b031 | ||
|
|
24313d6709 | ||
|
|
7acb30b981 | ||
|
|
7454620aa2 | ||
|
|
abb0799817 | ||
|
|
aebd28dbef | ||
|
|
152db9fb8e | ||
|
|
980cd520cd | ||
|
|
373ec8b5a1 | ||
|
|
bacb78e9e8 | ||
|
|
333e112e37 | ||
|
|
818d5d782f | ||
|
|
8774090086 | ||
|
|
0ca65c6d61 | ||
|
|
c38daac646 | ||
|
|
c31f5b1d59 | ||
|
|
2320a56a63 | ||
|
|
07bd91b456 | ||
|
|
803f7c3a4b | ||
|
|
a1926982c6 | ||
|
|
b3306d50eb | ||
|
|
3e6e5f95ec | ||
|
|
df71fb42ac | ||
|
|
fe81a354a3 | ||
|
|
67ba2e49c3 | ||
|
|
8dec42f295 | ||
|
|
5942553370 | ||
|
|
ae5d31746e | ||
|
|
1c1976abbf | ||
|
|
b3465ddf89 | ||
|
|
f67fafdb8e | ||
|
|
ffcac677e0 | ||
|
|
a9d643aa55 | ||
|
|
fa3647e8e5 | ||
|
|
db839f6d6d | ||
|
|
3a85d5b89f | ||
|
|
1575c2bc10 | ||
|
|
57189183d6 | ||
|
|
01c5cf98df | ||
|
|
9ad2995168 | ||
|
|
51fc6518e1 | ||
|
|
530db4e904 | ||
|
|
cd92ebd69c | ||
|
|
5c58552d91 | ||
|
|
584aebf76b | ||
|
|
43a2480699 | ||
|
|
699503042f | ||
|
|
02e71c23de | ||
|
|
c24c3868bb | ||
|
|
5c60819668 | ||
|
|
480a125a20 | ||
|
|
598a6ebaed | ||
|
|
185ad5e747 | ||
|
|
42d7e4312b | ||
|
|
41a741724f | ||
|
|
087e811586 | ||
|
|
fa07bc143e | ||
|
|
e13f5ed730 | ||
|
|
48108cebc9 | ||
|
|
ecac17a00a | ||
|
|
3ba215887c | ||
|
|
edbc1baf32 | ||
|
|
500fa7f314 | ||
|
|
a10dfa4ab4 | ||
|
|
b208571ed7 | ||
|
|
c1ec27045c | ||
|
|
111b12161c | ||
|
|
d23d18933c | ||
|
|
f0e736962d | ||
|
|
b12d1491d4 | ||
|
|
6d1a094b15 | ||
|
|
88d14792a4 | ||
|
|
7780a98abe | ||
|
|
a1248db3e7 | ||
|
|
6fd2d12d3f | ||
|
|
9fab52c044 | ||
|
|
a32f55d64e | ||
|
|
96d2b001ea | ||
|
|
e38d6c9f9e | ||
|
|
be129d243b | ||
|
|
c85355986b | ||
|
|
310c0e8379 | ||
|
|
f0dbffe4f8 | ||
|
|
598a482538 | ||
|
|
a995f3ab52 | ||
|
|
ec5454de44 | ||
|
|
ec55bddbd4 | ||
|
|
808591df56 | ||
|
|
96ae3da1e0 | ||
|
|
4f13df69c7 | ||
|
|
6d305e4a84 | ||
|
|
d3dab982a1 | ||
|
|
2f6adbae3c | ||
|
|
ccdc1eed5a | ||
|
|
65dee154f7 | ||
|
|
662db009de | ||
|
|
d07d8f6857 | ||
|
|
0327f6b1ea | ||
|
|
16dea2ee09 | ||
|
|
5e3fe139fc | ||
|
|
55d41fca05 | ||
|
|
0b7bb29557 | ||
|
|
6b683bd02d | ||
|
|
8f1a498953 | ||
|
|
293ed9065d | ||
|
|
8908fb7ee0 | ||
|
|
2877178b34 | ||
|
|
d527139f48 | ||
|
|
b3d8180541 | ||
|
|
3411c340ab | ||
|
|
4482089712 | ||
|
|
c8ce2343d7 | ||
|
|
d547d04277 | ||
|
|
8f1191733b | ||
|
|
00bdbcf857 | ||
|
|
bf8070c42d | ||
|
|
346a0b84ae | ||
|
|
ad48381744 | ||
|
|
0f30d7744d | ||
|
|
095a978120 | ||
|
|
1b72646772 | ||
|
|
a7b129147f | ||
|
|
6496a6643f | ||
|
|
e172217427 | ||
|
|
8c67eee4c8 | ||
|
|
ca9039b8d5 | ||
|
|
e260632a45 | ||
|
|
678f4fca8a | ||
|
|
5d88d07edc | ||
|
|
08aa591c65 | ||
|
|
f2a8edb29f | ||
|
|
50d7e8dc3d | ||
|
|
8403e36d4d | ||
|
|
2dda326cc4 | ||
|
|
9002a8db04 | ||
|
|
5ec5198dda | ||
|
|
0326b7d7ac | ||
|
|
2f5e7f3b2d | ||
|
|
0e17658269 | ||
|
|
87edda5972 | ||
|
|
ab8c3c2b75 | ||
|
|
44cef002ed | ||
|
|
bc80fe693a | ||
|
|
1898b51dc2 | ||
|
|
a5dcf5958e | ||
|
|
9fba72cbab | ||
|
|
912fdeaf09 | ||
|
|
36c417458d | ||
|
|
f1591e593a | ||
|
|
117ac0f5d6 | ||
|
|
e72a42fd2d | ||
|
|
e6e2f4c22c | ||
|
|
07b6e2b9f1 | ||
|
|
5ab10f4024 | ||
|
|
0ac08456bc | ||
|
|
80a3549ef5 | ||
|
|
770d5eb257 | ||
|
|
b32499f6ec | ||
|
|
d9819d8b3d | ||
|
|
932b825818 | ||
|
|
a0cbc5822e | ||
|
|
2ab50c6b61 | ||
|
|
d7426f6d35 | ||
|
|
8f15266f0a | ||
|
|
936c7190c7 | ||
|
|
3452984b8e | ||
|
|
3e17890528 | ||
|
|
2a7c50d356 | ||
|
|
05bca368c2 | ||
|
|
89c78f6030 | ||
|
|
b59b0259ca | ||
|
|
e46e1b20de | ||
|
|
7089abcef2 | ||
|
|
e6148a97a3 | ||
|
|
9e40033a92 | ||
|
|
08d4e19851 | ||
|
|
dcc0768411 | ||
|
|
f14062c721 | ||
|
|
0508b70658 | ||
|
|
04f8545397 | ||
|
|
633f985360 | ||
|
|
a649a6ebac | ||
|
|
634a8b4532 | ||
|
|
f3709a41e3 | ||
|
|
2bfebfee3c | ||
|
|
76ab5fbf78 | ||
|
|
c0b0c74638 | ||
|
|
6c0b771758 | ||
|
|
2f983fc305 | ||
|
|
3cf0d60f5d | ||
|
|
751e76b453 | ||
|
|
c2f95f7953 | ||
|
|
924b994df2 | ||
|
|
b10de5e82c | ||
|
|
65ffce8db2 | ||
|
|
58aeb2e40f | ||
|
|
141d737ca5 | ||
|
|
d0fd53a2ca | ||
|
|
3e0a6ea2cf | ||
|
|
758ad3eb06 | ||
|
|
b132a66707 | ||
|
|
f241f12ddb | ||
|
|
e1daf9467c | ||
|
|
5457ddb44f | ||
|
|
6fee13b0a5 | ||
|
|
2b17e173f5 | ||
|
|
569d4a5d8b | ||
|
|
51a88a23ac | ||
|
|
f41504ca57 | ||
|
|
bacb7018cb | ||
|
|
671ed3c2fe | ||
|
|
372e994617 | ||
|
|
e4560df62f | ||
|
|
920daf7fde | ||
|
|
ad1a15faaa | ||
|
|
459cf2e380 | ||
|
|
8d058a53fd | ||
|
|
d864ae9fef | ||
|
|
f1eeb61264 | ||
|
|
1418dd8b29 | ||
|
|
0297980ca3 | ||
|
|
5e94aaa2cb | ||
|
|
b929a8fe2e | ||
|
|
8c2f0bacf1 | ||
|
|
0bc02de012 | ||
|
|
411a282063 | ||
|
|
6c4d55622b | ||
|
|
e214bf3581 | ||
|
|
78e29d2bbf | ||
|
|
a93c10b794 | ||
|
|
3240d6f11a | ||
|
|
d5f38fe2f2 | ||
|
|
d4b1680727 | ||
|
|
b04e5760fb | ||
|
|
42c629ca45 | ||
|
|
68f45beb20 | ||
|
|
ea95897bbd | ||
|
|
4d1dc0c949 | ||
|
|
9fc892f723 | ||
|
|
5541381afe | ||
|
|
ed12bae6aa | ||
|
|
1520c1ebab | ||
|
|
790190e5c3 | ||
|
|
24889f7dcd | ||
|
|
8397685430 | ||
|
|
fc411c5c1c | ||
|
|
3a91f43bbb | ||
|
|
5e1f1675b8 | ||
|
|
9946987f69 | ||
|
|
526181a76b | ||
|
|
ce8f8c05e1 | ||
|
|
3844b88f7e | ||
|
|
db3c232173 | ||
|
|
22b77af9d3 | ||
|
|
3e29732e46 | ||
|
|
54e1efd794 | ||
|
|
8809c1634f | ||
|
|
13e1be1f74 | ||
|
|
26a123f5a8 | ||
|
|
f062fda2f7 | ||
|
|
e45e31d223 | ||
|
|
101261ca63 | ||
|
|
4ba9a19b5c | ||
|
|
f8eab7d611 | ||
|
|
40a9f19352 | ||
|
|
4b81e0d8af | ||
|
|
ea37bf8b45 | ||
|
|
c30f8b09b0 | ||
|
|
686f931fb4 | ||
|
|
1fe1e6f265 | ||
|
|
860decdac5 | ||
|
|
d5b90c91f5 | ||
|
|
20d6e365a1 | ||
|
|
e5e50c2220 | ||
|
|
e8da7baee2 | ||
|
|
8ab9e6bac7 | ||
|
|
9129301c89 | ||
|
|
9545e0145f | ||
|
|
15d3e4023b | ||
|
|
205e4dedd1 | ||
|
|
324d796aca | ||
|
|
5b31e8e9d8 | ||
|
|
0afb62ee88 | ||
|
|
1b0d053ab9 | ||
|
|
5871c4f092 | ||
|
|
5d415e6679 | ||
|
|
3a7384ec26 | ||
|
|
1d3a8bcacd | ||
|
|
dd187aef08 | ||
|
|
78b2c4d094 | ||
|
|
32b7a314b1 | ||
|
|
c8d768c59a | ||
|
|
3ef1c9167f | ||
|
|
36cdcbc3c1 | ||
|
|
83876532d0 | ||
|
|
edc824d05e | ||
|
|
9a7869dd40 | ||
|
|
1aa247d4da | ||
|
|
5db9f28b33 | ||
|
|
8599ad4a3c | ||
|
|
448c2a27d4 | ||
|
|
f2f4fa1b98 | ||
|
|
6f43a189c0 | ||
|
|
dd4de9822f | ||
|
|
c9e83e0517 | ||
|
|
4ac63950ad | ||
|
|
7a0b2c958b | ||
|
|
3fcc37e086 | ||
|
|
55181cec8c | ||
|
|
41d259006e | ||
|
|
93e8ec7f06 | ||
|
|
ba1d1c3bac | ||
|
|
fbaff2b75b | ||
|
|
9774e8807b | ||
|
|
b30103c790 | ||
|
|
bb9408b5d0 | ||
|
|
42c3c7bc48 | ||
|
|
464040895c | ||
|
|
525747dc53 | ||
|
|
c61d992559 | ||
|
|
2f79b079fd | ||
|
|
655bc39d85 | ||
|
|
1eb12d4fa0 | ||
|
|
2ab9186259 | ||
|
|
ab61aef985 | ||
|
|
65b3e9f8c1 | ||
|
|
1f57aa1ea5 | ||
|
|
340d827377 | ||
|
|
5cd25e24e4 | ||
|
|
58afc92a26 | ||
|
|
acb9931fe6 | ||
|
|
d4b035ac1a | ||
|
|
403dd5c005 | ||
|
|
7e4e1ec68f | ||
|
|
547764e3c1 | ||
|
|
541a7974e0 | ||
|
|
6bf6f82cad | ||
|
|
7be2325a95 | ||
|
|
fa1f739458 | ||
|
|
20289ff81b | ||
|
|
6d67d30aee | ||
|
|
bd0bd2e087 | ||
|
|
3d79799450 | ||
|
|
c99f9205b7 | ||
|
|
26bb54472f | ||
|
|
73e13fee37 | ||
|
|
205c1ac3b6 | ||
|
|
d317744f05 | ||
|
|
47611b7615 | ||
|
|
6420a51dd0 | ||
|
|
7c17d5bac0 | ||
|
|
0efd7c93c5 | ||
|
|
806be9551c | ||
|
|
b4dd3a9889 | ||
|
|
6b4a1b6758 | ||
|
|
4510b69798 | ||
|
|
84a3ee209a | ||
|
|
d6b0fccbda | ||
|
|
d1e31da2e5 | ||
|
|
923d32ee6d | ||
|
|
4b0fe879cb | ||
|
|
b87aeffcd8 | ||
|
|
88aafec6e3 | ||
|
|
6fe9dae3d6 | ||
|
|
2cb6ddf3ca | ||
|
|
799622a932 | ||
|
|
4c1e22b0f6 | ||
|
|
2283652704 | ||
|
|
33fb2daabf | ||
|
|
c79f59ec05 | ||
|
|
845aaad891 | ||
|
|
3c0b061220 | ||
|
|
af7de73f5c | ||
|
|
1a8a9f0047 | ||
|
|
a3b4e8db44 | ||
|
|
f9e8875803 | ||
|
|
e4c11d9a88 | ||
|
|
6d1d8da101 | ||
|
|
77303e668f | ||
|
|
72725b91c7 | ||
|
|
46f50f55c2 | ||
|
|
5e880f6bfa | ||
|
|
058a73f8a0 | ||
|
|
1ad8d34ecb | ||
|
|
3f9f926c8e | ||
|
|
80cf88dcc1 | ||
|
|
dddc7f348f | ||
|
|
ce45f2e114 | ||
|
|
d22a7c0a63 | ||
|
|
59162155de | ||
|
|
0f347cd0b4 | ||
|
|
1f983db47c | ||
|
|
dc50793733 | ||
|
|
b98329f91c | ||
|
|
587d8fbfa9 | ||
|
|
26a2e9ef53 | ||
|
|
e5ca98a1d3 | ||
|
|
5bd5e9000e | ||
|
|
d566642c98 | ||
|
|
f81ddc60ec | ||
|
|
6e0b20c921 | ||
|
|
0c308b38c5 | ||
|
|
8e0fdf68e4 | ||
|
|
9c7a9b5674 | ||
|
|
0a49e31b30 | ||
|
|
9478206202 | ||
|
|
c86e6f5b88 | ||
|
|
87868acecd | ||
|
|
6d877754da | ||
|
|
dd5521a07c | ||
|
|
3a6a84917b | ||
|
|
cca142ce86 | ||
|
|
fa3567cb9f | ||
|
|
7d22230b13 | ||
|
|
9694c796e3 | ||
|
|
1b7f684ab2 | ||
|
|
fef8f4d29c | ||
|
|
0d7e945623 | ||
|
|
13ea8eae77 | ||
|
|
cdb2ef3ac7 | ||
|
|
f216e0198f | ||
|
|
c5c3698f43 | ||
|
|
299d3b9f60 | ||
|
|
eaaebeaebb | ||
|
|
2ef2d2b9c5 | ||
|
|
da6698b216 | ||
|
|
c9f391dfc1 | ||
|
|
0f62926623 | ||
|
|
a856b4027b | ||
|
|
e2f72ecffc | ||
|
|
d888bcd473 | ||
|
|
0bfd5fa9a3 | ||
|
|
9c05ccef69 | ||
|
|
c7eb2ffe5c | ||
|
|
5281b6df77 | ||
|
|
cd5bb6a309 | ||
|
|
94a44d7af4 | ||
|
|
662050b89f | ||
|
|
3f7f3140eb | ||
|
|
a419694f70 | ||
|
|
0a20f77b08 | ||
|
|
dc11d18161 | ||
|
|
cde83e9d7d | ||
|
|
1476fda014 | ||
|
|
7a875f2db4 | ||
|
|
b868f37da5 | ||
|
|
9bef5a62dd | ||
|
|
d1aff30c9e | ||
|
|
a356dafde0 | ||
|
|
09477384fe | ||
|
|
6b923542e8 | ||
|
|
9722cf718c | ||
|
|
702b973c87 | ||
|
|
472372c9ed | ||
|
|
d358f0d27b | ||
|
|
d66bbd95f0 | ||
|
|
aae498509b | ||
|
|
4987fb5f15 | ||
|
|
b1ed299286 | ||
|
|
679ac3e5b1 | ||
|
|
181ef788a3 | ||
|
|
d2caa0953f | ||
|
|
3f88e02587 | ||
|
|
245da9b422 | ||
|
|
8cc075aff3 | ||
|
|
128a243166 | ||
|
|
0e41365020 | ||
|
|
bd6d5ffbb9 | ||
|
|
de7951f4db | ||
|
|
bdbf1fbb43 | ||
|
|
a7b6010ce2 | ||
|
|
5bba109873 | ||
|
|
d69ae60bcb | ||
|
|
a0277aba2e | ||
|
|
caba631db9 | ||
|
|
5095620005 | ||
|
|
abcdc0875c | ||
|
|
a4e41a57d7 | ||
|
|
e8bb3864e3 | ||
|
|
3e03d52fce | ||
|
|
4f64d466fb | ||
|
|
3102c545ce | ||
|
|
3cd1066a8d | ||
|
|
6494b7ea89 | ||
|
|
f232b327c0 | ||
|
|
204ed1f257 | ||
|
|
2f5d13ac10 | ||
|
|
65a379c8da | ||
|
|
99df5fadbc | ||
|
|
c8e6dca263 | ||
|
|
9dec40eca7 | ||
|
|
92cdb27e23 | ||
|
|
4896043599 | ||
|
|
5f0ddeedd0 | ||
|
|
e679e760ee | ||
|
|
a439688b3c | ||
|
|
0d17757729 | ||
|
|
899bbc2dbc | ||
|
|
57b68880db | ||
|
|
06c59763bc | ||
|
|
71c1d16c06 | ||
|
|
64c1b72481 | ||
|
|
e5742e057d | ||
|
|
a9d6176fd2 | ||
|
|
1b0aa2a9b1 | ||
|
|
a49c230bb2 | ||
|
|
b65749cf70 | ||
|
|
0cf54a6a03 | ||
|
|
4d77277f2d | ||
|
|
8b81506ed3 | ||
|
|
24c6509a61 | ||
|
|
3c32c4160d | ||
|
|
1f912d86e1 | ||
|
|
9c93ab0b6d | ||
|
|
6646a20a5d | ||
|
|
92f471c476 | ||
|
|
4c7ce97650 | ||
|
|
4d1fc994c0 | ||
|
|
c4310c554e | ||
|
|
c603326e58 | ||
|
|
a93e04a44e | ||
|
|
db9e649f6e | ||
|
|
c26aca4686 | ||
|
|
f822268ae1 | ||
|
|
4ebcf40619 | ||
|
|
a884b94ac0 | ||
|
|
194e705982 | ||
|
|
c77ec3bf20 | ||
|
|
0a1857249b | ||
|
|
3be3a1f2e6 | ||
|
|
62f9488829 | ||
|
|
9bcaef192c | ||
|
|
bcb1630f20 | ||
|
|
5f7922d7fd | ||
|
|
66b1d297ba | ||
|
|
eb4780a952 | ||
|
|
34f724a4a4 | ||
|
|
c5b250236f | ||
|
|
e5b122ee61 | ||
|
|
3b20021981 | ||
|
|
a7d1f180a4 | ||
|
|
68374e7c62 | ||
|
|
ba26a97ddc | ||
|
|
2db7ce8da1 | ||
|
|
6958da1adb | ||
|
|
cf48cd0ae5 | ||
|
|
b1b3966d41 | ||
|
|
c171a37f24 | ||
|
|
c13f1991c9 | ||
|
|
da15cc4de7 | ||
|
|
44c686f494 | ||
|
|
03bd5ad426 | ||
|
|
914a3d71c2 | ||
|
|
5c2e0935c6 | ||
|
|
e1ec604655 | ||
|
|
0dad10d6ab | ||
|
|
136138daab | ||
|
|
6efe563a69 | ||
|
|
fd068443aa | ||
|
|
82d0f62d73 | ||
|
|
01ba6ddecd | ||
|
|
769b379a8b | ||
|
|
1b981e0695 | ||
|
|
9798b9fd50 | ||
|
|
10792c0bc6 | ||
|
|
1c61afd3ee | ||
|
|
737ef583ee | ||
|
|
7b4365bd8a | ||
|
|
041fce743e | ||
|
|
ad4904a0ec | ||
|
|
42a1bca64d | ||
|
|
492a5bbb38 | ||
|
|
c40ef22c20 | ||
|
|
783aac561a | ||
|
|
02245c150c | ||
|
|
54a93775e4 | ||
|
|
ca778aac70 | ||
|
|
007ca4c6b0 | ||
|
|
b3dfce7b5a | ||
|
|
c75f1685c5 | ||
|
|
db5b103ab3 | ||
|
|
1925b7b324 | ||
|
|
d39bcfb7bd | ||
|
|
c7770c37d0 | ||
|
|
ca2fb81247 | ||
|
|
b2f1c9e832 | ||
|
|
cff4eebb74 | ||
|
|
a3aab5aeca | ||
|
|
63e5d8f7ea | ||
|
|
e4df7b10f6 | ||
|
|
f39a1e7d03 | ||
|
|
a473f6aa16 | ||
|
|
6907c24690 | ||
|
|
ef3d8a9277 | ||
|
|
1a183b7f17 | ||
|
|
88f7b30128 | ||
|
|
4b38389dc8 | ||
|
|
865a45044f | ||
|
|
7378d06bfd | ||
|
|
55e19de8a1 | ||
|
|
4d7cb06481 | ||
|
|
7179a2995d | ||
|
|
2b853df75b | ||
|
|
ae6bcc2987 | ||
|
|
ed61e5c7f7 | ||
|
|
3581ac5ebd | ||
|
|
1f369b47d7 | ||
|
|
bb9049bef4 | ||
|
|
94f15aba40 | ||
|
|
b16b8388ef | ||
|
|
b1e89e7904 | ||
|
|
f48e2f3b18 | ||
|
|
bd673a3f26 | ||
|
|
51ec699649 | ||
|
|
ed6be510fb | ||
|
|
55f05ba839 | ||
|
|
17c9382a21 | ||
|
|
43c0eda2be | ||
|
|
f2c5515317 | ||
|
|
c1441eb758 | ||
|
|
cf92fb921d | ||
|
|
559ca3e97b | ||
|
|
7c095175ab | ||
|
|
3b2635014c | ||
|
|
755040444a | ||
|
|
59afb012b6 | ||
|
|
7d9a52301c | ||
|
|
50a53181dc | ||
|
|
36f6fec99f | ||
|
|
83eeb488f9 | ||
|
|
5394a35e1a | ||
|
|
0cd68ff8f8 | ||
|
|
e9ae8063db | ||
|
|
1c4e23512b | ||
|
|
51bdfa44b1 | ||
|
|
98d0a397a3 | ||
|
|
1dc060123d | ||
|
|
14349cb583 | ||
|
|
eca959034c | ||
|
|
9844550d6c | ||
|
|
82fcf08d84 | ||
|
|
845a35a9b8 | ||
|
|
0e4751ebee | ||
|
|
56badd44f3 | ||
|
|
399b3fd198 | ||
|
|
43a7ca7fe8 | ||
|
|
b951624ed3 | ||
|
|
1b21f2d1c7 | ||
|
|
43ea0effa2 | ||
|
|
6df9b95dea | ||
|
|
630aa53d98 | ||
|
|
40c81b88d4 | ||
|
|
027a317291 | ||
|
|
81b538556d | ||
|
|
6aece1cf8c | ||
|
|
cd7b9d31c9 | ||
|
|
03a6e6fc6a | ||
|
|
1d1aae03f3 | ||
|
|
b47ad50d42 | ||
|
|
a924fd0e7e | ||
|
|
82ae908e6a | ||
|
|
8e497e2a48 | ||
|
|
cbb4565a48 | ||
|
|
471fbee090 | ||
|
|
d66de937d9 | ||
|
|
3ea230fd17 | ||
|
|
34bc571f80 | ||
|
|
db46804bfe | ||
|
|
2bd0faac2e | ||
|
|
a9a6e58d60 | ||
|
|
b40f980c62 | ||
|
|
12ac781ef8 | ||
|
|
8373ffbf10 | ||
|
|
0233dca884 | ||
|
|
c1a3162a54 | ||
|
|
fc2f5c3615 | ||
|
|
3a5ac9df10 | ||
|
|
63f634af00 | ||
|
|
9cb3eefdc4 | ||
|
|
1c9e9da10f | ||
|
|
71c0ba63ca | ||
|
|
c04d3b2ace | ||
|
|
e8497bb0cc | ||
|
|
3430349dd1 | ||
|
|
fa6a5f75af | ||
|
|
7b9eb4c87c | ||
|
|
808411bc0b | ||
|
|
c3ab510b57 | ||
|
|
cbc653be37 | ||
|
|
e9efe5bbb7 | ||
|
|
a7c234b272 | ||
|
|
bb64d0dd54 | ||
|
|
f82b478a77 | ||
|
|
2028642efe | ||
|
|
9af9bd0c4c | ||
|
|
662bf83a88 | ||
|
|
2d474ccbda | ||
|
|
cec746d632 | ||
|
|
8371ac5b0d | ||
|
|
f248788d14 | ||
|
|
bf202f25dd | ||
|
|
2d2472dbe9 | ||
|
|
3adfa3c2a8 | ||
|
|
bf05155c5e | ||
|
|
d50df6a6fc | ||
|
|
a2b38c8d05 | ||
|
|
d546da8b5f | ||
|
|
7c60ffa88d | ||
|
|
6b235ab083 | ||
|
|
7c4cdef66d | ||
|
|
c0a2da443a | ||
|
|
e53658759b | ||
|
|
6dc4c1c03a | ||
|
|
818c3b6092 | ||
|
|
6e5dee13e1 | ||
|
|
cae78622f6 | ||
|
|
c5db677663 | ||
|
|
c6942daf74 | ||
|
|
ea644a2293 | ||
|
|
01e69ce2b0 | ||
|
|
187a017c4d | ||
|
|
f9ce1d17c8 | ||
|
|
ef4cd6a4a7 | ||
|
|
6a1543cb82 | ||
|
|
80c8dcacb3 | ||
|
|
0ad2dea722 | ||
|
|
dec3c45f6c | ||
|
|
32a73ad4b9 | ||
|
|
452e03b894 | ||
|
|
01bdddaee4 | ||
|
|
f7c82b0920 | ||
|
|
820eeb7752 | ||
|
|
2e25ef6f81 | ||
|
|
5736d2c9cc | ||
|
|
056a1f6a33 | ||
|
|
f96e211cd6 | ||
|
|
0d473cbe18 | ||
|
|
95514b05ca | ||
|
|
a2c0b47908 | ||
|
|
f2528b5e9a | ||
|
|
02f301dae0 | ||
|
|
6c47fc9023 | ||
|
|
f03adf727b | ||
|
|
77684dfe31 | ||
|
|
ee688d9ae4 | ||
|
|
9b16d3624e | ||
|
|
dc622a9bd5 | ||
|
|
2fc75be3dd | ||
|
|
eb883bc51e | ||
|
|
fdc5ed93fc | ||
|
|
148960eecd | ||
|
|
0265fc36fa | ||
|
|
f4c2a0a7f8 | ||
|
|
de3eb861ed | ||
|
|
f5b64b4958 | ||
|
|
20eb59d9b6 | ||
|
|
ca1bb8e634 | ||
|
|
6213c098ce | ||
|
|
31023a1a71 | ||
|
|
b963b9547b | ||
|
|
fa4c0af78d | ||
|
|
ef0e0432a7 | ||
|
|
d16f2b54fe | ||
|
|
a3a3da309c | ||
|
|
fa7b71cabe | ||
|
|
d3490f6a2e | ||
|
|
82dc126952 | ||
|
|
6f90e765d4 | ||
|
|
b1382e8e89 | ||
|
|
0fb739935f | ||
|
|
e49a9f1f06 | ||
|
|
0f5dd99167 | ||
|
|
2f9f3db198 | ||
|
|
00ebc265d8 | ||
|
|
5995b42872 | ||
|
|
9edb0abda0 | ||
|
|
eaa966e72b | ||
|
|
a48df23252 | ||
|
|
3aa8eb9533 | ||
|
|
3ddd1d5f21 | ||
|
|
ea15f0690c | ||
|
|
8751ef7439 | ||
|
|
8c393e3144 | ||
|
|
a3ef2a43ac | ||
|
|
d2b3029f67 | ||
|
|
3e800ec7c8 | ||
|
|
47d963b585 | ||
|
|
397ae3407e | ||
|
|
e407eeea40 | ||
|
|
873232d560 | ||
|
|
47cced540e | ||
|
|
5b4bddc2e0 | ||
|
|
cd511da678 | ||
|
|
c4fbef2dd3 | ||
|
|
92b997fb78 | ||
|
|
05d602c313 | ||
|
|
e1d92bd630 | ||
|
|
373951a75e | ||
|
|
f17898d43d | ||
|
|
129eef79a3 | ||
|
|
e3988e7b84 | ||
|
|
9174338140 | ||
|
|
3f9e2d5d39 | ||
|
|
31449552d1 | ||
|
|
642dc36c41 | ||
|
|
1016c3e22f | ||
|
|
b74d49b0bf | ||
|
|
8b29369b7e | ||
|
|
cb5fe06e58 | ||
|
|
4ebb2baf06 | ||
|
|
0f4a938dfc | ||
|
|
2a16fb5e09 | ||
|
|
c22cf71099 | ||
|
|
c739718710 | ||
|
|
2db9fd9657 | ||
|
|
56b613ff8a | ||
|
|
cd2e9e29d4 | ||
|
|
d1917db47e | ||
|
|
8024f6a804 | ||
|
|
46a0ce8e98 | ||
|
|
c7ccff914f | ||
|
|
8efb6f8808 | ||
|
|
006bf72c17 | ||
|
|
ec3af04f29 | ||
|
|
b45399a045 | ||
|
|
12ed70fec2 | ||
|
|
c3ce0a61b6 | ||
|
|
526e0725d8 | ||
|
|
7e4e0567ef | ||
|
|
ee13978115 | ||
|
|
f5d847f320 | ||
|
|
1df0da7509 | ||
|
|
e4bfd0ef5e | ||
|
|
2e66601c19 | ||
|
|
2484fb85e9 | ||
|
|
5f2fee5a99 | ||
|
|
b2557c38dd | ||
|
|
56acbfc85c | ||
|
|
77f962eed4 | ||
|
|
18a6ecc79a | ||
|
|
c3fc6a087a | ||
|
|
02a47dc7b9 | ||
|
|
30413e6f8f | ||
|
|
6ed7354884 | ||
|
|
94f89acc84 | ||
|
|
392a6cfbca | ||
|
|
e03b6b3824 | ||
|
|
51940cea3d | ||
|
|
5ab346e5d1 | ||
|
|
243024e232 | ||
|
|
e62fd4dc00 | ||
|
|
547522a0a4 | ||
|
|
4fd3ce606a | ||
|
|
ad364b6184 | ||
|
|
3269ba10ec | ||
|
|
b0a7fe4079 | ||
|
|
31afae71d1 | ||
|
|
e7ae969c8e | ||
|
|
fc5bb7417f | ||
|
|
81e6c5c2fa | ||
|
|
e9f73cbb45 | ||
|
|
b36cc8f1e9 | ||
|
|
6f6938deb7 | ||
|
|
b63bddacb0 | ||
|
|
b1d56924e6 | ||
|
|
85d80e7ca0 | ||
|
|
d481d9cca5 | ||
|
|
fe25dbd872 | ||
|
|
0dcc645f22 | ||
|
|
f3090e7827 | ||
|
|
37b9895878 | ||
|
|
d5b4d66272 | ||
|
|
653f706f1b | ||
|
|
d106e6485b | ||
|
|
460a60440a | ||
|
|
9e66c699e1 | ||
|
|
86d2431925 | ||
|
|
d30659c37c | ||
|
|
1402133c32 | ||
|
|
5a99e18d7c | ||
|
|
afe326c1c1 | ||
|
|
e40612a032 | ||
|
|
9c6cca7db6 | ||
|
|
a5283a26ab | ||
|
|
e2020fa7f2 | ||
|
|
de3f6d3e82 | ||
|
|
e7cde2ca5f | ||
|
|
0c7b2ae702 | ||
|
|
1c822901e2 | ||
|
|
0cafb3fac5 | ||
|
|
d8718cc20f | ||
|
|
c484e4afe5 | ||
|
|
e155cca65e | ||
|
|
5cad5b095a | ||
|
|
2dff805d40 | ||
|
|
0afd65539f | ||
|
|
664d5777fd | ||
|
|
9a307269ca | ||
|
|
ab2657b795 | ||
|
|
57d435b6db | ||
|
|
de2e77cc86 | ||
|
|
ee5e22c574 | ||
|
|
1ce6a630d2 | ||
|
|
aee89b1f63 | ||
|
|
0f791be195 | ||
|
|
45248bcb65 | ||
|
|
3c092f36cb | ||
|
|
9a5afb70b5 | ||
|
|
f9275a70af | ||
|
|
8ee443a43c | ||
|
|
26223bb383 | ||
|
|
ea0c5e291f | ||
|
|
8ef7cacdda | ||
|
|
6d956c6138 | ||
|
|
b028e62731 | ||
|
|
fc43ec8185 | ||
|
|
491b5dcd6f | ||
|
|
02bbe0e6f5 | ||
|
|
b827b7ffce | ||
|
|
459374db1c | ||
|
|
97a65059e5 | ||
|
|
d629f4b501 | ||
|
|
f486c02b5e | ||
|
|
d63669ac22 | ||
|
|
ad82b0064a | ||
|
|
58f2d7117a | ||
|
|
735b0f8593 | ||
|
|
2bf012100a | ||
|
|
7abcc42a42 | ||
|
|
4d77e7dd6b | ||
|
|
5678fe3b83 | ||
|
|
f74888419c | ||
|
|
f21dcb8265 | ||
|
|
5bd07716eb | ||
|
|
db63c91f99 | ||
|
|
c37f0cfaa9 | ||
|
|
9621d76faa | ||
|
|
32c252393a | ||
|
|
ef5d1d6e58 | ||
|
|
660d36e001 | ||
|
|
2cc67f23ab | ||
|
|
6fe3054738 | ||
|
|
7811521c08 | ||
|
|
96135c9875 | ||
|
|
0038eab6ab | ||
|
|
a34e8fbc9a | ||
|
|
0399b3daed | ||
|
|
64a15db791 | ||
|
|
49cb446f8b | ||
|
|
82c32d7dee | ||
|
|
9c87c36644 | ||
|
|
be9f5ad951 | ||
|
|
d065a0cbc4 | ||
|
|
02dfa638ca | ||
|
|
bd71e779c3 | ||
|
|
bfd0ceac53 | ||
|
|
ba20936c17 | ||
|
|
4b058a8c56 | ||
|
|
49ba0cab27 | ||
|
|
b9c4f888b9 | ||
|
|
09e3c5ecfc | ||
|
|
b180f06c2a | ||
|
|
90345addce | ||
|
|
328172cfeb | ||
|
|
a75e5d914c | ||
|
|
a783479306 | ||
|
|
ecb557daa5 | ||
|
|
d5e811f9f1 | ||
|
|
3e5a6986f9 | ||
|
|
8e346f18bf | ||
|
|
34c7dededf | ||
|
|
e56cc85e96 | ||
|
|
8d660ff386 | ||
|
|
2e3c658bc8 | ||
|
|
7af50c3951 | ||
|
|
0bbada27f3 | ||
|
|
fcd2b778ea | ||
|
|
cbef08eeff | ||
|
|
6d3f430b24 | ||
|
|
e4516c19d3 | ||
|
|
8eb52f9a88 | ||
|
|
f2956670cd | ||
|
|
18d83b8c50 | ||
|
|
5b7afd72e3 | ||
|
|
643566bbfd | ||
|
|
5e0e61b7e5 | ||
|
|
608480c1d2 | ||
|
|
5979baa874 | ||
|
|
fc2e16dd4e | ||
|
|
73a2823d0b | ||
|
|
804ffb826d | ||
|
|
4bcbe577c6 | ||
|
|
2b1b858776 | ||
|
|
8089f52744 | ||
|
|
3aaa887d68 | ||
|
|
b617d60b60 | ||
|
|
321a5533df | ||
|
|
921fcbdcd0 | ||
|
|
06d0357f74 | ||
|
|
2f7681f881 | ||
|
|
e156badef6 | ||
|
|
ae6d379cce | ||
|
|
a822ec729a | ||
|
|
38370c7f2e | ||
|
|
37f65eb3dd | ||
|
|
9347ce2ede | ||
|
|
c4a839f47a | ||
|
|
43f7dcd08f | ||
|
|
71bfe4dd44 | ||
|
|
5bc44e7190 | ||
|
|
84c1b92fdf | ||
|
|
be6e222d8d | ||
|
|
7db488cdfb | ||
|
|
1a414ac69c | ||
|
|
f82099143f | ||
|
|
93743b11b2 | ||
|
|
a94696e037 | ||
|
|
0255e8980b | ||
|
|
eff9c69069 | ||
|
|
ca8a70a1ee | ||
|
|
903cc8ee83 | ||
|
|
2dccd2f30b | ||
|
|
b775cbb3bf | ||
|
|
79ef6f2f75 | ||
|
|
451ac297d4 | ||
|
|
0fd8a4507c | ||
|
|
13fe318110 | ||
|
|
49c7e7ce2d | ||
|
|
1af7d01d96 | ||
|
|
66c6938df0 | ||
|
|
bb9fb04788 | ||
|
|
f5cf2b2b55 | ||
|
|
b9b396a279 | ||
|
|
a2755221d0 | ||
|
|
3e8afaeae4 | ||
|
|
43169ced69 | ||
|
|
708844857d | ||
|
|
83ec89fa20 | ||
|
|
68b193a782 | ||
|
|
fa5fd1e71c | ||
|
|
abe2e544bb | ||
|
|
e051d02ad3 | ||
|
|
a3796fe128 | ||
|
|
c1e89bd1c3 | ||
|
|
aded1dd4da | ||
|
|
1e39281423 | ||
|
|
d92cc0f365 | ||
|
|
a5e39d1db3 | ||
|
|
7052ce9e63 | ||
|
|
8d036ab1d4 | ||
|
|
48276f989f | ||
|
|
57f2d3e26a | ||
|
|
c4924e4005 | ||
|
|
5c193f49df | ||
|
|
5b2ef77c2c | ||
|
|
371b660b33 | ||
|
|
228a95f776 | ||
|
|
cf93b72edd | ||
|
|
90c60cc5e4 | ||
|
|
e79ab4f47a | ||
|
|
4e946cbb27 | ||
|
|
d5c5070e59 | ||
|
|
50b3aabb76 | ||
|
|
b2fd84192b | ||
|
|
1a7f7cb197 | ||
|
|
ecab61929e | ||
|
|
ab4f0f87ca | ||
|
|
ae5b3c4c2d | ||
|
|
06240d1183 | ||
|
|
f3b3d8d759 | ||
|
|
8420f6ccfe | ||
|
|
f007ecf6c5 | ||
|
|
758a023267 | ||
|
|
fe6a576d84 | ||
|
|
d4f2d99a6b | ||
|
|
cb390325a6 | ||
|
|
1922ef974b | ||
|
|
de495aa1c5 | ||
|
|
cf0b4c8f03 | ||
|
|
aa4a4b07d8 | ||
|
|
75a4d8a2b9 | ||
|
|
b92214461e | ||
|
|
3f4ba87079 | ||
|
|
f1cfa14750 | ||
|
|
b24f5b6ad6 | ||
|
|
3dbce0e800 | ||
|
|
872fd126f4 | ||
|
|
efca50c6ac | ||
|
|
3cf013b25b | ||
|
|
92a5fa19fb | ||
|
|
1fcf13d149 | ||
|
|
bd20050db8 | ||
|
|
ce0233d0a2 | ||
|
|
ce777348b3 | ||
|
|
c052325487 | ||
|
|
0479e9b3f3 | ||
|
|
abdf1156d4 | ||
|
|
9ed30f563a | ||
|
|
d1985bad3b | ||
|
|
c83a4dc8e4 | ||
|
|
5484bbf8bf | ||
|
|
62e8d70d74 | ||
|
|
b2f1477b45 | ||
|
|
7323a5e393 | ||
|
|
f8205cc376 | ||
|
|
1b639ab978 | ||
|
|
4828f7478e | ||
|
|
9646f7039a | ||
|
|
6f921028de | ||
|
|
2508db0550 | ||
|
|
775141b7f7 | ||
|
|
a2d9c1aa72 | ||
|
|
4b639843ec | ||
|
|
464389a862 | ||
|
|
48b3eb259d | ||
|
|
4cebfbcd13 | ||
|
|
1767cf8ad4 | ||
|
|
b1981bb70c | ||
|
|
3dc581efbb | ||
|
|
655cc3256c | ||
|
|
ce69410f49 | ||
|
|
5f0be0cc7f | ||
|
|
dca6347ea9 | ||
|
|
94c4db9072 | ||
|
|
7f63be2cd2 | ||
|
|
1236dea4c5 | ||
|
|
c5c46df613 | ||
|
|
a96269150a | ||
|
|
75e347e8e3 | ||
|
|
d641cc5057 | ||
|
|
bf5b660cb5 | ||
|
|
712dc493ca | ||
|
|
f4fba64ffb | ||
|
|
02430916cb | ||
|
|
e3ad115698 | ||
|
|
c078bb04b2 | ||
|
|
d95e133792 | ||
|
|
a04f1045bc | ||
|
|
cf64145ff3 | ||
|
|
195eca6b09 | ||
|
|
b0ef077e48 | ||
|
|
e40a698d1a | ||
|
|
69c34b1b27 | ||
|
|
4700c2583d | ||
|
|
db6975e07a | ||
|
|
93127489e7 | ||
|
|
83064294ac | ||
|
|
0b64758360 | ||
|
|
4e1a2c04a5 | ||
|
|
8412c1db21 | ||
|
|
18a7a9fdce | ||
|
|
fc90d00354 | ||
|
|
55861a8f44 | ||
|
|
4fbd307163 | ||
|
|
3e4c03852d | ||
|
|
c8a04b998b | ||
|
|
568a652fb4 | ||
|
|
a2c9b5c042 | ||
|
|
fd3a4b069d | ||
|
|
4aaafa6de7 | ||
|
|
97475fb27b | ||
|
|
26e29df657 | ||
|
|
269ab3884a | ||
|
|
d15a853bf7 | ||
|
|
b3f7f440c8 | ||
|
|
6cf79a3c73 | ||
|
|
2c110f7796 | ||
|
|
c298c968f5 | ||
|
|
5feac3a7ff | ||
|
|
215c1c53f5 | ||
|
|
7890085c6c | ||
|
|
aebea0b57f | ||
|
|
8684455ea5 | ||
|
|
12c427a9cf | ||
|
|
7cbb103376 | ||
|
|
d686a0dadf | ||
|
|
eb186f550c | ||
|
|
01b631aea6 | ||
|
|
293114f1a0 | ||
|
|
20b92c03cb | ||
|
|
b6d76eb84e | ||
|
|
25bb51f4a3 | ||
|
|
4a3f51e550 | ||
|
|
d629a13499 | ||
|
|
07c0de71ec | ||
|
|
7470f4ffcf | ||
|
|
81f9748313 | ||
|
|
58928a5000 | ||
|
|
4c44ede945 | ||
|
|
d3c4105429 | ||
|
|
9cf8ec5dd7 | ||
|
|
f5187b1533 | ||
|
|
6230a65a79 | ||
|
|
f13c96839e | ||
|
|
776f68c9dd | ||
|
|
714ed89a4c | ||
|
|
ed307adb22 | ||
|
|
8001688daf | ||
|
|
4c0687b9a5 | ||
|
|
33043dd8af | ||
|
|
0b2b29b7cf | ||
|
|
a41c0a0519 | ||
|
|
026e28114e | ||
|
|
0840719289 | ||
|
|
aad875e113 | ||
|
|
6b059d94ba | ||
|
|
39eeaea7e7 | ||
|
|
81a8e91180 | ||
|
|
4fc6f6f59b | ||
|
|
dd2f573f27 | ||
|
|
ff8ddc431b | ||
|
|
d703945aa3 | ||
|
|
f4aba5f9ea | ||
|
|
393113c3e3 | ||
|
|
f2db18820a | ||
|
|
e04d300e18 | ||
|
|
685f836f41 | ||
|
|
d4f5ad641a | ||
|
|
007d437ee8 | ||
|
|
00e380e8d8 | ||
|
|
56749d9494 | ||
|
|
cf10d37c90 | ||
|
|
f9de34e36d | ||
|
|
aa889be140 | ||
|
|
6da6838bde | ||
|
|
07a0be303f | ||
|
|
ddbe0af290 | ||
|
|
e71f0f44a4 | ||
|
|
39f3bc7100 | ||
|
|
211a145e58 | ||
|
|
d2339b915f | ||
|
|
24c2651745 | ||
|
|
36e95b93b4 | ||
|
|
e7a44e0b15 | ||
|
|
fbdb21ac72 | ||
|
|
c9522cf6ae | ||
|
|
7bf9d334ad | ||
|
|
422ff93dcd | ||
|
|
eee1ea7a09 | ||
|
|
b90e482add | ||
|
|
875b51720b | ||
|
|
5272d4f9e3 | ||
|
|
c980f4f6e3 | ||
|
|
89525330c4 | ||
|
|
806db24c0e | ||
|
|
ba7d6df5a4 | ||
|
|
112301e0e0 | ||
|
|
c07065e457 | ||
|
|
b9e1afae17 | ||
|
|
549b4a9ebf | ||
|
|
fa9a3fb7c4 | ||
|
|
ccb15f278a | ||
|
|
f0fb4b8842 | ||
|
|
dacaf293b2 | ||
|
|
627d0e4e6f | ||
|
|
f32b9e26e0 | ||
|
|
db2b1a0a35 | ||
|
|
f734a60c62 | ||
|
|
9aa815c1ed | ||
|
|
1848f96efa | ||
|
|
51440cc7f7 | ||
|
|
09f100c0c2 | ||
|
|
a8b66abe15 | ||
|
|
03c45a78a9 | ||
|
|
6574d4450f | ||
|
|
d7f0ff84d6 | ||
|
|
5ef4c8e83e | ||
|
|
5ab48c6015 | ||
|
|
9119e08342 | ||
|
|
ce82ce1444 | ||
|
|
bbffd3d113 | ||
|
|
85cff2c0f3 | ||
|
|
9a0c621ad6 | ||
|
|
5c66104d25 | ||
|
|
c642d76e91 | ||
|
|
6d78ed3462 | ||
|
|
437142ed7b | ||
|
|
634c6dd455 | ||
|
|
3652931be8 | ||
|
|
7de3022a4a | ||
|
|
f82e52b7a2 | ||
|
|
c274f27810 | ||
|
|
88954b9bf6 | ||
|
|
f418f9de4c | ||
|
|
57f6ee7f78 | ||
|
|
f8457bd918 | ||
|
|
71c1369365 | ||
|
|
b015a6ea6c | ||
|
|
34072f3947 | ||
|
|
036b82afd9 | ||
|
|
52b5b3f741 | ||
|
|
c2f7f2ad27 | ||
|
|
bc9c78acfe | ||
|
|
7bd27ebd52 | ||
|
|
43ed8be114 | ||
|
|
a896fe7425 | ||
|
|
6c52e4936f | ||
|
|
32657793c8 | ||
|
|
63eb88c6ae | ||
|
|
28520cc493 | ||
|
|
8be05b404c | ||
|
|
96b791b5f9 | ||
|
|
ba9eac3ea4 | ||
|
|
717841877f | ||
|
|
cf06686d67 | ||
|
|
8d7594c96a | ||
|
|
ed36869f1d | ||
|
|
ea3adc44fd | ||
|
|
5fafc97bc0 | ||
|
|
fba900707a | ||
|
|
175a455d75 | ||
|
|
ffcef907b3 | ||
|
|
33317782ea | ||
|
|
3b9a0124fa | ||
|
|
5d5d03fd4c | ||
|
|
148f3172e6 | ||
|
|
972c14225b | ||
|
|
ce86c757cd | ||
|
|
cd6ffba9ac | ||
|
|
ab7209ceba | ||
|
|
63cca6190f | ||
|
|
0f2ec90064 | ||
|
|
4568dfabb9 | ||
|
|
e0772500c9 | ||
|
|
78c5522966 | ||
|
|
2a78da6d07 | ||
|
|
c3505f865e | ||
|
|
3364e6c63b | ||
|
|
a129f2c5c5 | ||
|
|
770b0c7022 | ||
|
|
15a7a0459a | ||
|
|
6490858f43 | ||
|
|
aac6f75025 | ||
|
|
86945218de | ||
|
|
718f79775e | ||
|
|
4261c1768a | ||
|
|
01603185c3 | ||
|
|
4632ba3ae5 | ||
|
|
38d63c3dc9 | ||
|
|
c64e5a5799 | ||
|
|
f1adf24f3b | ||
|
|
856765a775 | ||
|
|
075da34cdb | ||
|
|
7c6ef51cb2 | ||
|
|
1e1297378c | ||
|
|
5ce543002d | ||
|
|
ac53b30f25 | ||
|
|
a5448549b1 | ||
|
|
700b1c50af | ||
|
|
9e1c363a0a | ||
|
|
bbe3065f19 | ||
|
|
1716a0ebca | ||
|
|
ed66339e94 | ||
|
|
441774e61c | ||
|
|
c6fd14afd2 | ||
|
|
27ed9ca7fd | ||
|
|
50fda906bd | ||
|
|
6c7c60037b | ||
|
|
91a429ea77 | ||
|
|
2dbe01e90a | ||
|
|
3d7dd41223 | ||
|
|
a83b9109bf | ||
|
|
fdb079548e | ||
|
|
91495c8595 | ||
|
|
c3e997168a | ||
|
|
c3e6f4f7b6 | ||
|
|
effd837cd0 | ||
|
|
089d564934 | ||
|
|
e600ec95ed | ||
|
|
cbd5853389 | ||
|
|
4e3a086993 | ||
|
|
5f23dfb034 | ||
|
|
90c65c2927 | ||
|
|
7958775c6a | ||
|
|
99f59490a3 | ||
|
|
ff99812c4d | ||
|
|
741ac31ba6 | ||
|
|
f953b4dc0f | ||
|
|
76ce921778 | ||
|
|
4819f3ca15 | ||
|
|
48dd722db9 | ||
|
|
57c2613d37 | ||
|
|
804927f893 | ||
|
|
da82887cc0 | ||
|
|
f151920404 | ||
|
|
02f36a1abe | ||
|
|
c04041f110 | ||
|
|
a4702d48b4 | ||
|
|
ba27a4cc4a | ||
|
|
c28da78294 | ||
|
|
61f6ef4c19 | ||
|
|
d46b9b5aad | ||
|
|
7fc014f5d9 | ||
|
|
b28e0d15d8 | ||
|
|
0cc1679f64 | ||
|
|
e7a0e9ac70 | ||
|
|
025a43ea4e | ||
|
|
050fcf2ab8 | ||
|
|
c9642fcf35 | ||
|
|
79c257642c | ||
|
|
4f9d9d7a1d | ||
|
|
f14ac355f0 | ||
|
|
e0217477ce | ||
|
|
5e3bad2a36 | ||
|
|
26d6450f0a | ||
|
|
5923f7d859 | ||
|
|
57f6a5ca8c | ||
|
|
dd30ffa7ce | ||
|
|
8f5aa0ea16 | ||
|
|
1ddf21a256 | ||
|
|
9d8796c703 | ||
|
|
59a97272bb | ||
|
|
e9d328a309 | ||
|
|
448f2913eb | ||
|
|
d92b630069 | ||
|
|
584955caa8 | ||
|
|
951e81158c | ||
|
|
2a88e598ff | ||
|
|
3e5e88b369 | ||
|
|
4806c52ba6 | ||
|
|
86d186e279 | ||
|
|
5bf5388552 | ||
|
|
c19ed471ca | ||
|
|
9d694a1589 | ||
|
|
4dadf0cb95 | ||
|
|
de4bc67159 | ||
|
|
af37616e48 | ||
|
|
07f7ad0a05 | ||
|
|
fd355636d0 | ||
|
|
e8528271ee | ||
|
|
41ed80e0c4 | ||
|
|
e8fef8104d | ||
|
|
30c48df1f0 | ||
|
|
f14add2791 | ||
|
|
14cb6d21a9 | ||
|
|
eaa607b48d | ||
|
|
0bd2a032bb | ||
|
|
d6961889fb | ||
|
|
51ffd0d64a | ||
|
|
120ac31394 | ||
|
|
4284b97b43 | ||
|
|
d1615567e2 | ||
|
|
9ad3e50511 | ||
|
|
45a59f9aec | ||
|
|
57408d18ae | ||
|
|
372372a0aa | ||
|
|
7f35ff5fe5 | ||
|
|
c28cd8a270 | ||
|
|
3a97db804f | ||
|
|
4a44b35ea5 | ||
|
|
47aafe9042 | ||
|
|
973940fcb2 | ||
|
|
53d94a1d3d | ||
|
|
5dd3c7c8e8 | ||
|
|
a740f60734 | ||
|
|
0c2a13f27f | ||
|
|
da0d3133df | ||
|
|
2b557a0f8d | ||
|
|
7abd9a3db9 | ||
|
|
98b9f57e0e | ||
|
|
e064ccd585 | ||
|
|
b5a63ed3fc | ||
|
|
147edddb90 | ||
|
|
cd19fc7c81 | ||
|
|
b5f9501001 | ||
|
|
8c0cd28f64 | ||
|
|
e8e10d4224 | ||
|
|
3e187df75b | ||
|
|
88d2ed9e93 | ||
|
|
ab5674aa4e | ||
|
|
81e4b6b37b | ||
|
|
b1507952df | ||
|
|
c4ac7cf375 | ||
|
|
c23292db8a | ||
|
|
a350ffeaa1 | ||
|
|
0efb7e67c9 | ||
|
|
a61e0f6cec | ||
|
|
0f5b36e9c5 | ||
|
|
93e7133076 | ||
|
|
2411edd461 | ||
|
|
af83065df5 | ||
|
|
1557c567d4 | ||
|
|
8bdaeab998 | ||
|
|
6825e3f7ce | ||
|
|
4602549ec8 | ||
|
|
a7b2df2450 | ||
|
|
3c0f6d3631 | ||
|
|
7ac37b75f3 | ||
|
|
b1e6d57bf1 | ||
|
|
f19c6a0a5b | ||
|
|
789279fe76 | ||
|
|
39a8d8803a | ||
|
|
f4ce73fc0d | ||
|
|
cac9d9266c | ||
|
|
7e94d02fb7 | ||
|
|
f3913b1dd2 | ||
|
|
50fc716c15 | ||
|
|
50412392f8 | ||
|
|
1b80859022 | ||
|
|
c6bd758793 | ||
|
|
cd4d657815 | ||
|
|
a4852b7a21 | ||
|
|
0b3c06abc0 | ||
|
|
1b351ad5bb | ||
|
|
1a1fc3ef21 | ||
|
|
fa3f18c88b | ||
|
|
904454d737 | ||
|
|
c1fb54ecad | ||
|
|
bd88b28310 | ||
|
|
de2397fa05 | ||
|
|
2513cf0969 | ||
|
|
15e16d86e4 | ||
|
|
26118ee881 | ||
|
|
232cf69006 | ||
|
|
9d2fba308d | ||
|
|
1171c9a0b2 | ||
|
|
9b397245f8 | ||
|
|
59b80ab8f6 | ||
|
|
18258877a8 | ||
|
|
e2b12c730e | ||
|
|
0a85b4b383 | ||
|
|
d5af9806ea | ||
|
|
104761d064 | ||
|
|
59065418ac | ||
|
|
7ccdc50637 | ||
|
|
f8ae61058e | ||
|
|
cc9d896cf8 | ||
|
|
c5637ea29b | ||
|
|
be3c4abbce | ||
|
|
d5c48567b3 | ||
|
|
5b4e7df856 | ||
|
|
23f04b3d09 | ||
|
|
050e3e86e3 | ||
|
|
c21d0c64a0 | ||
|
|
970b176fbf | ||
|
|
9e918cc717 | ||
|
|
4a31467afb | ||
|
|
86f07245d4 | ||
|
|
d51f179c2d | ||
|
|
974942a736 | ||
|
|
31d17cada7 | ||
|
|
647686e68e | ||
|
|
959212a95f | ||
|
|
45df8c0f74 | ||
|
|
1dbd41a746 | ||
|
|
8c43f4f628 | ||
|
|
633445883e | ||
|
|
e6acc3c336 | ||
|
|
90b947a7da | ||
|
|
b6b4015a82 | ||
|
|
2fd8940c02 | ||
|
|
7408710761 | ||
|
|
e4a4dd3219 | ||
|
|
745ad7cc34 | ||
|
|
821f8fea6f | ||
|
|
b0d90bb612 | ||
|
|
b439e0cfa0 | ||
|
|
68952b273b | ||
|
|
df148e4946 | ||
|
|
8b2f2fe24d | ||
|
|
4b8a91fb8c | ||
|
|
ee668df440 | ||
|
|
6cae917058 | ||
|
|
cf99a7bf18 | ||
|
|
727b519750 | ||
|
|
861d093d80 | ||
|
|
c3d2decdec | ||
|
|
d862d701f3 | ||
|
|
883c4a185d | ||
|
|
7eb35ef33d | ||
|
|
1563b0bf55 | ||
|
|
bad731c86f | ||
|
|
5309cc5916 | ||
|
|
f8ef6ab397 | ||
|
|
9e61991ad2 | ||
|
|
c644e8a30f | ||
|
|
45a237af16 | ||
|
|
0450fdb542 | ||
|
|
7d304fbd51 | ||
|
|
33df895709 | ||
|
|
4fb677ed23 | ||
|
|
4f0bd7f461 | ||
|
|
01eecdb698 | ||
|
|
22ef6ca56a | ||
|
|
2e015c9816 | ||
|
|
1d40b5010e | ||
|
|
9d25f1c073 | ||
|
|
2a8de9cb28 | ||
|
|
67767ede17 | ||
|
|
03db4d73ad | ||
|
|
fcb1f4665f | ||
|
|
5ca41a6fff | ||
|
|
e4f71420fc | ||
|
|
d5456ed1db | ||
|
|
e3335c5843 | ||
|
|
77ea0d3ea6 | ||
|
|
23ff035eb3 | ||
|
|
9906173a3f | ||
|
|
c6dd18ce40 | ||
|
|
a31ad2c367 | ||
|
|
7e20422e20 | ||
|
|
bd2f63c232 | ||
|
|
532a874ba6 | ||
|
|
48fa46e0d5 | ||
|
|
f72119f1b6 | ||
|
|
3063d53a2b | ||
|
|
e4163c5da4 | ||
|
|
a34ae45b05 | ||
|
|
d8e4f1150e | ||
|
|
c2534ae6da | ||
|
|
342ea97406 | ||
|
|
6f66c06111 | ||
|
|
aaeffe61a6 | ||
|
|
f5daa96c8e | ||
|
|
67fed5f3d7 | ||
|
|
067e6bf93d | ||
|
|
13dc31dc1f | ||
|
|
7f6bf21270 | ||
|
|
d647258856 | ||
|
|
1eb7ed5e9c | ||
|
|
e78f1b05a7 | ||
|
|
4531b017b3 | ||
|
|
101a03c38d | ||
|
|
e45140b7ea | ||
|
|
41747a7a04 | ||
|
|
e448430d8a | ||
|
|
394b1a1602 | ||
|
|
85abd5a8c3 | ||
|
|
b9e0eb5b76 | ||
|
|
a8eae73b66 | ||
|
|
9edd8d6f66 | ||
|
|
8147f648a1 | ||
|
|
30b1fa9c5b | ||
|
|
fa66c2692f | ||
|
|
1814f6b545 | ||
|
|
9d04ad5097 | ||
|
|
93b48ba973 | ||
|
|
047983d7bf | ||
|
|
ebccbf28a7 | ||
|
|
1dc84f9b58 | ||
|
|
35f3987803 | ||
|
|
b6bd132066 | ||
|
|
3ce2f28303 | ||
|
|
0d9cda8a85 | ||
|
|
f2decc09a5 | ||
|
|
b1c55b23ee | ||
|
|
4622600ab0 | ||
|
|
396358d4e5 | ||
|
|
8b975f50dd | ||
|
|
a1ea371c73 | ||
|
|
acd5442246 | ||
|
|
d176dd0623 | ||
|
|
68310bb479 | ||
|
|
e822966464 | ||
|
|
febce68bc8 | ||
|
|
fadffeedca | ||
|
|
2fc501fe59 | ||
|
|
21aac76ba2 | ||
|
|
fa3ebf2ca7 | ||
|
|
d2bf2539b5 | ||
|
|
8a0acedc94 | ||
|
|
11e5cd4f84 | ||
|
|
27fdb3116c | ||
|
|
b9c0c89a24 | ||
|
|
8078889a09 | ||
|
|
5dd4266ccc | ||
|
|
7d14676bce | ||
|
|
db113da121 | ||
|
|
5b2bfcef7d | ||
|
|
4d266f4ad2 | ||
|
|
b81a325b28 | ||
|
|
09eca10eb6 | ||
|
|
7b86465d7b | ||
|
|
40da5a849d | ||
|
|
ad170ed854 | ||
|
|
8d7c47a5e4 | ||
|
|
d7b5382c32 | ||
|
|
4d8f7c67d4 | ||
|
|
e53337bcdc | ||
|
|
e5d883f97e | ||
|
|
548a55792c | ||
|
|
43f0f2a0fd | ||
|
|
7b1c696810 | ||
|
|
8d69c3764d | ||
|
|
87acd9d7ee | ||
|
|
06391c9de6 | ||
|
|
b42b41216b | ||
|
|
0a1d215560 | ||
|
|
44b6136ce2 | ||
|
|
ba3c6023a8 | ||
|
|
be7f6ae7d1 | ||
|
|
984c7a67f5 | ||
|
|
a4bf6c1f7a | ||
|
|
690ae1a7b6 | ||
|
|
eae9a10a7d | ||
|
|
7c6765b969 | ||
|
|
a6c143a1c7 | ||
|
|
714da0ab3b | ||
|
|
377ec37257 |
@@ -5,6 +5,7 @@ Demos
|
||||
./Aristo
|
||||
WebSite
|
||||
.push-package
|
||||
*.xcodeproj*
|
||||
*.xcodeproj/*.pbxuser
|
||||
*.xcodeproj/*.perspectivev3
|
||||
xcuserdata/
|
||||
@@ -15,3 +16,5 @@ xcuserdata/
|
||||
Tests/Manual/**/*.xcodeproj
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
*.tm_properties
|
||||
*.idea
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 0.8
|
||||
install: ./bootstrap.sh --quiet --noprompt --directory ./narwhal
|
||||
install: ./bootstrap.sh --noprompt --directory ./narwhal
|
||||
script: jake test
|
||||
env: PATH="$TRAVIS_BUILD_DIR/narwhal/bin:$PATH" CAPP_BUILD="$TRAVIS_BUILD_DIR/Build" NARWHAL_ENGINE=rhino
|
||||
|
||||
+8
-1
@@ -20,12 +20,15 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "_CPObject+Theme.j"
|
||||
@import "_CPToolTip.j"
|
||||
@import "CALayer.j"
|
||||
@import "CGGeometry.j"
|
||||
@import "CPAccordionView.j"
|
||||
@import "CPAlert.j"
|
||||
@import "CPAnimation.j"
|
||||
@import "CPAnimationContext.j"
|
||||
@import "CPAppearance.j"
|
||||
@import "CPApplication.j"
|
||||
@import "CPArrayController.j"
|
||||
@import "CPBezierPath.j"
|
||||
@@ -98,15 +101,19 @@
|
||||
@import "CPTabView.j"
|
||||
@import "CPText.j"
|
||||
@import "CPTextField.j"
|
||||
@import "CPTextView.j"
|
||||
@import "CPTokenField.j"
|
||||
@import "CPToolbar.j"
|
||||
@import "CPToolbarItem.j"
|
||||
@import "CPTrackingArea.j"
|
||||
@import "CPTreeNode.j"
|
||||
@import "CPUserDefaultsController.j"
|
||||
@import "CPView.j"
|
||||
@import "CPViewAnimator.j"
|
||||
@import "CPViewAnimation.j"
|
||||
@import "CPViewController.j"
|
||||
@import "CPVisualEffectView.j"
|
||||
@import "CPWebView.j"
|
||||
@import "CPWindow.j"
|
||||
@import "CPWindowController.j"
|
||||
@import "CPWorkspace.j"
|
||||
@import "CPWorkspace.j"
|
||||
+131
-65
@@ -41,6 +41,10 @@
|
||||
|
||||
@global CPApp
|
||||
|
||||
var CPAlertDelegate_alertShowHelp_ = 1 << 0,
|
||||
CPAlertDelegate_alertDidEnd_returnCode_ = 1 << 1;
|
||||
|
||||
@typedef CPAlertStyle
|
||||
/*
|
||||
@global
|
||||
@group CPAlertStyle
|
||||
@@ -59,6 +63,62 @@ CPCriticalAlertStyle = 2;
|
||||
|
||||
var bottomHeight = 71;
|
||||
|
||||
@protocol CPAlertDelegate <CPObject>
|
||||
|
||||
@optional
|
||||
- (BOOL)alertShowHelp:(CPAlert)alert;
|
||||
- (void)alertDidEnd:(CPAlert)theAlert returnCode:(int)returnCode;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation _CPAlertThemeView : CPView
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return @"alert";
|
||||
}
|
||||
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return @{
|
||||
@"size": CGSizeMake(400.0, 110.0),
|
||||
@"content-inset": CGInsetMake(15, 15, 15, 50),
|
||||
@"informative-offset": 6,
|
||||
@"button-offset": 10,
|
||||
@"message-text-alignment": CPJustifiedTextAlignment,
|
||||
@"message-text-color": [CPColor blackColor],
|
||||
@"message-text-font": [CPFont boldSystemFontOfSize:13.0],
|
||||
@"message-text-shadow-color": [CPNull null],
|
||||
@"message-text-shadow-offset": CGSizeMakeZero(),
|
||||
@"informative-text-alignment": CPJustifiedTextAlignment,
|
||||
@"informative-text-color": [CPColor blackColor],
|
||||
@"informative-text-font": [CPFont systemFontOfSize:12.0],
|
||||
@"informative-text-shadow-color": [CPNull null],
|
||||
@"informative-text-shadow-offset": CGSizeMakeZero(),
|
||||
@"image-offset": CGPointMake(15, 12),
|
||||
@"information-image": [CPNull null],
|
||||
@"warning-image": [CPNull null],
|
||||
@"error-image": [CPNull null],
|
||||
@"help-image": [CPNull null],
|
||||
@"help-image-left-offset": 15,
|
||||
@"help-image-pressed": [CPNull null],
|
||||
@"suppression-button-y-offset": 0.0,
|
||||
@"suppression-button-x-offset": 0.0,
|
||||
@"default-elements-margin": 3.0,
|
||||
@"suppression-button-text-color": [CPColor blackColor],
|
||||
@"suppression-button-text-font": [CPFont systemFontOfSize:12.0],
|
||||
@"suppression-button-text-shadow-color": [CPNull null],
|
||||
@"suppression-button-text-shadow-offset": 0.0,
|
||||
@"modal-window-button-margin-y": 0.0,
|
||||
@"modal-window-button-margin-x": 0.0,
|
||||
@"standard-window-button-margin-y": 0.0,
|
||||
@"standard-window-button-margin-x": 0.0,
|
||||
};
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
|
||||
@@ -83,32 +143,33 @@ var bottomHeight = 71;
|
||||
*/
|
||||
@implementation CPAlert : CPObject
|
||||
{
|
||||
BOOL _showHelp @accessors(property=showsHelp);
|
||||
BOOL _showSuppressionButton @accessors(property=showsSuppressionButton);
|
||||
BOOL _showHelp @accessors(property=showsHelp);
|
||||
BOOL _showSuppressionButton @accessors(property=showsSuppressionButton);
|
||||
|
||||
CPAlertStyle _alertStyle @accessors(property=alertStyle);
|
||||
CPString _title @accessors(property=title);
|
||||
CPView _accessoryView @accessors(property=accessoryView);
|
||||
CPImage _icon @accessors(property=icon);
|
||||
CPAlertStyle _alertStyle @accessors(property=alertStyle);
|
||||
CPString _title @accessors(property=title);
|
||||
CPView _accessoryView @accessors(property=accessoryView);
|
||||
CPImage _icon @accessors(property=icon);
|
||||
|
||||
CPArray _buttons @accessors(property=buttons, readonly);
|
||||
CPCheckBox _suppressionButton @accessors(property=suppressionButton, readonly);
|
||||
CPArray _buttons @accessors(property=buttons, readonly);
|
||||
CPCheckBox _suppressionButton @accessors(property=suppressionButton, readonly);
|
||||
|
||||
id _delegate @accessors(property=delegate);
|
||||
id _modalDelegate;
|
||||
SEL _didEndSelector @accessors(property=didEndSelector);
|
||||
Function _didEndBlock;
|
||||
id <CPAlertDelegate> _delegate @accessors(property=delegate);
|
||||
id _modalDelegate;
|
||||
SEL _didEndSelector @accessors(property=didEndSelector);
|
||||
Function _didEndBlock;
|
||||
unsigned _implementedDelegateMethods;
|
||||
|
||||
_CPAlertThemeView _themeView @accessors(property=themeView, readonly);
|
||||
CPWindow _window @accessors(property=window, readonly);
|
||||
int _defaultWindowStyle;
|
||||
_CPAlertThemeView _themeView @accessors(property=themeView, readonly);
|
||||
CPWindow _window @accessors(property=window, readonly);
|
||||
int _defaultWindowStyle;
|
||||
|
||||
CPImageView _alertImageView;
|
||||
CPTextField _informativeLabel;
|
||||
CPTextField _messageLabel;
|
||||
CPButton _alertHelpButton;
|
||||
CPImageView _alertImageView;
|
||||
CPTextField _informativeLabel;
|
||||
CPTextField _messageLabel;
|
||||
CPButton _alertHelpButton;
|
||||
|
||||
BOOL _needsLayout;
|
||||
BOOL _needsLayout;
|
||||
}
|
||||
|
||||
#pragma mark Creating Alerts
|
||||
@@ -187,6 +248,30 @@ var bottomHeight = 71;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Delegate
|
||||
|
||||
/*!
|
||||
Set the delegate of the receiver
|
||||
@param aDelegate the delegate object for the alert.
|
||||
*/
|
||||
- (void)setDelegate:(id <CPAlertDelegate>)aDelegate
|
||||
{
|
||||
if (_delegate === aDelegate)
|
||||
return;
|
||||
|
||||
_delegate = aDelegate;
|
||||
_implementedDelegateMethods = 0;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(alertShowHelp:)])
|
||||
_implementedDelegateMethods |= CPAlertDelegate_alertShowHelp_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
|
||||
_implementedDelegateMethods |= CPAlertDelegate_alertDidEnd_returnCode_;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Accessors
|
||||
|
||||
- (CPTheme)theme
|
||||
@@ -219,7 +304,7 @@ var bottomHeight = 71;
|
||||
[_themeView setValue:aValue forThemeAttribute:aName];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forThemeAttribute:(CPString)aName inState:(CPThemeState)aState
|
||||
- (void)setValue:(id)aValue forThemeAttribute:(CPString)aName inState:(ThemeState)aState
|
||||
{
|
||||
[_themeView setValue:aValue forThemeAttribute:aName inState:aState];
|
||||
}
|
||||
@@ -696,8 +781,7 @@ var bottomHeight = 71;
|
||||
*/
|
||||
- (@action)_showHelp:(id)aSender
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(alertShowHelp:)])
|
||||
[_delegate alertShowHelp:self];
|
||||
[self _sendDelegateAlertShowHelp];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -737,62 +821,44 @@ var bottomHeight = 71;
|
||||
else if (_modalDelegate)
|
||||
{
|
||||
if (_didEndSelector)
|
||||
objj_msgSend(_modalDelegate, _didEndSelector, self, returnCode, contextInfo);
|
||||
_modalDelegate.isa.objj_msgSend3(_modalDelegate, _didEndSelector, self, returnCode, contextInfo);
|
||||
}
|
||||
else if (_delegate)
|
||||
{
|
||||
if (_didEndSelector)
|
||||
objj_msgSend(_delegate, _didEndSelector, self, returnCode);
|
||||
else if ([_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
|
||||
[_delegate alertDidEnd:self returnCode:returnCode];
|
||||
_delegate.isa.objj_msgSend2(_delegate, _didEndSelector, self, returnCode);
|
||||
else
|
||||
[self _sendDelegateAlertDidEndReturnCode:returnCode];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPAlertThemeView : CPView
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
@implementation CPAlert (CPAlertDelegate)
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call the delegate alertDidEnd:returnCode
|
||||
*/
|
||||
- (void)_sendDelegateAlertDidEndReturnCode:(int)returnCode
|
||||
{
|
||||
return @"alert";
|
||||
if (!(_implementedDelegateMethods & CPAlertDelegate_alertDidEnd_returnCode_))
|
||||
return;
|
||||
|
||||
[_delegate alertDidEnd:self returnCode:returnCode];
|
||||
}
|
||||
|
||||
+ (CPDictionary)themeAttributes
|
||||
/*!
|
||||
@ignore
|
||||
Call the delegate alertShowHelp:
|
||||
*/
|
||||
- (BOOL)_sendDelegateAlertShowHelp
|
||||
{
|
||||
return @{
|
||||
@"size": CGSizeMake(400.0, 110.0),
|
||||
@"content-inset": CGInsetMake(15, 15, 15, 50),
|
||||
@"informative-offset": 6,
|
||||
@"button-offset": 10,
|
||||
@"message-text-alignment": CPJustifiedTextAlignment,
|
||||
@"message-text-color": [CPColor blackColor],
|
||||
@"message-text-font": [CPFont boldSystemFontOfSize:13.0],
|
||||
@"message-text-shadow-color": [CPNull null],
|
||||
@"message-text-shadow-offset": CGSizeMakeZero(),
|
||||
@"informative-text-alignment": CPJustifiedTextAlignment,
|
||||
@"informative-text-color": [CPColor blackColor],
|
||||
@"informative-text-font": [CPFont systemFontOfSize:12.0],
|
||||
@"informative-text-shadow-color": [CPNull null],
|
||||
@"informative-text-shadow-offset": CGSizeMakeZero(),
|
||||
@"image-offset": CGPointMake(15, 12),
|
||||
@"information-image": [CPNull null],
|
||||
@"warning-image": [CPNull null],
|
||||
@"error-image": [CPNull null],
|
||||
@"help-image": [CPNull null],
|
||||
@"help-image-left-offset": 15,
|
||||
@"help-image-pressed": [CPNull null],
|
||||
@"suppression-button-y-offset": 0.0,
|
||||
@"suppression-button-x-offset": 0.0,
|
||||
@"default-elements-margin": 3.0,
|
||||
@"suppression-button-text-color": [CPColor blackColor],
|
||||
@"suppression-button-text-font": [CPFont systemFontOfSize:12.0],
|
||||
@"suppression-button-text-shadow-color": [CPNull null],
|
||||
@"suppression-button-text-shadow-offset": 0.0,
|
||||
@"modal-window-button-margin-y": 0.0,
|
||||
@"modal-window-button-margin-x": 0.0,
|
||||
@"standard-window-button-margin-y": 0.0,
|
||||
@"standard-window-button-margin-x": 0.0,
|
||||
};
|
||||
if (!(_implementedDelegateMethods & CPAlertDelegate_alertShowHelp_))
|
||||
return YES;
|
||||
|
||||
return [_delegate alertShowHelp:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+111
-33
@@ -26,25 +26,26 @@
|
||||
@import "CAMediaTimingFunction.j"
|
||||
|
||||
|
||||
/*
|
||||
@global
|
||||
@group CPAnimationCurve
|
||||
*/
|
||||
@protocol CPAnimationDelegate <CPObject>
|
||||
|
||||
@optional
|
||||
- (BOOL)animationShouldStart:(CPAnimation)animation;
|
||||
- (float)animation:(CPAnimation)animation valueForProgress:(float)progress;
|
||||
- (void)animationDidEnd:(CPAnimation)animation;
|
||||
- (void)animationDidStop:(CPAnimation)animation;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPAnimationDelegate_animationShouldStart_ = 1 << 1,
|
||||
CPAnimationDelegate_animation_valueForProgress_ = 1 << 2,
|
||||
CPAnimationDelegate_animationDidEnd_ = 1 << 3,
|
||||
CPAnimationDelegate_animationDidStop_ = 1 << 4;
|
||||
|
||||
@typedef CPAnimationCurve
|
||||
CPAnimationEaseInOut = 0;
|
||||
/*
|
||||
@global
|
||||
@group CPAnimationCurve
|
||||
*/
|
||||
CPAnimationEaseIn = 1;
|
||||
/*
|
||||
@global
|
||||
@group CPAnimationCurve
|
||||
*/
|
||||
CPAnimationEaseOut = 2;
|
||||
/*
|
||||
@global
|
||||
@group CPAnimationCurve
|
||||
*/
|
||||
CPAnimationLinear = 3;
|
||||
|
||||
ACTUAL_FRAME_RATE = 0;
|
||||
@@ -80,17 +81,18 @@ ACTUAL_FRAME_RATE = 0;
|
||||
*/
|
||||
@implementation CPAnimation : CPObject
|
||||
{
|
||||
CPTimeInterval _lastTime;
|
||||
CPTimeInterval _duration;
|
||||
CPTimeInterval _lastTime;
|
||||
CPTimeInterval _duration;
|
||||
|
||||
CPAnimationCurve _animationCurve;
|
||||
CAMediaTimingFunction _timingFunction;
|
||||
CPAnimationCurve _animationCurve;
|
||||
CAMediaTimingFunction _timingFunction;
|
||||
|
||||
float _frameRate;
|
||||
float _progress;
|
||||
float _frameRate;
|
||||
float _progress;
|
||||
|
||||
id _delegate;
|
||||
CPTimer _timer;
|
||||
id <CPAnimationDelegate> _delegate;
|
||||
CPTimer _timer;
|
||||
unsigned _implementedDelegateMethods;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -214,9 +216,25 @@ ACTUAL_FRAME_RATE = 0;
|
||||
Sets the animation's delegate.
|
||||
@param aDelegate the new delegate
|
||||
*/
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
- (void)setDelegate:(id <CPAnimationDelegate>)aDelegate
|
||||
{
|
||||
if (_delegate === aDelegate)
|
||||
return;
|
||||
|
||||
_delegate = aDelegate;
|
||||
_implementedDelegateMethods = 0;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(animationShouldStart:)])
|
||||
_implementedDelegateMethods |= CPAnimationDelegate_animationShouldStart_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(animationDidEnd:)])
|
||||
_implementedDelegateMethods |= CPAnimationDelegate_animationDidEnd_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(animationDidStop:)])
|
||||
_implementedDelegateMethods |= CPAnimationDelegate_animationDidStop_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)])
|
||||
_implementedDelegateMethods |= CPAnimationDelegate_animation_valueForProgress_;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -227,7 +245,7 @@ ACTUAL_FRAME_RATE = 0;
|
||||
- (void)startAnimation
|
||||
{
|
||||
// If we're already animating, or our delegate stops us, animate.
|
||||
if (_timer || _delegate && [_delegate respondsToSelector:@selector(animationShouldStart:)] && ![_delegate animationShouldStart:self])
|
||||
if (_timer || ![self _sendDelegateAnimationShouldStart])
|
||||
return;
|
||||
|
||||
if (_progress === 1.0)
|
||||
@@ -236,7 +254,7 @@ ACTUAL_FRAME_RATE = 0;
|
||||
ACTUAL_FRAME_RATE = 0;
|
||||
_lastTime = new Date();
|
||||
|
||||
var timerInterval = _frameRate <= 0.0 ? 0.0001 : 1.0/_frameRate;
|
||||
var timerInterval = _frameRate <= 0.0 ? 0.0001 : 1.0 / _frameRate;
|
||||
|
||||
_timer = [CPTimer scheduledTimerWithTimeInterval:timerInterval target:self selector:@selector(animationTimerDidFire:) userInfo:nil repeats:YES];
|
||||
}
|
||||
@@ -260,8 +278,7 @@ ACTUAL_FRAME_RATE = 0;
|
||||
[_timer invalidate];
|
||||
_timer = nil;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(animationDidEnd:)])
|
||||
[_delegate animationDidEnd:self];
|
||||
[self _sendDelegateAnimationDidEnd];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,8 +293,7 @@ ACTUAL_FRAME_RATE = 0;
|
||||
[_timer invalidate];
|
||||
_timer = nil;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(animationDidStop:)])
|
||||
[_delegate animationDidStop:self];
|
||||
[self _sendDelegateAnimationDidStop];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -313,8 +329,8 @@ ACTUAL_FRAME_RATE = 0;
|
||||
{
|
||||
var t = [self currentProgress];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)])
|
||||
return [_delegate animation:self valueForProgress:t];
|
||||
if ([self _delegateRespondsToAnimationValueForProgress])
|
||||
return [self _sendDelegateAnimationValueForProgress:t];
|
||||
|
||||
if (_animationCurve == CPAnimationLinear)
|
||||
return t;
|
||||
@@ -330,6 +346,68 @@ ACTUAL_FRAME_RATE = 0;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation CPAnimation (CPAnimationDelegate)
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Check if the delegate responds to animation:valueForProgress:
|
||||
*/
|
||||
- (BOOL)_delegateRespondsToAnimationValueForProgress
|
||||
{
|
||||
return _implementedDelegateMethods & CPAnimationDelegate_animation_valueForProgress_;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate animationShouldStart:
|
||||
*/
|
||||
- (BOOL)_sendDelegateAnimationShouldStart
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPAnimationDelegate_animationShouldStart_))
|
||||
return YES;
|
||||
|
||||
return [_delegate animationShouldStart:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate animation:valueForProgress:
|
||||
*/
|
||||
- (float)_sendDelegateAnimationValueForProgress:(float)aProgress
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPAnimationDelegate_animation_valueForProgress_))
|
||||
return aProgress;
|
||||
|
||||
return [_delegate animation:self valueForProgress:aProgress];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate animationDidEnd:
|
||||
*/
|
||||
- (void)_sendDelegateAnimationDidEnd
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPAnimationDelegate_animationDidEnd_))
|
||||
return;
|
||||
|
||||
[_delegate animationDidEnd:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate animationDidStop:
|
||||
*/
|
||||
- (void)_sendDelegateAnimationDidStop
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPAnimationDelegate_animationDidStop_))
|
||||
return;
|
||||
|
||||
[_delegate animationDidStop:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// currently used function to determine time
|
||||
// 1:1 conversion to js from webkit source files
|
||||
// UnitBezier.h, WebCore_animation_AnimationBase.cpp
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* CPAppearance.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Antoine Mercadal.
|
||||
* Copyright 2015, Cappuccino Project.
|
||||
*
|
||||
* 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/Foundation.j>
|
||||
@import "CPTheme.j"
|
||||
|
||||
CPAppearanceNameAqua = @"CPAppearanceNameAqua";
|
||||
CPAppearanceNameLightContent = @"CPAppearanceNameLightContent";
|
||||
CPAppearanceNameVibrantDark = @"CPAppearanceNameVibrantDark";
|
||||
CPAppearanceNameVibrantLight = @"CPAppearanceNameVibrantLight";
|
||||
|
||||
var _CPAppearanceCurrent = nil,
|
||||
_CPAppearancesRegistry = @{};
|
||||
|
||||
|
||||
@protocol CPAppearanceCustomization <CPObject>
|
||||
|
||||
@required
|
||||
- (CPAppearance)appearance;
|
||||
- (void)setAppearance:(CPAppearance)appearance;
|
||||
- (CPAppearance)effectiveAppearance;
|
||||
- (void)setEffectiveAppearance:(CPAppearance)appearance;
|
||||
|
||||
@end
|
||||
|
||||
CPThemeStateAppearanceAqua = CPThemeState("appearance-aqua");
|
||||
CPThemeStateAppearanceLightContent = CPThemeState("appearance-light-content");
|
||||
CPThemeStateAppearanceVibrantLight = CPThemeState("appearance-vibrant-light");
|
||||
CPThemeStateAppearanceVibrantDark = CPThemeState("appearance-vibrant-dark");
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
|
||||
A CPAppareance represents the appearance of an to a subset of UI elements.
|
||||
This is a very lightweight implementation of the NSAppearance system, but
|
||||
We are using it for compliance, and especially for the CPVisualEffectView
|
||||
*/
|
||||
@implementation CPAppearance : CPObject
|
||||
{
|
||||
BOOL _allowsVibrancy @accessors(property=allowsVibrancy);
|
||||
|
||||
CPString _name;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Class Methods
|
||||
|
||||
/*! Returns the current default CPAppearance
|
||||
*/
|
||||
+ (CPAppearance)currentAppearance
|
||||
{
|
||||
if (!_CPAppearanceCurrent)
|
||||
_CPAppearanceCurrent = [CPAppearance appearanceNamed:CPAppearanceNameAqua];
|
||||
|
||||
return _CPAppearanceCurrent;
|
||||
}
|
||||
|
||||
/*! Sets the current default CPAppearance
|
||||
@param appearance the new current appearance
|
||||
*/
|
||||
+ (void)setCurrentAppearance:(CPAppearance)anAppearance
|
||||
{
|
||||
_CPAppearanceCurrent = anAppearance;
|
||||
}
|
||||
|
||||
/*! Returns the CPAppearance object with the given name
|
||||
@param name the name of the appearance
|
||||
*/
|
||||
+ (CPAppearance)appearanceNamed:(CPString)aName
|
||||
{
|
||||
if (![_CPAppearancesRegistry containsKey:aName])
|
||||
{
|
||||
[_CPAppearancesRegistry setObject:[[CPAppearance alloc] initWithAppearanceNamed:aName bundle:nil]
|
||||
forKey:aName];
|
||||
}
|
||||
|
||||
return [_CPAppearancesRegistry objectForKey:aName];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization
|
||||
|
||||
/*! Creates a CPAppearance object initialized to the specified appearance file in the specified bundle
|
||||
This method does actually nothing special. It just creates a default appearance object
|
||||
*/
|
||||
- (id)initWithAppearanceNamed:(CPString)aName bundle:(CPBundle)bundle
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_name = aName;
|
||||
_allowsVibrancy = YES;
|
||||
|
||||
if ([_CPAppearancesRegistry containsKey:aName])
|
||||
[CPException raise:CPInternalInconsistencyException reason:"Appearance with name '" + aName + "' is already declared."];
|
||||
|
||||
[_CPAppearancesRegistry setObject:self forKey:aName];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Implementation
|
||||
|
||||
- (BOOL)isEqual:(id)anObject
|
||||
{
|
||||
if (![anObject isKindOfClass:CPAppearance])
|
||||
return NO;
|
||||
|
||||
return self._name == anObject._name;
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
return @"<CPAppearance @" + [self UID] + @" name: " + _name + ">";
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark CPCoding
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_name = [aCoder decodeObjectForKey:@"_name"];
|
||||
_allowsVibrancy = [aCoder decodeBoolForKey:@"_allowsVibrancy"];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeObject:_name forKey:@"_name"];
|
||||
[aCoder encodeBool:_allowsVibrancy forKey:@"_allowsVibrancy"];
|
||||
}
|
||||
|
||||
@end
|
||||
+92
-32
@@ -37,10 +37,32 @@
|
||||
@import "CPWindowController.j"
|
||||
@import "_CPPopoverWindow.j"
|
||||
|
||||
@typedef CPModalSession
|
||||
|
||||
var CPMainCibFile = @"CPMainCibFile",
|
||||
CPMainCibFileHumanFriendly = @"Main cib file base name",
|
||||
CPEventModifierFlags = 0;
|
||||
|
||||
|
||||
@protocol CPApplicationDelegate <CPObject>
|
||||
|
||||
@optional
|
||||
- (CPApplicationTerminateReply)applicationShouldTerminate:(CPApplication)sender;
|
||||
- (CPString)applicationShouldTerminateMessage:(CPApplication)sender;
|
||||
- (void)applicationDidBecomeActive:(CPNotification)aNotification;
|
||||
- (void)applicationDidChangeScreenParameters:(CPNotification)aNotification;
|
||||
- (void)applicationDidFinishLaunching:(CPNotification)aNotification;
|
||||
- (void)applicationDidResignActive:(CPNotification)aNotification;
|
||||
- (void)applicationWillBecomeActive:(CPNotification)aNotification;
|
||||
- (void)applicationWillFinishLaunching:(CPNotification)aNotification;
|
||||
- (void)applicationWillResignActive:(CPNotification)aNotification;
|
||||
- (void)applicationWillTerminate:(CPNotification)aNotification;
|
||||
|
||||
@end
|
||||
|
||||
var CPApplicationDelegate_applicationShouldTerminate_ = 1 << 0,
|
||||
CPApplicationDelegate_applicationShouldTerminateMessage_ = 1 << 1;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPApplication
|
||||
@@ -68,36 +90,38 @@ var CPMainCibFile = @"CPMainCibFile",
|
||||
*/
|
||||
@implementation CPApplication : CPResponder
|
||||
{
|
||||
CPArray _eventListeners;
|
||||
int _eventListenerInsertionIndex;
|
||||
CPArray _eventListeners;
|
||||
int _eventListenerInsertionIndex;
|
||||
|
||||
CPEvent _currentEvent;
|
||||
CPWindow _lastMouseMoveWindow;
|
||||
CPEvent _currentEvent;
|
||||
CPWindow _lastMouseMoveWindow;
|
||||
|
||||
CPArray _windows;
|
||||
CPWindow _keyWindow;
|
||||
CPWindow _mainWindow;
|
||||
CPWindow _previousKeyWindow;
|
||||
CPWindow _previousMainWindow;
|
||||
CPArray _windows;
|
||||
CPWindow _keyWindow;
|
||||
CPWindow _mainWindow;
|
||||
CPWindow _previousKeyWindow;
|
||||
CPWindow _previousMainWindow;
|
||||
|
||||
CPDocumentController _documentController;
|
||||
CPDocumentController _documentController;
|
||||
|
||||
CPModalSession _currentSession;
|
||||
CPModalSession _currentSession;
|
||||
|
||||
//
|
||||
id _delegate;
|
||||
BOOL _finishedLaunching;
|
||||
BOOL _isActive;
|
||||
id <CPApplicationDelegate> _delegate;
|
||||
CPInteger _implementedDelegateMethods;
|
||||
|
||||
CPDictionary _namedArgs;
|
||||
CPArray _args;
|
||||
CPString _fullArgsString;
|
||||
BOOL _finishedLaunching;
|
||||
BOOL _isActive;
|
||||
|
||||
CPImage _applicationIconImage;
|
||||
CPDictionary _namedArgs;
|
||||
CPArray _args;
|
||||
CPString _fullArgsString;
|
||||
|
||||
CPPanel _aboutPanel;
|
||||
CPImage _applicationIconImage;
|
||||
|
||||
CPThemeBlend _themeBlend @accessors(property=themeBlend);
|
||||
CPPanel _aboutPanel;
|
||||
|
||||
CPThemeBlend _themeBlend @accessors(property=themeBlend);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -143,11 +167,13 @@ var CPMainCibFile = @"CPMainCibFile",
|
||||
react to these events.
|
||||
@param aDelegate the delegate object
|
||||
*/
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
- (void)setDelegate:(id <CPApplicationDelegate>)aDelegate
|
||||
{
|
||||
if (_delegate == aDelegate)
|
||||
return;
|
||||
|
||||
_implementedDelegateMethods = 0;
|
||||
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter],
|
||||
delegateNotifications =
|
||||
[
|
||||
@@ -188,6 +214,12 @@ var CPMainCibFile = @"CPMainCibFile",
|
||||
if ([_delegate respondsToSelector:selector])
|
||||
[defaultCenter addObserver:_delegate selector:selector name:notificationName object:self];
|
||||
}
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(applicationShouldTerminate:)])
|
||||
_implementedDelegateMethods |= CPApplicationDelegate_applicationShouldTerminate_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(applicationShouldTerminateMessage:)])
|
||||
_implementedDelegateMethods |= CPApplicationDelegate_applicationShouldTerminateMessage_
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -409,12 +441,7 @@ var CPMainCibFile = @"CPMainCibFile",
|
||||
{
|
||||
// callback method for terminate:
|
||||
if (didCloseAll)
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(applicationShouldTerminate:)])
|
||||
[self replyToApplicationShouldTerminate:[_delegate applicationShouldTerminate:self]];
|
||||
else
|
||||
[self replyToApplicationShouldTerminate:YES];
|
||||
}
|
||||
[self replyToApplicationShouldTerminate:[self _sendDelegateApplicationShouldTerminate]];
|
||||
}
|
||||
|
||||
- (void)replyToApplicationShouldTerminate:(BOOL)terminate
|
||||
@@ -428,16 +455,22 @@ var CPMainCibFile = @"CPMainCibFile",
|
||||
|
||||
- (void)activateIgnoringOtherApps:(BOOL)shouldIgnoreOtherApps
|
||||
{
|
||||
if (_isActive)
|
||||
return;
|
||||
|
||||
[self _willBecomeActive];
|
||||
|
||||
[CPPlatform activateIgnoringOtherApps:shouldIgnoreOtherApps];
|
||||
_isActive = YES;
|
||||
|
||||
[self _willResignActive];
|
||||
[self _didBecomeActive];
|
||||
}
|
||||
|
||||
- (void)deactivate
|
||||
{
|
||||
if (!_isActive)
|
||||
return;
|
||||
|
||||
[self _willResignActive];
|
||||
|
||||
[CPPlatform deactivate];
|
||||
@@ -463,6 +496,15 @@ var CPMainCibFile = @"CPMainCibFile",
|
||||
- (void)run
|
||||
{
|
||||
[self finishLaunching];
|
||||
[self sendEvent:[CPEvent otherEventWithType:CPAppKitDefined
|
||||
location:CGPointMakeZero()
|
||||
modifierFlags:0
|
||||
timestamp:[CPEvent currentTimestamp]
|
||||
windowNumber:[_keyWindow windowNumber]
|
||||
context:nil
|
||||
subtype:nil
|
||||
data1:nil
|
||||
data2:nil]];
|
||||
}
|
||||
|
||||
// Managing the Event Loop
|
||||
@@ -942,7 +984,7 @@ var CPMainCibFile = @"CPMainCibFile",
|
||||
*/
|
||||
- (void)setTarget:(id)aTarget selector:(SEL)aSelector forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
|
||||
{
|
||||
_eventListeners.splice(_eventListenerInsertionIndex++, 0, _CPEventListenerMake(aMask, function (anEvent) { objj_msgSend(aTarget, aSelector, anEvent); }, shouldDequeue));
|
||||
_eventListeners.splice(_eventListenerInsertionIndex++, 0, _CPEventListenerMake(aMask, function (anEvent) { if (aTarget != null) aTarget.isa.objj_msgSend1(aTarget, aSelector, anEvent); }, shouldDequeue));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -971,7 +1013,9 @@ var CPMainCibFile = @"CPMainCibFile",
|
||||
return;
|
||||
}
|
||||
|
||||
[aSheet._windowView _enableSheet:YES inWindow:aWindow];
|
||||
if (![aWindow attachedSheet])
|
||||
[aSheet._windowView _enableSheet:YES inWindow:aWindow];
|
||||
|
||||
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:didEndSelector contextInfo:contextInfo];
|
||||
}
|
||||
|
||||
@@ -1158,7 +1202,7 @@ var CPMainCibFile = @"CPMainCibFile",
|
||||
[[self keyWindow] orderFront:self];
|
||||
else if ([self mainWindow])
|
||||
[[self mainWindow] makeKeyAndOrderFront:self];
|
||||
else
|
||||
else if ([self mainMenu])
|
||||
[[self mainMenu]._menuWindow makeKeyWindow]; //FIXME this may not actually work
|
||||
|
||||
_previousKeyWindow = nil;
|
||||
@@ -1176,6 +1220,22 @@ var CPMainCibFile = @"CPMainCibFile",
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
- (BOOL)_sendDelegateApplicationShouldTerminate
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPApplicationDelegate_applicationShouldTerminate_))
|
||||
return YES;
|
||||
|
||||
return [_delegate applicationShouldTerminate:self];
|
||||
}
|
||||
|
||||
- (CPString)_sendDelegateApplicationShouldTerminateMessage
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPApplicationDelegate_applicationShouldTerminateMessage_))
|
||||
return @"You have attempted to leave this page. Are you sure you want to exit this page?";
|
||||
|
||||
return [_delegate applicationShouldTerminateMessage:self];
|
||||
}
|
||||
|
||||
- (void)_didResignActive
|
||||
{
|
||||
if (self._activeMenu)
|
||||
@@ -1298,7 +1358,7 @@ var _CPAppBootstrapperActions = nil;
|
||||
{
|
||||
var action = _CPAppBootstrapperActions.shift();
|
||||
|
||||
if (objj_msgSend(self, action))
|
||||
if (self.isa.objj_msgSend0(self, action))
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ CPApplicationWillResignActiveNotification = @"CPApplicationWillResignA
|
||||
CPApplicationDidResignActiveNotification = @"CPApplicationDidResignActiveNotification";
|
||||
CPApplicationDidChangeScreenParametersNotification = @"CPApplicationDidChangeScreenParametersNotification";
|
||||
|
||||
@typedef CPApplicationTerminateReply
|
||||
CPTerminateNow = YES;
|
||||
CPTerminateCancel = NO;
|
||||
CPTerminateLater = -1; // not currently supported
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
*/
|
||||
|
||||
@import <Foundation/CPIndexSet.j>
|
||||
|
||||
@import <Foundation/CPPredicate.j>
|
||||
@import "CPObjectController.j"
|
||||
@import "CPKeyValueBinding.j"
|
||||
|
||||
@@ -563,7 +563,7 @@
|
||||
*/
|
||||
- (BOOL)setSelectionIndexes:(CPIndexSet)indexes
|
||||
{
|
||||
[self _selectionWillChange]
|
||||
[self _selectionWillChange];
|
||||
var r = [self __setSelectionIndexes:indexes avoidEmpty:NO];
|
||||
[self _selectionDidChange];
|
||||
return r;
|
||||
|
||||
+24
-2
@@ -24,6 +24,7 @@
|
||||
@import "CPView.j"
|
||||
|
||||
// CPBoxType
|
||||
@typedef CPBoxType
|
||||
CPBoxPrimary = 0;
|
||||
CPBoxSecondary = 1;
|
||||
CPBoxSeparator = 2;
|
||||
@@ -31,12 +32,14 @@ CPBoxOldStyle = 3;
|
||||
CPBoxCustom = 4;
|
||||
|
||||
// CPBorderType
|
||||
@typedef CPBorderType
|
||||
CPNoBorder = 0;
|
||||
CPLineBorder = 1;
|
||||
CPBezelBorder = 2;
|
||||
CPGrooveBorder = 3;
|
||||
|
||||
// CPTitlePosition
|
||||
@typedef CPTitlePosition
|
||||
CPNoTitle = 0;
|
||||
CPAboveTop = 1;
|
||||
CPAtTop = 2;
|
||||
@@ -595,7 +598,8 @@ var CPBoxTypeKey = @"CPBoxTypeKey",
|
||||
CPBoxBorderTypeKey = @"CPBoxBorderTypeKey",
|
||||
CPBoxTitle = @"CPBoxTitle",
|
||||
CPBoxTitlePosition = @"CPBoxTitlePosition",
|
||||
CPBoxTitleView = @"CPBoxTitleView";
|
||||
CPBoxTitleView = @"CPBoxTitleView",
|
||||
CPBoxContentView = @"CPBoxContentView";
|
||||
|
||||
@implementation CPBox (CPCoding)
|
||||
|
||||
@@ -612,8 +616,25 @@ var CPBoxTypeKey = @"CPBoxTypeKey",
|
||||
_titlePosition = [aCoder decodeIntForKey:CPBoxTitlePosition];
|
||||
_titleView = [aCoder decodeObjectForKey:CPBoxTitleView] || [CPTextField labelWithTitle:_title];
|
||||
|
||||
_contentView = [self subviews][0];
|
||||
if (_boxType != CPBoxSeparator)
|
||||
{
|
||||
// FIXME: we have a problem with CIB decoding here.
|
||||
// We should be able to simply add : _contentView = [self subviews][0]
|
||||
// but first box subview seems to be malformed (badly decoded).
|
||||
// For example, when deployed, this view doesn't have its _trackingAreas array initialized.
|
||||
// As a (temporary) workaround, we encode/decode the _contentView property. We then transfer the subview hierarchy
|
||||
// and replace the first (and only) box subview with this _contentView
|
||||
|
||||
_contentView = [aCoder decodeObjectForKey:CPBoxContentView] || [[CPView alloc] initWithFrame:[self bounds]];
|
||||
var malformedContentView = [self subviews][0];
|
||||
[_contentView setSubviews:[malformedContentView subviews]];
|
||||
[self replaceSubview:malformedContentView with:_contentView];
|
||||
}
|
||||
else
|
||||
{
|
||||
_titlePosition = CPNoTitle;
|
||||
}
|
||||
|
||||
[self setAutoresizesSubviews:YES];
|
||||
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
@@ -632,6 +653,7 @@ var CPBoxTypeKey = @"CPBoxTypeKey",
|
||||
[aCoder encodeObject:_title forKey:CPBoxTitle];
|
||||
[aCoder encodeInt:_titlePosition forKey:CPBoxTitlePosition];
|
||||
[aCoder encodeObject:_titleView forKey:CPBoxTitleView];
|
||||
[aCoder encodeObject:_contentView forKey:CPBoxContentView];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+256
-69
@@ -20,6 +20,7 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPIndexSet.j>
|
||||
|
||||
@import "CPControl.j"
|
||||
@@ -30,40 +31,86 @@
|
||||
|
||||
@global CPApp
|
||||
|
||||
@protocol CPBrowserDelegate <CPObject>
|
||||
|
||||
@optional
|
||||
- (BOOL)browser:(CPBrowser)browser acceptDrop:(id)info atRow:(CPInteger)row column:(CPInteger)column dropOperation:(CPTableViewDropOperation)dropOperation;
|
||||
- (BOOL)browser:(CPBrowser)browser canDragRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)column withEvent:(CPEvent )event;
|
||||
- (BOOL)browser:(CPBrowser)browser isLeafItem:(id)item;
|
||||
- (BOOL)browser:(CPBrowser)browser shouldSelectRowIndexes:(CPIndexSet)anIndexSet inColumn:(CPInteger)column;
|
||||
- (BOOL)browser:(CPBrowser)browser writeRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)column toPasteboard:(CPPasteboard)pasteboard;
|
||||
- (CPDragOperation)browser:(CPBrowser)browser validateDrop:(id)info proposedRow:(CPInteger)row column:(CPInteger)column dropOperation:(CPTableViewDropOperation)dropOperation;
|
||||
- (CPImage)browser:(CPBrowser)browser imageValueForItem:(id)anItem;
|
||||
- (CPImage)browser:(CPBrowser)browser draggingImageForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)column withEvent:(CPEvent)event offset:(CGPoint)dragImageOffset;
|
||||
- (CPImage)browser:(CPBrowser)browser imageValueForItem:(id)item;
|
||||
- (CPIndexSet)browser:(CPBrowser)browser selectionIndexesForProposedSelection:(CPIndexSet)proposedSelectionIndexes inColumn:(CPInteger)column;
|
||||
- (CPInteger)browser:(CPBrowser)browser numberOfChildrenOfItem:(id)item;
|
||||
- (CPView)browser:(CPBrowser)browser draggingViewForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)column withEvent:(CPEvent)event offset:(CGPoint)dragImageOffset;
|
||||
- (id)browser:(CPBrowser)browser child:(CPInteger)index ofItem:(id)item;
|
||||
- (id)browser:(CPBrowser)browser objectValueForItem:(id)item;
|
||||
- (id)rootItemForBrowser:(CPBrowser)browser;
|
||||
- (void)browser:(CPBrowser)browser didChangeLastColumn:(CPInteger)oldLastColumn toColumn:(CPInteger)column;
|
||||
- (void)browser:(CPBrowser)browser didResizeColumn:(CPInteger)column;
|
||||
- (void)browserSelectionIsChanging:(CPBrowser)browser;
|
||||
- (void)browserSelectionDidChange:(CPBrowser)browser;
|
||||
|
||||
@end
|
||||
|
||||
var CPBrowserDelegate_browser_acceptDrop_atRow_column_dropOperation_ = 1 << 1,
|
||||
CPBrowserDelegate_browser_canDragRowsWithIndexes_inColumn_withEvent_ = 1 << 2,
|
||||
CPBrowserDelegate_browser_isLeafItem_ = 1 << 3,
|
||||
CPBrowserDelegate_browser_shouldSelectRowIndexes_inColumn_ = 1 << 4,
|
||||
CPBrowserDelegate_browser_writeRowsWithIndexes_inColumn_toPasteboard_ = 1 << 5,
|
||||
CPBrowserDelegate_browser_validateDrop_proposedRow_column_dropOperation_ = 1 << 6,
|
||||
CPBrowserDelegate_browser_imageValueForItem_ = 1 << 7,
|
||||
CPBrowserDelegate_browser_draggingImageForRowsWithIndexes_inColumn_withEvent_offset_ = 1 << 8,
|
||||
CPBrowserDelegate_browser_imageValueForItem_ = 1 << 9,
|
||||
CPBrowserDelegate_browser_selectionIndexesForProposedSelection_inColumn_ = 1 << 10,
|
||||
CPBrowserDelegate_browser_numberOfChildrenOfItem_ = 1 << 11,
|
||||
CPBrowserDelegate_browser_draggingViewForRowsWithIndexes_inColumn_withEvent_offset_ = 1 << 12,
|
||||
CPBrowserDelegate_browser_child_ofItem_ = 1 << 13,
|
||||
CPBrowserDelegate_browser_objectValueForItem_ = 1 << 14,
|
||||
CPBrowserDelegate_rootItemForBrowser_ = 1 << 15,
|
||||
CPBrowserDelegate_browser_didChangeLastColumn_toColumn_ = 1 << 16,
|
||||
CPBrowserDelegate_browser_didResizeColumn_ = 1 << 17,
|
||||
CPBrowserDelegate_browserSelectionIsChanging_ = 1 << 18,
|
||||
CPBrowserDelegate_browserSelectionDidChange_ = 1 << 19;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPBrowser
|
||||
*/
|
||||
@implementation CPBrowser : CPControl
|
||||
{
|
||||
id _delegate;
|
||||
CPString _pathSeparator;
|
||||
id <CPBrowserDelegate> _delegate;
|
||||
CPString _pathSeparator;
|
||||
unsigned _implementedDelegateMethods;
|
||||
|
||||
CPView _contentView;
|
||||
CPScrollView _horizontalScrollView;
|
||||
CPView _prototypeView;
|
||||
CPView _contentView;
|
||||
CPScrollView _horizontalScrollView;
|
||||
CPView _prototypeView;
|
||||
|
||||
CPArray _tableViews;
|
||||
CPArray _tableDelegates;
|
||||
CPArray _tableViews;
|
||||
CPArray _tableDelegates;
|
||||
|
||||
id _rootItem;
|
||||
id _rootItem;
|
||||
|
||||
BOOL _delegateSupportsImages;
|
||||
BOOL _delegateSupportsImages;
|
||||
|
||||
SEL _doubleAction @accessors(property=doubleAction);
|
||||
SEL _doubleAction @accessors(property=doubleAction);
|
||||
|
||||
BOOL _allowsMultipleSelection;
|
||||
BOOL _allowsEmptySelection;
|
||||
BOOL _allowsMultipleSelection;
|
||||
BOOL _allowsEmptySelection;
|
||||
|
||||
Class _tableViewClass @accessors(property=tableViewClass);
|
||||
Class _tableViewClass @accessors(property=tableViewClass);
|
||||
|
||||
float _rowHeight;
|
||||
float _imageWidth;
|
||||
float _leafWidth;
|
||||
float _minColumnWidth;
|
||||
float _defaultColumnWidth @accessors(property=defaultColumnWidth);
|
||||
float _rowHeight;
|
||||
float _imageWidth;
|
||||
float _leafWidth;
|
||||
float _minColumnWidth;
|
||||
float _defaultColumnWidth @accessors(property=defaultColumnWidth);
|
||||
|
||||
CPArray _columnWidths;
|
||||
CPArray _columnWidths;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
@@ -137,10 +184,74 @@
|
||||
[CPKeyedArchiver archivedDataWithRootObject:_prototypeView]];
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)anObject
|
||||
- (void)setDelegate:(id <CPBrowserDelegate>)anObject
|
||||
{
|
||||
if (_delegate === anObject)
|
||||
return;
|
||||
|
||||
_delegate = anObject;
|
||||
_delegateSupportsImages = [_delegate respondsToSelector:@selector(browser:imageValueForItem:)];
|
||||
_implementedDelegateMethods = 0;
|
||||
_delegateSupportsImages = NO;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:acceptDrop:atRow:column:dropOperation:)])
|
||||
_implementedDelegateMethods |= CPBrowserDelegate_browser_acceptDrop_atRow_column_dropOperation_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:canDragRowsWithIndexes:inColumn:withEvent:)])
|
||||
_implementedDelegateMethods |= CPBrowserDelegate_browser_canDragRowsWithIndexes_inColumn_withEvent_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:isLeafItem:)])
|
||||
_implementedDelegateMethods |= CPBrowserDelegate_browser_isLeafItem_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:shouldSelectRowIndexes:inColumn:)])
|
||||
_implementedDelegateMethods |= CPBrowserDelegate_browser_shouldSelectRowIndexes_inColumn_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:)])
|
||||
_implementedDelegateMethods |= CPBrowserDelegate_browser_writeRowsWithIndexes_inColumn_toPasteboard_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:validateDrop:proposedRow:column:dropOperation:)])
|
||||
_implementedDelegateMethods |= CPBrowserDelegate_browser_validateDrop_proposedRow_column_dropOperation_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:imageValueForItem:)])
|
||||
_implementedDelegateMethods |= CPBrowserDelegate_browser_imageValueForItem_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:draggingImageForRowsWithIndexes:inColumn:withEvent:offset:)])
|
||||
_implementedDelegateMethods |= CPBrowserDelegate_browser_draggingImageForRowsWithIndexes_inColumn_withEvent_offset_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:imageValueForItem:)])
|
||||
{
|
||||
_delegateSupportsImages = YES;
|
||||
_implementedDelegateMethods |= CPBrowserDelegate_browser_imageValueForItem_;
|
||||
}
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:selectionIndexesForProposedSelection:inColumn:)])
|
||||
_implementedDelegateMethods |= CPBrowserDelegate_browser_selectionIndexesForProposedSelection_inColumn_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:numberOfChildrenOfItem:)])
|
||||
_implementedDelegateMethods |= CPBrowserDelegate_browser_numberOfChildrenOfItem_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:draggingViewForRowsWithIndexes:inColumn:withEvent:offset:)])
|
||||
_implementedDelegateMethods |= CPBrowserDelegate_browser_draggingViewForRowsWithIndexes_inColumn_withEvent_offset_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:child:ofItem:)])
|
||||
_implementedDelegateMethods |= CPBrowserDelegate_browser_child_ofItem_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:objectValueForItem:)])
|
||||
_implementedDelegateMethods |= CPBrowserDelegate_browser_objectValueForItem_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(rootItemForBrowser:)])
|
||||
_implementedDelegateMethods |= CPBrowserDelegate_rootItemForBrowser_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:didChangeLastColumn:toColumn:)])
|
||||
_implementedDelegateMethods |= CPBrowserDelegate_browser_didChangeLastColumn_toColumn_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:didChangeLastColumn:)])
|
||||
_implementedDelegateMethods |= CPBrowserDelegate_browser_didResizeColumn_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browserSelectionIsChanging:)])
|
||||
_implementedDelegateMethods |= CPBrowserDelegate_browserSelectionIsChanging_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browserSelectionDidChange:)])
|
||||
_implementedDelegateMethods |= CPBrowserDelegate_browserSelectionDidChange_;
|
||||
|
||||
[self loadColumnZero];
|
||||
}
|
||||
@@ -162,10 +273,7 @@
|
||||
|
||||
- (void)loadColumnZero
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(rootItemForBrowser:)])
|
||||
_rootItem = [_delegate rootItemForBrowser:self];
|
||||
else
|
||||
_rootItem = nil;
|
||||
_rootItem = [self _sendDelegateRootItemForBrowser];
|
||||
|
||||
[self setLastColumn:-1];
|
||||
[self addColumn];
|
||||
@@ -190,8 +298,7 @@
|
||||
_tableViews = _tableViews.slice(0, indexPlusOne);
|
||||
_tableDelegates = _tableDelegates.slice(0, indexPlusOne);
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:didChangeLastColumn:toColumn:)])
|
||||
[_delegate browser:self didChangeLastColumn:oldValue toColumn:columnIndex];
|
||||
[self _sendDelegateBrowserDidChangeLastColumn:oldValue toColumn:columnIndex];
|
||||
|
||||
[self tile];
|
||||
}
|
||||
@@ -366,7 +473,7 @@
|
||||
|
||||
- (BOOL)isLeafItem:(id)item
|
||||
{
|
||||
return [_delegate respondsToSelector:@selector(browser:isLeafItem:)] && [_delegate browser:self isLeafItem:item];
|
||||
return (_implementedDelegateMethods & CPBrowserDelegate_browser_isLeafItem_) && [_delegate browser:self isLeafItem:item];
|
||||
}
|
||||
|
||||
- (id)parentForItemsInColumn:(CPInteger)column
|
||||
@@ -493,9 +600,7 @@
|
||||
{
|
||||
_columnWidths[column] = aWidth;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:didResizeColumn:)])
|
||||
[_delegate browser:self didResizeColumn:column];
|
||||
|
||||
[self _sendDelegateBrowserDidResizeColumn:column];
|
||||
[self tile];
|
||||
}
|
||||
|
||||
@@ -610,15 +715,12 @@
|
||||
if (column < 0 || column > [self lastColumn] + 1)
|
||||
return;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:selectionIndexesForProposedSelection:inColumn:)])
|
||||
indexSet = [_delegate browser:self selectionIndexesForProposedSelection:indexSet inColumn:column];
|
||||
indexSet = [self _sendDelegateBrowserSelectionIndexesForProposedSelection:indexSet inColumn:column];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browser:shouldSelectRowIndexes:inColumn:)] &&
|
||||
![_delegate browser:self shouldSelectRowIndexes:indexSet inColumn:column])
|
||||
if (![self _sendDelegateBrowserShouldSelectRowIndexes:indexSet inColumn:column])
|
||||
return;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browserSelectionIsChanging:)])
|
||||
[_delegate browserSelectionIsChanging:self];
|
||||
[self _sendDelegateBrowserSelectionIsChanging];
|
||||
|
||||
if (column > [self lastColumn])
|
||||
[self addColumn];
|
||||
@@ -629,8 +731,7 @@
|
||||
|
||||
[self scrollColumnToVisible:column];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browserSelectionDidChange:)])
|
||||
[_delegate browserSelectionDidChange:self];
|
||||
[self _sendDelegateBrowserSelectionDidChange];
|
||||
}
|
||||
|
||||
- (void)setBackgroundColor:(CPColor)aColor
|
||||
@@ -652,30 +753,6 @@
|
||||
[_tableViews makeObjectsPerformSelector:@selector(registerForDraggedTypes:) withObject:types];
|
||||
}
|
||||
|
||||
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)columnIndex withEvent:(CPEvent)dragEvent
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(browser:canDragRowsWithIndexes:inColumn:withEvent:)])
|
||||
return [_delegate browser:self canDragRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CPImage)draggingImageForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(browser:draggingImageForRowsWithIndexes:inColumn:withEvent:offset:)])
|
||||
return [_delegate browser:self draggingImageForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CPView)draggingViewForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(browser:draggingViewForRowsWithIndexes:inColumn:withEvent:offset:)])
|
||||
return [_delegate browser:self draggingViewForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPBrowser (CPCoding)
|
||||
@@ -860,8 +937,6 @@
|
||||
|
||||
@end
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
@implementation _CPBrowserTableDelegate : CPObject
|
||||
{
|
||||
CPBrowser _browser @accessors;
|
||||
@@ -909,7 +984,7 @@
|
||||
|
||||
- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id)info row:(CPInteger)row dropOperation:(CPTableViewDropOperation)operation
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(browser:acceptDrop:atRow:column:dropOperation:)])
|
||||
if (_browser._implementedDelegateMethods & CPBrowserDelegate_browser_acceptDrop_atRow_column_dropOperation_)
|
||||
return [_delegate browser:_browser acceptDrop:info atRow:row column:_index dropOperation:operation];
|
||||
else
|
||||
return NO;
|
||||
@@ -917,7 +992,7 @@
|
||||
|
||||
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id)info proposedRow:(CPInteger)row proposedDropOperation:(CPTableViewDropOperation)operation
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(browser:validateDrop:proposedRow:column:dropOperation:)])
|
||||
if (_browser._implementedDelegateMethods & CPBrowserDelegate_browser_validateDrop_proposedRow_column_dropOperation_)
|
||||
return [_delegate browser:_browser validateDrop:info proposedRow:row column:_index dropOperation:operation];
|
||||
else
|
||||
return CPDragOperationNone;
|
||||
@@ -925,7 +1000,7 @@
|
||||
|
||||
- (BOOL)tableView:(CPTableView)aTableView writeRowsWithIndexes:(CPIndexSet)rowIndexes toPasteboard:(CPPasteboard)pboard
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(browser:writeRowsWithIndexes:inColumn:toPasteboard:)])
|
||||
if (_browser._implementedDelegateMethods & CPBrowserDelegate_browser_writeRowsWithIndexes_inColumn_toPasteboard_)
|
||||
return [_delegate browser:_browser writeRowsWithIndexes:rowIndexes inColumn:_index toPasteboard:pboard];
|
||||
else
|
||||
return NO;
|
||||
@@ -980,7 +1055,7 @@
|
||||
var imageView = [self layoutEphemeralSubviewNamed:@"image-view"
|
||||
positioned:CPWindowAbove
|
||||
relativeToEphemeralSubviewNamed:nil],
|
||||
isHighlighted = [self themeState] & CPThemeStateSelectedDataView;
|
||||
isHighlighted = [self hasThemeState:CPThemeStateSelectedDataView];
|
||||
|
||||
[imageView setImage: _isLeaf ? (isHighlighted ? _highlightedBranchImage : _branchImage) : nil];
|
||||
[imageView setImageScaling:CPImageScaleNone];
|
||||
@@ -1008,3 +1083,115 @@
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPBrowser (CPBrowserDelegate)
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate rootItemForBrowser:
|
||||
*/
|
||||
- (id)_sendDelegateRootItemForBrowser
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPBrowserDelegate_rootItemForBrowser_))
|
||||
return nil;
|
||||
|
||||
return [_delegate rootItemForBrowser:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate browser:didChangeLastColumn:toColumn:
|
||||
*/
|
||||
- (void)_sendDelegateBrowserDidChangeLastColumn:(CPInteger)lastColumn toColumn:(CPInteger)newColumn
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPBrowserDelegate_browser_didChangeLastColumn_toColumn_))
|
||||
return;
|
||||
|
||||
[_delegate browser:self didChangeLastColumn:lastColumn toColumn:newColumn];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate browser:didResizeColumn:
|
||||
*/
|
||||
- (void)_sendDelegateBrowserDidResizeColumn:(CPInteger)column
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPBrowserDelegate_browser_didResizeColumn_))
|
||||
return;
|
||||
|
||||
[_delegate browser:self didResizeColumn:column];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate browserSelectionIsChanging:
|
||||
*/
|
||||
- (void)_sendDelegateBrowserSelectionIsChanging
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPBrowserDelegate_browserSelectionIsChanging_))
|
||||
return;
|
||||
|
||||
[_delegate browserSelectionIsChanging:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate browser:shouldSelectRowIndexes:inColumn:
|
||||
*/
|
||||
- (BOOL)_sendDelegateBrowserShouldSelectRowIndexes:(CPIndexSet)anIndexSet inColumn:(CPInteger)aColumn
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPBrowserDelegate_browser_shouldSelectRowIndexes_inColumn_))
|
||||
return YES;
|
||||
|
||||
return [_delegate browser:self shouldSelectRowIndexes:anIndexSet inColumn:aColumn];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate browser:selectionIndexesForProposedSelection:inColumn:
|
||||
*/
|
||||
- (CPIndexSet)_sendDelegateBrowserSelectionIndexesForProposedSelection:(CPIndexSet)anIndexSet inColumn:(CPInteger)aColumn
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPBrowserDelegate_browser_selectionIndexesForProposedSelection_inColumn_))
|
||||
return anIndexSet;
|
||||
|
||||
return [_delegate browser:self selectionIndexesForProposedSelection:anIndexSet inColumn:aColumn];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate browserSelectionDidChange
|
||||
*/
|
||||
- (void)_sendDelegateBrowserSelectionDidChange
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPBrowserDelegate_browserSelectionDidChange_))
|
||||
return;
|
||||
|
||||
[_delegate browserSelectionDidChange:self];
|
||||
}
|
||||
|
||||
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)columnIndex withEvent:(CPEvent)dragEvent
|
||||
{
|
||||
if (_implementedDelegateMethods & CPBrowserDelegate_browser_canDragRowsWithIndexes_inColumn_withEvent_)
|
||||
return [_delegate browser:self canDragRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CPImage)draggingImageForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
||||
{
|
||||
if (_implementedDelegateMethods & CPBrowserDelegate_browser_draggingImageForRowsWithIndexes_inColumn_withEvent_offset_)
|
||||
return [_delegate browser:self draggingImageForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CPView)draggingViewForRowsWithIndexes:(CPIndexSet)rowIndexes inColumn:(CPInteger)columnIndex withEvent:(CPEvent)dragEvent offset:(CGPoint)dragImageOffset
|
||||
{
|
||||
if (_implementedDelegateMethods & CPBrowserDelegate_browser_draggingViewForRowsWithIndexes_inColumn_withEvent_offset_)
|
||||
return [_delegate browser:self draggingViewForRowsWithIndexes:rowIndexes inColumn:columnIndex withEvent:dragEvent offset:dragImageOffset];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+22
-10
@@ -29,8 +29,7 @@
|
||||
@import "CPWindow_Constants.j"
|
||||
|
||||
/* @group CPBezelStyle */
|
||||
|
||||
// IB style
|
||||
@typedef CPBezelStyle
|
||||
CPRoundedBezelStyle = 1; // Push
|
||||
CPRegularSquareBezelStyle = 2; // Bevel
|
||||
CPThickSquareBezelStyle = 3;
|
||||
@@ -49,6 +48,7 @@ CPHUDBezelStyle = -1;
|
||||
|
||||
|
||||
/* @group CPButtonType */
|
||||
@typedef CPButtonType
|
||||
CPMomentaryLightButton = 0;
|
||||
CPPushOnPushOffButton = 1;
|
||||
CPToggleButton = 2;
|
||||
@@ -72,13 +72,14 @@ CPPushInCellMask = CPPushInButtonMask;
|
||||
CPChangeGrayCellMask = CPGrayButtonMask;
|
||||
CPChangeBackgroundCellMask = CPBackgroundButtonMask;
|
||||
|
||||
CPButtonStateMixed = CPThemeState("mixed");
|
||||
CPButtonStateBezelStyleRounded = CPThemeState("rounded");
|
||||
CPButtonStateMixed = CPThemeState("mixed");
|
||||
CPButtonStateBezelStyleRounded = CPThemeState("rounded");
|
||||
CPButtonStateBezelStyleRoundRect = CPThemeState("roundRect");
|
||||
|
||||
// add all future correspondance between bezel styles and theme state here.
|
||||
var CPButtonBezelStyleStateMap = @{
|
||||
CPRoundedBezelStyle: CPButtonStateBezelStyleRounded,
|
||||
CPRoundRectBezelStyle: [CPNull null],
|
||||
CPRoundRectBezelStyle: CPButtonStateBezelStyleRoundRect,
|
||||
};
|
||||
|
||||
/// @cond IGNORE
|
||||
@@ -107,7 +108,6 @@ CPButtonImageOffset = 3.0;
|
||||
|
||||
// NS-style Display Properties
|
||||
CPBezelStyle _bezelStyle;
|
||||
CPControlSize _controlSize;
|
||||
|
||||
CPString _keyEquivalent;
|
||||
unsigned _keyEquivalentModifierMask;
|
||||
@@ -188,8 +188,6 @@ CPButtonImageOffset = 3.0;
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_controlSize = CPRegularControlSize;
|
||||
|
||||
_keyEquivalent = @"";
|
||||
_keyEquivalentModifierMask = 0;
|
||||
|
||||
@@ -200,6 +198,20 @@ CPButtonImageOffset = 3.0;
|
||||
[self setButtonType:CPMomentaryPushInButton];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Control Size
|
||||
|
||||
- (void)setControlSize:(CPControlSize)aControlSize
|
||||
{
|
||||
[super setControlSize:aControlSize];
|
||||
|
||||
if ([self isBordered])
|
||||
[self _sizeToControlSize];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
|
||||
// Setting the state
|
||||
/*!
|
||||
Returns a Boolean value indicating whether the button allows a mixed state.
|
||||
@@ -268,7 +280,7 @@ CPButtonImageOffset = 3.0;
|
||||
break;
|
||||
|
||||
case CPOffState:
|
||||
[self unsetThemeState:CPThemeStateSelected | CPButtonStateMixed | CPThemeStateHighlighted];
|
||||
[self unsetThemeStates:[CPThemeStateSelected, CPButtonStateMixed, CPThemeStateHighlighted]];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,7 +378,7 @@ CPButtonImageOffset = 3.0;
|
||||
|
||||
- (void)setImage:(CPImage)anImage
|
||||
{
|
||||
[self setValue:anImage forThemeAttribute:@"image"];
|
||||
[self setValue:anImage forThemeAttribute:@"image" inState:CPThemeStateNormal];
|
||||
}
|
||||
|
||||
- (CPImage)image
|
||||
|
||||
+40
-10
@@ -26,7 +26,10 @@
|
||||
@class CPSplitView
|
||||
|
||||
@global CPPopUpButtonStatePullsDown
|
||||
|
||||
@global CPKeyValueChangeOldKey
|
||||
@global CPKeyValueChangeNewKey
|
||||
@global CPKeyValueObservingOptionNew
|
||||
@global CPKeyValueObservingOptionOld
|
||||
|
||||
@implementation CPButtonBar : CPView
|
||||
{
|
||||
@@ -109,6 +112,8 @@
|
||||
|
||||
- (void)awakeFromCib
|
||||
{
|
||||
[super awakeFromCib];
|
||||
|
||||
var view = [self superview],
|
||||
subview = self;
|
||||
|
||||
@@ -129,10 +134,20 @@
|
||||
|
||||
- (void)setButtons:(CPArray)buttons
|
||||
{
|
||||
for (var i = [_buttons count] - 1; i >= 0; i--)
|
||||
{
|
||||
[_buttons[i] removeFromSuperview];
|
||||
[_buttons[i] removeObserver:self forKeyPath:@"hidden"];
|
||||
}
|
||||
|
||||
|
||||
_buttons = [CPArray arrayWithArray:buttons];
|
||||
|
||||
for (var i = 0, count = [_buttons count]; i < count; i++)
|
||||
for (var i = [_buttons count] - 1; i >= 0; i--)
|
||||
{
|
||||
[_buttons[i] addObserver:self forKeyPath:@"hidden" options:CPKeyValueObservingOptionNew | CPKeyValueObservingOptionOld context:nil];
|
||||
[_buttons[i] setBordered:YES];
|
||||
}
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
@@ -218,8 +233,15 @@
|
||||
count = [buttonsNotHidden count];
|
||||
|
||||
while (count--)
|
||||
if ([buttonsNotHidden[count] isHidden])
|
||||
[buttonsNotHidden removeObject:buttonsNotHidden[count]];
|
||||
{
|
||||
var button = buttonsNotHidden[count];
|
||||
|
||||
if ([button isHidden])
|
||||
{
|
||||
[button removeFromSuperview];
|
||||
[buttonsNotHidden removeObject:button];
|
||||
}
|
||||
}
|
||||
|
||||
var currentButtonOffset = _resizeControlIsLeftAligned ? CGRectGetMaxX([self bounds]) + 1 : -1,
|
||||
bounds = [self bounds],
|
||||
@@ -250,15 +272,15 @@
|
||||
currentButtonOffset += width - 1;
|
||||
}
|
||||
|
||||
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal | CPThemeStateBordered];
|
||||
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted | CPThemeStateBordered];
|
||||
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled | CPThemeStateBordered];
|
||||
[button setValue:normalColor forThemeAttribute:@"bezel-color" inStates:[CPThemeStateNormal, CPThemeStateBordered]];
|
||||
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inStates:[CPThemeStateHighlighted, CPThemeStateBordered, ]];
|
||||
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inStates:[CPThemeStateDisabled, CPThemeStateBordered]];
|
||||
[button setValue:textColor forThemeAttribute:@"text-color" inState:CPThemeStateBordered];
|
||||
|
||||
// FIXME shouldn't need this
|
||||
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal | CPThemeStateBordered | CPPopUpButtonStatePullsDown];
|
||||
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted | CPThemeStateBordered | CPPopUpButtonStatePullsDown];
|
||||
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled | CPThemeStateBordered | CPPopUpButtonStatePullsDown];
|
||||
[button setValue:normalColor forThemeAttribute:@"bezel-color" inStates:[CPThemeStateNormal, CPThemeStateBordered, CPPopUpButtonStatePullsDown]];
|
||||
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inStates:[CPThemeStateHighlighted, CPThemeStateBordered, CPPopUpButtonStatePullsDown]];
|
||||
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inStates:[CPThemeStateDisabled, CPThemeStateBordered, CPPopUpButtonStatePullsDown]];
|
||||
|
||||
[self addSubview:button];
|
||||
}
|
||||
@@ -274,6 +296,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(CPString)keyPath ofObject:(id)object change:(CPDictionary)change context:(id)context
|
||||
{
|
||||
if ([change objectForKey:CPKeyValueChangeOldKey] == [change objectForKey:CPKeyValueChangeNewKey])
|
||||
return;
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)setFrameSize:(CGSize)aSize
|
||||
{
|
||||
[super setFrameSize:aSize];
|
||||
|
||||
@@ -111,6 +111,30 @@ CPCheckBoxImageOffset = 4.0;
|
||||
return startedTracking;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Override methods from CPButton
|
||||
|
||||
- (CGSize)_minimumFrameSize
|
||||
{
|
||||
var size = [super _minimumFrameSize],
|
||||
contentView = [self ephemeralSubviewNamed:@"content-view"];
|
||||
|
||||
if (!contentView && [[self title] length])
|
||||
{
|
||||
var minSize = [self currentValueForThemeAttribute:@"min-size"],
|
||||
maxSize = [self currentValueForThemeAttribute:@"max-size"];
|
||||
|
||||
// Here we always add the min size to the control which is the size of the view of the checkBox
|
||||
size.width += minSize.width + CPCheckBoxImageOffset;
|
||||
|
||||
if (maxSize.width >= 0.0)
|
||||
size.width = MIN(size.width, maxSize.width);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPCheckBoxValueBinder : CPBinder
|
||||
|
||||
+5
-38
@@ -46,49 +46,12 @@
|
||||
return;
|
||||
|
||||
if (_documentView)
|
||||
{
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
[defaultCenter
|
||||
removeObserver:self
|
||||
name:CPViewFrameDidChangeNotification
|
||||
object:_documentView];
|
||||
|
||||
[defaultCenter
|
||||
removeObserver:self
|
||||
name:CPViewBoundsDidChangeNotification
|
||||
object:_documentView];
|
||||
|
||||
[_documentView removeFromSuperview];
|
||||
}
|
||||
|
||||
_documentView = aView;
|
||||
|
||||
if (_documentView)
|
||||
{
|
||||
[self addSubview:_documentView];
|
||||
[self _observeDocumentView];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_observeDocumentView
|
||||
{
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
[_documentView setPostsFrameChangedNotifications:YES];
|
||||
[_documentView setPostsBoundsChangedNotifications:YES];
|
||||
|
||||
[defaultCenter
|
||||
addObserver:self
|
||||
selector:@selector(viewFrameChanged:)
|
||||
name:CPViewFrameDidChangeNotification
|
||||
object:_documentView];
|
||||
|
||||
[defaultCenter
|
||||
addObserver:self
|
||||
selector:@selector(viewBoundsChanged:)
|
||||
name:CPViewBoundsDidChangeNotification
|
||||
object:_documentView];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -230,6 +193,11 @@
|
||||
return [self scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)];
|
||||
}
|
||||
|
||||
- (CGRect)documentVisibleRect
|
||||
{
|
||||
return [_documentView visibleRect];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -244,7 +212,6 @@ var CPClipViewDocumentViewKey = @"CPScrollViewDocumentView";
|
||||
// Don't call setDocumentView: here. It calls addSubview:, but it's A) not necessary since the
|
||||
// view hierarchy is fully encoded and B) dangerous if the subview is not fully decoded.
|
||||
_documentView = [aCoder decodeObjectForKey:CPClipViewDocumentViewKey];
|
||||
[self _observeDocumentView];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
+303
-106
@@ -31,6 +31,37 @@
|
||||
@import "CPDragServer_Constants.j"
|
||||
@import "CPPasteboard.j"
|
||||
@import "CPView.j"
|
||||
@import "CPKeyValueBinding.j"
|
||||
|
||||
@class _CPCollectionViewDropIndicator
|
||||
|
||||
var CPCollectionViewDelegate_collectionView_acceptDrop_index_dropOperation_ = 1 << 0,
|
||||
CPCollectionViewDelegate_collectionView_canDragItemsAtIndexes_withEvent_ = 1 << 1,
|
||||
CPCollectionViewDelegate_collectionView_writeItemsAtIndexes_toPasteboard_ = 1 << 2,
|
||||
CPCollectionViewDelegate_collectionView_dragTypesForItemsAtIndexes_ = 1 << 3,
|
||||
CPCollectionViewDelegate_collectionView_dataForItemsAtIndexes_forType_ = 1 << 4,
|
||||
CPCollectionViewDelegate_collectionView_validateDrop_proposedIndex_dropOperation_ = 1 << 5,
|
||||
CPCollectionViewDelegate_collectionView_didDoubleClickOnItemAtIndex_ = 1 << 6,
|
||||
CPCollectionViewDelegate_collectionView_menuForItemAtIndex_ = 1 << 7,
|
||||
CPCollectionViewDelegate_collectionView_draggingViewForItemsAtIndexes_withEvent_offset = 1 << 8;
|
||||
|
||||
|
||||
@protocol CPCollectionViewDelegate <CPObject>
|
||||
|
||||
@optional
|
||||
- (BOOL)collectionView:(CPCollectionView)collectionView acceptDrop:(id)draggingInfo index:(CPInteger)index dropOperation:(CPCollectionViewDropOperation)dropOperation;
|
||||
- (BOOL)collectionView:(CPCollectionView)collectionView canDragItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)event;
|
||||
- (BOOL)collectionView:(CPCollectionView)collectionView writeItemsAtIndexes:(CPIndexSet)indexes toPasteboard:(CPPasteboard)pasteboard;
|
||||
- (CPArray)collectionView:(CPCollectionView)collectionView dragTypesForItemsAtIndexes:(CPIndexSet)indexes;
|
||||
- (CPData)collectionView:(CPCollectionView)collectionView dataForItemsAtIndexes:(CPIndexSet)indices forType:(CPString)aType;
|
||||
- (CPDragOperation)collectionView:(CPCollectionView)collectionView validateDrop:(id)draggingInfo proposedIndex:(CPInteger)proposedDropIndex dropOperation:(CPCollectionViewDropOperation)proposedDropOperation;
|
||||
- (CPMenu)collectionView:(CPCollectionView)collectionView menuForItemAtIndex:(CPInteger)anIndex;
|
||||
- (CPView)collectionView:(CPCollectionView)collectionView draggingViewForItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)event offset:(CGPoint)dragImageOffset;
|
||||
- (void)collectionView:(CPCollectionView)collectionView didDoubleClickOnItemAtIndex:(int)index;
|
||||
|
||||
@end
|
||||
|
||||
var HORIZONTAL_MARGIN = 2;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -42,10 +73,6 @@
|
||||
|
||||
@par Delegate Methods
|
||||
|
||||
@delegate - (void)collectionViewDidChangeSelection:(CPCollectionView)collectionView;
|
||||
DEPRECATED: Please do not use.
|
||||
@param collectionView the collection view who's selection changed
|
||||
|
||||
@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
|
||||
@@ -64,56 +91,61 @@
|
||||
@param indices the indices to obtain drag types
|
||||
@return an array of drag types (CPString)
|
||||
*/
|
||||
|
||||
var HORIZONTAL_MARGIN = 2;
|
||||
|
||||
@implementation CPCollectionView : CPView
|
||||
{
|
||||
CPArray _content;
|
||||
CPArray _items;
|
||||
CPArray _content;
|
||||
CPArray _items;
|
||||
|
||||
CPData _itemData;
|
||||
CPCollectionViewItem _itemPrototype;
|
||||
CPCollectionViewItem _itemForDragging;
|
||||
CPMutableArray _cachedItems;
|
||||
CPData _itemData;
|
||||
CPCollectionViewItem _itemPrototype;
|
||||
CPCollectionViewItem _itemForDragging;
|
||||
CPMutableArray _cachedItems;
|
||||
|
||||
unsigned _maxNumberOfRows;
|
||||
unsigned _maxNumberOfColumns;
|
||||
unsigned _maxNumberOfRows;
|
||||
unsigned _maxNumberOfColumns;
|
||||
|
||||
CGSize _minItemSize;
|
||||
CGSize _maxItemSize;
|
||||
CGSize _minItemSize;
|
||||
CGSize _maxItemSize;
|
||||
|
||||
CPArray _backgroundColors;
|
||||
CPArray _backgroundColors;
|
||||
|
||||
float _tileWidth;
|
||||
float _tileWidth;
|
||||
|
||||
BOOL _isSelectable;
|
||||
BOOL _allowsMultipleSelection;
|
||||
BOOL _allowsEmptySelection;
|
||||
CPIndexSet _selectionIndexes;
|
||||
BOOL _isSelectable;
|
||||
BOOL _allowsMultipleSelection;
|
||||
BOOL _allowsEmptySelection;
|
||||
CPIndexSet _selectionIndexes;
|
||||
|
||||
CGSize _itemSize;
|
||||
CGSize _itemSize;
|
||||
|
||||
float _horizontalMargin;
|
||||
float _verticalMargin;
|
||||
float _horizontalMargin;
|
||||
float _verticalMargin;
|
||||
|
||||
unsigned _numberOfRows;
|
||||
unsigned _numberOfColumns;
|
||||
unsigned _numberOfRows;
|
||||
unsigned _numberOfColumns;
|
||||
|
||||
id _delegate;
|
||||
id <CPCollectionViewDelegate> _delegate;
|
||||
unsigned _implementedDelegateMethods;
|
||||
|
||||
CPEvent _mouseDownEvent;
|
||||
CPEvent _mouseDownEvent;
|
||||
|
||||
BOOL _needsMinMaxItemSizeUpdate;
|
||||
CGSize _storedFrameSize;
|
||||
BOOL _needsMinMaxItemSizeUpdate;
|
||||
CGSize _storedFrameSize;
|
||||
|
||||
BOOL _uniformSubviewsResizing @accessors(property=uniformSubviewsResizing);
|
||||
BOOL _lockResizing;
|
||||
BOOL _uniformSubviewsResizing @accessors(property=uniformSubviewsResizing);
|
||||
|
||||
CPInteger _currentDropIndex;
|
||||
CPDragOperation _currentDragOperation;
|
||||
CPInteger _currentDropIndex;
|
||||
CPDragOperation _currentDragOperation;
|
||||
|
||||
_CPCollectionViewDropIndicator _dropView;
|
||||
_CPCollectionViewDropIndicator _dropView;
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding == CPContentBinding)
|
||||
return [_CPCollectionViewContentBinder class];
|
||||
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -158,7 +190,7 @@ var HORIZONTAL_MARGIN = 2;
|
||||
|
||||
_needsMinMaxItemSizeUpdate = YES;
|
||||
_uniformSubviewsResizing = NO;
|
||||
_lockResizing = NO;
|
||||
_inLiveResize = NO;
|
||||
|
||||
_currentDropIndex = -1;
|
||||
_currentDragOperation = CPDragOperationNone;
|
||||
@@ -168,6 +200,51 @@ var HORIZONTAL_MARGIN = 2;
|
||||
[self setAutoresizingMask:0];
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Delegate
|
||||
|
||||
/*!
|
||||
Set the delegate of the receiver
|
||||
@param aDelegate the delegate object for the collectionView.
|
||||
*/
|
||||
- (void)setDelegate:(id <CPCollectionViewDelegate>)aDelegate
|
||||
{
|
||||
if (_delegate === aDelegate)
|
||||
return;
|
||||
|
||||
_delegate = aDelegate;
|
||||
_implementedDelegateMethods = 0;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(collectionView:acceptDrop:index:dropOperation:)])
|
||||
_implementedDelegateMethods |= CPCollectionViewDelegate_collectionView_acceptDrop_index_dropOperation_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(collectionView:canDragItemsAtIndexes:withEvent:)])
|
||||
_implementedDelegateMethods |= CPCollectionViewDelegate_collectionView_canDragItemsAtIndexes_withEvent_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(collectionView:writeItemsAtIndexes:toPasteboard:)])
|
||||
_implementedDelegateMethods |= CPCollectionViewDelegate_collectionView_writeItemsAtIndexes_toPasteboard_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(collectionView:dragTypesForItemsAtIndexes:)])
|
||||
_implementedDelegateMethods |= CPCollectionViewDelegate_collectionView_dragTypesForItemsAtIndexes_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(collectionView:dataForItemsAtIndexes:forType:)])
|
||||
_implementedDelegateMethods |= CPCollectionViewDelegate_collectionView_dataForItemsAtIndexes_forType_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(collectionView:validateDrop:proposedIndex:dropOperation:)])
|
||||
_implementedDelegateMethods |= CPCollectionViewDelegate_collectionView_validateDrop_proposedIndex_dropOperation_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(collectionView:didDoubleClickOnItemAtIndex:)])
|
||||
_implementedDelegateMethods |= CPCollectionViewDelegate_collectionView_didDoubleClickOnItemAtIndex_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(collectionView:menuForItemAtIndex:)])
|
||||
_implementedDelegateMethods |= CPCollectionViewDelegate_collectionView_menuForItemAtIndex_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(collectionView:draggingViewForItemsAtIndexes:withEvent:offset:)])
|
||||
_implementedDelegateMethods |= CPCollectionViewDelegate_collectionView_draggingViewForItemsAtIndexes_withEvent_offset;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the item prototype to \c anItem
|
||||
@param anItem the new item prototype.
|
||||
@@ -315,14 +392,7 @@ var HORIZONTAL_MARGIN = 2;
|
||||
_isSelectable = isSelectable;
|
||||
|
||||
if (!_isSelectable)
|
||||
{
|
||||
var index = CPNotFound,
|
||||
itemCount = [_items count];
|
||||
|
||||
// Be wary of invalid selection ranges since setContent: does not clear selection indexes.
|
||||
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound && index < itemCount)
|
||||
[_items[index] setSelected:NO];
|
||||
}
|
||||
[self _applySelectionToItems:NO];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -376,31 +446,18 @@ var HORIZONTAL_MARGIN = 2;
|
||||
{
|
||||
if (!anIndexSet)
|
||||
anIndexSet = [CPIndexSet indexSet];
|
||||
|
||||
if (!_isSelectable || [_selectionIndexes isEqual:anIndexSet])
|
||||
return;
|
||||
|
||||
var index = CPNotFound,
|
||||
itemCount = [_items count];
|
||||
|
||||
// Be wary of invalid selection ranges since setContent: does not clear selection indexes.
|
||||
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) !== CPNotFound && index < itemCount)
|
||||
[_items[index] setSelected:NO];
|
||||
[self _applySelectionToItems:NO];
|
||||
|
||||
_selectionIndexes = anIndexSet;
|
||||
|
||||
var index = CPNotFound;
|
||||
|
||||
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) !== CPNotFound)
|
||||
[_items[index] setSelected:YES];
|
||||
[self _applySelectionToItems:YES];
|
||||
|
||||
var binderClass = [[self class] _binderClassForBinding:@"selectionIndexes"];
|
||||
[[binderClass getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)])
|
||||
{
|
||||
CPLog.warn("The delegate method collectionViewDidChangeSelection: is deprecated and will be removed in a future version, please bind to selectionIndexes instead.");
|
||||
[_delegate collectionViewDidChangeSelection:self];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -462,14 +519,14 @@ var HORIZONTAL_MARGIN = 2;
|
||||
|
||||
- (void)resizeWithOldSuperviewSize:(CGSize)oldBoundsSize
|
||||
{
|
||||
if (_lockResizing)
|
||||
if (_inLiveResize)
|
||||
return;
|
||||
|
||||
_lockResizing = YES;
|
||||
_inLiveResize = YES;
|
||||
|
||||
[self tile];
|
||||
|
||||
_lockResizing = NO;
|
||||
_inLiveResize = NO;
|
||||
}
|
||||
|
||||
- (void)tile
|
||||
@@ -545,7 +602,7 @@ var HORIZONTAL_MARGIN = 2;
|
||||
|
||||
height = MAX(height, numberOfRows * (_minItemSize.height + _verticalMargin));
|
||||
|
||||
var itemSizeHeight = FLOOR(height / numberOfRows);
|
||||
var itemSizeHeight = FLOOR(height / numberOfRows) - _verticalMargin;
|
||||
|
||||
if (maxItemSizeHeight > 0)
|
||||
itemSizeHeight = MIN(itemSizeHeight, maxItemSizeHeight);
|
||||
@@ -755,8 +812,8 @@ var HORIZONTAL_MARGIN = 2;
|
||||
|
||||
- (void)mouseUp:(CPEvent)anEvent
|
||||
{
|
||||
if ([_selectionIndexes count] && [anEvent clickCount] == 2 && [_delegate respondsToSelector:@selector(collectionView:didDoubleClickOnItemAtIndex:)])
|
||||
[_delegate collectionView:self didDoubleClickOnItemAtIndex:[_selectionIndexes firstIndex]];
|
||||
if ([_selectionIndexes count] && [anEvent clickCount] == 2)
|
||||
[self _sendDelegateDidDoubleClickOnItemAtIndex:[_selectionIndexes firstIndex]];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
@@ -846,15 +903,6 @@ var HORIZONTAL_MARGIN = 2;
|
||||
return _verticalMargin;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the collection view's delegate
|
||||
@param aDelegate the new delegate
|
||||
*/
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
{
|
||||
_delegate = aDelegate;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the collection view's delegate
|
||||
*/
|
||||
@@ -868,13 +916,13 @@ var HORIZONTAL_MARGIN = 2;
|
||||
*/
|
||||
- (CPMenu)menuForEvent:(CPEvent)theEvent
|
||||
{
|
||||
if (![[self delegate] respondsToSelector:@selector(collectionView:menuForItemAtIndex:)])
|
||||
if (![self _delegateRespondsToCollectionViewMenuForItemAtIndex])
|
||||
return [super menuForEvent:theEvent];
|
||||
|
||||
var location = [self convertPoint:[theEvent locationInWindow] fromView:nil],
|
||||
index = [self _indexAtPoint:location];
|
||||
|
||||
return [_delegate collectionView:self menuForItemAtIndex:index];
|
||||
return [self _sendDelegateMenuForItemAtIndex:index];
|
||||
}
|
||||
|
||||
- (int)_indexAtPoint:(CGPoint)thePoint
|
||||
@@ -918,6 +966,20 @@ var HORIZONTAL_MARGIN = 2;
|
||||
return frame;
|
||||
}
|
||||
|
||||
- (void)_applySelectionToItems:(BOOL)select
|
||||
{
|
||||
var numberOfItems = [_items count];
|
||||
|
||||
[_selectionIndexes enumerateIndexesUsingBlock:function(idx, stop)
|
||||
{
|
||||
if (idx < numberOfItems)
|
||||
[[_items objectAtIndex:idx] setSelected:select];
|
||||
else {
|
||||
stop(YES);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPCollectionView (DragAndDrop)
|
||||
@@ -932,7 +994,7 @@ var HORIZONTAL_MARGIN = 2;
|
||||
*/
|
||||
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
|
||||
{
|
||||
[aPasteboard setData:[_delegate collectionView:self dataForItemsAtIndexes:_selectionIndexes forType:aType] forType:aType];
|
||||
[aPasteboard setData:[self _sendDelegateDataForItemsAtIndexes:_selectionIndexes forType:aType] forType:aType];
|
||||
}
|
||||
|
||||
- (void)_createDropIndicatorIfNeeded
|
||||
@@ -962,24 +1024,23 @@ var HORIZONTAL_MARGIN = 2;
|
||||
(ABS(locationInWindow.y - mouseDownLocationInWindow.y) < 3))
|
||||
return;
|
||||
|
||||
if (![_delegate respondsToSelector:@selector(collectionView:dragTypesForItemsAtIndexes:)])
|
||||
if (![self _delegateRespondsToCollectionViewDragTypesForItemsAtIndexes])
|
||||
return;
|
||||
|
||||
// If we don't have any selected items, we've clicked away, and thus the drag is meaningless.
|
||||
if (![_selectionIndexes count])
|
||||
return;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(collectionView:canDragItemsAtIndexes:withEvent:)] &&
|
||||
![_delegate collectionView:self canDragItemsAtIndexes:_selectionIndexes withEvent:_mouseDownEvent])
|
||||
if (![self _sendDelegateCanDragItemsAtIndexes:_selectionIndexes withEvent:_mouseDownEvent])
|
||||
return;
|
||||
|
||||
// Set up the pasteboard
|
||||
var dragTypes = [_delegate collectionView:self dragTypesForItemsAtIndexes:_selectionIndexes];
|
||||
var dragTypes = [self _sendDelegateDragTypesForItemsAtIndexes:_selectionIndexes];
|
||||
|
||||
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:dragTypes owner:self];
|
||||
|
||||
var dragImageOffset = CGSizeMakeZero(),
|
||||
view = [self _draggingViewForItemsAtIndexes:_selectionIndexes withEvent:_mouseDownEvent offset:dragImageOffset];
|
||||
view = [self _sendDelegateDraggingViewForItemsAtIndexes:_selectionIndexes withEvent:_mouseDownEvent offset:dragImageOffset];
|
||||
|
||||
[view setFrameSize:_itemSize];
|
||||
[view setAlphaValue:0.7];
|
||||
@@ -996,14 +1057,6 @@ var HORIZONTAL_MARGIN = 2;
|
||||
slideBack:YES];
|
||||
}
|
||||
|
||||
- (CPView)_draggingViewForItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)anEvent offset:(CGPoint)offset
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(collectionView:draggingViewForItemsAtIndexes:withEvent:offset:)])
|
||||
return [_delegate collectionView:self draggingViewForItemsAtIndexes:indexes withEvent:anEvent offset:offset];
|
||||
|
||||
return [self draggingViewForItemsAtIndexes:indexes withEvent:anEvent offset:offset];
|
||||
}
|
||||
|
||||
- (CPView)draggingViewForItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)event offset:(CGPoint)dragImageOffset
|
||||
{
|
||||
var idx = _content[[indexes firstIndex]];
|
||||
@@ -1016,14 +1069,6 @@ var HORIZONTAL_MARGIN = 2;
|
||||
return [_itemForDragging view];
|
||||
}
|
||||
|
||||
- (BOOL)_canDragItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)anEvent
|
||||
{
|
||||
if ([self respondsToSelector:@selector(collectionView:canDragItemsAtIndexes:withEvent:)])
|
||||
return [_delegate collectionView:self canDragItemsAtIndexes:indexes withEvent:anEvent];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CPDragOperation)draggingEntered:(id)draggingInfo
|
||||
{
|
||||
var dropIndex = -1,
|
||||
@@ -1061,16 +1106,14 @@ var HORIZONTAL_MARGIN = 2;
|
||||
var result = CPDragOperationMove,
|
||||
dropIndex = [self _dropIndexForDraggingInfo:draggingInfo proposedDropOperation:dropOperation];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(collectionView:validateDrop:proposedIndex:dropOperation:)])
|
||||
if ([self _delegateRespondsToCollectionViewValidateDropProposedIndexDropOperation])
|
||||
{
|
||||
var dropIndexRef2 = @ref(dropIndex);
|
||||
|
||||
result = [_delegate collectionView:self validateDrop:draggingInfo proposedIndex:dropIndexRef2 dropOperation:dropOperation];
|
||||
result = [self _sendDelegateValidateDrop:draggingInfo proposedIndex:dropIndexRef2 dropOperation:dropOperation];
|
||||
|
||||
if (result !== CPDragOperationNone)
|
||||
{
|
||||
dropIndex = dropIndexRef2();
|
||||
}
|
||||
}
|
||||
|
||||
dropIndexRef(dropIndex);
|
||||
@@ -1104,7 +1147,7 @@ Not supported. Use -collectionView:dataForItemsAtIndexes:fortype:
|
||||
var result = NO;
|
||||
|
||||
if (_currentDragOperation && _currentDropIndex !== -1)
|
||||
result = [_delegate collectionView:self acceptDrop:draggingInfo index:_currentDropIndex dropOperation:1];
|
||||
result = [self _sendDelegateAcceptDrop:draggingInfo index:_currentDropIndex dropOperation:1];
|
||||
|
||||
[self draggingEnded:draggingInfo]; // Is this correct ?
|
||||
|
||||
@@ -1329,6 +1372,7 @@ Not supported. Use -collectionView:dataForItemsAtIndexes:fortype:
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation CPCollectionView (Deprecated)
|
||||
|
||||
- (CGRect)rectForItemAtIndex:(int)anIndex
|
||||
@@ -1349,6 +1393,148 @@ Not supported. Use -collectionView:dataForItemsAtIndexes:fortype:
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation CPCollectionView (CPCollectionViewDelegate)
|
||||
|
||||
/*
|
||||
@ignore
|
||||
Return YES if the delegate implements collectionView:validateDrop:proposedIndex:dropOperation:
|
||||
*/
|
||||
- (BOOL)_delegateRespondsToCollectionViewValidateDropProposedIndexDropOperation
|
||||
{
|
||||
return _implementedDelegateMethods & CPCollectionViewDelegate_collectionView_validateDrop_proposedIndex_dropOperation_;
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
Return YES if the delegate implements collectionView:menuForItemAtIndex:
|
||||
*/
|
||||
- (BOOL)_delegateRespondsToCollectionViewMenuForItemAtIndex
|
||||
{
|
||||
return _implementedDelegateMethods & CPCollectionViewDelegate_collectionView_menuForItemAtIndex_;
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
Return YES if the delegate implements collectionView:dragTypesForItemsAtIndexes:
|
||||
*/
|
||||
- (BOOL)_delegateRespondsToCollectionViewDragTypesForItemsAtIndexes
|
||||
{
|
||||
return _implementedDelegateMethods & CPCollectionViewDelegate_collectionView_dragTypesForItemsAtIndexes_;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate collectionView:acceptDrop:index:dropOperation:
|
||||
*/
|
||||
- (BOOL)_sendDelegateAcceptDrop:(id)draggingInfo index:(CPInteger)index dropOperation:(CPCollectionViewDropOperation)dropOperation
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_acceptDrop_index_dropOperation_))
|
||||
return NO;
|
||||
|
||||
return [_delegate collectionView:self acceptDrop:draggingInfo index:index dropOperation:dropOperation];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate collectionView:canDragItemsAtIndexes:withEvent:
|
||||
*/
|
||||
- (BOOL)_sendDelegateCanDragItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)anEvent
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_canDragItemsAtIndexes_withEvent_))
|
||||
return YES;
|
||||
|
||||
return [_delegate collectionView:self canDragItemsAtIndexes:indexes withEvent:anEvent];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate collectionView:writeItemsAtIndexes:toPasteboard:
|
||||
*/
|
||||
- (BOOL)_sendDelegateWriteItemsAtIndexes:(CPIndexSet)indexes toPasteboard:(CPPasteboard)pasteboard
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_writeItemsAtIndexes_toPasteboard_))
|
||||
return NO;
|
||||
|
||||
return [_delegate collectionView:self writeItemsAtIndexes:indexes toPasteboard:pasteboard];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate collectionView:dragTypesForItemsAtIndexes:
|
||||
*/
|
||||
- (CPArray)_sendDelegateDragTypesForItemsAtIndexes:(CPIndexSet)indexes
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_dragTypesForItemsAtIndexes_))
|
||||
return [];
|
||||
|
||||
return [_delegate collectionView:self dragTypesForItemsAtIndexes:indexes];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate collectionView:dataForItemsAtIndexes:forType:
|
||||
*/
|
||||
- (CPData)_sendDelegateDataForItemsAtIndexes:(CPIndexSet)indexes forType:(CPString)aType
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_dataForItemsAtIndexes_forType_))
|
||||
return nil;
|
||||
|
||||
return [_delegate collectionView:self dataForItemsAtIndexes:indexes forType:aType];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate collectionView:validateDrop:proposedIndex:dropOperation:
|
||||
*/
|
||||
- (CPDragOperation)_sendDelegateValidateDrop:(id)draggingInfo proposedIndex:(CPInteger)proposedDropIndex dropOperation:(CPCollectionViewDropOperation)proposedDropOperation
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_validateDrop_proposedIndex_dropOperation_))
|
||||
return CPDragOperationNone;
|
||||
|
||||
return [_delegate collectionView:self validateDrop:draggingInfo proposedIndex:proposedDropIndex dropOperation:proposedDropOperation];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate collectionView:didDoubleClickOnItemAtIndex:
|
||||
*/
|
||||
- (void)_sendDelegateDidDoubleClickOnItemAtIndex:(int)index
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_didDoubleClickOnItemAtIndex_))
|
||||
return;
|
||||
|
||||
return [_delegate collectionView:self didDoubleClickOnItemAtIndex:index];
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate collectionView:menuForItemAtIndex:
|
||||
*/
|
||||
- (void)_sendDelegateMenuForItemAtIndex:(CPInteger)anIndex
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_menuForItemAtIndex_))
|
||||
return nil;
|
||||
|
||||
return [_delegate collectionView:self menuForItemAtIndex:anIndex];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate draggingViewForItemsAtIndexes:withEvent:offset:
|
||||
*/
|
||||
- (CPView)_sendDelegateDraggingViewForItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)anEvent offset:(CGPoint)dragImageOffset
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPCollectionViewDelegate_collectionView_draggingViewForItemsAtIndexes_withEvent_offset))
|
||||
return [self draggingViewForItemsAtIndexes:indexes withEvent:anEvent offset:dragImageOffset];
|
||||
|
||||
return [_delegate collectionView:self draggingViewForItemsAtIndexes:indexes withEvent:anEvent offset:dragImageOffset];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
||||
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
|
||||
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
|
||||
@@ -1408,3 +1594,14 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeK
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPCollectionViewContentBinder : CPBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
[_source setContent:aValue];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+300
-9
@@ -25,6 +25,7 @@
|
||||
|
||||
@import "CGColor.j"
|
||||
|
||||
@import "_CPObject+Theme.j"
|
||||
@import "CPCompatibility.j"
|
||||
@import "CPImage.j"
|
||||
|
||||
@@ -65,7 +66,8 @@ var cachedBlackColor,
|
||||
cachedOrangeColor,
|
||||
cachedPurpleColor,
|
||||
cachedShadowColor,
|
||||
cachedClearColor;
|
||||
cachedClearColor,
|
||||
cachedThemeColor;
|
||||
|
||||
/// @endcond
|
||||
|
||||
@@ -78,7 +80,7 @@ var cachedBlackColor,
|
||||
<p>It also provides some class helper methods that
|
||||
returns instances of commonly used colors.</p>
|
||||
*/
|
||||
@implementation CPColor : CPObject
|
||||
@implementation CPColor : CPObject <CPTheme>
|
||||
{
|
||||
CPArray _components;
|
||||
|
||||
@@ -86,6 +88,30 @@ var cachedBlackColor,
|
||||
CPString _cssString;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Theming
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return "color";
|
||||
}
|
||||
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return @{
|
||||
@"alternate-selected-control-color": [CPNull null],
|
||||
@"secondary-selected-control-color": [CPNull null],
|
||||
@"selected-text-background-color": [CPNull null],
|
||||
@"selected-text-inactive-background-color": [CPNull null],
|
||||
@"css-based": NO
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Static methods
|
||||
|
||||
/*!
|
||||
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
|
||||
@@ -436,14 +462,22 @@ var cachedBlackColor,
|
||||
return cachedClearColor;
|
||||
}
|
||||
|
||||
+ (CPColor)_cachedThemeColor
|
||||
{
|
||||
if (!cachedThemeColor)
|
||||
cachedThemeColor = [self colorWithCalibratedWhite:0.0 alpha:0.0];
|
||||
|
||||
return cachedThemeColor;
|
||||
}
|
||||
|
||||
+ (CPColor)alternateSelectedControlColor
|
||||
{
|
||||
return [[CPColor alloc] _initWithRGBA:[0.22, 0.46, 0.84, 1.0]];
|
||||
return [[self _cachedThemeColor] valueForThemeAttribute:@"alternate-selected-control-color"];
|
||||
}
|
||||
|
||||
+ (CPColor)secondarySelectedControlColor
|
||||
{
|
||||
return [[CPColor alloc] _initWithRGBA:[0.83, 0.83, 0.83, 1.0]];
|
||||
return [[self _cachedThemeColor] valueForThemeAttribute:@"secondary-selected-control-color"];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -467,6 +501,16 @@ var cachedBlackColor,
|
||||
return [[CPColor alloc] _initWithCSSString: aString];
|
||||
}
|
||||
|
||||
+ (CPColor)selectedTextBackgroundColor
|
||||
{
|
||||
return [[self _cachedThemeColor] valueForThemeAttribute:@"selected-text-background-color"] || [CPColor colorWithHexString:"99CCFF"];
|
||||
}
|
||||
|
||||
+ (CPColor)_selectedTextBackgroundColorUnfocussed
|
||||
{
|
||||
return [[self _cachedThemeColor] valueForThemeAttribute:@"selected-text-inactive-background-color"] || [CPColor colorWithHexString:"CCCCCC"];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (id)_initWithCSSString:(CPString)aString
|
||||
{
|
||||
@@ -489,6 +533,10 @@ var cachedBlackColor,
|
||||
// use it (issue #1413.)
|
||||
[self _initCSSStringFromComponents];
|
||||
|
||||
_theme = [CPTheme defaultTheme];
|
||||
_themeState = CPThemeStateNormal;
|
||||
[self _loadThemeAttributes];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -502,6 +550,10 @@ var cachedBlackColor,
|
||||
_components = components;
|
||||
|
||||
[self _initCSSStringFromComponents];
|
||||
|
||||
_theme = [CPTheme defaultTheme];
|
||||
_themeState = CPThemeStateNormal;
|
||||
[self _loadThemeAttributes];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -528,6 +580,10 @@ var cachedBlackColor,
|
||||
_patternImage = anImage;
|
||||
_cssString = "url(\"" + [_patternImage filename] + "\")";
|
||||
_components = [0.0, 0.0, 0.0, 1.0];
|
||||
|
||||
_theme = [CPTheme defaultTheme];
|
||||
_themeState = CPThemeStateNormal;
|
||||
[self _loadThemeAttributes];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -813,11 +869,229 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
|
||||
return [CPColor colorWithRed:RAND() green:RAND() blue:RAND() alpha:1.0];
|
||||
}
|
||||
|
||||
+ (CPColor)checkerBoardColor
|
||||
{
|
||||
// Thanks to cocco http://stackoverflow.com/a/18368212/76900.
|
||||
return [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEX////MzMw46qqDAAAAEElEQVQImWNg+M+AFeEQBgB+vw/xfUUZkgAAAABJRU5ErkJggg=="]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark CSS Theming
|
||||
|
||||
// The code below adds support for CSS theming with 100% compatibility with current theming system.
|
||||
// The idea is to extend CPColor (and CPImage) with CSS components and adapt low level UI components to
|
||||
// support this new kind of CPColor/CPImage. See CPImageView, CPView and _CPImageAndTextView.
|
||||
//
|
||||
// To create a CPColor that uses CSS, simply use the new class method :
|
||||
// + (CPColor)colorWithCSSDictionary:(CPDictionary)aDictionary beforeDictionary:(CPDictionary)beforeDictionary afterDictionary:(CPDictionary)afterDictionary
|
||||
// where beforeDictionary & afterDictionary are related to ::before & ::after pseudo-elements.
|
||||
// If you don't need them, just use the simplified class method :
|
||||
// + (CPColor)colorWithCSSDictionary:(CPDictionary)aDictionary
|
||||
//
|
||||
// Example :
|
||||
// buttonCssColor = [CPColor colorWithCSSDictionary:@{
|
||||
// @"background-color": A3ColorBackgroundWhite,
|
||||
// @"border-color": A3ColorActiveBorder,
|
||||
// @"border-style": @"solid",
|
||||
// @"border-width": @"1px",
|
||||
// @"border-radius": @"3px",
|
||||
// @"box-sizing": @"border-box"
|
||||
// }
|
||||
// beforeDictionary:@{
|
||||
// @"background-color": @"rgb(225,225,225)",
|
||||
// @"bottom": @"3px",
|
||||
// @"content": @"''",
|
||||
// @"position": @"absolute",
|
||||
// @"right": @"21px",
|
||||
// @"top": @"3px",
|
||||
// @"width": @"1px"
|
||||
// }
|
||||
// afterDictionary:@{
|
||||
// @"content": @"''",
|
||||
// @"bottom": @"3px",
|
||||
// @"right": @"6px",
|
||||
// @"top": @"1px",
|
||||
// @"position": @"absolute",
|
||||
// @"height": @"14px",
|
||||
// @"width": @"9px",
|
||||
// @"margin": @"2px 0px 2px 0px",
|
||||
// @"background-image": @"url(%%packed.png)",
|
||||
// @"background-position": @"0px -64px",
|
||||
// @"background-repeat": @"no-repeat",
|
||||
// @"background-size": @"100px 400px"
|
||||
// }];
|
||||
//
|
||||
// Remark : Please note the special URL of the background image used in this example : url(%%packed.png)
|
||||
// During theme loading, "%%" will be replaced by the path to the theme blend resources folder.
|
||||
// Typically, a CSS theme will use some (rare) images all packed together in a single image resource (see packed.png in Aristo3 theme)
|
||||
//
|
||||
// Also, please note that if you don't use one of the CSS components, you can either set it to nil (best solution) or to an empty dictionary, like :
|
||||
// aCssColor = [CPColor colorWithCSSDictionary:@{} beforeDictionary:nil afterDictionary:@{ ... }];
|
||||
//
|
||||
// You can use -(BOOL)isCSSBased to determine how to cope with it in your code.
|
||||
// -(BOOL)hasCSSDictionary, -(BOOL)hasCSSBeforeDictionary and -(BOOL)hasCSSAfterDictionary are convience methods you can use.
|
||||
//
|
||||
// Remark : -(void)restorePreviousCSSState and -(DOMElement)applyCSSColorForView are meant to be used by low level UI widgets (like CPView) to implement
|
||||
// CSS theme support.
|
||||
|
||||
@implementation CPColor (CSSTheming)
|
||||
{
|
||||
CPDictionary _cssDictionary @accessors(property=cssDictionary);
|
||||
CPDictionary _cssBeforeDictionary @accessors(property=cssBeforeDictionary);
|
||||
CPDictionary _cssAfterDictionary @accessors(property=cssAfterDictionary);
|
||||
}
|
||||
|
||||
+ (CPColor)colorWithCSSDictionary:(CPDictionary)aDictionary
|
||||
{
|
||||
return [[CPColor alloc] _initWithCSSDictionary:aDictionary beforeDictionary:nil afterDictionary:nil];
|
||||
}
|
||||
|
||||
+ (CPColor)colorWithCSSDictionary:(CPDictionary)aDictionary beforeDictionary:(CPDictionary)beforeDictionary afterDictionary:(CPDictionary)afterDictionary
|
||||
{
|
||||
return [[CPColor alloc] _initWithCSSDictionary:aDictionary beforeDictionary:beforeDictionary afterDictionary:afterDictionary];
|
||||
}
|
||||
|
||||
- (id)_initWithCSSDictionary:(CPDictionary)aDictionary beforeDictionary:(CPDictionary)beforeDictionary afterDictionary:(CPDictionary)afterDictionary
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_cssDictionary = aDictionary;
|
||||
_cssBeforeDictionary = beforeDictionary;
|
||||
_cssAfterDictionary = afterDictionary;
|
||||
_components = [0.0, 0.0, 0.0, 1.0];
|
||||
|
||||
_theme = [CPTheme defaultTheme];
|
||||
_themeState = CPThemeStateNormal;
|
||||
[self _loadThemeAttributes];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isCSSBased
|
||||
{
|
||||
return !!(_cssDictionary || _cssBeforeDictionary || _cssAfterDictionary);
|
||||
}
|
||||
|
||||
- (BOOL)hasCSSDictionary
|
||||
{
|
||||
return ([_cssDictionary count] > 0);
|
||||
}
|
||||
|
||||
- (BOOL)hasCSSBeforeDictionary
|
||||
{
|
||||
return ([_cssBeforeDictionary count] > 0);
|
||||
}
|
||||
|
||||
- (BOOL)hasCSSAfterDictionary
|
||||
{
|
||||
return ([_cssAfterDictionary count] > 0);
|
||||
}
|
||||
|
||||
- (void)restorePreviousCSSState:(CPArrayRef)aPreviousStateRef forDOMElement:(DOMElement)aDOMElement
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
var aPreviousState = @deref(aPreviousStateRef);
|
||||
|
||||
for (var i = 0, count = aPreviousState.length; i < count; i++)
|
||||
aDOMElement.style[aPreviousState[i][0]] = aPreviousState[i][1];
|
||||
|
||||
@deref(aPreviousStateRef) = @[];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (DOMElement)applyCSSColorForView:(CPView)aView onDOMElement:(DOMElement)aDOMElement styleNode:(DOMElement)aStyleNode previousState:(CPArrayRef)aPreviousStateRef
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
var aPreviousState = @deref(aPreviousStateRef);
|
||||
|
||||
[_cssDictionary enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
|
||||
{
|
||||
[aPreviousState addObject:@[aKey, aDOMElement.style[aKey]]];
|
||||
aDOMElement.style[aKey] = anObject;
|
||||
}];
|
||||
|
||||
if ([self hasCSSBeforeDictionary] || [self hasCSSAfterDictionary])
|
||||
{
|
||||
// We need to create a unique class name
|
||||
|
||||
var styleClassName = @".CP" + [aView UID],
|
||||
styleContent = @"";
|
||||
|
||||
if ([self hasCSSBeforeDictionary])
|
||||
{
|
||||
styleContent += styleClassName + @"::before { ";
|
||||
|
||||
[_cssBeforeDictionary enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
|
||||
{
|
||||
styleContent += aKey + ": " + anObject + "; ";
|
||||
}];
|
||||
|
||||
styleContent += "} ";
|
||||
}
|
||||
|
||||
if ([self hasCSSAfterDictionary])
|
||||
{
|
||||
styleContent += styleClassName + @"::after { ";
|
||||
|
||||
[_cssAfterDictionary enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
|
||||
{
|
||||
styleContent += aKey + ": " + anObject + "; ";
|
||||
}];
|
||||
|
||||
styleContent += "} ";
|
||||
}
|
||||
|
||||
var styleDescription = document.createTextNode(styleContent);
|
||||
|
||||
if (!aStyleNode)
|
||||
{
|
||||
aStyleNode = document.createElement("style");
|
||||
|
||||
aView._DOMElement.insertBefore(aStyleNode, aView._DOMElement.firstChild);
|
||||
|
||||
aStyleNode.appendChild(styleDescription);
|
||||
}
|
||||
else
|
||||
{
|
||||
aStyleNode.replaceChild(styleDescription, aStyleNode.firstChild);
|
||||
}
|
||||
|
||||
[aView setDOMClassName:@"CP"+[aView UID]];
|
||||
}
|
||||
else
|
||||
{
|
||||
// no before/after so remove aStyleNode if existing
|
||||
|
||||
if (aStyleNode)
|
||||
{
|
||||
aView._DOMElement.removeChild(aStyleNode);
|
||||
aStyleNode = nil;
|
||||
}
|
||||
}
|
||||
|
||||
// Return actualised values
|
||||
|
||||
@deref(aPreviousStateRef) = aPreviousState;
|
||||
|
||||
return aStyleNode;
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
/// @cond IGNORE
|
||||
var CPColorComponentsKey = @"CPColorComponentsKey",
|
||||
CPColorPatternImageKey = @"CPColorPatternImageKey";
|
||||
var CPColorComponentsKey = @"CPColorComponentsKey",
|
||||
CPColorPatternImageKey = @"CPColorPatternImageKey",
|
||||
CPColorCssDictionaryKey = @"CPColorCssDictionaryKey",
|
||||
CPColorCssBeforeDictionaryKey = @"CPColorCssBeforeDictionaryKey",
|
||||
CPColorCssAfterDictionaryKey = @"CPColorCssAfterDictionaryKey";
|
||||
/// @endcond
|
||||
|
||||
@implementation CPColor (CPCoding)
|
||||
@@ -829,9 +1103,17 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if ([aCoder containsValueForKey:CPColorPatternImageKey])
|
||||
return [self _initWithPatternImage:[aCoder decodeObjectForKey:CPColorPatternImageKey]];
|
||||
self = [self _initWithPatternImage:[aCoder decodeObjectForKey:CPColorPatternImageKey]];
|
||||
else if ([aCoder containsValueForKey:CPColorCssDictionaryKey])
|
||||
self = [self _initWithCSSDictionary:[aCoder decodeObjectForKey:CPColorCssDictionaryKey]
|
||||
beforeDictionary:[aCoder decodeObjectForKey:CPColorCssBeforeDictionaryKey]
|
||||
afterDictionary:[aCoder decodeObjectForKey:CPColorCssAfterDictionaryKey]];
|
||||
else
|
||||
self = [self _initWithRGBA:[aCoder decodeObjectForKey:CPColorComponentsKey]];
|
||||
|
||||
return [self _initWithRGBA:[aCoder decodeObjectForKey:CPColorComponentsKey]];
|
||||
[self _decodeThemeObjectsWithCoder:aCoder];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -842,8 +1124,16 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
|
||||
{
|
||||
if (_patternImage)
|
||||
[aCoder encodeObject:_patternImage forKey:CPColorPatternImageKey];
|
||||
else if (_cssDictionary)
|
||||
{
|
||||
[aCoder encodeObject:_cssDictionary forKey:CPColorCssDictionaryKey];
|
||||
[aCoder encodeObject:_cssBeforeDictionary forKey:CPColorCssBeforeDictionaryKey];
|
||||
[aCoder encodeObject:_cssAfterDictionary forKey:CPColorCssAfterDictionaryKey];
|
||||
}
|
||||
else
|
||||
[aCoder encodeObject:_components forKey:CPColorComponentsKey];
|
||||
|
||||
[self _encodeThemeObjectsWithCoder:aCoder];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1180,7 +1470,8 @@ var patternColorsFromPattern = function(pattern, attributes, imageFactory)
|
||||
bottomHeight,
|
||||
centerWidthHeight,
|
||||
centerIsNil,
|
||||
numParts;
|
||||
numParts,
|
||||
isVertical;
|
||||
|
||||
// positions are mandatory
|
||||
if (pattern.indexOf("{position}") < 0)
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
@import "CPView.j"
|
||||
|
||||
@class CPSlider
|
||||
@class _CPColorPanelToolbar
|
||||
@class _CPColorPanelSwatches
|
||||
@class _CPColorPanelPreview
|
||||
|
||||
@global CPApp
|
||||
|
||||
@@ -68,7 +71,6 @@ var SharedColorPanel = nil,
|
||||
*/
|
||||
@implementation CPColorPanel : CPPanel
|
||||
{
|
||||
_CPColorPanelToolbar _toolbar;
|
||||
_CPColorPanelSwatches _swatchView;
|
||||
_CPColorPanelPreview _previewView;
|
||||
|
||||
@@ -481,13 +483,12 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
];
|
||||
}
|
||||
|
||||
var cookieValue = eval(cookieValue),
|
||||
result = [];
|
||||
var cookieValue = eval(cookieValue);
|
||||
|
||||
for (var i = 0; i < cookieValue.length; i++)
|
||||
result.push([CPColor colorWithHexString:cookieValue[i]]);
|
||||
|
||||
return result;
|
||||
return [cookieValue arrayByApplyingBlock:function(value)
|
||||
{
|
||||
return [CPColor colorWithHexString:value];
|
||||
}];
|
||||
}
|
||||
|
||||
- (CPArray)saveColorList
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
@import "CPView.j"
|
||||
|
||||
@class CPSlider
|
||||
@class CPColorPanel
|
||||
@class __CPColorWheel
|
||||
|
||||
@global CPColorPickerViewWidth
|
||||
@global CPColorPickerViewHeight
|
||||
@@ -123,7 +125,8 @@
|
||||
_brightnessSlider = [[CPSlider alloc] initWithFrame:CGRectMake(0, (aFrame.size.height - 34), aFrame.size.width, 15)];
|
||||
|
||||
[_brightnessSlider setValue:15.0 forThemeAttribute:@"track-width"];
|
||||
[_brightnessSlider setValue:[CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPColorPicker class]] pathForResource:@"brightness_bar.png"]]] forThemeAttribute:@"track-color"];
|
||||
var brightnessImage = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPColorPicker class]] pathForResource:@"brightness_bar.png"] size:CGSizeMake(272, 20)];
|
||||
[_brightnessSlider setValue:[CPColor colorWithPatternImage:brightnessImage] forThemeAttribute:@"track-color"];
|
||||
|
||||
[_brightnessSlider setMinValue:0.0];
|
||||
[_brightnessSlider setMaxValue:100.0];
|
||||
@@ -244,7 +247,7 @@
|
||||
_blackWheelImage = new Image();
|
||||
_blackWheelImage.src = path;
|
||||
_blackWheelImage.style.opacity = "0";
|
||||
_blackWheelImage.style.filter = "alpha(opacity=0)"
|
||||
_blackWheelImage.style.filter = "alpha(opacity=0)";
|
||||
_blackWheelImage.style.position = "absolute";
|
||||
|
||||
_DOMElement.appendChild(_wheelImage);
|
||||
|
||||
+41
-5
@@ -86,14 +86,12 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
_active = NO;
|
||||
_color = [CPColor whiteColor];
|
||||
[self setBordered:YES];
|
||||
|
||||
[self _registerForNotifications];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_registerForNotifications
|
||||
- (void)_registerNotifications
|
||||
{
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
@@ -110,6 +108,22 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
object:[CPColorPanel sharedColorPanel]];
|
||||
}
|
||||
|
||||
- (void)_removeNotifications
|
||||
{
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
[defaultCenter
|
||||
removeObserver:self
|
||||
name:_CPColorWellDidBecomeExclusiveNotification
|
||||
object:nil];
|
||||
|
||||
[defaultCenter
|
||||
removeObserver:self
|
||||
name:CPWindowWillCloseNotification
|
||||
object:[CPColorPanel sharedColorPanel]];
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets whether the color well is bordered.
|
||||
*/
|
||||
@@ -241,6 +255,8 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
|
||||
var colorPanel = [CPColorPanel sharedColorPanel];
|
||||
|
||||
[colorPanel setPlatformWindow:[[self window] platformWindow]];
|
||||
|
||||
[colorPanel setColor:_color];
|
||||
[colorPanel orderFront:self];
|
||||
}
|
||||
@@ -312,6 +328,28 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
[contentBorderView setBackgroundColor:[self currentValueForThemeAttribute:@"content-border-color"]];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Observers method
|
||||
|
||||
- (void)_addObservers
|
||||
{
|
||||
if (_isObserving)
|
||||
return;
|
||||
|
||||
[super _addObservers];
|
||||
[self _registerNotifications];
|
||||
}
|
||||
|
||||
- (void)_removeObservers
|
||||
{
|
||||
if (!_isObserving)
|
||||
return;
|
||||
|
||||
[super _removeObservers];
|
||||
[self _removeNotifications];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPColorWellValueBinder : CPBinder
|
||||
@@ -363,8 +401,6 @@ var CPColorWellColorKey = "CPColorWellColorKey",
|
||||
_active = NO;
|
||||
_color = [aCoder decodeObjectForKey:CPColorWellColorKey];
|
||||
[self setBordered:[aCoder decodeBoolForKey:CPColorWellBorderedKey]];
|
||||
|
||||
[self _registerForNotifications];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
+181
-80
@@ -25,6 +25,27 @@
|
||||
@import "_CPPopUpList.j"
|
||||
|
||||
|
||||
// TODO : should conform to protocol CPTextFieldDelegate
|
||||
@protocol CPComboBoxDelegate <CPObject>
|
||||
|
||||
@optional
|
||||
- (void)comboBoxSelectionIsChanging:(CPNotification)aNotification;
|
||||
- (void)comboBoxSelectionDidChange:(CPNotification)aNotification;
|
||||
- (void)comboBoxWillPopUp:(CPNotification)aNotification;
|
||||
- (void)comboBoxWillDismiss:(CPNotification)aNotification;
|
||||
|
||||
@end
|
||||
|
||||
@protocol CPComboBoxDataSource <CPObject>
|
||||
|
||||
@optional
|
||||
- (CPString)comboBox:(CPComboBox)aComboBox completedString:(CPString)uncompletedString;
|
||||
- (id)comboBox:(CPComboBox)aComboBox objectValueForItemAtIndex:(int)index;
|
||||
- (int)comboBox:(CPComboBox)aComboBox indexOfItemWithStringValue:(CPString)stringValue;
|
||||
- (int)numberOfItemsInComboBox:(CPComboBox)aComboBox;
|
||||
|
||||
@end
|
||||
|
||||
CPComboBoxSelectionDidChangeNotification = @"CPComboBoxSelectionDidChangeNotification";
|
||||
CPComboBoxSelectionIsChangingNotification = @"CPComboBoxSelectionIsChangingNotification";
|
||||
CPComboBoxWillDismissNotification = @"CPComboBoxWillDismissNotification";
|
||||
@@ -32,6 +53,11 @@ CPComboBoxWillPopUpNotification = @"CPComboBoxWillPopUpNotification";
|
||||
|
||||
CPComboBoxStateButtonBordered = CPThemeState("button-bordered");
|
||||
|
||||
var CPComboBoxDelegate_comboBoxSelectionIsChanging_ = 1 << 0,
|
||||
CPComboBoxDelegate_comboBoxSelectionDidChange_ = 1 << 1,
|
||||
CPComboBoxDelegate_comboBoxWillPopUp_ = 1 << 2,
|
||||
CPComboBoxDelegate_comboBoxWillDismiss_ = 1 << 3;
|
||||
|
||||
var CPComboBoxTextSubview = @"text",
|
||||
CPComboBoxButtonSubview = @"button",
|
||||
CPComboBoxDefaultNumberOfVisibleItems = 5,
|
||||
@@ -40,17 +66,20 @@ var CPComboBoxTextSubview = @"text",
|
||||
|
||||
@implementation CPComboBox : CPTextField
|
||||
{
|
||||
CPArray _items;
|
||||
_CPPopUpList _listDelegate;
|
||||
CPComboBoxDataSource _dataSource;
|
||||
BOOL _usesDataSource;
|
||||
BOOL _completes;
|
||||
BOOL _canComplete;
|
||||
int _numberOfVisibleItems;
|
||||
BOOL _forceSelection;
|
||||
BOOL _hasVerticalScroller;
|
||||
CPString _selectedStringValue;
|
||||
BOOL _popUpButtonCausedResign;
|
||||
BOOL _canComplete;
|
||||
BOOL _completes;
|
||||
BOOL _forceSelection;
|
||||
BOOL _hasVerticalScroller;
|
||||
BOOL _popUpButtonCausedResign;
|
||||
BOOL _usesDataSource;
|
||||
CGSize _intercellSpacing;
|
||||
CPArray _items;
|
||||
id <CPComboBoxDataSource> _dataSource;
|
||||
CPInteger _implementedDelegateComboBoxMethods;
|
||||
CPString _selectedStringValue;
|
||||
float _itemHeight;
|
||||
int _numberOfVisibleItems;
|
||||
_CPPopUpList _listDelegate;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
@@ -119,7 +148,9 @@ var CPComboBoxTextSubview = @"text",
|
||||
return;
|
||||
|
||||
_hasVerticalScroller = flag;
|
||||
[[_listDelegate scrollView] setHasVerticalScroller:flag];
|
||||
|
||||
if (_listDelegate)
|
||||
[[_listDelegate scrollView] setHasVerticalScroller:_hasVerticalScroller];
|
||||
}
|
||||
|
||||
- (CGSize)intercellSpacing
|
||||
@@ -129,7 +160,13 @@ var CPComboBoxTextSubview = @"text",
|
||||
|
||||
- (void)setIntercellSpacing:(CGSize)aSize
|
||||
{
|
||||
[[_listDelegate tableView] setIntercellSpacing:aSize];
|
||||
if (_intercellSpacing && CGSizeEqualToSize(aSize, _intercellSpacing))
|
||||
return;
|
||||
|
||||
_intercellSpacing = aSize;
|
||||
|
||||
if (_listDelegate)
|
||||
[[_listDelegate tableView] setIntercellSpacing:_intercellSpacing];
|
||||
}
|
||||
|
||||
- (BOOL)isButtonBordered
|
||||
@@ -152,10 +189,18 @@ var CPComboBoxTextSubview = @"text",
|
||||
|
||||
- (void)setItemHeight:(float)itemHeight
|
||||
{
|
||||
[[_listDelegate tableView] setRowHeight:itemHeight];
|
||||
if (itemHeight === _itemHeight)
|
||||
return;
|
||||
|
||||
// FIXME: This shouldn't be necessary, but CPTableView does not tile after setRowHeight
|
||||
[[_listDelegate tableView] reloadData];
|
||||
_itemHeight = itemHeight;
|
||||
|
||||
if (_listDelegate)
|
||||
{
|
||||
[[_listDelegate tableView] setRowHeight:_itemHeight];
|
||||
|
||||
// FIXME: This shouldn't be necessary, but CPTableView does not tile after setRowHeight
|
||||
[[_listDelegate tableView] reloadData];
|
||||
}
|
||||
}
|
||||
|
||||
- (int)numberOfVisibleItems
|
||||
@@ -171,7 +216,7 @@ var CPComboBoxTextSubview = @"text",
|
||||
|
||||
#pragma mark Setting a Delegate
|
||||
|
||||
- (id /*< CPComboBoxDelegate >*/)delegate
|
||||
- (id <CPComboBoxDelegate>)delegate
|
||||
{
|
||||
return [super delegate];
|
||||
}
|
||||
@@ -182,48 +227,28 @@ var CPComboBoxTextSubview = @"text",
|
||||
protocol, in actual fact it doesn't. Also note that the same
|
||||
delegate may conform to the NSTextFieldDelegate protocol.
|
||||
*/
|
||||
- (void)setDelegate:(id /*< CPComboBoxDelegate >*/)aDelegate
|
||||
- (void)setDelegate:(id <CPComboBoxDelegate>)aDelegate
|
||||
{
|
||||
var delegate = [self delegate];
|
||||
|
||||
if (aDelegate === delegate)
|
||||
return;
|
||||
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
if (delegate)
|
||||
{
|
||||
[defaultCenter removeObserver:delegate name:CPComboBoxSelectionIsChangingNotification object:self];
|
||||
[defaultCenter removeObserver:delegate name:CPComboBoxSelectionDidChangeNotification object:self];
|
||||
[defaultCenter removeObserver:delegate name:CPComboBoxWillDismissNotification object:self];
|
||||
[defaultCenter removeObserver:delegate name:CPComboBoxWillPopUpNotification object:self];
|
||||
}
|
||||
_implementedDelegateComboBoxMethods = 0;
|
||||
|
||||
if (aDelegate)
|
||||
{
|
||||
if ([aDelegate respondsToSelector:@selector(comboBoxSelectionIsChanging:)])
|
||||
[defaultCenter addObserver:delegate
|
||||
selector:@selector(comboBoxSelectionIsChanging:)
|
||||
name:CPComboBoxSelectionIsChangingNotification
|
||||
object:self];
|
||||
_implementedDelegateComboBoxMethods |= CPComboBoxDelegate_comboBoxSelectionIsChanging_;
|
||||
|
||||
if ([aDelegate respondsToSelector:@selector(comboBoxSelectionDidChange:)])
|
||||
[defaultCenter addObserver:delegate
|
||||
selector:@selector(comboBoxSelectionDidChange:)
|
||||
name:CPComboBoxSelectionDidChangeNotification
|
||||
object:self];
|
||||
_implementedDelegateComboBoxMethods |= CPComboBoxDelegate_comboBoxSelectionDidChange_;
|
||||
|
||||
if ([aDelegate respondsToSelector:@selector(comboBoxWillPopUp:)])
|
||||
[defaultCenter addObserver:delegate
|
||||
selector:@selector(comboBoxWillPopUp:)
|
||||
name:CPComboBoxWillPopUpNotification
|
||||
object:self];
|
||||
_implementedDelegateComboBoxMethods |= CPComboBoxDelegate_comboBoxWillPopUp_;
|
||||
|
||||
if ([aDelegate respondsToSelector:@selector(comboBoxWillDismiss:)])
|
||||
[defaultCenter addObserver:delegate
|
||||
selector:@selector(comboBoxWillDissmis:)
|
||||
name:CPComboBoxWillDismissNotification
|
||||
object:self];
|
||||
_implementedDelegateComboBoxMethods |= CPComboBoxDelegate_comboBoxWillDismiss_;
|
||||
}
|
||||
|
||||
[super setDelegate:aDelegate];
|
||||
@@ -231,7 +256,7 @@ var CPComboBoxTextSubview = @"text",
|
||||
|
||||
#pragma mark Setting a Data Source
|
||||
|
||||
- (id /*< CPComboBoxDataSource >*/)dataSource
|
||||
- (id <CPComboBoxDataSource>)dataSource
|
||||
{
|
||||
if (!_usesDataSource)
|
||||
[self _dataSourceWarningForMethod:_cmd condition:NO];
|
||||
@@ -239,10 +264,12 @@ var CPComboBoxTextSubview = @"text",
|
||||
return _dataSource;
|
||||
}
|
||||
|
||||
- (void)setDataSource:(id /*< CPComboBoxDataSource >*/)aSource
|
||||
- (void)setDataSource:(id <CPComboBoxDataSource>)aSource
|
||||
{
|
||||
if (!_usesDataSource)
|
||||
{
|
||||
[self _dataSourceWarningForMethod:_cmd condition:NO];
|
||||
}
|
||||
else if (_dataSource !== aSource)
|
||||
{
|
||||
if (![aSource respondsToSelector:@selector(numberOfItemsInComboBox:)] ||
|
||||
@@ -251,7 +278,9 @@ var CPComboBoxTextSubview = @"text",
|
||||
CPLog.warn("Illegal %s data source (%s). Must implement numberOfItemsInComboBox: and comboBox:objectValueForItemAtIndex:", [self className], [aSource description]);
|
||||
}
|
||||
else
|
||||
{
|
||||
_dataSource = aSource;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,49 +398,57 @@ var CPComboBoxTextSubview = @"text",
|
||||
if (_listDelegate === aDelegate)
|
||||
return;
|
||||
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
if (_listDelegate)
|
||||
{
|
||||
[defaultCenter removeObserver:self name:_CPPopUpListWillPopUpNotification object:_listDelegate];
|
||||
[defaultCenter removeObserver:self name:_CPPopUpListWillDismissNotification object:_listDelegate];
|
||||
[defaultCenter removeObserver:self name:_CPPopUpListDidDismissNotification object:_listDelegate];
|
||||
[defaultCenter removeObserver:self name:_CPPopUpListItemWasClickedNotification object:_listDelegate];
|
||||
|
||||
var oldTableView = [_listDelegate tableView];
|
||||
|
||||
if (oldTableView)
|
||||
{
|
||||
[defaultCenter removeObserver:self name:CPTableViewSelectionIsChangingNotification object:oldTableView];
|
||||
[defaultCenter removeObserver:self name:CPTableViewSelectionDidChangeNotification object:oldTableView];
|
||||
}
|
||||
}
|
||||
[self _removeObserversForListDelegate:_listDelegate];
|
||||
|
||||
_listDelegate = aDelegate;
|
||||
|
||||
// We only add the observers if the CPComboBox is displayed
|
||||
if ([self window])
|
||||
[self _addObserversForListDelegate:_listDelegate]
|
||||
|
||||
// Apply our text style to the list
|
||||
[_listDelegate setFont:[self font]];
|
||||
[_listDelegate setAlignment:[self alignment]];
|
||||
|
||||
[[_listDelegate scrollView] setHasVerticalScroller:_hasVerticalScroller];
|
||||
|
||||
if (_intercellSpacing)
|
||||
[[_listDelegate tableView] setIntercellSpacing:_intercellSpacing];
|
||||
|
||||
if (_itemHeight)
|
||||
[[_listDelegate tableView] setRowHeight:_itemHeight];
|
||||
}
|
||||
|
||||
- (void)_addObserversForListDelegate:(_CPPopUpList)aDelegate
|
||||
{
|
||||
if (!aDelegate)
|
||||
return;
|
||||
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
[defaultCenter addObserver:self
|
||||
selector:@selector(comboBoxWillPopUp:)
|
||||
name:_CPPopUpListWillPopUpNotification
|
||||
object:_listDelegate];
|
||||
object:aDelegate];
|
||||
|
||||
[defaultCenter addObserver:self
|
||||
selector:@selector(comboBoxWillDismiss:)
|
||||
name:_CPPopUpListWillDismissNotification
|
||||
object:_listDelegate];
|
||||
object:aDelegate];
|
||||
|
||||
[defaultCenter addObserver:self
|
||||
selector:@selector(listDidDismiss:)
|
||||
name:_CPPopUpListDidDismissNotification
|
||||
object:_listDelegate];
|
||||
object:aDelegate];
|
||||
|
||||
[defaultCenter addObserver:self
|
||||
selector:@selector(itemWasClicked:)
|
||||
name:_CPPopUpListItemWasClickedNotification
|
||||
object:_listDelegate];
|
||||
object:aDelegate];
|
||||
|
||||
[[_listDelegate scrollView] setHasVerticalScroller:_hasVerticalScroller];
|
||||
[[aDelegate scrollView] setHasVerticalScroller:_hasVerticalScroller];
|
||||
|
||||
var tableView = [_listDelegate tableView];
|
||||
var tableView = [aDelegate tableView];
|
||||
|
||||
[defaultCenter addObserver:self
|
||||
selector:@selector(comboBoxSelectionIsChanging:)
|
||||
@@ -422,10 +459,27 @@ var CPComboBoxTextSubview = @"text",
|
||||
selector:@selector(comboBoxSelectionDidChange:)
|
||||
name:CPTableViewSelectionDidChangeNotification
|
||||
object:tableView];
|
||||
}
|
||||
|
||||
// Apply our text style to the list
|
||||
[_listDelegate setFont:[self font]];
|
||||
[_listDelegate setAlignment:[self alignment]];
|
||||
- (void)_removeObserversForListDelegate:(_CPPopUpList)aDelegate
|
||||
{
|
||||
if (!aDelegate)
|
||||
return;
|
||||
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
[defaultCenter removeObserver:self name:_CPPopUpListWillPopUpNotification object:aDelegate];
|
||||
[defaultCenter removeObserver:self name:_CPPopUpListWillDismissNotification object:aDelegate];
|
||||
[defaultCenter removeObserver:self name:_CPPopUpListDidDismissNotification object:aDelegate];
|
||||
[defaultCenter removeObserver:self name:_CPPopUpListItemWasClickedNotification object:aDelegate];
|
||||
|
||||
var oldTableView = [aDelegate tableView];
|
||||
|
||||
if (oldTableView)
|
||||
{
|
||||
[defaultCenter removeObserver:self name:CPTableViewSelectionIsChangingNotification object:oldTableView];
|
||||
[defaultCenter removeObserver:self name:CPTableViewSelectionDidChangeNotification object:oldTableView];
|
||||
}
|
||||
}
|
||||
|
||||
- (int)indexOfItemWithObjectValue:(id)anObject
|
||||
@@ -470,8 +524,6 @@ var CPComboBoxTextSubview = @"text",
|
||||
if (!_listDelegate)
|
||||
[self setListDelegate:[[_CPPopUpList alloc] initWithDataSource:self]];
|
||||
|
||||
[self _selectMatchingItem];
|
||||
|
||||
// Note the offset here is 1 less than the focus ring width because the outer edge
|
||||
// of the focus ring is very transparent and it looks better if the list is closer.
|
||||
if (CPComboBoxFocusRingWidth < 0)
|
||||
@@ -482,6 +534,7 @@ var CPComboBoxTextSubview = @"text",
|
||||
}
|
||||
|
||||
[_listDelegate popUpRelativeToRect:[self _borderFrame] view:self offset:CPComboBoxFocusRingWidth - 1];
|
||||
[self _selectMatchingItem];
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
@@ -790,7 +843,17 @@ var CPComboBoxTextSubview = @"text",
|
||||
// In FireFox this needs to be done in setTimeout, otherwise there is no caret
|
||||
// We have to save the input element now, when we lose focus it will change.
|
||||
var element = [self _inputElement];
|
||||
window.setTimeout(function() { element.focus(); }, 0);
|
||||
|
||||
[[CPRunLoop mainRunLoop] performBlock:function()
|
||||
{
|
||||
// This will prevent to jump to the focused element
|
||||
var previousScrollingOrigin = [self _scrollToVisibleRectAndReturnPreviousOrigin];
|
||||
|
||||
element.focus();
|
||||
|
||||
[self _restorePreviousScrollingOrigin:previousScrollingOrigin];
|
||||
|
||||
} argument:nil order:0 modes:[CPDefaultRunLoopMode]];
|
||||
#endif
|
||||
|
||||
return NO;
|
||||
@@ -817,13 +880,17 @@ var CPComboBoxTextSubview = @"text",
|
||||
- (void)setFont:(CPFont)aFont
|
||||
{
|
||||
[super setFont:aFont];
|
||||
[_listDelegate setFont:aFont];
|
||||
|
||||
if (_listDelegate)
|
||||
[_listDelegate setFont:aFont];
|
||||
}
|
||||
|
||||
- (void)setAlignment:(CPTextAlignment)alignment
|
||||
{
|
||||
[super setAlignment:alignment];
|
||||
[_listDelegate setAlignment:alignment];
|
||||
|
||||
if (_listDelegate)
|
||||
[_listDelegate setAlignment:alignment];
|
||||
}
|
||||
|
||||
#pragma mark Pop Up Button Layout
|
||||
@@ -894,7 +961,9 @@ var CPComboBoxTextSubview = @"text",
|
||||
index = [_dataSource comboBox:self indexOfItemWithStringValue:stringValue]
|
||||
}
|
||||
else
|
||||
{
|
||||
index = [self indexOfItemWithObjectValue:stringValue];
|
||||
}
|
||||
|
||||
[_listDelegate selectRow:index];
|
||||
|
||||
@@ -946,6 +1015,28 @@ var CPComboBoxTextSubview = @"text",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Observers method
|
||||
|
||||
- (void)_addObservers
|
||||
{
|
||||
if (_isObserving)
|
||||
return;
|
||||
|
||||
[super _addObservers];
|
||||
[self _addObserversForListDelegate:_listDelegate];
|
||||
}
|
||||
|
||||
- (void)_removeObservers
|
||||
{
|
||||
if (!_isObserving)
|
||||
return;
|
||||
|
||||
[super _removeObservers];
|
||||
[self _removeObserversForListDelegate:_listDelegate];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPComboBox (CPComboBoxDelegate)
|
||||
@@ -953,24 +1044,36 @@ var CPComboBoxTextSubview = @"text",
|
||||
/*! @ignore */
|
||||
- (void)comboBoxSelectionIsChanging:(CPNotification)aNotification
|
||||
{
|
||||
if (_implementedDelegateComboBoxMethods & CPComboBoxDelegate_comboBoxSelectionIsChanging_)
|
||||
[_delegate comboBoxSelectionIsChanging:[[CPNotification alloc] initWithName:CPComboBoxSelectionIsChangingNotification object:self userInfo:nil]];
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPComboBoxSelectionIsChangingNotification object:self];
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (void)comboBoxSelectionDidChange:(CPNotification)aNotification
|
||||
{
|
||||
if (_implementedDelegateComboBoxMethods & CPComboBoxDelegate_comboBoxSelectionDidChange_)
|
||||
[_delegate comboBoxSelectionDidChange:[[CPNotification alloc] initWithName:CPComboBoxSelectionDidChangeNotification object:self userInfo:nil]];
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPComboBoxSelectionDidChangeNotification object:self];
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (void)comboBoxWillPopUp:(CPNotification)aNotification
|
||||
{
|
||||
if (_implementedDelegateComboBoxMethods & CPComboBoxDelegate_comboBoxWillPopUp_)
|
||||
[_delegate comboBoxWillPopUp:[[CPNotification alloc] initWithName:CPComboBoxWillPopUpNotification object:self userInfo:nil]];
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPComboBoxWillPopUpNotification object:self];
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (void)comboBoxWillDismiss:(CPNotification)aNotification
|
||||
{
|
||||
if (_implementedDelegateComboBoxMethods & CPComboBoxDelegate_comboBoxWillDismiss_)
|
||||
[_delegate comboBoxWillDismiss:[[CPNotification alloc] initWithName:CPComboBoxWillDismissNotification object:self userInfo:nil]];
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPComboBoxWillDismissNotification object:self];
|
||||
}
|
||||
|
||||
@@ -1039,11 +1142,9 @@ var CPComboBoxTextSubview = @"text",
|
||||
// Directly nuke _items, [_items removeAll] will trigger an extra call to setContent
|
||||
_items = [];
|
||||
|
||||
var values = [];
|
||||
|
||||
[anArray enumerateObjectsUsingBlock:function(object)
|
||||
var values = [anArray arrayByApplyingBlock:function(object)
|
||||
{
|
||||
values.push([object description]);
|
||||
return [object description];
|
||||
}];
|
||||
|
||||
[self addItemsWithObjectValues:values];
|
||||
|
||||
+61
-15
@@ -26,11 +26,12 @@
|
||||
|
||||
// Browser Engines
|
||||
CPUnknownBrowserEngine = 0;
|
||||
CPGeckoBrowserEngine = 1;
|
||||
CPInternetExplorerBrowserEngine = 2;
|
||||
CPKHTMLBrowserEngine = 3;
|
||||
CPOperaBrowserEngine = 4;
|
||||
CPWebKitBrowserEngine = 5;
|
||||
CPGeckoBrowserEngine = 1 << 0;
|
||||
CPInternetExplorerBrowserEngine = 1 << 1;
|
||||
CPKHTMLBrowserEngine = 1 << 2;
|
||||
CPOperaBrowserEngine = 1 << 3;
|
||||
CPWebKitBrowserEngine = 1 << 4; // Safari + Chrome
|
||||
CPBlinkBrowserEngine = 1 << 5; // Recent Chrome
|
||||
|
||||
// Operating Systems
|
||||
CPMacOperatingSystem = 0;
|
||||
@@ -78,18 +79,29 @@ CPInputOnInputEventFeature = 30;
|
||||
|
||||
CPFileAPIFeature = 31;
|
||||
|
||||
CPAltEnterTextAreaFeature = 32;
|
||||
|
||||
CPCSSAnimationFeature = 33;
|
||||
|
||||
/*
|
||||
When an absolutely positioned div (CPView) with an absolutely positioned canvas in it (CPView with drawRect:) moves things on top of the canvas (subviews) don't redraw correctly. E.g. if you have a bunch of text fields in a CPBox in a sheet which animates in, some of the text fields might not be visible because the CPBox has a canvas at the bottom and the box moved form offscreen to onscreen. This bug is probably very related: https://bugs.webkit.org/show_bug.cgi?id=67203
|
||||
*/
|
||||
*/
|
||||
CPCanvasParentDrawErrorsOnMovementBug = 1 << 0;
|
||||
|
||||
// The paste event is only sent if an input or textarea has focus.
|
||||
CPJavaScriptPasteRequiresEditableTarget = 1 << 1;
|
||||
CPJavaScriptPasteRequiresEditableTarget = 1 << 1;
|
||||
// Redirecting the focus of the browser on keydown to an input for Cmd-V or Ctrl-V makes the paste fail.
|
||||
CPJavaScriptPasteCantRefocus = 1 << 2;
|
||||
|
||||
/*
|
||||
Safari calculates incorrect text size unless you set the canvas font even if it is already set
|
||||
You can see the bug after disabling the workaround and opening any panel while typing.
|
||||
You can use the font panel in the manual test for CPTextView.
|
||||
Look out for a displaced cursor, i.e. after typing letters of small width, such as the 'i'.
|
||||
https://bugs.webkit.org/show_bug.cgi?id=150224
|
||||
*/
|
||||
CPTextSizingAlwaysNeedsSetFontBug = 1 << 3;
|
||||
|
||||
|
||||
var USER_AGENT = "",
|
||||
PLATFORM_ENGINE = CPUnknownBrowserEngine,
|
||||
@@ -100,6 +112,7 @@ var USER_AGENT = "",
|
||||
// default these features to true
|
||||
PLATFORM_FEATURES[CPInputTypeCanBeChangedFeature] = YES;
|
||||
PLATFORM_FEATURES[CPInputSetFontOutsideOfDOM] = YES;
|
||||
PLATFORM_FEATURES[CPAltEnterTextAreaFeature] = YES;
|
||||
|
||||
if (typeof window !== "undefined" && typeof window.navigator !== "undefined")
|
||||
USER_AGENT = window.navigator.userAgent;
|
||||
@@ -107,15 +120,15 @@ if (typeof window !== "undefined" && typeof window.navigator !== "undefined")
|
||||
// Opera
|
||||
if (typeof window !== "undefined" && window.opera)
|
||||
{
|
||||
PLATFORM_ENGINE = CPOperaBrowserEngine;
|
||||
PLATFORM_ENGINE |= CPOperaBrowserEngine;
|
||||
|
||||
PLATFORM_FEATURES[CPJavaScriptCanvasDrawFeature] = YES;
|
||||
}
|
||||
|
||||
// Internet Explorer
|
||||
else if (typeof window !== "undefined" && window.attachEvent) // Must follow Opera check.
|
||||
else if (typeof window !== "undefined" && (window.attachEvent || (!(window.ActiveXObject) && "ActiveXObject" in window))) // Must follow Opera check.
|
||||
{
|
||||
PLATFORM_ENGINE = CPInternetExplorerBrowserEngine;
|
||||
PLATFORM_ENGINE |= CPInternetExplorerBrowserEngine;
|
||||
|
||||
// Features we can only be sure of with IE (no known independent tests)
|
||||
PLATFORM_FEATURES[CPVMLFeature] = YES;
|
||||
@@ -133,10 +146,10 @@ else if (typeof window !== "undefined" && window.attachEvent) // Must follow Ope
|
||||
PLATFORM_FEATURES[CPJavaScriptClipboardAccessFeature] = YES;
|
||||
}
|
||||
|
||||
// WebKit
|
||||
// Safari + Chrome (WebKit and Blink)
|
||||
else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
|
||||
{
|
||||
PLATFORM_ENGINE = CPWebKitBrowserEngine;
|
||||
PLATFORM_ENGINE |= CPWebKitBrowserEngine;
|
||||
|
||||
// Features we can only be sure of with WebKit (no known independent tests)
|
||||
PLATFORM_FEATURES[CPCSSRGBAFeature] = YES;
|
||||
@@ -176,7 +189,10 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
|
||||
PLATFORM_BUGS |= CPJavaScriptPasteRequiresEditableTarget;
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=39689
|
||||
PLATFORM_BUGS |= CPJavaScriptPasteCantRefocus;
|
||||
PLATFORM_BUGS |= CPTextSizingAlwaysNeedsSetFontBug;
|
||||
}
|
||||
else if ((window.chrome || (window.Intl && Intl.v8BreakIterator)) && 'CSS' in window)
|
||||
PLATFORM_ENGINE |= CPBlinkBrowserEngine;
|
||||
|
||||
// Assume this bug was introduced around Safari 5.1/Chrome 16. This could probably be tighter.
|
||||
if (majorVersion > 533)
|
||||
@@ -186,13 +202,13 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
|
||||
// KHTML
|
||||
else if (USER_AGENT.indexOf("KHTML") != -1) // Must follow WebKit check.
|
||||
{
|
||||
PLATFORM_ENGINE = CPKHTMLBrowserEngine;
|
||||
PLATFORM_ENGINE |= CPKHTMLBrowserEngine;
|
||||
}
|
||||
|
||||
// Gecko
|
||||
else if (USER_AGENT.indexOf("Gecko") !== -1) // Must follow KHTML check.
|
||||
{
|
||||
PLATFORM_ENGINE = CPGeckoBrowserEngine;
|
||||
PLATFORM_ENGINE |= CPGeckoBrowserEngine;
|
||||
|
||||
PLATFORM_FEATURES[CPJavaScriptCanvasDrawFeature] = YES;
|
||||
|
||||
@@ -208,6 +224,7 @@ else if (USER_AGENT.indexOf("Gecko") !== -1) // Must follow KHTML check.
|
||||
// Some day this might be fixed and should be version prefixed. No known fixed version yet.
|
||||
PLATFORM_FEATURES[CPInput1PxLeftPadding] = YES;
|
||||
|
||||
PLATFORM_FEATURES[CPAltEnterTextAreaFeature] = NO;
|
||||
// This was supposed to be added in Firefox 22, but when testing with the latest beta as of 2013-06-14
|
||||
// it does not seem to work. It seems to exhibit the CPJavaScriptPasteRequiresEditableTarget problem,
|
||||
// and in addition doesn't seem to work with our native copy code either.
|
||||
@@ -282,7 +299,7 @@ function CPPlatformHasBug(aBug)
|
||||
|
||||
function CPBrowserIsEngine(anEngine)
|
||||
{
|
||||
return PLATFORM_ENGINE === anEngine;
|
||||
return PLATFORM_ENGINE & anEngine;
|
||||
}
|
||||
|
||||
function CPBrowserIsOperatingSystem(anOperatingSystem)
|
||||
@@ -318,6 +335,14 @@ else
|
||||
CPRedoKeyEquivalentModifierMask = CPControlKeyMask;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets a feature with the given value.
|
||||
*/
|
||||
function CPSetPlatformFeature(aFeature, aBool)
|
||||
{
|
||||
PLATFORM_FEATURES[aFeature] = aBool;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the properly prefixed JS property for the given name. E.g. in a webkit browser,
|
||||
CPBrowserStyleProperty('transition') -> WebkitTransition
|
||||
@@ -365,6 +390,18 @@ function CPBrowserStyleProperty(aProperty)
|
||||
r = candidates[PLATFORM_STYLE_JS_PROPERTIES['transform']] || nil;
|
||||
break;
|
||||
|
||||
case 'animationend':
|
||||
var candidates = {
|
||||
'WebkitAnimation' : 'webkitAnimationEnd',
|
||||
'MozAnimation' : 'animationend',
|
||||
'OAnimation' : 'oAnimationEnd',
|
||||
'msAnimation' : 'MSAnimationEnd',
|
||||
'animation' : 'animationend'
|
||||
};
|
||||
|
||||
r = candidates[PLATFORM_STYLE_JS_PROPERTIES['animation']] || nil;
|
||||
break;
|
||||
|
||||
default:
|
||||
var prefixes = ["Webkit", "Moz", "O", "ms"],
|
||||
strippedProperty = aProperty.split('-').join(' '),
|
||||
@@ -434,3 +471,12 @@ function CPBrowserCSSProperty(aProperty)
|
||||
|
||||
return browserProperty.toLowerCase();
|
||||
}
|
||||
|
||||
function CPBrowserBackingStorePixelRatio(context)
|
||||
{
|
||||
return context.webkitBackingStorePixelRatio ||
|
||||
context.mozBackingStorePixelRatio ||
|
||||
context.msBackingStorePixelRatio ||
|
||||
context.oBackingStorePixelRatio ||
|
||||
context.backingStorePixelRatio || 1;
|
||||
}
|
||||
|
||||
+185
-13
@@ -25,21 +25,30 @@
|
||||
|
||||
@import "CPFont.j"
|
||||
@import "CPShadow.j"
|
||||
@import "CPView.j"
|
||||
@import "CPText.j"
|
||||
@import "CPKeyValueBinding.j"
|
||||
@import "CPTrackingArea.j"
|
||||
|
||||
@global CPApp
|
||||
|
||||
CPLeftTextAlignment = 0;
|
||||
CPRightTextAlignment = 1;
|
||||
CPCenterTextAlignment = 2;
|
||||
CPJustifiedTextAlignment = 3;
|
||||
CPNaturalTextAlignment = 4;
|
||||
@protocol CPControlTextEditingDelegate <CPObject>
|
||||
|
||||
@optional
|
||||
- (void)controlTextDidBeginEditing:(CPNotification)aNotification;
|
||||
- (void)controlTextDidChange:(CPNotification)aNotification;
|
||||
- (void)controlTextDidEndEditing:(CPNotification)aNotification;
|
||||
- (void)controlTextDidFocus:(CPNotification)aNotification;
|
||||
- (void)controlTextDidBlur:(CPNotification)aNotification;
|
||||
- (BOOL)control:(CPControl)control didFailToFormatString:(CPString)string errorDescription:(CPString)error;
|
||||
|
||||
@end
|
||||
|
||||
@typedef CPControlSize
|
||||
CPRegularControlSize = 0;
|
||||
CPSmallControlSize = 1;
|
||||
CPMiniControlSize = 2;
|
||||
|
||||
@typedef CPLineBreakMode
|
||||
CPLineBreakByWordWrapping = 0;
|
||||
CPLineBreakByCharWrapping = 1;
|
||||
CPLineBreakByClipping = 2;
|
||||
@@ -47,11 +56,13 @@ CPLineBreakByTruncatingHead = 3;
|
||||
CPLineBreakByTruncatingTail = 4;
|
||||
CPLineBreakByTruncatingMiddle = 5;
|
||||
|
||||
@typedef CPVerticalTextAlignment
|
||||
CPTopVerticalTextAlignment = 1;
|
||||
CPCenterVerticalTextAlignment = 2;
|
||||
CPBottomVerticalTextAlignment = 3;
|
||||
|
||||
// Deprecated for use with images, use the CPImageScale constants
|
||||
@typedef CPImageScaling
|
||||
CPScaleProportionally = 0;
|
||||
CPScaleToFit = 1;
|
||||
CPScaleNone = 2;
|
||||
@@ -61,6 +72,7 @@ CPImageScaleAxesIndependently = 1;
|
||||
CPImageScaleNone = 2;
|
||||
CPImageScaleProportionallyUpOrDown = 3;
|
||||
|
||||
@typedef CPCellImagePosition
|
||||
CPNoImage = 0;
|
||||
CPImageOnly = 1;
|
||||
CPImageLeft = 2;
|
||||
@@ -106,6 +118,10 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
BOOL _trackingWasWithinFrame;
|
||||
unsigned _trackingMouseDownFlags;
|
||||
CGPoint _previousTrackingLocation;
|
||||
|
||||
CPControlSize _controlSize;
|
||||
|
||||
CPWritingDirection _baseWritingDirection @accessors(property=baseWritingDirection);
|
||||
}
|
||||
|
||||
+ (CPDictionary)themeAttributes
|
||||
@@ -122,6 +138,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
@"image-scaling": CPScaleToFit,
|
||||
@"min-size": CGSizeMakeZero(),
|
||||
@"max-size": CGSizeMake(-1.0, -1.0),
|
||||
@"nib2cib-adjustment-frame": CGRectMakeZero()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -152,7 +169,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
}
|
||||
|
||||
/*!
|
||||
Reverse set the binding iff the CPContinuouslyUpdatesValueBindingOption is set.
|
||||
Reverse set the binding if the CPContinuouslyUpdatesValueBindingOption is set.
|
||||
*/
|
||||
- (void)_continuouslyReverseSetBinding
|
||||
{
|
||||
@@ -177,13 +194,94 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_sendActionOn = CPLeftMouseUpMask;
|
||||
_sendActionOn = CPLeftMouseUpMask;
|
||||
_trackingMouseDownFlags = 0;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Control Size
|
||||
|
||||
/*!
|
||||
Returns the control's control size
|
||||
*/
|
||||
- (CPControlSize)controlSize
|
||||
{
|
||||
return _controlSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the control's size.
|
||||
@param aControlSize the control's size
|
||||
*/
|
||||
- (void)setControlSize:(CPControlSize)aControlSize
|
||||
{
|
||||
if (_controlSize === aControlSize)
|
||||
return;
|
||||
|
||||
[self unsetThemeState:[self _controlSizeThemeState]];
|
||||
_controlSize = aControlSize;
|
||||
[self setThemeState:[self _controlSizeThemeState]];
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
Gets the current theme state according to the current controlSize.
|
||||
@return a CPThemeState
|
||||
*/
|
||||
- (ThemeState)_controlSizeThemeState
|
||||
{
|
||||
switch (_controlSize)
|
||||
{
|
||||
case CPSmallControlSize:
|
||||
return CPThemeStateControlSizeSmall;
|
||||
|
||||
case CPMiniControlSize:
|
||||
return CPThemeStateControlSizeMini;
|
||||
|
||||
case CPRegularControlSize:
|
||||
default:
|
||||
return CPThemeStateControlSizeRegular;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Change frame size according to the theme control size theme constraints
|
||||
Basically for height to min-size.
|
||||
*/
|
||||
- (void)_sizeToControlSize
|
||||
{
|
||||
var frameSize = [self frameSize],
|
||||
minSize = [self currentValueForThemeAttribute:@"min-size"],
|
||||
maxSize = [self currentValueForThemeAttribute:@"max-size"];
|
||||
|
||||
if (minSize.width > 0)
|
||||
{
|
||||
frameSize.width = MAX(minSize.width, frameSize.width);
|
||||
|
||||
if (maxSize.width > 0)
|
||||
frameSize.width = MIN(maxSize.width, frameSize.width);
|
||||
}
|
||||
|
||||
if (minSize.height > 0)
|
||||
{
|
||||
frameSize.height = MAX(minSize.height, frameSize.height);
|
||||
|
||||
if (maxSize.height > 0)
|
||||
frameSize.height = MIN(maxSize.height, frameSize.height);
|
||||
}
|
||||
|
||||
[self setFrameSize:frameSize];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
|
||||
/*!
|
||||
Sets the receiver's target action.
|
||||
|
||||
@@ -913,16 +1011,81 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
return [self hasThemeState:CPThemeStateHighlighted];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Base writing direction
|
||||
|
||||
/*!
|
||||
Sets the initial writing direction of the receiver
|
||||
@param writingDirection - It could be CPWritingDirectionNatural, CPWritingDirectionLeftToRight, CPWritingDirectionRightToLeft
|
||||
*/
|
||||
- (void)setBaseWritingDirection:(CPWritingDirection)writingDirection
|
||||
{
|
||||
if (writingDirection == _baseWritingDirection)
|
||||
return;
|
||||
|
||||
[self willChangeValueForKey:@"baseWritingDirection"];
|
||||
_baseWritingDirection = writingDirection;
|
||||
[self didChangeValueForKey:@"baseWritingDirection"];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var style;
|
||||
|
||||
switch (_baseWritingDirection)
|
||||
{
|
||||
case CPWritingDirectionNatural:
|
||||
style = "initial";
|
||||
break;
|
||||
|
||||
case CPWritingDirectionLeftToRight:
|
||||
style = "ltr";
|
||||
break;
|
||||
|
||||
case CPWritingDirectionRightToLeft:
|
||||
style = "rtl";
|
||||
break;
|
||||
|
||||
default:
|
||||
style = "initial";
|
||||
}
|
||||
|
||||
_DOMElement.style.direction = style;
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPControlValueKey = @"CPControlValueKey",
|
||||
@implementation CPControl (CPTrackingArea)
|
||||
{
|
||||
CPTrackingArea _controlTrackingArea;
|
||||
}
|
||||
|
||||
- (void)updateTrackingAreas
|
||||
{
|
||||
if (_controlTrackingArea)
|
||||
[self removeTrackingArea:_controlTrackingArea];
|
||||
|
||||
_controlTrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero()
|
||||
options:CPTrackingMouseEnteredAndExited | CPTrackingActiveInKeyWindow | CPTrackingInVisibleRect
|
||||
owner:self
|
||||
userInfo:nil];
|
||||
[self addTrackingArea:_controlTrackingArea];
|
||||
[super updateTrackingAreas];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPControlActionKey = @"CPControlActionKey",
|
||||
CPControlControlSizeKey = @"CPControlControlSizeKey",
|
||||
CPControlControlStateKey = @"CPControlControlStateKey",
|
||||
CPControlIsEnabledKey = @"CPControlIsEnabledKey",
|
||||
CPControlTargetKey = @"CPControlTargetKey",
|
||||
CPControlActionKey = @"CPControlActionKey",
|
||||
CPControlSendActionOnKey = @"CPControlSendActionOnKey",
|
||||
CPControlFormatterKey = @"CPControlFormatterKey",
|
||||
CPControlIsEnabledKey = @"CPControlIsEnabledKey",
|
||||
CPControlSendActionOnKey = @"CPControlSendActionOnKey",
|
||||
CPControlSendsActionOnEndEditingKey = @"CPControlSendsActionOnEndEditingKey",
|
||||
CPControlTargetKey = @"CPControlTargetKey",
|
||||
CPControlValueKey = @"CPControlValueKey",
|
||||
CPControlBaseWrittingDirectionKey = @"CPControlBaseWrittingDirectionKey";
|
||||
|
||||
__Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
|
||||
|
||||
@@ -949,6 +1112,10 @@ var CPControlValueKey = @"CPControlValueKey",
|
||||
[self setSendsActionOnEndEditing:[aCoder decodeBoolForKey:CPControlSendsActionOnEndEditingKey]];
|
||||
|
||||
[self setFormatter:[aCoder decodeObjectForKey:CPControlFormatterKey]];
|
||||
|
||||
[self setControlSize:[aCoder decodeIntForKey:CPControlControlSizeKey]];
|
||||
|
||||
[self setBaseWritingDirection:[aCoder decodeIntForKey:CPControlBaseWrittingDirectionKey]];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -981,6 +1148,11 @@ var CPControlValueKey = @"CPControlValueKey",
|
||||
|
||||
if (_formatter !== nil)
|
||||
[aCoder encodeObject:_formatter forKey:CPControlFormatterKey];
|
||||
|
||||
[aCoder encodeInt:_controlSize forKey:CPControlControlSizeKey];
|
||||
|
||||
[aCoder encodeInt:_baseWritingDirection forKey:CPControlBaseWrittingDirectionKey];
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -22,6 +22,7 @@ Cursor support by browser:
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import "CPImage.j"
|
||||
|
||||
@global CPApp
|
||||
|
||||
@@ -122,6 +123,9 @@ var currentCursor = nil,
|
||||
|
||||
- (void)set
|
||||
{
|
||||
if (currentCursor === self)
|
||||
return;
|
||||
|
||||
currentCursor = self;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
@import <Foundation/CPArray.j>
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPDate.j>
|
||||
@import <Foundation/CPDateFormatter.j>
|
||||
@import <Foundation/CPLocale.j>
|
||||
@import <Foundation/CPTimeZone.j>
|
||||
|
||||
@@ -76,6 +75,7 @@ CPEraDatePickerElementFlag = 0x0100;
|
||||
CPInteger _datePickerStyle @accessors(property=datePickerStyle);
|
||||
CPInteger _timeInterval @accessors(property=timeInterval);
|
||||
|
||||
BOOL _invokedByUserEvent;
|
||||
_CPDatePickerTextField _datePickerTextfield;
|
||||
_CPDatePickerCalendar _datePickerCalendar;
|
||||
unsigned _implementedCDatePickerDelegateMethods;
|
||||
@@ -206,24 +206,32 @@ CPEraDatePickerElementFlag = 0x0100;
|
||||
if (!_locale)
|
||||
_locale = [CPLocale currentLocale];
|
||||
|
||||
if (!_timeZone)
|
||||
_timeZone = [CPTimeZone systemTimeZone];
|
||||
|
||||
_datePickerTextfield = [[_CPDatePickerTextField alloc] initWithFrame:[self bounds] withDatePicker:self];
|
||||
|
||||
[_datePickerTextfield setDateValue:_dateValue];
|
||||
[self addSubview:_datePickerTextfield];
|
||||
|
||||
_datePickerCalendar = [[_CPDatePickerCalendar alloc] initWithFrame:[self bounds] withDatePicker:self];
|
||||
[_datePickerCalendar setDateValue:_dateValue];
|
||||
[_datePickerCalendar setHidden:YES];
|
||||
[self addSubview:_datePickerCalendar];
|
||||
|
||||
// We might have been unarchived in a disabled state.
|
||||
[_datePickerTextfield setEnabled:[self isEnabled]];
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Control Size
|
||||
|
||||
- (void)setControlSize:(CPControlSize)aControlSize
|
||||
{
|
||||
[super setControlSize:aControlSize];
|
||||
|
||||
if ([self datePickerStyle] == CPTextFieldAndStepperDatePickerStyle || [self datePickerStyle] == CPTextFieldDatePickerStyle)
|
||||
[self _sizeToControlSize];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Delegate methods
|
||||
|
||||
@@ -252,15 +260,26 @@ CPEraDatePickerElementFlag = 0x0100;
|
||||
|
||||
if (_datePickerStyle == CPTextFieldAndStepperDatePickerStyle || _datePickerStyle == CPTextFieldDatePickerStyle)
|
||||
{
|
||||
[_datePickerTextfield setHidden:NO];
|
||||
[_datePickerCalendar setHidden:YES];
|
||||
if (![_datePickerTextfield superview])
|
||||
[self addSubview:_datePickerTextfield];
|
||||
|
||||
if ([_datePickerCalendar superview])
|
||||
[_datePickerCalendar removeFromSuperview];
|
||||
|
||||
[_datePickerTextfield setControlSize:[self controlSize]];
|
||||
[_datePickerTextfield setNeedsLayout];
|
||||
[_datePickerTextfield setNeedsDisplay:YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_datePickerCalendar setHidden:NO];
|
||||
[_datePickerTextfield setHidden:YES];
|
||||
if (![_datePickerCalendar superview])
|
||||
[self addSubview:_datePickerCalendar];
|
||||
|
||||
if ([_datePickerTextfield superview])
|
||||
[_datePickerTextfield removeFromSuperview];
|
||||
|
||||
[_datePickerCalendar setNeedsLayout];
|
||||
[_datePickerCalendar setNeedsDisplay:YES];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,11 +294,14 @@ CPEraDatePickerElementFlag = 0x0100;
|
||||
return _dateValue
|
||||
}
|
||||
|
||||
/*! Set the objectValue ofhe datePier. It has to be a CPDate
|
||||
/*! Set the objectValue of the datePicker. It has to be a CPDate
|
||||
@param aDateValue the dateValue
|
||||
*/
|
||||
- (void)setObjectValue:(CPDate)aValue
|
||||
{
|
||||
if (![aValue isKindOfClass:[CPDate class]])
|
||||
return;
|
||||
|
||||
[self setDateValue:aValue];
|
||||
}
|
||||
|
||||
@@ -291,6 +313,7 @@ CPEraDatePickerElementFlag = 0x0100;
|
||||
if (aDateValue == nil)
|
||||
return;
|
||||
|
||||
_invokedByUserEvent = NO;
|
||||
[self _setDateValue:aDateValue timeInterval:_timeInterval];
|
||||
}
|
||||
|
||||
@@ -300,6 +323,14 @@ CPEraDatePickerElementFlag = 0x0100;
|
||||
*/
|
||||
- (void)_setDateValue:(CPDate)aDateValue timeInterval:(CPTimeInterval)aTimeInterval
|
||||
{
|
||||
// Make sure to have a valid date and avoid NaN values
|
||||
if (!isFinite(aDateValue))
|
||||
{
|
||||
[CPException raise:CPInvalidArgumentException
|
||||
reason:@"aDateValue is not valid"];
|
||||
return;
|
||||
}
|
||||
|
||||
if (_minDate)
|
||||
aDateValue = new Date (MAX(aDateValue, _minDate));
|
||||
|
||||
@@ -309,13 +340,20 @@ CPEraDatePickerElementFlag = 0x0100;
|
||||
aTimeInterval = MAX(MIN(aTimeInterval, [_maxDate timeIntervalSinceDate:aDateValue]), [_minDate timeIntervalSinceDate:aDateValue]);
|
||||
|
||||
if ([aDateValue isEqualToDate:_dateValue] && aTimeInterval == _timeInterval)
|
||||
{
|
||||
if (_datePickerStyle == CPTextFieldAndStepperDatePickerStyle || _datePickerStyle == CPTextFieldDatePickerStyle)
|
||||
[_datePickerTextfield setDateValue:_dateValue];
|
||||
else
|
||||
[_datePickerCalendar setDateValue:_dateValue];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (_implementedCDatePickerDelegateMethods & CPDatePicker_validateProposedDateValue_timeInterval)
|
||||
{
|
||||
// constrain timeInterval also
|
||||
var aStartDateRef = function(x){if (typeof x == 'undefined') return aDateValue; aDateValue = x;}
|
||||
var aTimeIntervalRef = function(x){if (typeof x == 'undefined') return aTimeInterval; aTimeInterval = x;}
|
||||
var aStartDateRef = function(x){if (typeof x == 'undefined') return aDateValue; aDateValue = x;};
|
||||
var aTimeIntervalRef = function(x){if (typeof x == 'undefined') return aTimeInterval; aTimeInterval = x;};
|
||||
|
||||
[_delegate datePicker:self validateProposedDateValue:aStartDateRef timeInterval:aTimeIntervalRef];
|
||||
}
|
||||
@@ -331,7 +369,8 @@ CPEraDatePickerElementFlag = 0x0100;
|
||||
_timeInterval = (_datePickerMode == CPSingleDateMode)? 0 : aTimeInterval;
|
||||
[self didChangeValueForKey:@"timeInterval"];
|
||||
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
if (_invokedByUserEvent)
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
|
||||
if (_datePickerStyle == CPTextFieldAndStepperDatePickerStyle || _datePickerStyle == CPTextFieldDatePickerStyle)
|
||||
[_datePickerTextfield setDateValue:_dateValue];
|
||||
@@ -370,6 +409,8 @@ CPEraDatePickerElementFlag = 0x0100;
|
||||
{
|
||||
_datePickerStyle = aDatePickerStyle;
|
||||
|
||||
[self setControlSize:[self controlSize]];
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
@@ -509,6 +550,11 @@ CPEraDatePickerElementFlag = 0x0100;
|
||||
[self didChangeValueForKey:@"timeZone"];
|
||||
|
||||
[self setNeedsLayout];
|
||||
|
||||
if (_datePickerStyle == CPTextFieldAndStepperDatePickerStyle || _datePickerStyle == CPTextFieldDatePickerStyle)
|
||||
[_datePickerTextfield setDateValue:_dateValue];
|
||||
else
|
||||
[_datePickerCalendar setDateValue:_dateValue];
|
||||
}
|
||||
|
||||
|
||||
@@ -520,11 +566,16 @@ CPEraDatePickerElementFlag = 0x0100;
|
||||
- (BOOL)becomeFirstResponder
|
||||
{
|
||||
if (_datePickerStyle == CPTextFieldAndStepperDatePickerStyle || _datePickerStyle == CPTextFieldDatePickerStyle)
|
||||
[_datePickerTextfield _selecteTextFieldWithFlags:[[CPApp currentEvent] modifierFlags]];
|
||||
else
|
||||
return NO;
|
||||
{
|
||||
if (![super becomeFirstResponder])
|
||||
return NO;
|
||||
|
||||
return YES;
|
||||
[_datePickerTextfield _selectTextFieldWithFlags:[[CPApp currentEvent] modifierFlags]];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
/*! Return YES
|
||||
@@ -579,14 +630,6 @@ CPEraDatePickerElementFlag = 0x0100;
|
||||
return [[_locale objectForKey:CPLocaleCountryCode] isEqualToString:@"US"];
|
||||
}
|
||||
|
||||
/*! Check if we are in the english format or not. Depending on the locale
|
||||
*/
|
||||
- (BOOL)_isEnglishFormat
|
||||
{
|
||||
return [[_locale objectForKey:CPLocaleLanguageCode] isEqualToString:@"en"];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Key event
|
||||
|
||||
@@ -628,12 +671,13 @@ var CPDatePickerModeKey = @"CPDatePickerModeKey",
|
||||
_timeInterval = [aCoder decodeDoubleForKey:CPIntervalKey];
|
||||
_datePickerMode = [aCoder decodeIntForKey:CPDatePickerModeKey];
|
||||
_datePickerElements = [aCoder decodeIntForKey:CPDatePickerElementsKey];
|
||||
_datePickerStyle = [aCoder decodeIntForKey:CPDatePickerStyleKey];
|
||||
[self setDatePickerStyle:[aCoder decodeIntForKey:CPDatePickerStyleKey]];
|
||||
_locale = [aCoder decodeObjectForKey:CPLocaleKey];
|
||||
_dateValue = [aCoder decodeObjectForKey:CPDateValueKey];
|
||||
_backgroundColor = [aCoder decodeObjectForKey:CPBackgroundColorKey];
|
||||
_drawsBackground = [aCoder decodeBoolForKey:CPDrawsBackgroundKey];
|
||||
_isBordered = [aCoder decodeBoolForKey:CPBorderedKey];
|
||||
|
||||
[self _init];
|
||||
}
|
||||
|
||||
@@ -642,19 +686,22 @@ var CPDatePickerModeKey = @"CPDatePickerModeKey",
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
// FIXME Do we need to encode _datePickerTextfield and _datePickerCalendar? As subviews they'll be encoded, but when we decode we recreate them anyhow.
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeDouble:_timeInterval forKey:CPIntervalKey];
|
||||
[aCoder encodeInt:_datePickerMode forKey:CPDatePickerModeKey];
|
||||
[aCoder encodeInt:_datePickerStyle forKey:CPDatePickerStyleKey];
|
||||
[aCoder encodeInt:_datePickerElements forKey:CPDatePickerElementsKey];
|
||||
[aCoder encodeObject:_minDate forKey:CPMinDateKey];
|
||||
[aCoder encodeObject:_maxDate forKey:CPMaxDateKey]
|
||||
[aCoder encodeObject:_maxDate forKey:CPMaxDateKey];
|
||||
[aCoder encodeObject:_dateValue forKey:CPDateValueKey];;
|
||||
[aCoder encodeObject:_textFont forKey:CPTextFontKey];
|
||||
[aCoder encodeObject:_locale forKey:CPLocaleKey];
|
||||
[aCoder encodeObject:_backgroundColor forKey:CPBackgroundColorKey];
|
||||
[aCoder encodeObject:_drawsBackground forKey:CPDrawsBackgroundKey];
|
||||
[aCoder encodeObject:_isBordered forKey:CPBorderedKey];
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -29,7 +29,11 @@
|
||||
@import <Foundation/Foundation.j>
|
||||
|
||||
@class CPDatePicker
|
||||
@class _CPDatePickerMonthView
|
||||
@class _CPDatePickerHeaderView
|
||||
@class _CPDatePickerBox
|
||||
|
||||
@global CPApp
|
||||
@global CPSingleDateMode
|
||||
@global CPRangeDateMode
|
||||
|
||||
@@ -43,6 +47,10 @@
|
||||
@global CPYearMonthDayDatePickerElementFlag
|
||||
@global CPEraDatePickerElementFlag
|
||||
|
||||
@global CPAlternateKeyMask
|
||||
@global CPCommandKeyMask
|
||||
@global CPControlKeyMask
|
||||
|
||||
var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"],
|
||||
CPShortWeekDayNameArrayUS = [@"Su", @"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa"],
|
||||
CPShortWeekDayNameArrayFr = [@"L", @"M", @"M", @"J", @"V", @"S", @"D"],
|
||||
@@ -58,7 +66,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
_CPDatePickerMonthView _monthView;
|
||||
_CPDatePickerHeaderView _headerView;
|
||||
_CPDatePickerClock _datePickerClock;
|
||||
CPBox _box;
|
||||
_CPDatePickerBox _box;
|
||||
CPDatePicker _datePicker;
|
||||
CPInteger _startSelectionIndex;
|
||||
CPInteger _currentSelectionIndex;
|
||||
@@ -77,9 +85,10 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
_datePicker = aDatePicker
|
||||
_datePicker = aDatePicker;
|
||||
[self _init];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -91,7 +100,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
sizeCalendar = [_datePicker valueForThemeAttribute:@"size-calendar"],
|
||||
sizeClock = [_datePicker valueForThemeAttribute:@"size-clock"];
|
||||
|
||||
_box = [[_DatePickerBox alloc] initWithFrame:CGRectMake(0, 0, sizeCalendar.width, sizeHeader.height + sizeCalendar.height)];
|
||||
_box = [[_CPDatePickerBox alloc] initWithFrame:CGRectMake(0, 0, sizeCalendar.width, sizeHeader.height + sizeCalendar.height)];
|
||||
[_box setDatePicker:_datePicker];
|
||||
|
||||
_headerView = [[_CPDatePickerHeaderView alloc] initWithFrame:CGRectMake(0, 0, sizeHeader.width, sizeHeader.height) datePicker:_datePicker delegate:self];
|
||||
@@ -113,11 +122,6 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
#pragma mark -
|
||||
#pragma mark Responder methods
|
||||
|
||||
- (BOOL)becomeFirstResponder
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)acceptsFirstResponder
|
||||
{
|
||||
return YES;
|
||||
@@ -215,6 +219,8 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
[_headerView setHidden:YES];
|
||||
[_monthView setHidden:YES];
|
||||
}
|
||||
|
||||
[self setFrameSize:[_datePicker frameSize]];
|
||||
}
|
||||
|
||||
|
||||
@@ -223,16 +229,62 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
|
||||
/*! Move to the nextMonth without changing the dateValue of the datePicker
|
||||
*/
|
||||
- (void)_nextMonth:(id)sender
|
||||
- (void)_clickArrowNext:(id)sender
|
||||
{
|
||||
[self setDateValue:[_monthView nextMonth]];
|
||||
var currentEvent = [CPApp currentEvent],
|
||||
modifierFlags = [currentEvent modifierFlags];
|
||||
|
||||
if (modifierFlags & (CPCommandKeyMask | CPControlKeyMask | CPAlternateKeyMask))
|
||||
{
|
||||
var date = [[_monthView monthDate] copy];
|
||||
date.setDate(1);
|
||||
|
||||
if (modifierFlags & CPAlternateKeyMask)
|
||||
date.setUTCFullYear(date.getUTCFullYear() + 10);
|
||||
else
|
||||
date.setUTCFullYear(date.getUTCFullYear() + 1);
|
||||
|
||||
[self setDateValue:date];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self _displayNextMonth];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_displayNextMonth
|
||||
{
|
||||
[self setDateValue:[_monthView nextMonth]];
|
||||
}
|
||||
|
||||
- (void)_displayPreviousMonth
|
||||
{
|
||||
[self setDateValue:[_monthView previousMonth]];
|
||||
}
|
||||
|
||||
/*! Move to the previous month without changing the dateValue of the datePicker
|
||||
*/
|
||||
- (void)_previousMonth:(id)sender
|
||||
- (void)_clickArrowPrevious:(id)sender
|
||||
{
|
||||
[self setDateValue:[_monthView previousMonth]];
|
||||
var currentEvent = [CPApp currentEvent],
|
||||
modifierFlags = [currentEvent modifierFlags];
|
||||
|
||||
if (modifierFlags & (CPCommandKeyMask | CPControlKeyMask | CPAlternateKeyMask))
|
||||
{
|
||||
var date = [[_monthView monthDate] copy];
|
||||
date.setDate(1);
|
||||
|
||||
if (modifierFlags & CPAlternateKeyMask)
|
||||
date.setUTCFullYear(date.getUTCFullYear() - 10);
|
||||
else
|
||||
date.setUTCFullYear(date.getUTCFullYear() - 1);
|
||||
|
||||
[self setDateValue:date];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self _displayPreviousMonth];
|
||||
}
|
||||
}
|
||||
|
||||
/*! Move to the current selected day
|
||||
@@ -334,10 +386,12 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
[self addSubview:_currentButton];
|
||||
|
||||
[_previousButton setTarget:aDelegate];
|
||||
[_previousButton setAction:@selector(_previousMonth:)];
|
||||
[_previousButton setAction:@selector(_clickArrowPrevious:)];
|
||||
[_previousButton setContinuous:YES];
|
||||
|
||||
[_nextButton setTarget:aDelegate];
|
||||
[_nextButton setAction:@selector(_nextMonth:)];
|
||||
[_nextButton setAction:@selector(_clickArrowNext:)];
|
||||
[_nextButton setContinuous:YES];
|
||||
|
||||
[_currentButton setTarget:aDelegate];
|
||||
[_currentButton setAction:@selector(_currentMonth:)];
|
||||
@@ -381,7 +435,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
break;
|
||||
|
||||
default:
|
||||
return CPShortWeekDayNameArrayEn
|
||||
return CPShortWeekDayNameArrayEn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -410,7 +464,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
break;
|
||||
|
||||
default:
|
||||
return CPShortMonthNameArrayEn
|
||||
return CPShortMonthNameArrayEn;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -472,11 +526,11 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
var dayLabel = _dayLabels[i];
|
||||
|
||||
[dayLabel setStringValue:dayNames[i]];
|
||||
[dayLabel sizeToFit]
|
||||
[dayLabel sizeToFit];
|
||||
[dayLabel setFrameOrigin:CGPointMake(sizeTileWidth * (i + 1) - sizeTileWidth / 2 - [dayLabel frameSize].width / 2, 23)];
|
||||
|
||||
if (i == 0)
|
||||
firstDayTileX = sizeTileWidth * (i + 1) - sizeTileWidth / 2 - [dayLabel frameSize].width / 2
|
||||
firstDayTileX = sizeTileWidth * (i + 1) - sizeTileWidth / 2 - [dayLabel frameSize].width / 2;
|
||||
}
|
||||
|
||||
// Title
|
||||
@@ -683,7 +737,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
|
||||
[dayTile setDate:[currentDate copy]];
|
||||
[dayTile setStringValue:currentDate.getDate()];
|
||||
[dayTile setDisabled:![self isEnabled] || currentDate.getMonth() !== currentMonth.getMonth()];
|
||||
[dayTile setDisabled:![self isEnabled] || currentDate.getMonth() !== currentMonth.getMonth() || currentDate < [_datePicker minDate] || currentDate > [_datePicker maxDate]];
|
||||
[dayTile setHighlighted:isPresentMonth && currentDate.getDate() == now.getDate()];
|
||||
}
|
||||
|
||||
@@ -715,7 +769,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
tileDate = [[tile date] copy],
|
||||
selected = NO;
|
||||
|
||||
[tileDate _resetToMidnight]
|
||||
[tileDate _resetToMidnight];
|
||||
|
||||
if (aStartDate)
|
||||
selected = tileDate >= aStartDate && tileDate <= endDate;
|
||||
@@ -791,7 +845,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
|
||||
// Very usefull to avoid to have a line of two pixels instead one
|
||||
if (!isBorderPair)
|
||||
y += 0.5
|
||||
y += 0.5;
|
||||
|
||||
CGContextMoveToPoint(context, 0, y);
|
||||
CGContextAddLineToPoint(context, [self bounds].size.width, y);
|
||||
@@ -803,7 +857,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
|
||||
// Very usefull to avoid to have a line of two pixels instead one
|
||||
if (!isBorderPair)
|
||||
x += 0.5
|
||||
x += 0.5;
|
||||
|
||||
CGContextMoveToPoint(context, x, 0);
|
||||
CGContextAddLineToPoint(context, x, [self bounds].size.height);
|
||||
@@ -815,7 +869,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
|
||||
// Very usefull to avoid to have a line of two pixels instead one
|
||||
if (!isBorderPair)
|
||||
y += 0.5
|
||||
y += 0.5;
|
||||
|
||||
CGContextMoveToPoint(context, 0, y);
|
||||
CGContextAddLineToPoint(context, [self bounds].size.width, y);
|
||||
@@ -843,28 +897,64 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
_clickDate = [dateTile copy];
|
||||
_dragDate = nil;
|
||||
_indexDayTile = -1;
|
||||
_eventDragged = nil
|
||||
_eventDragged = nil;
|
||||
|
||||
_datePicker._invokedByUserEvent = YES;
|
||||
|
||||
// Check if we have to change or not the month of the component
|
||||
if ([dayTile date].getMonth() == _date.getMonth())
|
||||
{
|
||||
var minDate = [[_datePicker minDate] copy],
|
||||
maxDate = [[_datePicker maxDate] copy];
|
||||
if ([_datePicker datePickerMode] == CPRangeDateMode && [anEvent modifierFlags] & CPShiftKeyMask)
|
||||
{
|
||||
var dateValueAtMidnight = [[_datePicker dateValue] copy];
|
||||
|
||||
[minDate _resetToMidnight];
|
||||
[maxDate _resetToLastSeconds];
|
||||
[dateValueAtMidnight _resetToMidnight];
|
||||
|
||||
if (dateTile >= minDate && dateTile <= maxDate)
|
||||
[_datePicker _setDateValue:[self _hoursMinutesSecondsFromDatePickerForDate:dateTile] timeInterval:0];
|
||||
if (dateTile < dateValueAtMidnight)
|
||||
{
|
||||
var interval;
|
||||
|
||||
if (dateTile == dateValueAtMidnight)
|
||||
interval = [_datePicker timeInterval];
|
||||
else
|
||||
interval = ([dateValueAtMidnight timeIntervalSinceDate:dateTile] + [_datePicker timeInterval]);
|
||||
|
||||
[_datePicker _setDateValue:[self _hoursMinutesSecondsFromDatePickerForDate:dateTile] timeInterval:interval];
|
||||
}
|
||||
else if ([[dayTile date] isEqualToDate:dateValueAtMidnight])
|
||||
{
|
||||
[_datePicker _setDateValue:[self _hoursMinutesSecondsFromDatePickerForDate:dateTile] timeInterval:0];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_datePicker _setDateValue:[self _hoursMinutesSecondsFromDatePickerForDate:[dateValueAtMidnight copy]] timeInterval:([dateTile timeIntervalSinceDate:dateValueAtMidnight])];
|
||||
}
|
||||
|
||||
// Be sure to display the good month
|
||||
[_delegate setDateValue:dateTile];
|
||||
}
|
||||
else
|
||||
{
|
||||
var minDate = [[_datePicker minDate] copy],
|
||||
maxDate = [[_datePicker maxDate] copy];
|
||||
|
||||
[minDate _resetToMidnight];
|
||||
[maxDate _resetToLastSeconds];
|
||||
|
||||
if (dateTile >= minDate && dateTile <= maxDate)
|
||||
[_datePicker _setDateValue:[self _hoursMinutesSecondsFromDatePickerForDate:dateTile] timeInterval:0];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check the year and the month. The year is usefull when changing from Jan to Dec.
|
||||
if (_date.getMonth() - [dayTile date].getMonth() == 1 || _date.getFullYear() - [dayTile date].getFullYear() == 1)
|
||||
[_delegate _previousMonth:self];
|
||||
[_delegate _displayPreviousMonth];
|
||||
else
|
||||
[_delegate _nextMonth:self];
|
||||
[_delegate _displayNextMonth];
|
||||
}
|
||||
|
||||
_datePicker._invokedByUserEvent = NO;
|
||||
}
|
||||
|
||||
/*! Mouse dragged event
|
||||
@@ -882,6 +972,8 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
_indexDayTile = [self indexOfTileForEvent:anEvent];
|
||||
_eventDragged = anEvent;
|
||||
|
||||
_datePicker._invokedByUserEvent = YES;
|
||||
|
||||
if ([_datePicker datePickerMode] == CPSingleDateMode)
|
||||
{
|
||||
// Check if we have to change or not the month of the component
|
||||
@@ -899,9 +991,9 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
|
||||
// Check the year and the month. The year is usefull when changing from Jan to Dec.
|
||||
if (_date.getMonth() - [dayTile date].getMonth() == 1 || _date.getFullYear() - [dayTile date].getFullYear() == 1)
|
||||
[_delegate _previousMonth:self];
|
||||
[_delegate _displayPreviousMonth];
|
||||
else
|
||||
[_delegate _nextMonth:self];
|
||||
[_delegate _displayNextMonth];
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -923,6 +1015,8 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
[_datePicker _setDateValue:[self _hoursMinutesSecondsFromDatePickerForDate:_clickDate] timeInterval:[dateTile timeIntervalSinceDate:dateValueAtMidnight]];
|
||||
}
|
||||
}
|
||||
|
||||
_datePicker._invokedByUserEvent = NO;
|
||||
}
|
||||
|
||||
- (void)mouseUp:(CPEvent)anEvent
|
||||
@@ -944,7 +1038,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
if (_isMonthJustChanged)
|
||||
{
|
||||
_dragDate.setMonth(_date.getMonth() + 1);
|
||||
[_delegate _nextMonth:self];
|
||||
[_delegate _displayNextMonth];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -953,7 +1047,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
if (_isMonthJustChanged)
|
||||
{
|
||||
_dragDate.setMonth(_date.getMonth() - 1);
|
||||
[_delegate _previousMonth:self];
|
||||
[_delegate _displayPreviousMonth];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1020,30 +1114,30 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inState:CPThemeStateDisabled] forThemeAttribute:@"text-shadow-color" inState:CPThemeStateDisabled];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inState:CPThemeStateDisabled] forThemeAttribute:@"text-shadow-offset" inState:CPThemeStateDisabled];
|
||||
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inState:CPThemeStateDisabled | CPThemeStateSelected] forThemeAttribute:@"font" inState:CPThemeStateDisabled | CPThemeStateSelected];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inState:CPThemeStateDisabled | CPThemeStateSelected] forThemeAttribute:@"text-color" inState:CPThemeStateDisabled | CPThemeStateSelected];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inState:CPThemeStateDisabled | CPThemeStateSelected] forThemeAttribute:@"text-shadow-color" inState:CPThemeStateDisabled | CPThemeStateSelected];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inState:CPThemeStateDisabled | CPThemeStateSelected] forThemeAttribute:@"text-shadow-offset" inState:CPThemeStateDisabled | CPThemeStateSelected];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inStates:[CPThemeStateDisabled, CPThemeStateSelected]] forThemeAttribute:@"font" inStates:[CPThemeStateDisabled, CPThemeStateSelected]];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inStates:[CPThemeStateDisabled, CPThemeStateSelected]]forThemeAttribute:@"text-color" inStates:[CPThemeStateDisabled, CPThemeStateSelected]];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inStates:[CPThemeStateDisabled, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-color" inStates:[CPThemeStateDisabled, CPThemeStateSelected]];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inStates:[CPThemeStateDisabled, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-offset" inStates:[CPThemeStateDisabled, CPThemeStateSelected]];
|
||||
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inState:CPThemeStateHighlighted] forThemeAttribute:@"font" inState:CPThemeStateHighlighted];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inState:CPThemeStateHighlighted] forThemeAttribute:@"text-color" inState:CPThemeStateHighlighted];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inState:CPThemeStateHighlighted] forThemeAttribute:@"text-shadow-color" inState:CPThemeStateHighlighted];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inState:CPThemeStateHighlighted] forThemeAttribute:@"text-shadow-offset" inState:CPThemeStateHighlighted];
|
||||
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inState:CPThemeStateHighlighted | CPThemeStateSelected] forThemeAttribute:@"font" inState:CPThemeStateHighlighted | CPThemeStateSelected];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inState:CPThemeStateHighlighted | CPThemeStateSelected] forThemeAttribute:@"text-color" inState:CPThemeStateHighlighted | CPThemeStateSelected];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inState:CPThemeStateHighlighted | CPThemeStateSelected] forThemeAttribute:@"text-shadow-color" inState:CPThemeStateHighlighted | CPThemeStateSelected];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inState:CPThemeStateHighlighted | CPThemeStateSelected] forThemeAttribute:@"text-shadow-offset" inState:CPThemeStateHighlighted | CPThemeStateSelected];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"font" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-color" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-color" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-offset" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]];
|
||||
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inState: CPThemeStateDisabled | CPThemeStateHighlighted | CPThemeStateSelected] forThemeAttribute:@"font" inState: CPThemeStateDisabled | CPThemeStateHighlighted | CPThemeStateSelected];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inState: CPThemeStateDisabled | CPThemeStateHighlighted | CPThemeStateSelected] forThemeAttribute:@"text-color" inState: CPThemeStateDisabled | CPThemeStateHighlighted | CPThemeStateSelected];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inState: CPThemeStateDisabled | CPThemeStateHighlighted | CPThemeStateSelected] forThemeAttribute:@"text-shadow-color" inState: CPThemeStateDisabled | CPThemeStateHighlighted | CPThemeStateSelected];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inState: CPThemeStateDisabled | CPThemeStateHighlighted | CPThemeStateSelected] forThemeAttribute:@"text-shadow-offset" inState: CPThemeStateDisabled | CPThemeStateHighlighted | CPThemeStateSelected];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"font" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-offset" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]];
|
||||
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inState: CPThemeStateDisabled | CPThemeStateHighlighted ] forThemeAttribute:@"font" inState: CPThemeStateDisabled | CPThemeStateHighlighted ];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inState: CPThemeStateDisabled | CPThemeStateHighlighted ] forThemeAttribute:@"text-color" inState: CPThemeStateDisabled | CPThemeStateHighlighted ];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inState: CPThemeStateDisabled | CPThemeStateHighlighted ] forThemeAttribute:@"text-shadow-color" inState: CPThemeStateDisabled | CPThemeStateHighlighted ];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inState: CPThemeStateDisabled | CPThemeStateHighlighted ] forThemeAttribute:@"text-shadow-offset" inState: CPThemeStateDisabled | CPThemeStateHighlighted];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]] forThemeAttribute:@"font" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]] forThemeAttribute:@"text-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]] forThemeAttribute:@"text-shadow-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]];
|
||||
[_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]] forThemeAttribute:@"text-shadow-offset" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]];
|
||||
|
||||
[self addSubview:_textField];
|
||||
|
||||
@@ -1059,7 +1153,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
|
||||
/*! Set a theme
|
||||
*/
|
||||
- (BOOL)setThemeState:(CPThemeState)aState
|
||||
- (BOOL)setThemeState:(ThemeState)aState
|
||||
{
|
||||
[_textField setThemeState:aState];
|
||||
[super setThemeState:aState];
|
||||
@@ -1067,7 +1161,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
|
||||
/*! Unset a theme
|
||||
*/
|
||||
- (BOOL)unsetThemeState:(CPThemeState)aState
|
||||
- (BOOL)unsetThemeState:(ThemeState)aState
|
||||
{
|
||||
[_textField unsetThemeState:aState];
|
||||
[super unsetThemeState:aState];
|
||||
@@ -1156,7 +1250,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
var themeState = [self themeState],
|
||||
context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
if (themeState & CPThemeStateSelected)
|
||||
if (themeState.hasThemeState(CPThemeStateSelected))
|
||||
{
|
||||
[self setBackgroundColor:[_datePicker valueForThemeAttribute:@"bezel-color-calendar" inState:themeState]];
|
||||
CGContextSetLineWidth(context, [_datePicker valueForThemeAttribute:@"border-width"]);
|
||||
@@ -1175,19 +1269,11 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
@end
|
||||
|
||||
|
||||
@implementation _DatePickerBox : CPView
|
||||
@implementation _CPDatePickerBox : CPView
|
||||
{
|
||||
CPDatePicker _datePicker @accessors(property=datePicker);
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
[super drawRect:aRect];
|
||||
@@ -1201,10 +1287,10 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
CGContextSetStrokeColor(context, [_datePicker valueForThemeAttribute:@"border-color" inState:[_datePicker themeState]]);
|
||||
CGContextSetLineWidth(context, [_datePicker valueForThemeAttribute:@"border-width"]);
|
||||
|
||||
CGContextMoveToPoint(context, borderWidth,borderWidth);
|
||||
CGContextAddLineToPoint(context, aRect.size.width - borderWidth,borderWidth);
|
||||
CGContextAddLineToPoint(context, aRect.size.width - borderWidth,aRect.size.height - borderWidth);
|
||||
CGContextAddLineToPoint(context, borderWidth,aRect.size.height - borderWidth);
|
||||
CGContextMoveToPoint(context, borderWidth, borderWidth);
|
||||
CGContextAddLineToPoint(context, aRect.size.width - borderWidth, borderWidth);
|
||||
CGContextAddLineToPoint(context, aRect.size.width - borderWidth, aRect.size.height - borderWidth);
|
||||
CGContextAddLineToPoint(context, borderWidth, aRect.size.height - borderWidth);
|
||||
CGContextAddLineToPoint(context, borderWidth,borderWidth);
|
||||
|
||||
CGContextStrokePath(context);
|
||||
@@ -1223,5 +1309,4 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
|
||||
[self setBackgroundColor:[CPColor clearColor]];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
@import "CPImageView.j"
|
||||
@import "CALayer.j"
|
||||
|
||||
|
||||
@class _CPCibCustomResource
|
||||
@class CPDatePicker
|
||||
|
||||
@@ -140,10 +139,10 @@ var RADIANS = Math.PI / 180;
|
||||
[_minuteHandLayer setImage:[_datePicker currentValueForThemeAttribute:@"minute-hand-image"]];
|
||||
[_secondHandLayer setImage:[_datePicker currentValueForThemeAttribute:@"second-hand-image"]];
|
||||
|
||||
if ([_datePicker _isEnglishFormat])
|
||||
if ([_datePicker _isAmericanFormat])
|
||||
{
|
||||
if (dateValue.getHours() > 11)
|
||||
[_PMAMTextField setStringValue:@"PM"]
|
||||
[_PMAMTextField setStringValue:@"PM"];
|
||||
else
|
||||
[_PMAMTextField setStringValue:@"AM"];
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+22
-13
@@ -515,7 +515,9 @@ var CPDocumentUntitledCount = 0;
|
||||
|
||||
alert("There was an error retrieving the document.");
|
||||
|
||||
objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo);
|
||||
var theDelegate = session.delegate;
|
||||
|
||||
theDelegate.isa.objj_msgSend3(theDelegate, session.didReadSelector, self, NO, session.contextInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -540,7 +542,9 @@ var CPDocumentUntitledCount = 0;
|
||||
|
||||
_writeRequest = nil;
|
||||
|
||||
objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo);
|
||||
var theDelegate = session.delegate;
|
||||
|
||||
theDelegate.isa.objj_msgSend3(theDelegate, session.didSaveSelector, self, NO, session.contextInfo);
|
||||
[self _sendDocumentSavedNotification:NO];
|
||||
}
|
||||
}
|
||||
@@ -553,14 +557,15 @@ var CPDocumentUntitledCount = 0;
|
||||
*/
|
||||
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)aData
|
||||
{
|
||||
var session = aConnection.session;
|
||||
var session = aConnection.session,
|
||||
theDelegate = session.delegate;
|
||||
|
||||
// READ
|
||||
if (aConnection == _readConnection)
|
||||
{
|
||||
[self readFromData:[CPData dataWithRawString:aData] ofType:session.fileType error:nil];
|
||||
|
||||
objj_msgSend(session.delegate, session.didReadSelector, self, YES, session.contextInfo);
|
||||
theDelegate.isa.objj_msgSend3(theDelegate, session.didReadSelector, self, YES, session.contextInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -569,7 +574,7 @@ var CPDocumentUntitledCount = 0;
|
||||
|
||||
_writeRequest = nil;
|
||||
|
||||
objj_msgSend(session.delegate, session.didSaveSelector, self, YES, session.contextInfo);
|
||||
theDelegate.isa.objj_msgSend3(theDelegate, session.didSaveSelector, self, YES, session.contextInfo);
|
||||
[self _sendDocumentSavedNotification:YES];
|
||||
}
|
||||
}
|
||||
@@ -580,10 +585,11 @@ var CPDocumentUntitledCount = 0;
|
||||
*/
|
||||
- (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError
|
||||
{
|
||||
var session = aConnection.session;
|
||||
var session = aConnection.session,
|
||||
theDelegate = session.delegate;
|
||||
|
||||
if (_readConnection == aConnection)
|
||||
objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo);
|
||||
theDelegate.isa.objj_msgSend3(theDelegate, session.didReadSelector, self, NO, session.contextInfo);
|
||||
|
||||
else
|
||||
{
|
||||
@@ -597,7 +603,7 @@ var CPDocumentUntitledCount = 0;
|
||||
|
||||
alert("There was an error saving the document.");
|
||||
|
||||
objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo);
|
||||
theDelegate.isa.objj_msgSend3(theDelegate, session.didSaveSelector, self, NO, session.contextInfo);
|
||||
[self _sendDocumentSavedNotification:NO];
|
||||
}
|
||||
}
|
||||
@@ -858,21 +864,24 @@ var CPDocumentUntitledCount = 0;
|
||||
[self canCloseDocumentWithDelegate:self shouldCloseSelector:@selector(_document:shouldClose:context:) contextInfo:{delegate:delegate, selector:selector, context:info}];
|
||||
|
||||
else if ([delegate respondsToSelector:selector])
|
||||
objj_msgSend(delegate, selector, self, YES, info);
|
||||
delegate.isa.objj_msgSend3(delegate, selector, self, YES, info);
|
||||
}
|
||||
|
||||
- (void)_document:(CPDocument)aDocument shouldClose:(BOOL)shouldClose context:(Object)context
|
||||
{
|
||||
var theDelegate = context.delegate;
|
||||
|
||||
if (aDocument === self && shouldClose)
|
||||
[self close];
|
||||
|
||||
objj_msgSend(context.delegate, context.selector, aDocument, shouldClose, context.context);
|
||||
if (theDelegate != null)
|
||||
theDelegate.isa.objj_msgSend3(theDelegate, context.selector, aDocument, shouldClose, context.context);
|
||||
}
|
||||
|
||||
- (void)canCloseDocumentWithDelegate:(id)aDelegate shouldCloseSelector:(SEL)aSelector contextInfo:(Object)context
|
||||
{
|
||||
if (![self isDocumentEdited])
|
||||
return [aDelegate respondsToSelector:aSelector] && objj_msgSend(aDelegate, aSelector, self, YES, context);
|
||||
return [aDelegate respondsToSelector:aSelector] && aDelegate.isa.objj_msgSend3(aDelegate, aSelector, self, YES, context);
|
||||
|
||||
_canCloseAlert = [[CPAlert alloc] init];
|
||||
|
||||
@@ -901,8 +910,8 @@ var CPDocumentUntitledCount = 0;
|
||||
|
||||
if (returnCode === 0)
|
||||
[self saveDocumentWithDelegate:delegate didSaveSelector:selector contextInfo:context];
|
||||
else
|
||||
objj_msgSend(delegate, selector, self, returnCode === 2, context);
|
||||
else if (delegate != null)
|
||||
delegate.isa.objj_msgSend3(delegate, selector, self, returnCode === 2, context);
|
||||
|
||||
_canCloseAlert = nil;
|
||||
}
|
||||
|
||||
@@ -402,8 +402,10 @@ var CPSharedDocumentController = nil;
|
||||
}
|
||||
}
|
||||
|
||||
if ([context.delegate respondsToSelector:context.selector])
|
||||
objj_msgSend(context.delegate, context.selector, self, [[self documents] count] === 0, context.context);
|
||||
var theDelegate = context.delegate;
|
||||
|
||||
if ([theDelegate respondsToSelector:context.selector])
|
||||
theDelegate.isa.objj_msgSend3(theDelegate, context.selector, self, [[self documents] count] === 0, context.context);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@typedef CPDragOperation
|
||||
CPDragOperationNone = 0;
|
||||
CPDragOperationCopy = 1 << 1;
|
||||
CPDragOperationLink = 1 << 1;
|
||||
|
||||
+103
-2
@@ -28,11 +28,20 @@
|
||||
|
||||
@import "CPCompatibility.j"
|
||||
@import "CGGeometry.j"
|
||||
@import "CPText.j"
|
||||
@import "CPTrackingArea.j"
|
||||
|
||||
@class CPTextField
|
||||
@class CPWindow
|
||||
@class CPGraphicsContext
|
||||
|
||||
@global CPApp
|
||||
@global CPNewlineCharacter
|
||||
@global CPCarriageReturnCharacter
|
||||
@global CPEnterCharacter
|
||||
|
||||
@typedef DOMEvent
|
||||
@typedef CPEventType
|
||||
|
||||
|
||||
var _CPEventPeriodicEventPeriod = 0,
|
||||
_CPEventPeriodicEventTimer = nil,
|
||||
@@ -57,7 +66,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
CPWindow _window;
|
||||
Number _windowNumber;
|
||||
CPString _characters;
|
||||
CPString _charactersIgnoringModifiers
|
||||
CPString _charactersIgnoringModifiers;
|
||||
BOOL _isARepeat;
|
||||
unsigned _keyCode;
|
||||
DOMEvent _DOMEvent;
|
||||
@@ -68,11 +77,16 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
float _deltaX;
|
||||
float _deltaY;
|
||||
float _deltaZ;
|
||||
float _scrollingDeltaX;
|
||||
float _scrollingDeltaY;
|
||||
BOOL _hasPreciseScrollingDeltas;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
BOOL _suppressCappuccinoCut;
|
||||
BOOL _suppressCappuccinoPaste;
|
||||
#endif
|
||||
|
||||
CPTrackingArea _trackingArea;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -132,6 +146,27 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext eventNumber:anEventNumber clickCount:aClickCount pressure:aPressure];
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a new mouse tracking event.
|
||||
|
||||
@param anEventType the event type
|
||||
@param aPoint the location of the cursor in the window specified by \c aWindowNumber
|
||||
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
|
||||
@param aTimestamp the time the event occurred
|
||||
@param aWindowNumber the number of the CPWindow where the event occurred
|
||||
@param aGraphicsContext the graphics context where the event occurred
|
||||
@param anEventNumber a number for this event
|
||||
@param aTrackingArea the tracking area that triggered the event
|
||||
@throws CPInternalInconsistencyException if an invalid event type is provided
|
||||
@return the new mouse event
|
||||
*/
|
||||
+ (id)enterExitEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
|
||||
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
|
||||
eventNumber:(int)anEventNumber trackingArea:(CPTrackingArea)aTrackingArea
|
||||
{
|
||||
return [[self alloc] _initEnterExitEventWithType:anEventType location:aPoint modifierFlags:modifierFlags timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext eventNumber:anEventNumber trackingArea:aTrackingArea];
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a new custom event.
|
||||
|
||||
@@ -163,7 +198,9 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
|
||||
// Make sure these are 0 rather than nil.
|
||||
_deltaX = 0;
|
||||
_scrollingDeltaX = 0;
|
||||
_deltaY = 0;
|
||||
_scrollingDeltaY = 0;
|
||||
_deltaZ = 0;
|
||||
}
|
||||
|
||||
@@ -190,6 +227,28 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
return self;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (id)_initEnterExitEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
|
||||
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
|
||||
eventNumber:(int)anEventNumber trackingArea:(CPTrackingArea)aTrackingArea
|
||||
{
|
||||
if ((anEventType != CPMouseEntered) && (anEventType != CPMouseExited) && (anEventType != CPCursorUpdate))
|
||||
[CPException raise:CPInternalInconsistencyException reason:"Invalid event type"];
|
||||
|
||||
if (self = [self _initWithType:anEventType])
|
||||
{
|
||||
_location = CGPointCreateCopy(aPoint);
|
||||
_modifierFlags = modifierFlags;
|
||||
_timestamp = aTimestamp;
|
||||
_context = aGraphicsContext;
|
||||
_eventNumber = anEventNumber;
|
||||
_trackingArea = aTrackingArea;
|
||||
_window = [CPApp windowWithWindowNumber:aWindowNumber];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (id)_initKeyEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned int)modifierFlags
|
||||
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
|
||||
@@ -225,6 +284,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
_subtype = aSubtype;
|
||||
_data1 = aData1;
|
||||
_data2 = aData2;
|
||||
_windowNumber = aWindowNumber;
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -278,6 +338,14 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
return _type;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the subtype of the event.
|
||||
*/
|
||||
- (CPEventType)subtype
|
||||
{
|
||||
return _subtype;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the event's associated window.
|
||||
*/
|
||||
@@ -417,6 +485,31 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
return _deltaZ;
|
||||
}
|
||||
|
||||
- (BOOL)hasPreciseScrollingDeltas
|
||||
{
|
||||
return !!_hasPreciseScrollingDeltas;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the change in points on the x-axis for a mouse movement, unless hasPreciseScrollingDeltas is NO,
|
||||
in which case the change is measured in number of "lines" or "rows" and needs to be multiplied as appropriate
|
||||
to get change in pixels.
|
||||
*/
|
||||
- (float)scrollingDeltaX
|
||||
{
|
||||
return _scrollingDeltaX;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the change in points on the y-axis for a mouse movement, unless hasPreciseScrollingDeltas is NO,
|
||||
in which case the change is measured in number of "lines" or "columns" and needs to be multiplied as appropriate
|
||||
to get change in pixels.
|
||||
*/
|
||||
- (float)scrollingDeltaY
|
||||
{
|
||||
return _scrollingDeltaY;
|
||||
}
|
||||
|
||||
- (BOOL)_triggersKeyEquivalent:(CPString)aKeyEquivalent withModifierMask:aKeyEquivalentModifierMask
|
||||
{
|
||||
if (!aKeyEquivalent)
|
||||
@@ -546,6 +639,14 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
}
|
||||
}
|
||||
|
||||
- (CPTrackingArea)trackingArea
|
||||
{
|
||||
if ((_type !== CPMouseEntered) && (_type !== CPMouseExited) && (_type !== CPCursorUpdate))
|
||||
[CPException raise:CPInternalInconsistencyException format:@"You can't call trackingArea for events of type %#x", _type];
|
||||
|
||||
return _trackingArea;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
function _CPEventFirePeriodEvent()
|
||||
|
||||
@@ -43,6 +43,9 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
|
||||
CPLog.warn("CPFlashView is not supported by Cappuccino, this is now deprecated and it will be removed in the version 1.1 of Cappuccino");
|
||||
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
if (self)
|
||||
|
||||
+43
-5
@@ -24,6 +24,7 @@
|
||||
@import <Foundation/CPBundle.j>
|
||||
|
||||
@import "CPView.j"
|
||||
@import "CPFontDescriptor.j"
|
||||
|
||||
CPFontDefaultSystemFontFace = @"Arial, sans-serif";
|
||||
CPFontDefaultSystemFontSize = 12;
|
||||
@@ -162,7 +163,7 @@ following:
|
||||
if (normalizedFaces === _CPFontSystemFontFace)
|
||||
return;
|
||||
|
||||
[self _invalidateSystemFontCache]
|
||||
[self _invalidateSystemFontCache];
|
||||
_CPFontSystemFontFace = aFace;
|
||||
}
|
||||
|
||||
@@ -174,20 +175,20 @@ following:
|
||||
return _CPFontSystemFontSize;
|
||||
}
|
||||
|
||||
+ (float)systemFontSizeForControlSize:(CPControlSize)aSize
|
||||
+ (CPFont)systemFontForControlSize:(CPControlSize)aSize
|
||||
{
|
||||
// TODO These sizes should be themable or made less arbitrary in some other way.
|
||||
switch (aSize)
|
||||
{
|
||||
case CPSmallControlSize:
|
||||
return _CPFontSystemFontSize - 1;
|
||||
return [self systemFontOfSize:_CPFontSystemFontSize - 1];
|
||||
|
||||
case CPMiniControlSize:
|
||||
return _CPFontSystemFontSize - 2;
|
||||
return [self systemFontOfSize:_CPFontSystemFontSize - 2];
|
||||
|
||||
case CPRegularControlSize:
|
||||
default:
|
||||
return _CPFontSystemFontSize;
|
||||
return [self systemFontOfSize:_CPFontSystemFontSize];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,6 +434,43 @@ following:
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPFont(DescriptorAdditions)
|
||||
|
||||
- (id)_initWithFontDescriptor:(CPFontDescriptor)fontDescriptor
|
||||
{
|
||||
var aName = [fontDescriptor objectForKey: CPFontNameAttribute] ,
|
||||
aSize = [fontDescriptor pointSize],
|
||||
isBold = [fontDescriptor symbolicTraits] & CPFontBoldTrait,
|
||||
isItalic = [fontDescriptor symbolicTraits] & CPFontItalicTrait;
|
||||
|
||||
return [self _initWithName:aName size:aSize bold:isBold italic:isItalic system:NO];
|
||||
}
|
||||
|
||||
+ (CPFont)fontWithDescriptor:(CPFontDescriptor)fontDescriptor size:(float)aSize
|
||||
{
|
||||
var aName = [fontDescriptor objectForKey: CPFontNameAttribute],
|
||||
isBold = [fontDescriptor symbolicTraits] & CPFontBoldTrait,
|
||||
isItalic = [fontDescriptor symbolicTraits] & CPFontItalicTrait;
|
||||
|
||||
return [self _fontWithName:aName size:aSize || [fontDescriptor pointSize] bold:isBold italic:isItalic];
|
||||
}
|
||||
|
||||
- (CPFontDescriptor)fontDescriptor
|
||||
{
|
||||
var traits = 0;
|
||||
|
||||
if ([self isBold])
|
||||
traits |= CPFontBoldTrait;
|
||||
|
||||
if ([self isItalic])
|
||||
traits |= CPFontItalicTrait;
|
||||
|
||||
return [[CPFontDescriptor fontDescriptorWithName:_name size:_size] fontDescriptorWithSymbolicTraits:traits];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPFontNameKey = @"CPFontNameKey",
|
||||
CPFontSizeKey = @"CPFontSizeKey",
|
||||
CPFontIsBoldKey = @"CPFontIsBoldKey",
|
||||
|
||||
+208
-1
@@ -22,9 +22,12 @@
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
@import "CPControl.j"
|
||||
@import "CPFont.j"
|
||||
@import "CPFontDescriptor.j"
|
||||
|
||||
@global CPApp
|
||||
@class CPFontPanel
|
||||
|
||||
CPItalicFontMask = 1 << 0;
|
||||
CPBoldFontMask = 1 << 1;
|
||||
@@ -41,7 +44,20 @@ CPUnitalicFontMask = 1 << 24;
|
||||
|
||||
|
||||
var CPSharedFontManager = nil,
|
||||
CPFontManagerFactory = Nil;
|
||||
CPFontManagerFactory = nil,
|
||||
CPFontPanelFactory = nil;
|
||||
|
||||
/*
|
||||
modifyFont: sender's tag
|
||||
*/
|
||||
CPNoFontChangeAction = 0;
|
||||
CPViaPanelFontAction = 1;
|
||||
CPAddTraitFontAction = 2;
|
||||
CPSizeUpFontAction = 3;
|
||||
CPSizeDownFontAction = 4;
|
||||
CPHeavierFontAction = 5;
|
||||
CPLighterFontAction = 6;
|
||||
CPRemoveTraitFontAction = 7;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -59,6 +75,8 @@ var CPSharedFontManager = nil,
|
||||
BOOL _multiple @accessors(getter=isMultiple, setter=setMultiple:);
|
||||
|
||||
CPDictionary _activeChange;
|
||||
|
||||
unsigned _fontAction;
|
||||
}
|
||||
|
||||
// Getting the Shared Font Manager
|
||||
@@ -83,6 +101,15 @@ var CPSharedFontManager = nil,
|
||||
{
|
||||
CPFontManagerFactory = aClass;
|
||||
}
|
||||
/*!
|
||||
Sets the class that will be used to create the application's
|
||||
Font panel.
|
||||
*/
|
||||
+ (void)setFontPanelFactory:(Class)aClass
|
||||
{
|
||||
CPFontPanelFactory = aClass;
|
||||
}
|
||||
|
||||
|
||||
- (id)init
|
||||
{
|
||||
@@ -210,6 +237,7 @@ var CPSharedFontManager = nil,
|
||||
{
|
||||
var tag = [sender tag];
|
||||
_activeChange = tag === nil ? @{} : @{ @"addTraits": tag };
|
||||
_fontAction = CPAddTraitFontAction;
|
||||
|
||||
[self sendAction];
|
||||
}
|
||||
@@ -219,6 +247,185 @@ var CPSharedFontManager = nil,
|
||||
return [CPApp sendAction:_action to:_target from:self];
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
This method open the font panel, create it if necessary.
|
||||
@param sender The object that sent the message.
|
||||
*/
|
||||
- (CPFontPanel)fontPanel:(BOOL)createIt
|
||||
{
|
||||
var panel = nil,
|
||||
panelExists = [CPFontPanelFactory sharedFontPanelExists];
|
||||
|
||||
if ((panelExists) || (!panelExists && createIt))
|
||||
panel = [CPFontPanelFactory sharedFontPanel];
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
/*!
|
||||
Convert a font to have the specified Font traits. The font is unchanged expect for the specified Font traits.
|
||||
Using CPUnboldFontMask or CPUnitalicFontMask will respectively remove Bold and Italic traits.
|
||||
@param aFont The font to convert.
|
||||
@param fontTrait The new font traits mask.
|
||||
@result The converted font or \c aFont if the conversion failed.
|
||||
*/
|
||||
- (CPFont)convertFont:(CPFont)aFont toHaveTrait:(CPFontTraitMask)fontTrait
|
||||
{
|
||||
var attributes = [[[aFont fontDescriptor] fontAttributes] copy],
|
||||
symbolicTrait = [[aFont fontDescriptor] symbolicTraits];
|
||||
|
||||
if (fontTrait & CPBoldFontMask)
|
||||
symbolicTrait |= CPFontBoldTrait;
|
||||
|
||||
if (fontTrait & CPItalicFontMask)
|
||||
symbolicTrait |= CPFontItalicTrait;
|
||||
|
||||
if (fontTrait & CPUnboldFontMask) /* FIXME: this only change CPFontSymbolicTrait what about CPFontWeightTrait */
|
||||
symbolicTrait &= ~CPFontBoldTrait;
|
||||
|
||||
if (fontTrait & CPUnitalicFontMask)
|
||||
symbolicTrait &= ~CPFontItalicTrait;
|
||||
|
||||
if (fontTrait & CPExpandedFontMask)
|
||||
symbolicTrait |= CPFontExpandedTrait;
|
||||
|
||||
if (fontTrait & CPSmallCapsFontMask)
|
||||
symbolicTrait |= CPFontSmallCapsTrait;
|
||||
|
||||
if (![attributes containsKey:CPFontTraitsAttribute])
|
||||
[attributes setObject:[CPDictionary dictionaryWithObject:[CPNumber numberWithUnsignedInt:symbolicTrait]
|
||||
forKey:CPFontSymbolicTrait]
|
||||
forKey:CPFontTraitsAttribute];
|
||||
else
|
||||
[[attributes objectForKey:CPFontTraitsAttribute] setObject:[CPNumber numberWithUnsignedInt:symbolicTrait]
|
||||
forKey:CPFontSymbolicTrait];
|
||||
|
||||
return [[aFont class] fontWithDescriptor:[CPFontDescriptor fontDescriptorWithFontAttributes:attributes] size:0.0];
|
||||
}
|
||||
|
||||
/*!
|
||||
Convert a font to not have the specified Font traits. The font is unchanged expect for the specified Font traits.
|
||||
@param aFont The font to convert.
|
||||
@param fontTrait The font traits mask to remove.
|
||||
@result The converted font or \c aFont if the conversion failed.
|
||||
*/
|
||||
- (CPFont)convertFont:(CPFont)aFont toNotHaveTrait:(CPFontTraitMask)fontTrait
|
||||
{
|
||||
var attributes = [[[aFont fontDescriptor] fontAttributes] copy],
|
||||
symbolicTrait = [[aFont fontDescriptor] symbolicTraits];
|
||||
|
||||
if ((fontTrait & CPBoldFontMask) || (fontTrait & CPUnboldFontMask)) /* FIXME: see convertFont:toHaveTrait: about CPFontWeightTrait */
|
||||
symbolicTrait &= ~CPFontBoldTrait;
|
||||
|
||||
if ((fontTrait & CPItalicFontMask) || (fontTrait & CPUnitalicFontMask))
|
||||
symbolicTrait &= ~CPFontItalicTrait;
|
||||
|
||||
if (fontTrait & CPExpandedFontMask)
|
||||
symbolicTrait &= ~CPFontExpandedTrait;
|
||||
|
||||
if (fontTrait & CPSmallCapsFontMask)
|
||||
symbolicTrait &= ~CPFontSmallCapsTrait;
|
||||
|
||||
if (![attributes containsKey:CPFontTraitsAttribute])
|
||||
[attributes setObject:[CPDictionary dictionaryWithObject:[CPNumber numberWithUnsignedInt:symbolicTrait]
|
||||
forKey:CPFontSymbolicTrait]
|
||||
forKey:CPFontTraitsAttribute];
|
||||
else
|
||||
[[attributes objectForKey:CPFontTraitsAttribute] setObject:[CPNumber numberWithUnsignedInt:symbolicTrait]
|
||||
forKey:CPFontSymbolicTrait];
|
||||
|
||||
return [[aFont class] fontWithDescriptor:[CPFontDescriptor fontDescriptorWithFontAttributes:attributes] size:0.0];
|
||||
}
|
||||
|
||||
/*!
|
||||
Convert a font to have specified size. The font is unchanged expect for the specified size.
|
||||
@param aFont The font to convert.
|
||||
@param aSize The new font size.
|
||||
@result The converted font or \c aFont if the conversion failed.
|
||||
*/
|
||||
- (CPFont)convertFont:(CPFont)aFont toSize:(float)aSize
|
||||
{
|
||||
var descriptor = [aFont fontDescriptor];
|
||||
|
||||
return [[aFont class] fontWithDescriptor: descriptor size:aSize]
|
||||
}
|
||||
|
||||
- (void)orderFrontFontPanel:(id)sender
|
||||
{
|
||||
[[self fontPanel:YES] orderFront:sender];
|
||||
}
|
||||
|
||||
- (void)modifyFont:(id)sender
|
||||
{
|
||||
_fontAction = [sender tag];
|
||||
[self sendAction];
|
||||
|
||||
if (_selectedFont)
|
||||
[self setSelectedFont:[self convertFont:_selectedFont] isMultiple:NO];
|
||||
}
|
||||
|
||||
/*!
|
||||
This method causes the receiver to send its action message.
|
||||
@param sender The object that sent the message. (a Font panel)
|
||||
*/
|
||||
- (void)modifyFontViaPanel:(id)sender
|
||||
{
|
||||
_fontAction = CPViaPanelFontAction;
|
||||
if (_selectedFont)
|
||||
[self setSelectedFont:[self convertFont:_selectedFont] isMultiple:NO];
|
||||
|
||||
[self sendAction];
|
||||
}
|
||||
|
||||
/*!
|
||||
Convert a font according to current font changes, provided by the object that initiated the font change.
|
||||
@param aFont The font to convert.
|
||||
@result The converted font or \c aFont if the conversion failed.
|
||||
*/
|
||||
- (CPFont)convertFont:(CPFont)aFont
|
||||
{
|
||||
var newFont = nil;
|
||||
switch (_fontAction)
|
||||
{
|
||||
case CPNoFontChangeAction:
|
||||
newFont = aFont;
|
||||
break;
|
||||
|
||||
case CPViaPanelFontAction:
|
||||
newFont = [[self fontPanel:NO] panelConvertFont:aFont];
|
||||
break;
|
||||
|
||||
case CPAddTraitFontAction:
|
||||
newFont = aFont;
|
||||
if (!_activeChange)
|
||||
break;
|
||||
|
||||
var addTraits = [_activeChange valueForKey:@"addTraits"];
|
||||
|
||||
if (addTraits)
|
||||
newFont = [self convertFont:aFont toHaveTrait:addTraits];
|
||||
break;
|
||||
|
||||
case CPSizeUpFontAction:
|
||||
newFont = [self convertFont:aFont toSize:[aFont size] + 1.0]; /* any limit ? */
|
||||
break;
|
||||
|
||||
case CPSizeDownFontAction:
|
||||
if ([aFont size] > 1)
|
||||
newFont = [self convertFont:aFont toSize:[aFont size] - 1.0];
|
||||
/* else CPBeep() :-p */
|
||||
break;
|
||||
|
||||
default:
|
||||
CPLog.trace(@"-[" + [self className] + " " + _cmd + "] unsupported font action: " + _fontAction + " aFont unchanged");
|
||||
newFont = aFont;
|
||||
break;
|
||||
}
|
||||
|
||||
return newFont;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var _CPFontDetectSpan,
|
||||
|
||||
+6
-5
@@ -70,11 +70,12 @@ CPGradientDrawsAfterEndingLocation = kCGGradientDrawsAfterEndLocation;
|
||||
{
|
||||
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]));
|
||||
var colorSpace = [aColorSpace CGColorSpace] || CGColorSpaceCreateDeviceRGB,
|
||||
cgColors = [someColors arrayByApplyingBlock:function(color)
|
||||
{
|
||||
return CGColorCreate(colorSpace, [color components])
|
||||
}];
|
||||
|
||||
_gradient = CGGradientCreateWithColors(colorSpace, cgColors, someLocations);
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -43,10 +43,10 @@ function CPDrawTiledRects(
|
||||
if (sides.length != grays.length)
|
||||
[CPException raise:CPInvalidArgumentException reason:@"sides (length: " + sides.length + ") and grays (length: " + grays.length + ") must have the same length."];
|
||||
|
||||
var colors = [];
|
||||
|
||||
for (var i = 0; i < grays.length; ++i)
|
||||
colors.push([CPColor colorWithCalibratedWhite:grays[i] alpha:1.0]);
|
||||
var colors = [grays arrayByApplyingBlock:function(gray)
|
||||
{
|
||||
return [CPColor colorWithCalibratedWhite:gray alpha:1.0];
|
||||
}];
|
||||
|
||||
return CPDrawColorTiledRects(boundsRect, clipRect, sides, colors);
|
||||
}
|
||||
|
||||
+258
-13
@@ -30,6 +30,20 @@
|
||||
@import "CGGeometry.j"
|
||||
@import "CPCompatibility.j"
|
||||
|
||||
|
||||
@protocol CPImageDelegate <CPObject>
|
||||
|
||||
@optional
|
||||
- (void)imageDidLoad:(CPImage)anImage;
|
||||
- (void)imageDidError:(CPImage)anImage;
|
||||
- (void)imageDidAbort:(CPImage)anImage;
|
||||
|
||||
@end
|
||||
|
||||
var CPImageDelegate_imageDidLoad_ = 1 << 1,
|
||||
CPImageDelegate_imageDidError_ = 1 << 2,
|
||||
CPImageDelegate_imageDidAbort_ = 1 << 3;
|
||||
|
||||
CPImageLoadStatusInitialized = 0;
|
||||
CPImageLoadStatusLoading = 1;
|
||||
CPImageLoadStatusCompleted = 2;
|
||||
@@ -119,14 +133,15 @@ function CPAppKitImage(aFilename, aSize)
|
||||
*/
|
||||
@implementation CPImage : CPObject
|
||||
{
|
||||
CGSize _size;
|
||||
CPString _filename;
|
||||
CPString _name;
|
||||
CGSize _size;
|
||||
CPString _filename;
|
||||
CPString _name;
|
||||
|
||||
id _delegate;
|
||||
unsigned _loadStatus;
|
||||
id <CPImageDelegate> _delegate;
|
||||
unsigned _loadStatus;
|
||||
unsigned _implementedDelegateMethods;
|
||||
|
||||
Image _image;
|
||||
Image _image;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
@@ -231,7 +246,7 @@ function CPAppKitImage(aFilename, aSize)
|
||||
var canvas = document.createElement("canvas"),
|
||||
ctx = canvas.getContext("2d");
|
||||
|
||||
canvas.width = _image.width,
|
||||
canvas.width = _image.width;
|
||||
canvas.height = _image.height;
|
||||
|
||||
ctx.drawImage(_image, 0, 0);
|
||||
@@ -260,7 +275,7 @@ function CPAppKitImage(aFilename, aSize)
|
||||
*/
|
||||
- (CGSize)size
|
||||
{
|
||||
return _size;
|
||||
return CGSizeMakeCopy(_size);
|
||||
}
|
||||
|
||||
+ (id)imageNamed:(CPString)aName
|
||||
@@ -319,9 +334,22 @@ function CPAppKitImage(aFilename, aSize)
|
||||
Sets the receiver's delegate.
|
||||
@param the delegate
|
||||
*/
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
- (void)setDelegate:(id <CPImageDelegate>)aDelegate
|
||||
{
|
||||
if (_delegate === aDelegate)
|
||||
return;
|
||||
|
||||
_delegate = aDelegate;
|
||||
_implementedDelegateMethods = 0;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(imageDidLoad:)])
|
||||
_implementedDelegateMethods |= CPImageDelegate_imageDidLoad_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(imageDidError:)])
|
||||
_implementedDelegateMethods |= CPImageDelegate_imageDidError_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(imageDidAbort:)])
|
||||
_implementedDelegateMethods |= CPImageDelegate_imageDidAbort_;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -457,7 +485,7 @@ function CPAppKitImage(aFilename, aSize)
|
||||
postNotificationName:CPImageDidLoadNotification
|
||||
object:self];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(imageDidLoad:)])
|
||||
if (_implementedDelegateMethods & CPImageDelegate_imageDidLoad_)
|
||||
[_delegate imageDidLoad:self];
|
||||
}
|
||||
|
||||
@@ -466,7 +494,7 @@ function CPAppKitImage(aFilename, aSize)
|
||||
{
|
||||
_loadStatus = CPImageLoadStatusReadError;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(imageDidError:)])
|
||||
if (_implementedDelegateMethods & CPImageDelegate_imageDidError_)
|
||||
[_delegate imageDidError:self];
|
||||
}
|
||||
|
||||
@@ -475,12 +503,218 @@ function CPAppKitImage(aFilename, aSize)
|
||||
{
|
||||
_loadStatus = CPImageLoadStatusCancelled;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(imageDidAbort:)])
|
||||
if (_implementedDelegateMethods & CPImageDelegate_imageDidAbort_)
|
||||
[_delegate imageDidAbort:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark CSS Theming
|
||||
|
||||
// The code below adds support for CSS theming with 100% compatibility with current theming system.
|
||||
// The idea is to extend CPImage (and CPColor) with CSS components and adapt low level UI components to
|
||||
// support this new kind of CPColor/CPImage. See CPImageView, CPView and _CPImageAndTextView.
|
||||
//
|
||||
// To create a CPImage that uses CSS, simply use the new class method :
|
||||
// + (CPImage)imageWithCSSDictionary:(CPDictionary)aDictionary beforeDictionary:(CPDictionary)beforeDictionary afterDictionary:(CPDictionary)afterDictionary size:(CGSize)aSize
|
||||
// where beforeDictionary & afterDictionary are related to ::before & ::after pseudo-elements.
|
||||
// If you don't need them, just use the simplified class method :
|
||||
// + (CPImage)imageWithCSSDictionary:(CPDictionary)aDictionary size:(CGSize)aSize
|
||||
//
|
||||
// Examples :
|
||||
// regularImageNormal = [CPImage imageWithCSSDictionary:@{
|
||||
// @"border-color": A3ColorActiveBorder,
|
||||
// @"border-style": @"solid",
|
||||
// @"border-width": @"1px",
|
||||
// @"border-radius": @"50%",
|
||||
// @"box-sizing": @"border-box",
|
||||
// @"background-color": A3ColorBackgroundWhite,
|
||||
// @"transition-duration": @"0.35s",
|
||||
// @"transition-property": @"all",
|
||||
// @"transition-timing-function": @"ease"
|
||||
// }
|
||||
// size:CGSizeMake(16,16)];
|
||||
//
|
||||
// imageSearch = [CPImage imageWithCSSDictionary:@{
|
||||
// @"background-image": @"url(%%packed.png)",
|
||||
// @"background-position": @"-16px -32px",
|
||||
// @"background-repeat": @"no-repeat",
|
||||
// @"background-size": @"100px 400px"
|
||||
// }
|
||||
// size:CGSizeMake(16,16)];
|
||||
//
|
||||
// Remark : Please note the special URL of the background image used in this example : url(%%packed.png)
|
||||
// During theme loading, "%%" will be replaced by the path to the theme blend resources folder.
|
||||
// Typically, a CSS theme will use some (rare) images all packed together in a single image resource (see packed.png in Aristo3 theme)
|
||||
//
|
||||
// Also, please note that if you don't use one of the CSS components, you can either set it to nil (best solution) or to an empty dictionary, like :
|
||||
// aCssImage = [CPImage imageWithCSSDictionary:@{} beforeDictionary:nil afterDictionary:@{ ... }];
|
||||
//
|
||||
// You can use -(BOOL)isCSSBased to determine how to cope with it in your code.
|
||||
// -(BOOL)hasCSSDictionary, -(BOOL)hasCSSBeforeDictionary and -(BOOL)hasCSSAfterDictionary are convience methods you can use.
|
||||
//
|
||||
// Remark : -(DOMElement)applyCSSImageForView is meant to be used by low level UI widgets (like CPImageView and _CPImageAndTextView) to implement CSS theme support.
|
||||
//
|
||||
// In some circumstances, you may have to clear a CSS image. You can do this easily by replacing your current image with the special dummy empty CSS image :
|
||||
// [CPImage dummyCSSImageOfSize:CGSizeMake(someWidth, someHeight)]
|
||||
|
||||
@implementation CPImage (CSSTheming)
|
||||
{
|
||||
CPDictionary _cssDictionary @accessors(property=cssDictionary);
|
||||
CPDictionary _cssBeforeDictionary @accessors(property=cssBeforeDictionary);
|
||||
CPDictionary _cssAfterDictionary @accessors(property=cssAfterDictionary);
|
||||
}
|
||||
|
||||
+ (CPImage)imageWithCSSDictionary:(CPDictionary)aDictionary size:(CGSize)aSize
|
||||
{
|
||||
return [[CPImage alloc] initWithCSSDictionary:aDictionary beforeDictionary:nil afterDictionary:nil size:aSize];
|
||||
}
|
||||
|
||||
+ (CPImage)imageWithCSSDictionary:(CPDictionary)aDictionary beforeDictionary:(CPDictionary)beforeDictionary afterDictionary:(CPDictionary)afterDictionary size:(CGSize)aSize
|
||||
{
|
||||
return [[CPImage alloc] initWithCSSDictionary:aDictionary beforeDictionary:beforeDictionary afterDictionary:afterDictionary size:aSize];
|
||||
}
|
||||
|
||||
+ (CPImage)dummyCSSImageOfSize:(CGSize)aSize
|
||||
{
|
||||
// This is used to clear a previous CSS image
|
||||
return [[CPImage alloc] initWithCSSDictionary:@{} beforeDictionary:nil afterDictionary:nil size:aSize];
|
||||
}
|
||||
|
||||
- (id)initWithCSSDictionary:(CPDictionary)aDictionary beforeDictionary:(CPDictionary)beforeDictionary afterDictionary:(CPDictionary)afterDictionary size:(CGSize)aSize
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_size = CGSizeMakeCopy(aSize);
|
||||
_filename = @"CSS image";
|
||||
_loadStatus = CPImageLoadStatusCompleted;
|
||||
_cssDictionary = aDictionary;
|
||||
_cssBeforeDictionary = beforeDictionary;
|
||||
_cssAfterDictionary = afterDictionary;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isCSSBased
|
||||
{
|
||||
return !!(_cssDictionary || _cssBeforeDictionary || _cssAfterDictionary);
|
||||
}
|
||||
|
||||
- (BOOL)hasCSSDictionary
|
||||
{
|
||||
return ([_cssDictionary count] > 0);
|
||||
}
|
||||
|
||||
- (BOOL)hasCSSBeforeDictionary
|
||||
{
|
||||
return ([_cssBeforeDictionary count] > 0);
|
||||
}
|
||||
|
||||
- (BOOL)hasCSSAfterDictionary
|
||||
{
|
||||
return ([_cssAfterDictionary count] > 0);
|
||||
}
|
||||
|
||||
- (DOMElement)applyCSSImageForView:(CPView)aView onDOMElement:(DOMElement)aDOMElement styleNode:(DOMElement)aStyleNode previousState:(CPArrayRef)aPreviousStateRef
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
// First, restore previous CSS styling before applying the new one
|
||||
|
||||
var aPreviousState = @deref(aPreviousStateRef);
|
||||
|
||||
for (var i = 0, count = aPreviousState.length; i < count; i++)
|
||||
aDOMElement.style[aPreviousState[i][0]] = aPreviousState[i][1];
|
||||
|
||||
aPreviousState = @[];
|
||||
|
||||
// Then apply new CSS styling
|
||||
|
||||
[_cssDictionary enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
|
||||
{
|
||||
[aPreviousState addObject:@[aKey, aDOMElement.style[aKey]]];
|
||||
aDOMElement.style[aKey] = anObject;
|
||||
}];
|
||||
|
||||
if (_cssBeforeDictionary || _cssAfterDictionary)
|
||||
{
|
||||
// We need to create a unique class name
|
||||
|
||||
var styleClassName = @".CP" + [aView UID],
|
||||
styleContent = @"";
|
||||
|
||||
if (_cssBeforeDictionary)
|
||||
{
|
||||
styleContent += styleClassName + @"::before { ";
|
||||
|
||||
[_cssBeforeDictionary enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
|
||||
{
|
||||
styleContent += aKey + ": " + anObject + "; ";
|
||||
}];
|
||||
|
||||
styleContent += "} ";
|
||||
}
|
||||
|
||||
if (_cssAfterDictionary)
|
||||
{
|
||||
styleContent += styleClassName + @"::after { ";
|
||||
|
||||
[_cssAfterDictionary enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
|
||||
{
|
||||
styleContent += aKey + ": " + anObject + "; ";
|
||||
}];
|
||||
|
||||
styleContent += "} ";
|
||||
}
|
||||
|
||||
var styleDescription = document.createTextNode(styleContent);
|
||||
|
||||
if (!aStyleNode)
|
||||
{
|
||||
aStyleNode = document.createElement("style");
|
||||
|
||||
aView._DOMElement.insertBefore(aStyleNode, aView._DOMElement.firstChild);
|
||||
|
||||
aStyleNode.appendChild(styleDescription);
|
||||
}
|
||||
else
|
||||
{
|
||||
aStyleNode.replaceChild(styleDescription, aStyleNode.firstChild);
|
||||
}
|
||||
|
||||
[aView setDOMClassName:@"CP"+[aView UID]];
|
||||
}
|
||||
else
|
||||
{
|
||||
// no before/after so remove aStyleNode if existing
|
||||
|
||||
if (aStyleNode)
|
||||
{
|
||||
aView._DOMElement.removeChild(aStyleNode);
|
||||
aStyleNode = nil;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Return actualised values
|
||||
|
||||
@deref(aPreviousStateRef) = aPreviousState;
|
||||
|
||||
return aStyleNode;
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPImageCSSDictionaryKey = @"CPImageCSSDictionaryKey",
|
||||
CPImageCSSBeforeDictionaryKey = @"CPImageCSSBeforeDictionaryKey",
|
||||
CPImageCSSAfterDictionaryKey = @"CPImageCSSAfterDictionaryKey";
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation CPImage (CPCoding)
|
||||
|
||||
/*!
|
||||
@@ -490,7 +724,10 @@ function CPAppKitImage(aFilename, aSize)
|
||||
*/
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
return [self initWithContentsOfFile:[aCoder decodeObjectForKey:@"CPFilename"] size:[aCoder decodeSizeForKey:@"CPSize"]];
|
||||
if ([aCoder containsValueForKey:CPImageCSSDictionaryKey])
|
||||
return [self initWithCSSDictionary:[aCoder decodeObjectForKey:CPImageCSSDictionaryKey] beforeDictionary:[aCoder decodeObjectForKey:CPImageCSSBeforeDictionaryKey] afterDictionary:[aCoder decodeObjectForKey:CPImageCSSAfterDictionaryKey] size:[aCoder decodeSizeForKey:@"CPSize"]];
|
||||
else
|
||||
return [self initWithContentsOfFile:[aCoder decodeObjectForKey:@"CPFilename"] size:[aCoder decodeSizeForKey:@"CPSize"]];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -501,6 +738,14 @@ function CPAppKitImage(aFilename, aSize)
|
||||
{
|
||||
[aCoder encodeObject:_filename forKey:@"CPFilename"];
|
||||
[aCoder encodeSize:_size forKey:@"CPSize"];
|
||||
|
||||
// CSS Styling
|
||||
if ([self isCSSBased])
|
||||
{
|
||||
[aCoder encodeObject:_cssDictionary forKey:CPImageCSSDictionaryKey];
|
||||
[aCoder encodeObject:_cssBeforeDictionary forKey:CPImageCSSBeforeDictionaryKey];
|
||||
[aCoder encodeObject:_cssAfterDictionary forKey:CPImageCSSAfterDictionaryKey];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+35
-6
@@ -29,6 +29,7 @@
|
||||
@global CPImagesPboardType
|
||||
@global appkit_tag_dom_elements
|
||||
|
||||
@typedef CPImageAlignment
|
||||
CPImageAlignCenter = 0;
|
||||
CPImageAlignTop = 1;
|
||||
CPImageAlignTopLeft = 2;
|
||||
@@ -97,10 +98,32 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
||||
- (void)_createDOMImageElement
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
if (_DOMImageElement)
|
||||
return;
|
||||
var image = [self objectValue],
|
||||
isCSSBasedImage = [image isCSSBased],
|
||||
isIMGImageElement = _DOMImageElement && (_DOMImageElement.nodeName == "IMG");
|
||||
|
||||
_DOMImageElement = document.createElement("img");
|
||||
// First, check if we need to destroy a current DOM image element. This is the case if :
|
||||
// - we have one but not the right one (that is a DIV but needing an IMG, and vice versa)
|
||||
|
||||
if (_DOMImageElement)
|
||||
{
|
||||
if ((isIMGImageElement && isCSSBasedImage) || (!isIMGImageElement && !isCSSBasedImage))
|
||||
{
|
||||
// OK, destroy it
|
||||
|
||||
_DOMElement.removeChild(_DOMImageElement);
|
||||
|
||||
_DOMImageElement = nil;
|
||||
|
||||
// CSS styling cleaning
|
||||
_cssStylePreviousState = @[];
|
||||
_cssStyleNode = nil;
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
_DOMImageElement = document.createElement(isCSSBasedImage ? "div" : "img");
|
||||
_DOMImageElement.style.position = "absolute";
|
||||
_DOMImageElement.style.left = "0px";
|
||||
_DOMImageElement.style.top = "0px";
|
||||
@@ -149,10 +172,15 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
||||
var newImage = [self objectValue];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
if (!_DOMImageElement)
|
||||
[self _createDOMImageElement];
|
||||
[self _createDOMImageElement];
|
||||
|
||||
_DOMImageElement.src = newImage ? [newImage filename] : [CPImageViewEmptyPlaceholderImage filename];
|
||||
if ([newImage isCSSBased])
|
||||
_cssStyleNode = [newImage applyCSSImageForView:self
|
||||
onDOMElement:_DOMImageElement
|
||||
styleNode:_cssStyleNode
|
||||
previousState:@ref(_cssStylePreviousState)];
|
||||
else
|
||||
_DOMImageElement.src = newImage ? [newImage filename] : [CPImageViewEmptyPlaceholderImage filename];
|
||||
#endif
|
||||
|
||||
var size = [newImage size];
|
||||
@@ -178,6 +206,7 @@ var CPImageViewEmptyPlaceholderImage = nil;
|
||||
|
||||
- (void)imageDidLoad:(CPNotification)aNotification
|
||||
{
|
||||
[[CPNotificationCenter defaultCenter] removeObserver:self name:CPImageDidLoadNotification object:[self objectValue]];
|
||||
[self hideOrDisplayContents];
|
||||
|
||||
[self setNeedsLayout];
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
var exposedBindingsMap = @{},
|
||||
bindingsMap = @{};
|
||||
|
||||
@typedef CPBindingOperationKind
|
||||
var CPBindingOperationAnd = 0,
|
||||
CPBindingOperationOr = 1;
|
||||
|
||||
@@ -70,6 +71,20 @@ var CPBindingOperationAnd = 0,
|
||||
return [[bindingsMap objectForKey:[anObject UID]] objectForKey:aBinding];
|
||||
}
|
||||
|
||||
+ (void)_reverseSetValueFromExclusiveBinderForObject:(id)anObject
|
||||
{
|
||||
var bindersByBindingName = [bindingsMap objectForKey:[anObject UID]];
|
||||
|
||||
[bindersByBindingName enumerateKeysAndObjectsUsingBlock:function(binding, binder, stop)
|
||||
{
|
||||
if ([binder isKindOfClass:[self class]])
|
||||
{
|
||||
[binder reverseSetValueFor:binding];
|
||||
stop(YES);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+ (CPDictionary)infoForBinding:(CPString)aBinding forObject:(id)anObject
|
||||
{
|
||||
var theBinding = [self getBinding:aBinding forObject:anObject];
|
||||
@@ -116,7 +131,7 @@ var CPBindingOperationAnd = 0,
|
||||
count = allKeys.length;
|
||||
|
||||
while (count--)
|
||||
[anObject unbind:[bindings objectForKey:allKeys[count]]];
|
||||
[anObject unbind:allKeys[count]];
|
||||
|
||||
[bindingsMap removeObjectForKey:[anObject UID]];
|
||||
}
|
||||
@@ -142,7 +157,7 @@ var CPBindingOperationAnd = 0,
|
||||
|
||||
[self _updatePlaceholdersWithOptions:options forBinding:aName];
|
||||
|
||||
[aDestination addObserver:self forKeyPath:aKeyPath options:CPKeyValueObservingOptionNew context:aBinding];
|
||||
[aDestination addObserver:self forKeyPath:aKeyPath options:0 context:aBinding];
|
||||
|
||||
var bindings = [bindingsMap objectForKey:[_source UID]];
|
||||
|
||||
@@ -159,6 +174,24 @@ var CPBindingOperationAnd = 0,
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)isBindingAllowed:(CPString)aBinding forObject:(id)anObject
|
||||
{
|
||||
if ([[anObject class] isBindingExclusive:aBinding])
|
||||
{
|
||||
var bindingsForObject = [bindingsMap objectForKey:[anObject UID]],
|
||||
allBindings = [bindingsForObject allKeys],
|
||||
count = [allBindings count];
|
||||
|
||||
while (count--)
|
||||
{
|
||||
if ([[anObject class] isBindingExclusive:allBindings[count]])
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)raiseIfNotApplicable:(id)aValue forKeyPath:(CPString)keyPath options:(CPDictionary)options
|
||||
{
|
||||
if (aValue === CPNotApplicableMarker && [options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
|
||||
@@ -387,6 +420,11 @@ var CPBindingOperationAnd = 0,
|
||||
return [CPBinder class];
|
||||
}
|
||||
|
||||
+ (BOOL)isBindingExclusive:(CPString)aBinding
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (CPArray)exposedBindings
|
||||
{
|
||||
var exposedBindings = [],
|
||||
@@ -415,6 +453,11 @@ var CPBindingOperationAnd = 0,
|
||||
if (!anObject || !aKeyPath)
|
||||
return CPLog.error("Invalid object or path on " + self + " for " + aBinding);
|
||||
|
||||
if (![CPBinder isBindingAllowed:aBinding forObject:self])
|
||||
{
|
||||
CPLog.warn([self description] + " : cannot bind " + aBinding + " because another binding with the same functionality is already in use.");
|
||||
return;
|
||||
}
|
||||
//if (![[self exposedBindings] containsObject:aBinding])
|
||||
// CPLog.warn("No binding exposed on " + self + " for " + aBinding);
|
||||
|
||||
@@ -814,7 +857,7 @@ var CPBindingOperationAnd = 0,
|
||||
- (id)initWithName:(CPString)aName
|
||||
{
|
||||
if (self = [super init])
|
||||
_name = aName
|
||||
_name = aName;
|
||||
|
||||
return self;
|
||||
}
|
||||
@@ -875,6 +918,7 @@ CPTextColorBinding = @"textColor";
|
||||
CPTitleBinding = @"title";
|
||||
CPToolTipBinding = @"toolTip";
|
||||
CPValueBinding = @"value";
|
||||
CPAttributedStringBinding = @"attributedString";
|
||||
CPValueURLBinding = @"valueURL";
|
||||
CPValuePathBinding = @"valuePath";
|
||||
CPDataBinding = @"data";
|
||||
|
||||
@@ -25,11 +25,13 @@
|
||||
|
||||
@global CPApp
|
||||
|
||||
@typedef CPTickMarkPosition
|
||||
CPTickMarkBelow = 0;
|
||||
CPTickMarkAbove = 1;
|
||||
CPTickMarkLeft = CPTickMarkAbove;
|
||||
CPTickMarkRight = CPTickMarkBelow;
|
||||
|
||||
@typedef CPLevelIndicatorStyle
|
||||
CPRelevancyLevelIndicatorStyle = 0;
|
||||
CPContinuousCapacityLevelIndicatorStyle = 1;
|
||||
CPDiscreteCapacityLevelIndicatorStyle = 2;
|
||||
@@ -105,10 +107,21 @@ CPRatingLevelIndicatorStyle = 3;
|
||||
var filledColor = [self valueForThemeAttribute:@"color-normal"],
|
||||
value = [self doubleValue];
|
||||
|
||||
if (value <= _criticalValue)
|
||||
filledColor = [self valueForThemeAttribute:@"color-critical"];
|
||||
else if (value <= _warningValue)
|
||||
filledColor = [self valueForThemeAttribute:@"color-warning"];
|
||||
if (_warningValue < _criticalValue)
|
||||
{
|
||||
if (value >= _criticalValue)
|
||||
filledColor = [self valueForThemeAttribute:@"color-critical"];
|
||||
else if (value >= _warningValue)
|
||||
filledColor = [self valueForThemeAttribute:@"color-warning"];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value <= _criticalValue)
|
||||
filledColor = [self valueForThemeAttribute:@"color-critical"];
|
||||
else if (value <= _warningValue)
|
||||
filledColor = [self valueForThemeAttribute:@"color-warning"];
|
||||
}
|
||||
|
||||
|
||||
for (var i = 0; i < segmentCount; i++)
|
||||
{
|
||||
@@ -279,7 +292,7 @@ CPRatingLevelIndicatorStyle = 3;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)setWarningValue:(double)warningValue;
|
||||
- (void)setWarningValue:(double)warningValue
|
||||
{
|
||||
if (_warningValue === warningValue)
|
||||
return;
|
||||
@@ -288,7 +301,7 @@ CPRatingLevelIndicatorStyle = 3;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)setCriticalValue:(double)criticalValue;
|
||||
- (void)setCriticalValue:(double)criticalValue
|
||||
{
|
||||
if (_criticalValue === criticalValue)
|
||||
return;
|
||||
|
||||
+68
-21
@@ -30,6 +30,17 @@
|
||||
|
||||
@global CPApp
|
||||
|
||||
@protocol CPMenuDelegate <CPObject>
|
||||
|
||||
@optional
|
||||
- (void)menuWillOpen:(CPMenu)aMenu;
|
||||
- (void)menuDidClose:(CPMenu)aMenu;
|
||||
|
||||
@end
|
||||
|
||||
var CPMenuDelegate_menuWillOpen_ = 1 << 1,
|
||||
CPMenuDelegate_menuDidClose_ = 1 << 2;
|
||||
|
||||
CPMenuDidAddItemNotification = @"CPMenuDidAddItemNotification";
|
||||
CPMenuDidChangeItemNotification = @"CPMenuDidChangeItemNotification";
|
||||
CPMenuDidRemoveItemNotification = @"CPMenuDidRemoveItemNotification";
|
||||
@@ -50,26 +61,27 @@ var _CPMenuBarVisible = NO,
|
||||
*/
|
||||
@implementation CPMenu : CPObject
|
||||
{
|
||||
CPMenu _supermenu;
|
||||
CPMenu _supermenu;
|
||||
|
||||
CPString _title;
|
||||
CPString _name;
|
||||
CPString _title;
|
||||
CPString _name;
|
||||
|
||||
CPFont _font;
|
||||
CPFont _font;
|
||||
|
||||
float _minimumWidth;
|
||||
float _minimumWidth;
|
||||
|
||||
CPMutableArray _items;
|
||||
CPMutableArray _items;
|
||||
|
||||
BOOL _autoenablesItems;
|
||||
BOOL _showsStateColumn;
|
||||
BOOL _autoenablesItems;
|
||||
BOOL _showsStateColumn;
|
||||
|
||||
id _delegate;
|
||||
id <CPMenuDelegate> _delegate;
|
||||
unsigned _implementedDelegateMethods;
|
||||
|
||||
int _highlightedIndex;
|
||||
_CPMenuWindow _menuWindow;
|
||||
int _highlightedIndex;
|
||||
_CPMenuWindow _menuWindow;
|
||||
|
||||
CPEvent _lastCloseEvent;
|
||||
CPEvent _lastCloseEvent;
|
||||
}
|
||||
|
||||
// Managing the Menu Bar
|
||||
@@ -639,6 +651,7 @@ var _CPMenuBarVisible = NO,
|
||||
if (binder)
|
||||
{
|
||||
[binder setValueFor:CPEnabledBinding];
|
||||
[[_menuWindow _menuView] tile];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -941,9 +954,19 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
// Managing the Delegate
|
||||
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
- (void)setDelegate:(id <CPMenuDelegate>)aDelegate
|
||||
{
|
||||
if (_delegate === aDelegate)
|
||||
return;
|
||||
|
||||
_delegate = aDelegate;
|
||||
_implementedDelegateMethods = 0;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(menuWillOpen:)])
|
||||
_implementedDelegateMethods |= CPMenuDelegate_menuWillOpen_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(menuDidClose:)])
|
||||
_implementedDelegateMethods |= CPMenuDelegate_menuDidClose_;
|
||||
}
|
||||
|
||||
- (id)delegate
|
||||
@@ -953,10 +976,7 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
- (void)_menuWillOpen
|
||||
{
|
||||
var delegate = [self delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
|
||||
[delegate menuWillOpen:self];
|
||||
[self _sendDelegateMenuWillOpen];
|
||||
}
|
||||
|
||||
- (void)_menuDidClose
|
||||
@@ -965,10 +985,7 @@ var _CPMenuBarVisible = NO,
|
||||
// when a click on the button itself caused the menu to close.
|
||||
_lastCloseEvent = [CPApp currentEvent];
|
||||
|
||||
var delegate = [self delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuDidClose:)])
|
||||
[delegate menuDidClose:self];
|
||||
[self _sendDelegateMenuDidClose];
|
||||
}
|
||||
|
||||
// Handling Tracking
|
||||
@@ -1132,6 +1149,36 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation CPMenu (CPMenuDelegate)
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate menuWillOpen
|
||||
*/
|
||||
- (void)_sendDelegateMenuWillOpen
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPMenuDelegate_menuWillOpen_))
|
||||
return;
|
||||
|
||||
[_delegate menuWillOpen:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate menuDidClose
|
||||
*/
|
||||
- (void)_sendDelegateMenuDidClose
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPMenuDelegate_menuDidClose_))
|
||||
return;
|
||||
|
||||
[_delegate menuDidClose:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation CPMenu (CPKeyValueCoding)
|
||||
|
||||
- (CPUInteger)countOfItems
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
@import "_CPMenuManager.j"
|
||||
|
||||
@class _CPMenuView
|
||||
@class CPMenu
|
||||
|
||||
@global CPMenuDidAddItemNotification
|
||||
@global CPMenuDidChangeItemNotification
|
||||
@@ -31,7 +32,6 @@
|
||||
|
||||
@implementation _CPMenuBarWindow : CPPanel
|
||||
{
|
||||
CPMenu _menu;
|
||||
CPView _highlightView;
|
||||
CPArray _menuItemViews;
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
@import "CPWindow.j"
|
||||
@import "_CPMenuManager.j"
|
||||
|
||||
@class _CPMenuView
|
||||
|
||||
var _CPMenuWindowPool = [],
|
||||
_CPMenuWindowPoolCapacity = 5,
|
||||
|
||||
@@ -410,7 +412,7 @@ _CPMenuWindowAttachedMenuBackgroundStyle = 2;
|
||||
{
|
||||
// Don't return indexes of items that aren't visible.
|
||||
if (!CGRectContainsPoint([_menuClipView bounds], [_menuClipView convertPoint:aPoint fromView:nil]))
|
||||
return NO;
|
||||
return CPNotFound;
|
||||
|
||||
return [_menuView itemIndexAtPoint:[_menuView convertPoint:aPoint fromView:nil]];
|
||||
}
|
||||
|
||||
@@ -505,7 +505,7 @@ CPOffState
|
||||
if (_submenu)
|
||||
{
|
||||
[_submenu setSupermenu:_menu];
|
||||
[_submenu setTitle:[self title]]
|
||||
[_submenu setTitle:[self title]];
|
||||
|
||||
[self setTarget:_menu];
|
||||
[self setAction:@selector(submenuAction:)];
|
||||
@@ -843,7 +843,7 @@ CPControlKeyMask
|
||||
[item setTarget:_target];
|
||||
[item setAction:_action];
|
||||
[item setEnabled:_isEnabled];
|
||||
[item setHidden:_isHidden]
|
||||
[item setHidden:_isHidden];
|
||||
[item setTag:_tag];
|
||||
[item setState:_state];
|
||||
[item setImage:_image];
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
@class _CPMenuBarWindow
|
||||
@class _CPMenuView
|
||||
@class CPMenuItem
|
||||
|
||||
@implementation _CPMenuItemMenuBarView : CPView
|
||||
{
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
@import "CPImageView.j"
|
||||
@import "_CPImageAndTextView.j"
|
||||
|
||||
@class CPMenuItem
|
||||
|
||||
|
||||
@implementation _CPMenuItemStandardView : CPView
|
||||
{
|
||||
CPMenuItem _menuItem @accessors(property=menuItem);
|
||||
@@ -52,6 +55,7 @@
|
||||
@"menu-item-selection-color": [CPNull null],
|
||||
@"menu-item-text-shadow-color": [CPNull null],
|
||||
@"menu-item-text-color": [CPNull null],
|
||||
@"menu-item-disabled-text-color": [CPColor lightGrayColor],
|
||||
@"menu-item-default-off-state-image": [CPNull null],
|
||||
@"menu-item-default-off-state-highlighted-image": [CPNull null],
|
||||
@"menu-item-default-on-state-image": [CPNull null],
|
||||
@@ -121,7 +125,7 @@
|
||||
- (CPColor)textColor
|
||||
{
|
||||
if (![_menuItem isEnabled])
|
||||
return [CPColor lightGrayColor];
|
||||
return [self valueForThemeAttribute:@"menu-item-disabled-text-color"];
|
||||
|
||||
if (_highlighted)
|
||||
return [CPColor whiteColor];
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
@import "_CPMenuItemStandardView.j"
|
||||
@import "_CPMenuItemMenuBarView.j"
|
||||
|
||||
@class CPMenuItem
|
||||
@global CPApp
|
||||
|
||||
/*
|
||||
|
||||
+123
-16
@@ -27,6 +27,9 @@
|
||||
@import "CPController.j"
|
||||
@import "CPKeyValueBinding.j"
|
||||
|
||||
@class _CPManagedProxy
|
||||
@class CPPredicate;
|
||||
|
||||
/*!
|
||||
@class
|
||||
|
||||
@@ -47,6 +50,9 @@
|
||||
|
||||
BOOL _isEditable;
|
||||
BOOL _automaticallyPreparesContent;
|
||||
BOOL _usesLazyFetching @accessors(getter=usesLazyFetching, setter=setUsesLazyFetching:);
|
||||
BOOL _isUsingManagedProxy;
|
||||
_CPManagedProxy _managedProxy;
|
||||
|
||||
CPCountedSet _observedKeys;
|
||||
}
|
||||
@@ -179,6 +185,52 @@
|
||||
return _automaticallyPreparesContent;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the entity name the controller handles.
|
||||
|
||||
@param CPString newEntityName - The new entity name.
|
||||
*/
|
||||
- (void)setEntityName:(CPString)newEntityName
|
||||
{
|
||||
if (!_managedProxy)
|
||||
{
|
||||
_managedProxy = [[_CPManagedProxy alloc] init];
|
||||
_isUsingManagedProxy = YES;
|
||||
}
|
||||
|
||||
[_managedProxy setEntityName:newEntityName];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the entity name.
|
||||
|
||||
@return CPString - The name of the entity.
|
||||
*/
|
||||
- (CPString)entityName
|
||||
{
|
||||
return [_managedProxy entityName];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the predicate used to fetch content.
|
||||
|
||||
@param CPPredicate newPredicate - The fetch predicate.
|
||||
*/
|
||||
- (void)setFetchPredicate:(CPPredicate)newPredicate
|
||||
{
|
||||
[_managedProxy setFetchPredicate:newPredicate];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the fetch predicate.
|
||||
|
||||
@return CPPredicate - The predicate used to fetch content.
|
||||
*/
|
||||
- (CPPredicate)fetchPredicate
|
||||
{
|
||||
return [_managedProxy fetchPredicate];
|
||||
}
|
||||
|
||||
/*!
|
||||
Overridden by a subclass that require control over the creation of new objects.
|
||||
*/
|
||||
@@ -189,6 +241,7 @@
|
||||
|
||||
/*!
|
||||
Sets the object class when creating new objects.
|
||||
|
||||
@param Class - the class of new objects that will be created.
|
||||
*/
|
||||
- (void)setObjectClass:(Class)aClass
|
||||
@@ -363,7 +416,10 @@
|
||||
var CPObjectControllerContentKey = @"CPObjectControllerContentKey",
|
||||
CPObjectControllerObjectClassNameKey = @"CPObjectControllerObjectClassNameKey",
|
||||
CPObjectControllerIsEditableKey = @"CPObjectControllerIsEditableKey",
|
||||
CPObjectControllerAutomaticallyPreparesContentKey = @"CPObjectControllerAutomaticallyPreparesContentKey";
|
||||
CPObjectControllerAutomaticallyPreparesContentKey = @"CPObjectControllerAutomaticallyPreparesContentKey",
|
||||
CPObjectControllerUsesLazyFetchingKey = @"CPObjectControllerUsesLazyFetchingKey",
|
||||
CPObjectControllerIsUsingManagedProxyKey = @"CPObjectControllerIsUsingManagedProxyKey",
|
||||
CPObjectControllerManagedProxyKey = @"CPObjectControllerManagedProxyKey";
|
||||
|
||||
@implementation CPObjectController (CPCoding)
|
||||
|
||||
@@ -374,12 +430,18 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
if (self)
|
||||
{
|
||||
var objectClassName = [aCoder decodeObjectForKey:CPObjectControllerObjectClassNameKey],
|
||||
objectClass = CPClassFromString(objectClassName);
|
||||
objectClass = CPClassFromString(objectClassName),
|
||||
content = [aCoder decodeObjectForKey:CPObjectControllerContentKey];
|
||||
|
||||
[self setObjectClass:objectClass || [CPMutableDictionary class]];
|
||||
[self setEditable:[aCoder decodeBoolForKey:CPObjectControllerIsEditableKey]];
|
||||
[self setAutomaticallyPreparesContent:[aCoder decodeBoolForKey:CPObjectControllerAutomaticallyPreparesContentKey]];
|
||||
[self setContent:[aCoder decodeObjectForKey:CPObjectControllerContentKey]];
|
||||
[self setUsesLazyFetching:[aCoder decodeBoolForKey:CPObjectControllerUsesLazyFetchingKey]];
|
||||
_isUsingManagedProxy = [aCoder decodeBoolForKey:CPObjectControllerIsUsingManagedProxyKey];
|
||||
_managedProxy = [aCoder decodeObjectForKey:CPObjectControllerManagedProxyKey];
|
||||
|
||||
if (content != nil)
|
||||
[self setContent:content];
|
||||
|
||||
_observedKeys = [[CPCountedSet alloc] init];
|
||||
}
|
||||
@@ -398,6 +460,11 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
|
||||
[aCoder encodeBool:[self isEditable] forKey:CPObjectControllerIsEditableKey];
|
||||
[aCoder encodeBool:[self automaticallyPreparesContent] forKey:CPObjectControllerAutomaticallyPreparesContentKey];
|
||||
[aCoder encodeBool:[self usesLazyFetching] forKey:CPObjectControllerUsesLazyFetchingKey];
|
||||
[aCoder encodeBool:_isUsingManagedProxy forKey:CPObjectControllerIsUsingManagedProxyKey];
|
||||
|
||||
if (_managedProxy)
|
||||
[aCoder encodeObject:_managedProxy forKey:CPObjectControllerManagedProxyKey];
|
||||
}
|
||||
|
||||
- (void)awakeFromCib
|
||||
@@ -459,13 +526,13 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
|
||||
- (BOOL)isEqual:(id)anObject
|
||||
{
|
||||
if ([anObject class] === [self class])
|
||||
{
|
||||
if (anObject._observer === _observer && [anObject._keyPath isEqual:_keyPath] && [anObject._object isEqual:_object])
|
||||
return YES;
|
||||
}
|
||||
if (self === anObject)
|
||||
return YES;
|
||||
|
||||
return NO;
|
||||
if (!anObject || [anObject class] !== [self class] || anObject._observer !== _observer || anObject._keyPath !== _keyPath || anObject._object !== _object)
|
||||
return NO;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)change context:(id)context
|
||||
@@ -749,7 +816,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
|
||||
- (void)setValue:(id)theValue forKey:(CPString)theKeyPath
|
||||
{
|
||||
[self setValue:theKeyPath forKeyPath:theKeyPath];
|
||||
[self setValue:theValue forKeyPath:theKeyPath];
|
||||
}
|
||||
|
||||
- (unsigned)count
|
||||
@@ -808,15 +875,55 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
|
||||
- (void)removeObserver:(id)anObject forKeyPath:(CPString)aKeyPath
|
||||
{
|
||||
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObject object:self],
|
||||
index = [_observationProxies indexOfObject:proxy];
|
||||
[_observationProxies enumerateObjectsUsingBlock:function(aProxy, idx, stop)
|
||||
{
|
||||
if (aProxy._object === self && aProxy._keyPath == aKeyPath && aProxy._observer === anObject)
|
||||
{
|
||||
var observedObjects = _observedObjectsByKeyPath[aKeyPath];
|
||||
|
||||
var observedObjects = _observedObjectsByKeyPath[aKeyPath];
|
||||
[observedObjects removeObserver:[_observationProxies objectAtIndex:index] forKeyPath:aKeyPath];
|
||||
[observedObjects removeObserver:aProxy forKeyPath:aKeyPath];
|
||||
[_observationProxies removeObjectAtIndex:idx];
|
||||
|
||||
[_observationProxies removeObjectAtIndex:index];
|
||||
_observedObjectsByKeyPath[aKeyPath] = nil;
|
||||
|
||||
_observedObjectsByKeyPath[aKeyPath] = nil;
|
||||
stop(YES);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation _CPManagedProxy : CPObject
|
||||
{
|
||||
CPString _entityName @accessors(getter=entityName, setter=setEntityName:);
|
||||
CPPredicate _fetchPredicate @accessors(getter=fetchPredicate, setter=setFetchPredicate:);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPManagedProxyEntityNameKey = @"CPManagedProxyEntityNameKey",
|
||||
CPManagedProxyFetchPredicateKey = @"CPManagedProxyFetchPredicateKey";
|
||||
|
||||
@implementation _CPManagedProxy (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self setEntityName:[aCoder decodeObjectForKey:CPManagedProxyEntityNameKey]];
|
||||
[self setFetchPredicate:[aCoder decodeObjectForKey:CPManagedProxyFetchPredicateKey]];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeObject:[self entityName] forKey:CPManagedProxyEntityNameKey];
|
||||
[aCoder encodeObject:[self fetchPredicate] forKey:CPManagedProxyFetchPredicateKey];
|
||||
}
|
||||
|
||||
@end
|
||||
+472
-340
File diff suppressed because it is too large
Load Diff
+23
-2
@@ -22,10 +22,13 @@
|
||||
|
||||
@import "CPWindow.j"
|
||||
|
||||
@global CPApp
|
||||
|
||||
CPOKButton = 1;
|
||||
CPCancelButton = 0;
|
||||
|
||||
CPDocModalWindowMask = 1 << 6;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPPanel
|
||||
@@ -51,8 +54,6 @@ CPCancelButton = 0;
|
||||
@global
|
||||
@class CPWindow
|
||||
*/
|
||||
CPDocModalWindowMask = 1 << 6;
|
||||
|
||||
@implementation CPPanel : CPWindow
|
||||
{
|
||||
BOOL _becomesKeyOnlyIfNeeded;
|
||||
@@ -119,4 +120,24 @@ CPDocModalWindowMask = 1 << 6;
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Overrides
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (void)cancelOperation:(id)sender
|
||||
{
|
||||
if ([[CPApp currentEvent] _couldBeKeyEquivalent] && [self performKeyEquivalent:[CPApp currentEvent]])
|
||||
return;
|
||||
|
||||
[[self firstResponder] tryToPerform:@selector(cancel:) with:self];
|
||||
}
|
||||
|
||||
- (void)cancel:(id)sender
|
||||
{
|
||||
[self performClose:sender];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+6
-69
@@ -26,6 +26,9 @@
|
||||
@import <Foundation/CPDictionary.j>
|
||||
@import <Foundation/CPPropertyListSerialization.j>
|
||||
|
||||
@class CPWebScriptObject
|
||||
|
||||
@typedef DataTransfer
|
||||
|
||||
CPGeneralPboard = @"CPGeneralPboard";
|
||||
CPFontPboard = @"CPFontPboard";
|
||||
@@ -41,6 +44,8 @@ CPStringPboardType = @"CPStringPboardType";
|
||||
CPURLPboardType = @"CPURLPboardType";
|
||||
CPImagesPboardType = @"CPImagesPboardType";
|
||||
CPVideosPboardType = @"CPVideosPboardType";
|
||||
CPRTFPboardType = @"CPRTFPboardType";
|
||||
_CPSmartPboardType = @"_CPSmartPboardType";
|
||||
|
||||
UTF8PboardType = @"public.utf8-plain-text";
|
||||
|
||||
@@ -48,8 +53,7 @@ UTF8PboardType = @"public.utf8-plain-text";
|
||||
CPImagePboardType = @"CPImagePboardType";
|
||||
|
||||
|
||||
var CPPasteboards = nil,
|
||||
supportsNativePasteboard = NO;
|
||||
var CPPasteboards = nil;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -65,8 +69,6 @@ var CPPasteboards = nil,
|
||||
|
||||
unsigned _changeCount;
|
||||
CPString _stateUID;
|
||||
|
||||
WebScriptObject _nativePasteboard;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -80,9 +82,6 @@ var CPPasteboards = nil,
|
||||
[self setVersion:1.0];
|
||||
|
||||
CPPasteboards = @{};
|
||||
|
||||
if (typeof window.cpPasteboardWithName !== "undefined")
|
||||
supportsNativePasteboard = YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -125,12 +124,6 @@ var CPPasteboards = nil,
|
||||
_provided = @{};
|
||||
|
||||
_changeCount = 0;
|
||||
|
||||
if (supportsNativePasteboard)
|
||||
{
|
||||
_nativePasteboard = window.cpPasteboardWithName(aName);
|
||||
[self _synchronizePasteboard];
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -160,15 +153,6 @@ var CPPasteboards = nil,
|
||||
[_owners setObject:anOwner forKey:type];
|
||||
}
|
||||
|
||||
if (_nativePasteboard)
|
||||
{
|
||||
var nativeTypes = [types copy];
|
||||
if ([types containsObject:CPStringPboardType])
|
||||
nativeTypes.push(UTF8PboardType);
|
||||
|
||||
_nativePasteboard.addTypes_(nativeTypes);
|
||||
}
|
||||
|
||||
return ++_changeCount;
|
||||
}
|
||||
|
||||
@@ -179,12 +163,6 @@ var CPPasteboards = nil,
|
||||
@return the pasteboard's change count
|
||||
*/
|
||||
- (unsigned)declareTypes:(CPArray)types owner:(id)anOwner
|
||||
{
|
||||
[self _declareTypes:types owner:anOwner updateNativePasteboard:YES];
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (unsigned)_declareTypes:(CPArray)types owner:(id)anOwner updateNativePasteboard:(BOOL)shouldUpdate
|
||||
{
|
||||
[_types setArray:types];
|
||||
|
||||
@@ -198,16 +176,6 @@ var CPPasteboards = nil,
|
||||
[_owners setObject:anOwner forKey:_types[count]];
|
||||
}
|
||||
|
||||
if (_nativePasteboard && shouldUpdate)
|
||||
{
|
||||
var nativeTypes = [types copy];
|
||||
if ([types containsObject:CPStringPboardType])
|
||||
nativeTypes.push(UTF8PboardType);
|
||||
|
||||
_nativePasteboard.declareTypes_(nativeTypes);
|
||||
_changeCount = _nativePasteboard.changeCount();
|
||||
}
|
||||
|
||||
return ++_changeCount;
|
||||
}
|
||||
|
||||
@@ -270,7 +238,6 @@ var CPPasteboards = nil,
|
||||
*/
|
||||
- (CPArray)types
|
||||
{
|
||||
[self _synchronizePasteboard];
|
||||
return _types;
|
||||
}
|
||||
|
||||
@@ -309,36 +276,6 @@ var CPPasteboards = nil,
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)_synchronizePasteboard
|
||||
{
|
||||
if (_nativePasteboard && _nativePasteboard.changeCount() > _changeCount)
|
||||
{
|
||||
var nativeTypes = [_nativePasteboard.types() copy];
|
||||
if ([nativeTypes containsObject:UTF8PboardType])
|
||||
nativeTypes.push(CPStringPboardType);
|
||||
|
||||
[self _declareTypes:nativeTypes owner:self updateNativePasteboard:NO];
|
||||
|
||||
_changeCount = _nativePasteboard.changeCount();
|
||||
}
|
||||
}
|
||||
|
||||
/*! @ignore
|
||||
method provided for integration with native pasteboard
|
||||
*/
|
||||
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
|
||||
{
|
||||
if (aType === CPStringPboardType)
|
||||
{
|
||||
var string = _nativePasteboard.stringForType_(UTF8PboardType);
|
||||
|
||||
[self setString:string forType:CPStringPboardType];
|
||||
[self setString:string forType:UTF8PboardType];
|
||||
}
|
||||
else
|
||||
[self setString:_nativePasteboard.stringForType_(aType) forType:aType];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the property list for the specified data type
|
||||
@param aType the requested data type
|
||||
|
||||
+41
-43
@@ -26,8 +26,6 @@
|
||||
@import "CPMenu.j"
|
||||
@import "CPMenuItem.j"
|
||||
|
||||
var VISIBLE_MARGIN = 7.0;
|
||||
|
||||
CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
|
||||
/*!
|
||||
@@ -363,15 +361,10 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
*/
|
||||
- (CPArray)itemTitles
|
||||
{
|
||||
var titles = [],
|
||||
items = [self itemArray],
|
||||
index = 0,
|
||||
count = [items count];
|
||||
|
||||
for (; index < count; ++index)
|
||||
titles.push([items[index] title]);
|
||||
|
||||
return titles;
|
||||
return [[self itemArray] arrayByApplyingBlock:function(item)
|
||||
{
|
||||
return [item title];
|
||||
}];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -773,13 +766,6 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
[[self selectedItem] setState:CPOffState];
|
||||
}
|
||||
|
||||
- (void)_reverseSetBinding
|
||||
{
|
||||
[_CPPopUpButtonSelectionBinder reverseSetValueForObject:self];
|
||||
|
||||
[super _reverseSetBinding];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPPopUpButton (BindingSupport)
|
||||
@@ -802,6 +788,20 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
+ (BOOL)isBindingExclusive:(CPString)aBinding
|
||||
{
|
||||
return (aBinding == CPSelectedIndexBinding ||
|
||||
aBinding == CPSelectedTagBinding ||
|
||||
aBinding == CPSelectedValueBinding);
|
||||
}
|
||||
|
||||
- (void)_reverseSetBinding
|
||||
{
|
||||
[_CPPopUpButtonSelectionBinder _reverseSetValueFromExclusiveBinderForObject:self];
|
||||
|
||||
[super _reverseSetBinding];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPPopUpButtonContentBinder : CPBinder
|
||||
@@ -847,7 +847,17 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
{
|
||||
var count = [aValue count],
|
||||
options = [_info objectForKey:CPOptionsKey],
|
||||
offset = [self _getInsertNullOffset];
|
||||
offset = [self _getInsertNullOffset],
|
||||
selectedBindingInfo = [_source infoForBinding:CPSelectedObjectBinding],
|
||||
selectedObject = nil;
|
||||
|
||||
if (selectedBindingInfo)
|
||||
{
|
||||
var destination = [selectedBindingInfo objectForKey:CPObservedObjectKey],
|
||||
keyPath = [selectedBindingInfo objectForKey:CPObservedKeyPathKey];
|
||||
|
||||
selectedObject = [destination valueForKeyPath:keyPath];
|
||||
}
|
||||
|
||||
if (count + offset != [_source numberOfItems])
|
||||
{
|
||||
@@ -858,9 +868,19 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var item = [[CPMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:nil];
|
||||
[self _setValue:[aValue objectAtIndex:i] forItem:item withOptions:options];
|
||||
var item = [[CPMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:nil],
|
||||
itemValue = [aValue objectAtIndex:i];
|
||||
|
||||
[self _setValue:itemValue forItem:item withOptions:options];
|
||||
[_source addItem:item];
|
||||
|
||||
// Select this item if it is the one selected by the selected object binding
|
||||
// This is needed if the selected object binding is set before the items
|
||||
// from the content binding
|
||||
if (itemValue === selectedObject)
|
||||
{
|
||||
[_source setSelectedIndex:[_source numberOfItems] - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -931,30 +951,8 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
|
||||
@end
|
||||
|
||||
var binderForObject = {};
|
||||
|
||||
@implementation _CPPopUpButtonSelectionBinder : CPBinder
|
||||
{
|
||||
CPString _selectionBinding @accessors;
|
||||
}
|
||||
|
||||
- (id)initWithBinding:(CPString)aBinding name:(CPString)aName to:(id)aDestination keyPath:(CPString)aKeyPath options:(CPDictionary)options from:(id)aSource
|
||||
{
|
||||
self = [super initWithBinding:aBinding name:aName to:aDestination keyPath:aKeyPath options:options from:aSource];
|
||||
|
||||
if (self)
|
||||
{
|
||||
binderForObject[[aSource UID]] = self;
|
||||
_selectionBinding = aName;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (void)reverseSetValueForObject:(id)aSource
|
||||
{
|
||||
var binder = binderForObject[[aSource UID]];
|
||||
[binder reverseSetValueFor:[binder _selectionBinding]];
|
||||
}
|
||||
|
||||
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||
|
||||
+70
-32
@@ -28,8 +28,19 @@
|
||||
@import "CPImageView.j"
|
||||
@import "CPResponder.j"
|
||||
@import "CPView.j"
|
||||
@import "CPViewController.j"
|
||||
@import "_CPPopoverWindow.j"
|
||||
|
||||
@protocol CPPopoverDelegate <CPObject>
|
||||
|
||||
@optional
|
||||
- (BOOL)popoverShouldClose:(CPPopover)aPopover;
|
||||
- (void)popoverWillClose:(CPPopover)aPopover;
|
||||
- (void)popoverDidClose:(CPPopover)aPopover;
|
||||
- (void)popoverWillShow:(CPPopover)aPopover;
|
||||
- (void)popoverDidShow:(CPPopover)aPopover;
|
||||
|
||||
@end
|
||||
|
||||
CPPopoverBehaviorApplicationDefined = 0;
|
||||
CPPopoverBehaviorTransient = 1;
|
||||
@@ -60,15 +71,16 @@ var CPPopoverDelegate_popover_willShow_ = 1 << 0,
|
||||
*/
|
||||
@implementation CPPopover : CPResponder
|
||||
{
|
||||
@outlet CPViewController _contentViewController @accessors(property=contentViewController);
|
||||
@outlet id _delegate @accessors(getter=delegate);
|
||||
@outlet CPViewController _contentViewController @accessors(property=contentViewController);
|
||||
@outlet id <CPPopoverDelegate> _delegate @accessors(getter=delegate);
|
||||
|
||||
BOOL _animates @accessors(getter=animates);
|
||||
int _appearance @accessors(property=appearance);
|
||||
int _behavior @accessors(getter=behavior);
|
||||
BOOL _animates @accessors(getter=animates);
|
||||
int _appearance @accessors(property=appearance);
|
||||
int _behavior @accessors(getter=behavior);
|
||||
|
||||
_CPPopoverWindow _popoverWindow;
|
||||
int _implementedDelegateMethods;
|
||||
_CPPopoverWindow _popoverWindow;
|
||||
CPView _positioningView;
|
||||
int _implementedDelegateMethods;
|
||||
}
|
||||
|
||||
|
||||
@@ -127,9 +139,6 @@ var CPPopoverDelegate_popover_willShow_ = 1 << 0,
|
||||
*/
|
||||
- (CGSize)contentSize
|
||||
{
|
||||
if (![_popoverWindow isVisible])
|
||||
return CGRectMakeZero();
|
||||
|
||||
return [[_contentViewController view] frameSize];
|
||||
}
|
||||
|
||||
@@ -140,7 +149,10 @@ var CPPopoverDelegate_popover_willShow_ = 1 << 0,
|
||||
*/
|
||||
- (void)setContentSize:(CGSize)aSize
|
||||
{
|
||||
[[_contentViewController view] setFrameSize:aSize];
|
||||
if (!_popoverWindow)
|
||||
[[_contentViewController view] setFrameSize:aSize];
|
||||
else
|
||||
[_popoverWindow updateFrameWithSize:aSize];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -181,10 +193,10 @@ Set the behavior of the CPPopover. It can be:
|
||||
return;
|
||||
|
||||
_behavior = aBehavior;
|
||||
[_popoverWindow setStyleMask:[self styleMaskForBehavior]];
|
||||
[_popoverWindow setStyleMask:[self _styleMaskForBehavior]];
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
- (void)setDelegate:(id <CPPopoverDelegate>)aDelegate
|
||||
{
|
||||
if (_delegate === aDelegate)
|
||||
return;
|
||||
@@ -226,17 +238,14 @@ Set the behavior of the CPPopover. It can be:
|
||||
if (!_contentViewController)
|
||||
[CPException raise:CPInternalInconsistencyException reason:@"contentViewController must not be nil"];
|
||||
|
||||
// If the popover is currently closing, do nothing. That is what Cocoa does.
|
||||
if ([_popoverWindow isClosing])
|
||||
// If the popover is currently closing or opening, do nothing. That is what Cocoa does.
|
||||
if ([_popoverWindow isClosing] || [_popoverWindow isOpening])
|
||||
return;
|
||||
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_willShow_)
|
||||
[_delegate popoverWillShow:self];
|
||||
_positioningView = positioningView;
|
||||
|
||||
if (!_popoverWindow)
|
||||
{
|
||||
_popoverWindow = [[_CPPopoverWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:[self styleMaskForBehavior]];
|
||||
}
|
||||
_popoverWindow = [[_CPPopoverWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:[self _styleMaskForBehavior]];
|
||||
|
||||
[_popoverWindow setPlatformWindow:[[positioningView window] platformWindow]];
|
||||
[_popoverWindow setAppearance:_appearance];
|
||||
@@ -245,15 +254,22 @@ Set the behavior of the CPPopover. It can be:
|
||||
[_popoverWindow setMovableByWindowBackground:NO];
|
||||
[_popoverWindow setFrame:[_popoverWindow frameRectForContentRect:[[_contentViewController view] frame]]];
|
||||
[_popoverWindow setContentView:[_contentViewController view]];
|
||||
|
||||
if (![self isShown])
|
||||
[self _popoverWillShow];
|
||||
|
||||
[_popoverWindow positionRelativeToRect:positioningRect ofView:positioningView preferredEdge:preferredEdge];
|
||||
|
||||
if (!_animates && _implementedDelegateMethods & CPPopoverDelegate_popover_didShow_)
|
||||
[_delegate popoverDidShow:self];
|
||||
if (![self isShown])
|
||||
[self _popoverWindowDidShow];
|
||||
}
|
||||
|
||||
- (unsigned)styleMaskForBehavior
|
||||
- (unsigned)_styleMaskForBehavior
|
||||
{
|
||||
return (_behavior == CPPopoverBehaviorTransient) ? CPClosableOnBlurWindowMask : 0;
|
||||
if (_behavior == CPPopoverBehaviorApplicationDefined)
|
||||
return 0;
|
||||
|
||||
return CPClosableOnBlurWindowMask
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -272,9 +288,9 @@ Set the behavior of the CPPopover. It can be:
|
||||
if ([_popoverWindow isClosing] || ![self isShown])
|
||||
return;
|
||||
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_willClose_)
|
||||
[_delegate popoverWillClose:self];
|
||||
[self _popoverWillClose];
|
||||
|
||||
_positioningView = nil;
|
||||
[_popoverWindow close];
|
||||
|
||||
// popoverDidClose will be sent from popoverWindowDidClose, since
|
||||
@@ -295,9 +311,8 @@ Set the behavior of the CPPopover. It can be:
|
||||
if ([_popoverWindow isClosing])
|
||||
return;
|
||||
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_shouldClose_)
|
||||
if (![_delegate popoverShouldClose:self])
|
||||
return;
|
||||
if (![self _popoverShouldClose])
|
||||
return;
|
||||
|
||||
[self _close];
|
||||
}
|
||||
@@ -307,7 +322,7 @@ Set the behavior of the CPPopover. It can be:
|
||||
#pragma mark Delegates
|
||||
|
||||
/*! @ignore */
|
||||
- (BOOL)popoverWindowShouldClose:(_CPPopoverWindow)aPopoverWindow
|
||||
- (BOOL)_popoverWindowShouldClose
|
||||
{
|
||||
[self performClose:self];
|
||||
|
||||
@@ -318,19 +333,42 @@ Set the behavior of the CPPopover. It can be:
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (void)popoverWindowDidClose:(_CPPopoverWindow)aPopoverWindow
|
||||
- (void)_popoverWindowDidClose
|
||||
{
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_didClose_)
|
||||
[_delegate popoverDidClose:self];
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (void)popoverWindowDidShow:(_CPPopoverWindow)aPopoverWindow
|
||||
- (void)_popoverWindowDidShow
|
||||
{
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_didShow_)
|
||||
[_delegate popoverDidShow:self];
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (BOOL)_popoverShouldClose
|
||||
{
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_shouldClose_)
|
||||
return [_delegate popoverShouldClose:self];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (void)_popoverWillClose
|
||||
{
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_willClose_)
|
||||
[_delegate popoverWillClose:self];
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (void)_popoverWillShow
|
||||
{
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_willShow_)
|
||||
[_delegate popoverWillShow:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPPopover (Deprecated)
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
@import "CPWindow_Constants.j"
|
||||
|
||||
|
||||
@typedef CPProgressIndicatorStyle
|
||||
/*
|
||||
@global
|
||||
@group CPProgressIndicatorStyle
|
||||
@@ -85,6 +86,9 @@ var CPProgressIndicatorSpinningStyleColors = [];
|
||||
@"spinning-mini-gif": [CPNull null],
|
||||
@"spinning-small-gif": [CPNull null],
|
||||
@"spinning-regular-gif": [CPNull null],
|
||||
@"circular-border-color": [CPNull null],
|
||||
@"circular-border-size": 1,
|
||||
@"circular-color": [CPNull null]
|
||||
};
|
||||
}
|
||||
|
||||
@@ -367,6 +371,7 @@ var CPProgressIndicatorSpinningStyleColors = [];
|
||||
- (void)drawBar
|
||||
{
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||
@@ -412,6 +417,9 @@ var CPProgressIndicatorSpinningStyleColors = [];
|
||||
{
|
||||
if (_style == CPProgressIndicatorSpinningStyle)
|
||||
{
|
||||
if (!_indeterminate)
|
||||
return;
|
||||
|
||||
// This will cause the bar view to go away due to having a nil rect when _style == CPProgressIndicatorSpinningStyle.
|
||||
[self layoutEphemeralSubviewNamed:"bar-view"
|
||||
positioned:CPWindowBelow
|
||||
@@ -437,6 +445,54 @@ var CPProgressIndicatorSpinningStyleColors = [];
|
||||
[self setBackgroundColor:nil];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
if (_style == CPProgressIndicatorSpinningStyle && !_indeterminate)
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
rect = CGRectMakeCopy(aRect),
|
||||
borderSize = [self currentValueForThemeAttribute:@"circular-border-size"];
|
||||
|
||||
rect.origin.x += borderSize;
|
||||
rect.origin.y += borderSize;
|
||||
rect.size.width = rect.size.width - borderSize * 2;
|
||||
rect.size.height = rect.size.height - borderSize * 2;
|
||||
|
||||
if ([self doubleValue] > [self minValue] && [self doubleValue] < [self maxValue])
|
||||
{
|
||||
var midX = CGRectGetMidX(rect),
|
||||
midY = CGRectGetMidY(rect),
|
||||
endAngle = Math.PI * 2 * (([self doubleValue] - [self minValue]) / ([self maxValue] - [self minValue])) - Math.PI / 2,
|
||||
radius = MIN(rect.size.width / 2, rect.size.height / 2);
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetLineWidth(context, borderSize);
|
||||
CGContextSetFillColor(context, [self currentValueForThemeAttribute:@"circular-color"]);
|
||||
CGContextMoveToPoint(context, midX, midY);
|
||||
CGContextAddArc(context, midX, midY, radius, 3 * Math.PI / 2, endAngle, YES);
|
||||
CGContextAddLineToPoint(context, midX, midY);
|
||||
CGContextClosePath(context);
|
||||
CGContextFillPath(context);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
else if ([self doubleValue] == [self maxValue])
|
||||
{
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetFillColor(context, [self currentValueForThemeAttribute:@"circular-color"]);
|
||||
CGContextAddEllipseInRect(context, rect);
|
||||
CGContextClosePath(context);
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetStrokeColor(context , [self currentValueForThemeAttribute:@"circular-border-color"]);
|
||||
CGContextSetLineWidth(context, borderSize);
|
||||
CGContextAddEllipseInRect(context, rect);
|
||||
CGContextClosePath(context);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
+14
-29
@@ -25,8 +25,11 @@
|
||||
|
||||
@import "CPButton.j"
|
||||
|
||||
@class CPRadioGroup
|
||||
|
||||
@global CPApp
|
||||
|
||||
CPRadioImageOffset = 4.0;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -65,9 +68,6 @@
|
||||
option.
|
||||
|
||||
*/
|
||||
|
||||
CPRadioImageOffset = 4.0;
|
||||
|
||||
@implementation CPRadio : CPButton
|
||||
{
|
||||
CPRadioGroup _radioGroup;
|
||||
@@ -267,9 +267,9 @@ var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
|
||||
- (BOOL)selectRadioWithTag:(int)tag
|
||||
{
|
||||
var index = [_radios indexOfObjectPassingTest:function(radio)
|
||||
{
|
||||
return [radio tag] === tag;
|
||||
}];
|
||||
{
|
||||
return [radio tag] === tag;
|
||||
}];
|
||||
|
||||
if (index !== CPNotFound)
|
||||
{
|
||||
@@ -356,7 +356,7 @@ var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
|
||||
[_selectedRadio setState:CPOffState];
|
||||
|
||||
_selectedRadio = aRadio;
|
||||
[_CPRadioGroupSelectionBinder reverseSetValueForObject:self];
|
||||
[_CPRadioGroupSelectionBinder _reverseSetValueFromExclusiveBinderForObject:self];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -407,32 +407,17 @@ var CPRadioGroupRadiosKey = @"CPRadioGroupRadiosKey",
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
@end
|
||||
+ (BOOL)isBindingExclusive:(CPString)aBinding
|
||||
{
|
||||
return (aBinding == CPSelectedIndexBinding ||
|
||||
aBinding == CPSelectedTagBinding ||
|
||||
aBinding == CPSelectedValueBinding);
|
||||
}
|
||||
|
||||
var binderForObject = {};
|
||||
@end
|
||||
|
||||
@implementation _CPRadioGroupSelectionBinder : CPBinder
|
||||
{
|
||||
CPString _selectionBinding @accessors;
|
||||
}
|
||||
|
||||
- (id)initWithBinding:(CPString)aBinding name:(CPString)aName to:(id)aDestination keyPath:(CPString)aKeyPath options:(CPDictionary)options from:(id)aSource
|
||||
{
|
||||
self = [super initWithBinding:aBinding name:aName to:aDestination keyPath:aKeyPath options:options from:aSource];
|
||||
|
||||
if (self)
|
||||
{
|
||||
binderForObject[[aSource UID]] = self;
|
||||
_selectionBinding = aName;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (void)reverseSetValueForObject:(id)aSource
|
||||
{
|
||||
var binder = binderForObject[[aSource UID]];
|
||||
[binder reverseSetValueFor:[binder _selectionBinding]];
|
||||
}
|
||||
|
||||
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||
|
||||
@@ -24,8 +24,10 @@
|
||||
@import <Foundation/CPObjJRuntime.j>
|
||||
|
||||
@import "CPEvent.j"
|
||||
@import "CPCursor.j"
|
||||
|
||||
@class CPKeyBinding
|
||||
@class CPMenu
|
||||
|
||||
CPDeleteKeyCode = 8;
|
||||
CPTabKeyCode = 9;
|
||||
@@ -199,6 +201,18 @@ CPDeleteForwardKeyCode = 46;
|
||||
[_nextResponder performSelector:_cmd withObject:anEvent];
|
||||
}
|
||||
|
||||
/*!
|
||||
Notifies the receiver that the mouse entered the receiver's area and that it can adapt the cursor.
|
||||
@param anEvent contains information about the exit
|
||||
*/
|
||||
- (void)cursorUpdate:(CPEvent)anEvent
|
||||
{
|
||||
if (_nextResponder)
|
||||
[_nextResponder performSelector:_cmd withObject:anEvent];
|
||||
else
|
||||
[[CPCursor arrowCursor] set];
|
||||
}
|
||||
|
||||
/*!
|
||||
Notifies the receiver that the mouse scroll wheel has moved.
|
||||
@param anEvent information about the scroll
|
||||
|
||||
@@ -27,8 +27,7 @@
|
||||
@import "CPMenuItem.j"
|
||||
@import "CPTextField.j"
|
||||
|
||||
// NOTE: CPDatePicker is not implemented yet
|
||||
@class CPDatePicker
|
||||
@import "CPDatePicker.j"
|
||||
|
||||
|
||||
CPUndefinedAttributeType = 0;
|
||||
@@ -472,9 +471,11 @@ CPTransformableAttributeType = 1800;
|
||||
|
||||
var value;
|
||||
if (attributeType >= CPInteger16AttributeType && attributeType <= CPFloatAttributeType)
|
||||
value = [aView intValue];
|
||||
value = [aView floatValue];
|
||||
else if (attributeType == CPBooleanAttributeType)
|
||||
value = [aView state];
|
||||
else if (attributeType == CPDateAttributeType)
|
||||
value = [aView dateValue];
|
||||
else
|
||||
value = [aView stringValue];
|
||||
|
||||
@@ -488,7 +489,36 @@ CPTransformableAttributeType = 1800;
|
||||
|
||||
- (id)copy
|
||||
{
|
||||
return [CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:self]];
|
||||
var views = [CPArray array],
|
||||
copy = [[[self class] alloc] init];
|
||||
|
||||
[copy _setTemplateType:_templateType];
|
||||
[copy _setOptions:_predicateOptions];
|
||||
[copy _setModifier:_predicateModifier];
|
||||
[copy _setLeftAttributeType:_leftAttributeType];
|
||||
[copy _setRightAttributeType:_rightAttributeType];
|
||||
[copy setLeftIsWildcard:_leftIsWildcard];
|
||||
[copy setRightIsWildcard:_rightIsWildcard];
|
||||
|
||||
[_views enumerateObjectsUsingBlock:function(aView, idx, stop)
|
||||
{
|
||||
var vcopy;
|
||||
|
||||
if ([aView implementsSelector:@selector(copy)])
|
||||
{
|
||||
vcopy = [aView copy];
|
||||
}
|
||||
else
|
||||
{
|
||||
vcopy = [CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:aView]];
|
||||
}
|
||||
|
||||
[views addObject:vcopy];
|
||||
}];
|
||||
|
||||
[copy setTemplateViews:views];
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
+ (id)_operatorsForAttributeType:(CPAttributeType)attributeType
|
||||
@@ -680,7 +710,10 @@ CPTransformableAttributeType = 1800;
|
||||
view = [[CPCheckBox alloc] initWithFrame:CGRectMake(0, 0, 50, 26)];
|
||||
}
|
||||
else if (attributeType == CPDateAttributeType)
|
||||
view = [[CPDatePicker alloc] initWithFrame:CGRectMake(0, 0, 150, 26)];
|
||||
{
|
||||
view = [[CPDatePicker alloc] initWithFrame:CGRectMake(0, 0, 180, 26)];
|
||||
[view setDatePickerElements:CPYearMonthDayDatePickerElementFlag];
|
||||
}
|
||||
else
|
||||
return nil;
|
||||
|
||||
@@ -797,5 +830,31 @@ var CPPredicateTemplateTypeKey = @"CPPredicateTemplateType",
|
||||
[coder encodeObject:_views forKey:CPPredicateTemplateViewsKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// Copy support for built-in types
|
||||
@implementation CPDatePicker (CPCopying)
|
||||
|
||||
- (id)copy
|
||||
{
|
||||
var ret = [[[self class] alloc] initWithFrame:[self frame]];
|
||||
|
||||
[ret setTextFont:[self textFont]];
|
||||
[ret setMinDate:[self minDate]];
|
||||
[ret setMaxDate:[self maxDate]];
|
||||
[ret setTimeInterval:[self timeInterval]];
|
||||
[ret setDatePickerMode:[self datePickerMode]];
|
||||
[ret setDatePickerElements:[self datePickerElements]];
|
||||
[ret setDatePickerStyle:[self datePickerStyle]];
|
||||
[ret setLocale:[self locale]];
|
||||
[ret setDateValue:[self dateValue]];
|
||||
[ret setBackgroundColor:[self backgroundColor]];
|
||||
[ret setDrawsBackground:[self drawsBackground]];
|
||||
[ret setBordered:[self isBordered]];
|
||||
[ret _init];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@end
|
||||
/*! @endcond */
|
||||
|
||||
@@ -41,6 +41,21 @@
|
||||
@global CPCaseInsensitivePredicateOption
|
||||
@global CPOrPredicateType
|
||||
|
||||
@protocol CPRuleEditorDelegate <CPObject>
|
||||
|
||||
@required
|
||||
- (id)ruleEditor:(CPRuleEditor)editor child:(CPInteger)index forCriterion:(id)criterion withRowType:(CPRuleEditorRowType)rowType;
|
||||
- (id)ruleEditor:(CPRuleEditor)editor displayValueForCriterion:(id)criterion inRow:(CPInteger)row;
|
||||
- (CPInteger)ruleEditor:(CPRuleEditor)editor numberOfChildrenForCriterion:(id)criterion withRowType:(CPRuleEditorRowType)rowType;
|
||||
|
||||
@optional
|
||||
- (CPDictionary)ruleEditor:(CPRuleEditor)editor predicatePartsForCriterion:(id)criterion withDisplayValue:(id)value inRow:(CPInteger)row;
|
||||
- (void)ruleEditorRowsDidChange:(CPNotification)notification;
|
||||
|
||||
@end
|
||||
|
||||
var CPRuleEditorDelegate_ruleEditor_predicatePartsForCriterion_withDisplayValue_inRow_ = 1 << 1;
|
||||
|
||||
var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
||||
itemsContext = "items",
|
||||
valuesContext = "values",
|
||||
@@ -69,50 +84,51 @@ var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
||||
|
||||
@implementation CPRuleEditor : CPControl
|
||||
{
|
||||
BOOL _suppressKeyDownHandling;
|
||||
BOOL _allowsEmptyCompoundRows;
|
||||
BOOL _disallowEmpty;
|
||||
BOOL _delegateWantsValidation;
|
||||
BOOL _editable;
|
||||
BOOL _sendAction;
|
||||
BOOL _suppressKeyDownHandling;
|
||||
BOOL _allowsEmptyCompoundRows;
|
||||
BOOL _disallowEmpty;
|
||||
BOOL _delegateWantsValidation;
|
||||
BOOL _editable;
|
||||
BOOL _sendAction;
|
||||
|
||||
Class _rowClass;
|
||||
Class _rowClass;
|
||||
|
||||
CPIndexSet _draggingRows;
|
||||
CPInteger _subviewIndexOfDropLine;
|
||||
CPView _dropLineView;
|
||||
CPIndexSet _draggingRows;
|
||||
CPInteger _subviewIndexOfDropLine;
|
||||
CPView _dropLineView;
|
||||
|
||||
CPMutableArray _rowCache;
|
||||
CPMutableArray _slices;
|
||||
CPMutableArray _rowCache;
|
||||
CPMutableArray _slices;
|
||||
|
||||
CPPredicate _predicate;
|
||||
CPPredicate _predicate;
|
||||
|
||||
CPString _itemsKeyPath;
|
||||
CPString _subrowsArrayKeyPath;
|
||||
CPString _typeKeyPath;
|
||||
CPString _valuesKeyPath;
|
||||
CPString _boundArrayKeyPath @accessors(property=boundArrayKeyPath);
|
||||
CPString _itemsKeyPath;
|
||||
CPString _subrowsArrayKeyPath;
|
||||
CPString _typeKeyPath;
|
||||
CPString _valuesKeyPath;
|
||||
CPString _boundArrayKeyPath @accessors(property=boundArrayKeyPath);
|
||||
|
||||
CPView _slicesHolder;
|
||||
CPViewAnimation _currentAnimation;
|
||||
CPView _slicesHolder;
|
||||
CPViewAnimation _currentAnimation;
|
||||
|
||||
CPInteger _lastRow;
|
||||
CPInteger _nestingMode;
|
||||
CPInteger _lastRow;
|
||||
CPInteger _nestingMode;
|
||||
|
||||
float _alignmentGridWidth;
|
||||
float _sliceHeight;
|
||||
float _alignmentGridWidth;
|
||||
float _sliceHeight;
|
||||
|
||||
id _ruleDataSource;
|
||||
id _ruleDelegate;
|
||||
id _boundArrayOwner;
|
||||
id _ruleDataSource;
|
||||
id <CPRuleEditorDelegate> _ruleDelegate;
|
||||
id _boundArrayOwner;
|
||||
unsigned _implementedDelegateMethods;
|
||||
|
||||
CPString _stringsFilename;
|
||||
CPString _stringsFilename;
|
||||
|
||||
BOOL _isKeyDown;
|
||||
BOOL _nestingModeDidChange;
|
||||
BOOL _isKeyDown;
|
||||
BOOL _nestingModeDidChange;
|
||||
|
||||
_CPRuleEditorLocalizer _standardLocalizer @accessors(property=standardLocalizer);
|
||||
CPDictionary _itemsAndValuesToAddForRowType;
|
||||
_CPRuleEditorLocalizer _standardLocalizer @accessors(property=standardLocalizer);
|
||||
CPDictionary _itemsAndValuesToAddForRowType;
|
||||
}
|
||||
|
||||
/*! @cond */
|
||||
@@ -130,9 +146,11 @@ var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
||||
@"slice-top-border-color": [CPNull null],
|
||||
@"slice-bottom-border-color": [CPNull null],
|
||||
@"slice-last-bottom-border-color": [CPNull null],
|
||||
@"font": [CPNull null],
|
||||
@"font": [CPFont systemFontOfSize:12],
|
||||
@"font-color": [CPNull null],
|
||||
@"add-image": [CPNull null],
|
||||
@"remove-image": [CPNull null],
|
||||
@"vertical-alignment": [CPNull null]
|
||||
};
|
||||
}
|
||||
|
||||
@@ -143,7 +161,7 @@ var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
||||
{
|
||||
_slices = [[CPMutableArray alloc] init];
|
||||
|
||||
_sliceHeight = 26.;
|
||||
_sliceHeight = 26.0;
|
||||
_nestingMode = CPRuleEditorNestingModeSimple; // 10.5 default is CPRuleEditorNestingModeCompound
|
||||
_editable = YES;
|
||||
_allowsEmptyCompoundRows = NO;
|
||||
@@ -213,19 +231,24 @@ var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
|
||||
@discussion CPRuleEditor requires a delegate that implements the required delegate methods to function.
|
||||
@see delegate
|
||||
*/
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
- (void)setDelegate:(id <CPRuleEditorDelegate>)aDelegate
|
||||
{
|
||||
if (_ruleDelegate === aDelegate)
|
||||
return;
|
||||
|
||||
var nc = [CPNotificationCenter defaultCenter];
|
||||
|
||||
if (_ruleDelegate)
|
||||
[nc removeObserver:_ruleDelegate name:nil object:self];
|
||||
|
||||
_ruleDelegate = aDelegate;
|
||||
_implementedDelegateMethods = 0;
|
||||
|
||||
if ([_ruleDelegate respondsToSelector:@selector(ruleEditorRowsDidChange:)])
|
||||
[nc addObserver:_ruleDelegate selector:@selector(ruleEditorRowsDidChange:) name:CPRuleEditorRowsDidChangeNotification object:nil];
|
||||
|
||||
if ([_ruleDelegate respondsToSelector:@selector(ruleEditor:predicatePartsForCriterion:withDisplayValue:inRow:)])
|
||||
_implementedDelegateMethods |= CPRuleEditorDelegate_ruleEditor_predicatePartsForCriterion_withDisplayValue_inRow_;
|
||||
}
|
||||
/*!
|
||||
@brief Returns a Boolean value that indicates whether the receiver is editable.
|
||||
@@ -810,7 +833,7 @@ TODO: implement
|
||||
var item = [items objectAtIndex:i],
|
||||
//var displayValue = [self _queryValueForItem:item inRow:aRow]; Ask the delegate or get cached value ?.
|
||||
displayValue = [[self displayValuesForRow:aRow] objectAtIndex:i],
|
||||
predpart = [_ruleDelegate ruleEditor:self predicatePartsForCriterion:item withDisplayValue:displayValue inRow:aRow];
|
||||
predpart = [self _sendDelegateRuleEditorPredicatePartsForCriterion:item withDisplayValue:displayValue inRow:aRow];
|
||||
|
||||
if (predpart)
|
||||
[predicateParts addEntriesFromDictionary:predpart];
|
||||
@@ -1716,8 +1739,7 @@ TODO: implement
|
||||
{
|
||||
if (_delegateWantsValidation)
|
||||
{
|
||||
var selector = @selector(ruleEditor:predicatePartsForCriterion:withDisplayValue:inRow:);
|
||||
if (![_ruleDelegate respondsToSelector:selector])
|
||||
if (![self _delegateRespondsToRuleEditorPredicatePartsForCriterionWithDisplayValueInRow])
|
||||
return;
|
||||
|
||||
_delegateWantsValidation = NO;
|
||||
@@ -1865,14 +1887,34 @@ TODO: implement
|
||||
return [self valueForThemeAttribute:@"font"];
|
||||
}
|
||||
|
||||
- (CPImage)_addImage
|
||||
- (CPColor)_fontColor
|
||||
{
|
||||
return [self valueForThemeAttribute:@"add-image"];
|
||||
return [self valueForThemeAttribute:@"font-color"];
|
||||
}
|
||||
|
||||
- (CPImage)_removeImage
|
||||
- (CPImage)_imageAdd
|
||||
{
|
||||
return [self valueForThemeAttribute:@"remove-image"];
|
||||
return [self valueForThemeAttribute:@"add-image" inState:CPThemeStateNormal];
|
||||
}
|
||||
|
||||
- (CPImage)_imageAddHighlighted
|
||||
{
|
||||
return [self valueForThemeAttribute:@"add-image" inState:CPThemeStateHighlighted];
|
||||
}
|
||||
|
||||
- (CPImage)_imageRemove
|
||||
{
|
||||
return [self valueForThemeAttribute:@"remove-image" inState:CPThemeStateNormal];
|
||||
}
|
||||
|
||||
- (CPImage)_imageRemoveHighlighted
|
||||
{
|
||||
return [self valueForThemeAttribute:@"remove-image" inState:CPThemeStateHighlighted];
|
||||
}
|
||||
|
||||
- (CPVerticalTextAlignment)_verticalAlignment
|
||||
{
|
||||
return [self valueForThemeAttribute:@"vertical-alignment"];
|
||||
}
|
||||
|
||||
- (CPString)_toolTipForAddCompoundRowButton
|
||||
@@ -2079,7 +2121,7 @@ TODO: implement
|
||||
return;
|
||||
|
||||
var point = [self convertPoint:[event locationInWindow] fromView:nil],
|
||||
view = [_slices objectAtIndex:FLOOR(point.y / _sliceHeight)];
|
||||
view = [_slices objectAtIndex:FLOOR(MAX(0, point.y) / _sliceHeight)];
|
||||
|
||||
if ([self _dragShouldBeginFromMouseDown:view])
|
||||
[self _performDragForSlice:view withEvent:event];
|
||||
@@ -2165,7 +2207,7 @@ TODO: implement
|
||||
indexOfDropLine = FLOOR(y / _sliceHeight),
|
||||
numberOfRows = [self numberOfRows];
|
||||
|
||||
if (indexOfDropLine < 0 || indexOfDropLine > numberOfRows || (indexOfDropLine >= [_draggingRows firstIndex] && indexOfDropLine <= [_draggingRows lastIndex] + 1))
|
||||
if (indexOfDropLine <= 0 || indexOfDropLine > numberOfRows || (indexOfDropLine >= [_draggingRows firstIndex] && indexOfDropLine <= [_draggingRows lastIndex] + 1))
|
||||
{
|
||||
if (_subviewIndexOfDropLine !== CPNotFound && indexOfDropLine !== _subviewIndexOfDropLine)
|
||||
[self _clearDropLine];
|
||||
@@ -2377,6 +2419,33 @@ TODO: implement
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation CPRuleEditor (CPRuleEditorDelegate)
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Check if the delegate responds to ruleEditor:predicatePartsForCriterion:withDisplayValue:inRow:
|
||||
*/
|
||||
- (BOOL)_delegateRespondsToRuleEditorPredicatePartsForCriterionWithDisplayValueInRow
|
||||
{
|
||||
return _implementedDelegateMethods & CPRuleEditorDelegate_ruleEditor_predicatePartsForCriterion_withDisplayValue_inRow_;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate ruleEditor:predicatePartsForCriterion:withDisplayValue:inRow:
|
||||
*/
|
||||
- (CPDictionary)_sendDelegateRuleEditorPredicatePartsForCriterion:(id)criterion withDisplayValue:(id)value inRow:(CPInteger)row
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPRuleEditorDelegate_ruleEditor_predicatePartsForCriterion_withDisplayValue_inRow_))
|
||||
return @{};
|
||||
|
||||
return [_ruleDelegate ruleEditor:self predicatePartsForCriterion:criterion withDisplayValue:value inRow:row];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPRuleEditorAlignmentGridWidthKey = @"CPRuleEditorAlignmentGridWidth",
|
||||
CPRuleEditorSliceHeightKey = @"CPRuleEditorSliceHeight",
|
||||
CPRuleEditorStringsFilenameKey = @"CPRuleEditorStringsFilename",
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
CPRuleEditorPredicateLeftExpression = "CPRuleEditorPredicateLeftExpression";
|
||||
CPRuleEditorPredicateRightExpression = "CPRuleEditorPredicateRightExpression";
|
||||
CPRuleEditorPredicateComparisonModifier = "CPRuleEditorPredicateComparisonModifier";
|
||||
@@ -36,5 +37,6 @@ CPRuleEditorNestingModeList = 1; // Allows a single list, with no nes
|
||||
CPRuleEditorNestingModeCompound = 2; // Unlimited nesting and compound rows; this is the default
|
||||
CPRuleEditorNestingModeSimple = 3; // One compound row at the top with subrows beneath it, and no further nesting allowed
|
||||
|
||||
@typedef CPRuleEditorRowType
|
||||
CPRuleEditorRowTypeSimple = 0;
|
||||
CPRuleEditorRowTypeCompound = 1;
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
@class CPPredicateEditorRowTemplate
|
||||
|
||||
@implementation _CPPredicateEditorTree : CPObject
|
||||
{
|
||||
CPPredicateEditorRowTemplate template @accessors;
|
||||
|
||||
@@ -1,203 +0,0 @@
|
||||
/*
|
||||
* Created by cacaodev@gmail.com.
|
||||
* Copyright (c) 2011 Pear, Inc. All rights reserved.
|
||||
*
|
||||
* 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 "CPBezierPath.j"
|
||||
@import "CPPopUpButton.j"
|
||||
|
||||
@class _CPRuleEditorViewSlice
|
||||
|
||||
var GRADIENT_START_COLOR = "#fcfcfc",
|
||||
GRADIENT_END_COLOR = "#dfdfdf",
|
||||
BORDER_COLOR = "#BDBDBD";
|
||||
|
||||
var GRADIENT_NORMAL,
|
||||
GRADIENT_HIGHLIGHTED,
|
||||
GRADIENT_PROPERTY;
|
||||
|
||||
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
|
||||
{
|
||||
GRADIENT_NORMAL = "-webkit-gradient(linear, left top, left bottom, from(" + GRADIENT_START_COLOR + "), to(" + GRADIENT_END_COLOR + "))",
|
||||
GRADIENT_HIGHLIGHTED = "-webkit-gradient(linear, left top, left bottom, from(" + GRADIENT_END_COLOR + "), to(" + GRADIENT_START_COLOR + "))";
|
||||
GRADIENT_PROPERTY = "background";
|
||||
}
|
||||
else if (CPBrowserIsEngine(CPGeckoBrowserEngine))
|
||||
{
|
||||
GRADIENT_NORMAL = "-moz-linear-gradient(top, " + GRADIENT_START_COLOR + ", " + GRADIENT_END_COLOR + ")",
|
||||
GRADIENT_HIGHLIGHTED = "-moz-linear-gradient(top, " + GRADIENT_END_COLOR + ", " + GRADIENT_START_COLOR + ")";
|
||||
GRADIENT_PROPERTY = "background";
|
||||
}
|
||||
else if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
{
|
||||
GRADIENT_NORMAL = "progid:DXImageTransform.Microsoft.gradient(startColorstr='" + GRADIENT_START_COLOR + "', endColorstr='" + GRADIENT_END_COLOR + "')";
|
||||
GRADIENT_HIGHLIGHTED = "progid:DXImageTransform.Microsoft.gradient(startColorstr='" + GRADIENT_END_COLOR + "', endColorstr='" + GRADIENT_START_COLOR + "')";
|
||||
GRADIENT_PROPERTY = "filter";
|
||||
}else
|
||||
{
|
||||
GRADIENT_NORMAL = GRADIENT_START_COLOR;
|
||||
GRADIENT_HIGHLIGHTED = GRADIENT_END_COLOR;
|
||||
GRADIENT_PROPERTY = "background";
|
||||
}
|
||||
|
||||
@implementation _CPRuleEditorPopUpButton : CPPopUpButton
|
||||
{
|
||||
CPInteger radius;
|
||||
}
|
||||
|
||||
- (void)_sharedInit
|
||||
{
|
||||
[self setBordered:NO];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
var style = _DOMElement.style;
|
||||
style.border = "1px solid " + BORDER_COLOR;
|
||||
style[GRADIENT_PROPERTY] = GRADIENT_NORMAL;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
[self _sharedInit];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
[self _sharedInit];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPView)hitTest:(CGPoint)point
|
||||
{
|
||||
if (!CGRectContainsPoint([self frame], point) || ![self sliceIsEditable])
|
||||
return nil;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)sliceIsEditable
|
||||
{
|
||||
var superview = [self superview];
|
||||
return ![superview isKindOfClass:[_CPRuleEditorViewSlice]] || [superview isEditable];
|
||||
}
|
||||
|
||||
- (void)trackMouse:(CPEvent)theEvent
|
||||
{
|
||||
if (![self sliceIsEditable])
|
||||
return;
|
||||
|
||||
[super trackMouse:theEvent];
|
||||
}
|
||||
|
||||
- (CGRect)contentRectForBounds:(CGRect)bounds
|
||||
{
|
||||
var contentRect = [super contentRectForBounds:bounds];
|
||||
contentRect.origin.x += radius;
|
||||
contentRect.size.width -= 2 * radius;
|
||||
|
||||
return contentRect;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
radius = FLOOR(CGRectGetHeight([self bounds]) / 2);
|
||||
var style = _DOMElement.style,
|
||||
radiusCSS = radius + "px";
|
||||
|
||||
style.borderRadius = radiusCSS;
|
||||
#endif
|
||||
|
||||
[super layoutSubviews];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
bounds = [self bounds],
|
||||
arrow_width = FLOOR(CGRectGetHeight(bounds) / 3.5);
|
||||
|
||||
CGContextTranslateCTM(context, CGRectGetWidth(bounds) - radius - arrow_width, CGRectGetHeight(bounds) / 2);
|
||||
|
||||
var arrowsPath = [CPBezierPath bezierPath];
|
||||
[arrowsPath moveToPoint:CGPointMake(0, 1)];
|
||||
[arrowsPath lineToPoint:CGPointMake(arrow_width, 1)];
|
||||
[arrowsPath lineToPoint:CGPointMake(arrow_width / 2, arrow_width + 1)];
|
||||
[arrowsPath closePath];
|
||||
|
||||
CGContextSetFillColor(context, [CPColor colorWithWhite:101 / 255 alpha:1]);
|
||||
[arrowsPath fill];
|
||||
|
||||
CGContextScaleCTM(context, 1 , -1);
|
||||
[arrowsPath fill];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPRuleEditorButton : CPButton
|
||||
{
|
||||
CPInteger radius;
|
||||
}
|
||||
|
||||
- (void)_sharedInit
|
||||
{
|
||||
[self setBordered:NO];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
var style = _DOMElement.style;
|
||||
style.border = "1px solid " + BORDER_COLOR;
|
||||
style[GRADIENT_PROPERTY] = GRADIENT_NORMAL;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
[self _sharedInit];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
[self _sharedInit];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
radius = FLOOR(CGRectGetHeight([self bounds]) / 2);
|
||||
|
||||
var style = _DOMElement.style,
|
||||
radiusCSS = radius + "px";
|
||||
|
||||
style.borderRadius = radiusCSS;
|
||||
style[GRADIENT_PROPERTY] = ([self isHighlighted]) ? GRADIENT_HIGHLIGHTED : GRADIENT_NORMAL;
|
||||
#endif
|
||||
|
||||
[super layoutSubviews];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
@import "CPView.j"
|
||||
|
||||
@class CPRuleEditor
|
||||
|
||||
@implementation _CPRuleEditorViewSlice : CPView
|
||||
{
|
||||
CPRuleEditor _ruleEditor;
|
||||
@@ -27,7 +29,6 @@
|
||||
CGRect _animationTargetRect @accessors(property=_animationTargetRect);
|
||||
BOOL _selected @accessors(getter=_isSelected, setter=_setSelected:);
|
||||
BOOL _lastSelected @accessors(getter=_isLastSelected, setter=_setLastSelected:);
|
||||
CPColor _backgroundColor @accessors(property=backgroundColor);
|
||||
BOOL _editable @accessors(getter=isEditable, setter=setEditable:);
|
||||
}
|
||||
|
||||
@@ -61,9 +62,9 @@
|
||||
- (void)drawRect:(CGRect)rect
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
bounds = [self bounds],
|
||||
maxX = CGRectGetWidth(bounds),
|
||||
maxY = CGRectGetHeight(bounds);
|
||||
bounds = [self bounds],
|
||||
maxX = CGRectGetWidth(bounds),
|
||||
maxY = CGRectGetHeight(bounds);
|
||||
|
||||
// Draw background
|
||||
if ([self _isSelected])
|
||||
|
||||
@@ -19,24 +19,27 @@
|
||||
|
||||
@import "CPRuleEditor_Constants.j"
|
||||
@import "_CPRuleEditorViewSlice.j"
|
||||
@import "_CPRuleEditorPopUpButton.j"
|
||||
|
||||
@import "CPButton.j"
|
||||
@import "CPDatePicker.j"
|
||||
@import "CPPopUpButton.j"
|
||||
|
||||
@global CPApp
|
||||
|
||||
var CONTROL_HEIGHT = 16.,
|
||||
BUTTON_HEIGHT = 16.;
|
||||
@global CPMiniControlSize
|
||||
@global CPSmallControlSize
|
||||
|
||||
@implementation _CPRuleEditorViewSliceRow : _CPRuleEditorViewSlice
|
||||
{
|
||||
CPMutableArray _ruleOptionViews;
|
||||
CPMutableArray _ruleOptionFrames;
|
||||
CPMutableArray _correspondingRuleItems;
|
||||
CPMutableArray _ruleOptionInitialViewFrames;
|
||||
CPButton _addButton;
|
||||
CPButton _subtractButton;
|
||||
CPButton _addButton;
|
||||
CPButton _subtractButton;
|
||||
CPMutableArray _correspondingRuleItems;
|
||||
CPMutableArray _ruleOptionFrames;
|
||||
CPMutableArray _ruleOptionInitialViewFrames;
|
||||
CPMutableArray _ruleOptionViews;
|
||||
|
||||
CPRuleEditorRowType _rowType @accessors;
|
||||
CPRuleEditorRowType _plusButtonRowType;
|
||||
|
||||
CPRuleEditorRowType _rowType @accessors;
|
||||
CPRuleEditorRowType _plusButtonRowType;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame ruleEditorView:(id)editor
|
||||
@@ -49,34 +52,33 @@ var CONTROL_HEIGHT = 16.,
|
||||
|
||||
- (void)_initShared
|
||||
{
|
||||
_correspondingRuleItems = [[CPMutableArray alloc] init];
|
||||
_ruleOptionFrames = [[CPMutableArray alloc] init];
|
||||
_ruleOptionInitialViewFrames = [[CPMutableArray alloc] init];
|
||||
_ruleOptionViews = [[CPMutableArray alloc] init];
|
||||
_editable = [_ruleEditor isEditable];
|
||||
_correspondingRuleItems = [[CPMutableArray alloc] init];
|
||||
_ruleOptionFrames = [[CPMutableArray alloc] init];
|
||||
_ruleOptionInitialViewFrames = [[CPMutableArray alloc] init];
|
||||
_ruleOptionViews = [[CPMutableArray alloc] init];
|
||||
_editable = [_ruleEditor isEditable];
|
||||
|
||||
_addButton = [self _createAddRowButton];
|
||||
_subtractButton = [self _createDeleteRowButton];
|
||||
|
||||
_addButton = [self _createAddRowButton];
|
||||
_subtractButton = [self _createDeleteRowButton];
|
||||
[_addButton setToolTip:[_ruleEditor _toolTipForAddSimpleRowButton]];
|
||||
[_subtractButton setToolTip:[_ruleEditor _toolTipForDeleteRowButton]];
|
||||
[_addButton setHidden:!_editable];
|
||||
[_subtractButton setHidden:!_editable];
|
||||
[self addSubview:_addButton];
|
||||
[self addSubview:_subtractButton];
|
||||
|
||||
[self setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
var center = [CPNotificationCenter defaultCenter];
|
||||
[center addObserver:self selector:@selector(_textDidChange:) name:CPControlTextDidChangeNotification object:nil];
|
||||
}
|
||||
|
||||
- (CPButton)_createRowButton
|
||||
{
|
||||
var button = [[_CPRuleEditorButton alloc] initWithFrame:CGRectMakeZero()];
|
||||
[button setFont:[CPFont boldFontWithName:@"Apple Symbol" size:12.0]];
|
||||
[button setTextColor:[CPColor colorWithWhite:150 / 255 alpha:1]];
|
||||
var button = [[CPButton alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[button setFont:[_ruleEditor font]];
|
||||
[button setTextColor:[_ruleEditor _fontColor]];
|
||||
|
||||
[button setAlignment:CPCenterTextAlignment];
|
||||
[button setAutoresizingMask:CPViewMinXMargin];
|
||||
[button setButtonType:CPMomentaryChangeButton];
|
||||
[button setBordered:NO];
|
||||
[button setHidden:!_editable];
|
||||
[button setImagePosition:CPImageOnly];
|
||||
|
||||
return button;
|
||||
@@ -86,7 +88,10 @@ var CONTROL_HEIGHT = 16.,
|
||||
{
|
||||
var button = [self _createRowButton];
|
||||
|
||||
[button setImage:[_ruleEditor _addImage]];
|
||||
[button setToolTip:[_ruleEditor _toolTipForAddSimpleRowButton]];
|
||||
[button setValue:[_ruleEditor _imageAdd] forThemeAttribute:@"image" inState:CPThemeStateNormal];
|
||||
[button setValue:[_ruleEditor _imageAddHighlighted] forThemeAttribute:@"image" inState:CPThemeStateHighlighted];
|
||||
|
||||
[button setAction:@selector(_addOption:)];
|
||||
[button setTarget:self];
|
||||
|
||||
@@ -97,7 +102,10 @@ var CONTROL_HEIGHT = 16.,
|
||||
{
|
||||
var button = [self _createRowButton];
|
||||
|
||||
[button setImage:[_ruleEditor _removeImage]];
|
||||
[button setToolTip:[_ruleEditor _toolTipForDeleteRowButton]];
|
||||
[button setValue:[_ruleEditor _imageRemove] forThemeAttribute:@"image" inState:CPThemeStateNormal];
|
||||
[button setValue:[_ruleEditor _imageRemoveHighlighted] forThemeAttribute:@"image" inState:CPThemeStateHighlighted];
|
||||
|
||||
[button setAction:@selector(_deleteOption:)];
|
||||
[button setTarget:self];
|
||||
|
||||
@@ -107,20 +115,17 @@ var CONTROL_HEIGHT = 16.,
|
||||
- (CPMenuItem)_createMenuItemWithTitle:(CPString )title
|
||||
{
|
||||
title = [[_ruleEditor standardLocalizer] localizedStringForString:title];
|
||||
var mItem = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
|
||||
return mItem;
|
||||
return [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
|
||||
}
|
||||
|
||||
- (CPPopUpButton)_createPopUpButtonWithItems:(CPArray)itemsArray selectedItemIndex:(int)index
|
||||
{
|
||||
var title = [[itemsArray objectAtIndex:index] title],
|
||||
font = [_ruleEditor font],
|
||||
width = [title sizeWithFont:font].width + 20,
|
||||
rect = CGRectMake(0, 0, (width - width % 40) + 80, CONTROL_HEIGHT),
|
||||
var title = [[itemsArray objectAtIndex:index] title],
|
||||
font = [_ruleEditor font],
|
||||
width = [title sizeWithFont:font].width + 35, // 35 for right arrows + margins
|
||||
rect = CGRectMake(0, 0, width, [_ruleEditor rowHeight]),
|
||||
popup = [[CPPopUpButton alloc] initWithFrame:rect];
|
||||
|
||||
popup = [[_CPRuleEditorPopUpButton alloc] initWithFrame:rect];
|
||||
|
||||
[popup setTextColor:[CPColor colorWithWhite:101 / 255 alpha:1]];
|
||||
[popup setValue:font forThemeAttribute:@"font"];
|
||||
|
||||
var count = [itemsArray count];
|
||||
@@ -137,17 +142,17 @@ var CONTROL_HEIGHT = 16.,
|
||||
return [CPMenuItem separatorItem];
|
||||
}
|
||||
|
||||
- (_CPRuleEditorTextField)_createStaticTextFieldWithStringValue:(CPString)text
|
||||
- (CPTextField)_createStaticTextFieldWithStringValue:(CPString)text
|
||||
{
|
||||
var textField = [[_CPRuleEditorTextField alloc] initWithFrame:CGRectMakeZero()],
|
||||
ruleEditorFont = [_ruleEditor font],
|
||||
font = [CPFont fontWithName:[ruleEditorFont familyName] size:[ruleEditorFont size] + 2],
|
||||
localizedText = [[_ruleEditor standardLocalizer] localizedStringForString:text],
|
||||
size = [localizedText sizeWithFont:font];
|
||||
|
||||
[textField setFrameSize:CGSizeMake(size.width + 4, CONTROL_HEIGHT + 2)];
|
||||
var textField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()],
|
||||
ruleEditorFont = [_ruleEditor font],
|
||||
font = [CPFont fontWithName:[ruleEditorFont familyName] size:[ruleEditorFont size] + 2],
|
||||
localizedText = [[_ruleEditor standardLocalizer] localizedStringForString:text],
|
||||
size = [localizedText sizeWithFont:font];
|
||||
|
||||
[textField setFrameSize:CGSizeMake(size.width + 4, [_ruleEditor rowHeight])];
|
||||
[textField setValue:font forThemeAttribute:@"font"];
|
||||
[textField setValue:[_ruleEditor _verticalAlignment] forThemeAttribute:@"vertical-alignment"];
|
||||
[textField setStringValue:localizedText];
|
||||
|
||||
return textField;
|
||||
@@ -159,6 +164,7 @@ var CONTROL_HEIGHT = 16.,
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
var type = _plusButtonRowType;
|
||||
|
||||
if ([_ruleEditor nestingMode] == CPRuleEditorNestingModeCompound && ([[CPApp currentEvent] modifierFlags] & CPAlternateKeyMask))
|
||||
type = CPRuleEditorRowTypeCompound;
|
||||
|
||||
@@ -170,12 +176,12 @@ var CONTROL_HEIGHT = 16.,
|
||||
[_ruleEditor _deleteSlice:self];
|
||||
}
|
||||
|
||||
- (void)_ruleOptionPopupChangedAction:(CPMenuItem )sender
|
||||
- (void)_ruleOptionPopupChangedAction:(CPMenuItem)sender
|
||||
{
|
||||
var layoutdict = [sender representedObject],
|
||||
newItem = [layoutdict objectForKey:@"item"],
|
||||
var layoutdict = [sender representedObject],
|
||||
newItem = [layoutdict objectForKey:@"item"],
|
||||
indexInCriteria = [layoutdict objectForKey:@"indexInCriteria"],
|
||||
oldItem = [_correspondingRuleItems objectAtIndex:indexInCriteria];
|
||||
oldItem = [_correspondingRuleItems objectAtIndex:indexInCriteria];
|
||||
|
||||
if (![newItem isEqual:oldItem])
|
||||
{
|
||||
@@ -203,8 +209,7 @@ var CONTROL_HEIGHT = 16.,
|
||||
|
||||
- (void)_reconfigureSubviews
|
||||
{
|
||||
var ruleItems,
|
||||
criteria,
|
||||
var criteria,
|
||||
repObject,
|
||||
menuItem,
|
||||
ruleView,
|
||||
@@ -307,8 +312,16 @@ var CONTROL_HEIGHT = 16.,
|
||||
|
||||
if (ruleView != nil)
|
||||
{
|
||||
[ruleView setControlSize:CPSmallControlSize];
|
||||
|
||||
var minSize = [ruleView currentValueForThemeAttribute:@"min-size"],
|
||||
frame = [ruleView frame];
|
||||
|
||||
// Force controls to their minimum size
|
||||
frame.size.height = minSize.height;
|
||||
[ruleView setFrame:frame];
|
||||
|
||||
[_ruleOptionViews addObject:ruleView];
|
||||
var frame = [ruleView frame];
|
||||
[_ruleOptionInitialViewFrames addObject:frame];
|
||||
[_ruleOptionFrames addObject:frame];
|
||||
|
||||
@@ -331,8 +344,6 @@ var CONTROL_HEIGHT = 16.,
|
||||
var aView = [_ruleOptionViews objectAtIndex:firstResponderIndex];
|
||||
[[self window] makeFirstResponder:aView]; // This is not working. bug in CPPopUpButton firstResponder ?
|
||||
}
|
||||
|
||||
//[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)_updateEnabledStateForSubviews
|
||||
@@ -350,14 +361,16 @@ var CONTROL_HEIGHT = 16.,
|
||||
var optionViewOriginX,
|
||||
leftHorizontalPadding,
|
||||
leftButtonMinX,
|
||||
rowHeight = [_ruleEditor rowHeight],
|
||||
count = [_ruleOptionViews count],
|
||||
sliceFrame = [self frame],
|
||||
rowHeight = [_ruleEditor rowHeight],
|
||||
count = [_ruleOptionViews count],
|
||||
sliceFrame = [self frame],
|
||||
image = [_ruleEditor _imageAdd],
|
||||
imageSize = image ? [image size] : CGSizeMake(0,0),
|
||||
|
||||
buttonFrame = CGRectMake(CGRectGetWidth(sliceFrame) - BUTTON_HEIGHT - [self _rowButtonsRightHorizontalPadding], ([_ruleEditor rowHeight] - BUTTON_HEIGHT) / 2 - 2, BUTTON_HEIGHT, BUTTON_HEIGHT);
|
||||
buttonFrame = CGRectMake(CGRectGetWidth(sliceFrame) - imageSize.width - [self _rowButtonsRightHorizontalPadding], ([_ruleEditor rowHeight] - imageSize.height) / 2 - 1, imageSize.width, imageSize.height);
|
||||
|
||||
[_addButton setFrame:buttonFrame];
|
||||
buttonFrame.origin.x -= BUTTON_HEIGHT + [self _rowButtonsInterviewHorizontalPadding];
|
||||
buttonFrame.origin.x -= imageSize.width + [self _rowButtonsInterviewHorizontalPadding];
|
||||
[_subtractButton setFrame:buttonFrame];
|
||||
|
||||
if (widthChanged)
|
||||
@@ -372,7 +385,8 @@ var CONTROL_HEIGHT = 16.,
|
||||
var ruleOptionView = _ruleOptionViews[i],
|
||||
optionFrame = _ruleOptionFrames[i];
|
||||
|
||||
optionFrame.origin.y = (rowHeight - CGRectGetHeight(optionFrame)) / 2 - 2;
|
||||
// Use a pixel correction to align controls
|
||||
optionFrame.origin.y = (rowHeight - CGRectGetHeight(optionFrame)) / 2;
|
||||
|
||||
if (widthChanged)
|
||||
{
|
||||
@@ -481,6 +495,26 @@ var CONTROL_HEIGHT = 16.,
|
||||
[self layoutSubviews];
|
||||
}
|
||||
|
||||
- (void)_addObservers
|
||||
{
|
||||
if (_isObserving)
|
||||
return;
|
||||
|
||||
[super _addObservers];
|
||||
|
||||
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_textDidChange:) name:CPControlTextDidChangeNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)_removeObservers
|
||||
{
|
||||
if (!_isObserving)
|
||||
return;
|
||||
|
||||
[super _removeObservers];
|
||||
|
||||
[[CPNotificationCenter defaultCenter] removeObserver:self name:CPControlTextDidChangeNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)rect
|
||||
{
|
||||
[super drawRect:rect];
|
||||
@@ -488,8 +522,9 @@ var CONTROL_HEIGHT = 16.,
|
||||
|
||||
- (BOOL)_isRulePopup:(CPView)view
|
||||
{
|
||||
if ([view isKindOfClass:[_CPRuleEditorPopUpButton class]])
|
||||
if ([view isKindOfClass:[CPPopUpButton class]])
|
||||
return YES;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@@ -506,28 +541,3 @@ var CONTROL_HEIGHT = 16.,
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPRuleEditorTextField : CPTextField
|
||||
{
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self)
|
||||
{
|
||||
[self setDrawsBackground:NO];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPView)hitTest:(CGPoint)point
|
||||
{
|
||||
if (!CGRectContainsPoint([self frame], point))
|
||||
return nil;
|
||||
|
||||
return [self superview];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -35,6 +35,11 @@
|
||||
CPArray _allowedFileTypes @accessors(property=allowedFileTypes);
|
||||
}
|
||||
|
||||
+ (CPURL)proposedFileURLWithDocumentName:(CPString)aDocumentName
|
||||
{
|
||||
return [CPURL URLWithString:aDocumentName];
|
||||
}
|
||||
|
||||
+ (id)savePanel
|
||||
{
|
||||
return [[CPSavePanel alloc] init];
|
||||
|
||||
+86
-38
@@ -33,6 +33,15 @@
|
||||
#define SHOULD_SHOW_CORNER_VIEW() (_scrollerStyle === CPScrollerStyleLegacy && _verticalScroller && ![_verticalScroller isHidden])
|
||||
|
||||
|
||||
@protocol CPScrollViewDelegate <CPObject>
|
||||
|
||||
@optional
|
||||
- (void)scrollViewWillScroll:(CPScrollView)aScrollView;
|
||||
- (void)scrollViewDidScroll:(CPScrollView)aScrollView;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/*! @ignore */
|
||||
var _isBrowserUsingOverlayScrollers = function()
|
||||
{
|
||||
@@ -77,15 +86,6 @@ var _isBrowserUsingOverlayScrollers = function()
|
||||
#endif
|
||||
};
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPScrollView
|
||||
|
||||
Used to display views that are too large for the viewing area. the CPScrollView
|
||||
places scroll bars on the side of the view to allow the user to scroll and see the entire
|
||||
contents of the view.
|
||||
*/
|
||||
|
||||
var TIMER_INTERVAL = 0.2,
|
||||
CPScrollViewDelegate_scrollViewWillScroll_ = 1 << 0,
|
||||
CPScrollViewDelegate_scrollViewDidScroll_ = 1 << 1,
|
||||
@@ -95,38 +95,45 @@ var TIMER_INTERVAL = 0.2,
|
||||
var CPScrollerStyleGlobal = CPScrollerStyleOverlay,
|
||||
CPScrollerStyleGlobalChangeNotification = @"CPScrollerStyleGlobalChangeNotification";
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPScrollView
|
||||
|
||||
Used to display views that are too large for the viewing area. the CPScrollView
|
||||
places scroll bars on the side of the view to allow the user to scroll and see the entire
|
||||
contents of the view.
|
||||
*/
|
||||
@implementation CPScrollView : CPView
|
||||
{
|
||||
CPClipView _contentView;
|
||||
CPClipView _headerClipView;
|
||||
CPView _cornerView;
|
||||
CPView _bottomCornerView;
|
||||
CPClipView _contentView;
|
||||
CPClipView _headerClipView;
|
||||
CPView _cornerView;
|
||||
CPView _bottomCornerView;
|
||||
|
||||
id _delegate;
|
||||
CPTimer _scrollTimer;
|
||||
id <CPScrollViewDelegate> _delegate;
|
||||
CPTimer _scrollTimer;
|
||||
|
||||
BOOL _hasVerticalScroller;
|
||||
BOOL _hasHorizontalScroller;
|
||||
BOOL _autohidesScrollers;
|
||||
BOOL _hasVerticalScroller;
|
||||
BOOL _hasHorizontalScroller;
|
||||
BOOL _autohidesScrollers;
|
||||
|
||||
CPScroller _verticalScroller;
|
||||
CPScroller _horizontalScroller;
|
||||
CPScroller _verticalScroller;
|
||||
CPScroller _horizontalScroller;
|
||||
|
||||
CPInteger _recursionCount;
|
||||
CPInteger _implementedDelegateMethods;
|
||||
CPInteger _recursionCount;
|
||||
CPInteger _implementedDelegateMethods;
|
||||
|
||||
float _verticalLineScroll;
|
||||
float _verticalPageScroll;
|
||||
float _horizontalLineScroll;
|
||||
float _horizontalPageScroll;
|
||||
float _verticalLineScroll;
|
||||
float _verticalPageScroll;
|
||||
float _horizontalLineScroll;
|
||||
float _horizontalPageScroll;
|
||||
|
||||
CPBorderType _borderType;
|
||||
CPBorderType _borderType;
|
||||
|
||||
CPTimer _timerScrollersHide;
|
||||
CPTimer _timerScrollersHide;
|
||||
|
||||
int _scrollerStyle;
|
||||
int _scrollerKnobStyle;
|
||||
int _scrollerStyle;
|
||||
int _scrollerKnobStyle;
|
||||
}
|
||||
|
||||
|
||||
@@ -264,11 +271,6 @@ var CPScrollerStyleGlobal = CPScrollerStyleOverlay,
|
||||
_delegate = nil;
|
||||
_scrollTimer = nil;
|
||||
_implementedDelegateMethods = 0;
|
||||
|
||||
[[CPNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(_didReceiveDefaultStyleChange:)
|
||||
name:CPScrollerStyleGlobalChangeNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -301,7 +303,7 @@ Notifies the delegate when the scroll view has finished scrolling.
|
||||
@endcode
|
||||
|
||||
*/
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
- (void)setDelegate:(id <CPScrollViewDelegate>)aDelegate
|
||||
{
|
||||
if (aDelegate === _delegate)
|
||||
return;
|
||||
@@ -1251,7 +1253,7 @@ Notifies the delegate when the scroll view has finished scrolling.
|
||||
}
|
||||
|
||||
if (_timerScrollersHide)
|
||||
[_timerScrollersHide invalidate]
|
||||
[_timerScrollersHide invalidate];
|
||||
|
||||
_timerScrollersHide = [CPTimer scheduledTimerWithTimeInterval:CPScrollViewFadeOutTime target:self selector:@selector(_hideScrollers:) userInfo:nil repeats:NO];
|
||||
}
|
||||
@@ -1262,10 +1264,45 @@ Notifies the delegate when the scroll view has finished scrolling.
|
||||
[self reflectScrolledClipView:_contentView];
|
||||
}
|
||||
|
||||
- (CGRect)documentVisibleRect
|
||||
{
|
||||
return [_contentView documentVisibleRect];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Overrides
|
||||
|
||||
|
||||
- (void)_removeObservers
|
||||
{
|
||||
if (!_isObserving)
|
||||
return;
|
||||
|
||||
[[CPNotificationCenter defaultCenter] removeObserver:self
|
||||
name:CPScrollerStyleGlobalChangeNotification
|
||||
object:nil];
|
||||
|
||||
[super _removeObservers];
|
||||
}
|
||||
|
||||
- (void)_addObservers
|
||||
{
|
||||
if (_isObserving)
|
||||
return;
|
||||
|
||||
//Make sure to have the last global style for the scroller
|
||||
[self _didReceiveDefaultStyleChange:nil];
|
||||
|
||||
[[CPNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(_didReceiveDefaultStyleChange:)
|
||||
name:CPScrollerStyleGlobalChangeNotification
|
||||
object:nil];
|
||||
|
||||
[super _addObservers];
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
[super drawRect:aRect];
|
||||
@@ -1399,7 +1436,16 @@ Notifies the delegate when the scroll view has finished scrolling.
|
||||
if (![_horizontalScroller isHidden] || ![_verticalScroller isHidden])
|
||||
_timerScrollersHide = [CPTimer scheduledTimerWithTimeInterval:CPScrollViewFadeOutTime target:self selector:@selector(_hideScrollers:) userInfo:nil repeats:NO];
|
||||
|
||||
[self _respondToScrollWheelEventWithDeltaX:[anEvent deltaX] deltaY:[anEvent deltaY]];
|
||||
var deltaX = [anEvent scrollingDeltaX],
|
||||
deltaY = [anEvent scrollingDeltaY];
|
||||
|
||||
if (![anEvent hasPreciseScrollingDeltas])
|
||||
{
|
||||
deltaX *= (_horizontalLineScroll || 1.0);
|
||||
deltaY *= (_verticalLineScroll || 1.0);
|
||||
}
|
||||
|
||||
[self _respondToScrollWheelEventWithDeltaX:deltaX deltaY:deltaY];
|
||||
}
|
||||
|
||||
- (void)scrollPageUp:(id)sender
|
||||
@@ -1536,6 +1582,8 @@ var CPScrollViewContentViewKey = @"CPScrollViewContentView",
|
||||
*/
|
||||
- (void)awakeFromCib
|
||||
{
|
||||
[super awakeFromCib];
|
||||
|
||||
[self _updateScrollerStyle];
|
||||
[self _updateCornerAndHeaderView];
|
||||
}
|
||||
|
||||
+20
-47
@@ -33,6 +33,7 @@
|
||||
@global CPApp
|
||||
|
||||
// CPScroller Constants
|
||||
@typedef CPScrollerPart
|
||||
CPScrollerNoPart = 0;
|
||||
CPScrollerDecrementPage = 1;
|
||||
CPScrollerKnob = 2;
|
||||
@@ -44,15 +45,11 @@ CPScrollerKnobSlot = 6;
|
||||
CPScrollerIncrementArrow = 0;
|
||||
CPScrollerDecrementArrow = 1;
|
||||
|
||||
@typedef CPUsableScrollerParts
|
||||
CPNoScrollerParts = 0;
|
||||
CPOnlyScrollerArrows = 1;
|
||||
CPAllScrollerParts = 2;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPScroller
|
||||
*/
|
||||
|
||||
var PARTS_ARRANGEMENT = [CPScrollerKnobSlot, CPScrollerDecrementLine, CPScrollerIncrementLine, CPScrollerKnob],
|
||||
NAMES_FOR_PARTS = {},
|
||||
PARTS_FOR_NAMES = {};
|
||||
@@ -76,9 +73,13 @@ CPThemeStateScrollViewLegacy = CPThemeState("scroller-style-legacy");
|
||||
CPThemeStateScrollerKnobLight = CPThemeState("scroller-knob-light");
|
||||
CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPScroller
|
||||
*/
|
||||
|
||||
@implementation CPScroller : CPControl
|
||||
{
|
||||
CPControlSize _controlSize;
|
||||
CPUsableScrollerParts _usableParts;
|
||||
CPArray _partRects;
|
||||
|
||||
@@ -172,7 +173,6 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
_controlSize = CPRegularControlSize;
|
||||
_partRects = [];
|
||||
|
||||
[self setFloatValue:0.0];
|
||||
@@ -243,29 +243,6 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
[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
|
||||
*/
|
||||
- (void)setControlSize:(CPControlSize)aControlSize
|
||||
{
|
||||
if (_controlSize == aControlSize)
|
||||
return;
|
||||
|
||||
_controlSize = aControlSize;
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
Return's the knob's proportion
|
||||
*/
|
||||
@@ -339,7 +316,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
// 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])
|
||||
if (![self hasThemeState:CPThemeStateSelected] && ![self hasThemeState:CPThemeStateScrollViewLegacy])
|
||||
return CPScrollerNoPart;
|
||||
|
||||
if (CGRectContainsPoint([self rectForPart:CPScrollerKnob], aPoint))
|
||||
@@ -403,9 +380,10 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
effectiveIncrementLineHeight = incrementLineSize.height + trackInset.bottom,
|
||||
slotSize = height - effectiveDecrementLineHeight - effectiveIncrementLineHeight,
|
||||
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
|
||||
knobVerticalInset = knobInset.top + knobInset.bottom,
|
||||
knobWidth = width - knobInset.left - knobInset.right,
|
||||
knobHeight = MAX(minimumKnobLength, (slotSize * _knobProportion)),
|
||||
knobLocation = effectiveDecrementLineHeight + (slotSize - knobHeight) * [self floatValue];
|
||||
knobHeight = MAX(minimumKnobLength, ((slotSize - knobVerticalInset) * _knobProportion)),
|
||||
knobLocation = effectiveDecrementLineHeight + (slotSize - knobHeight - knobVerticalInset) * [self floatValue] + knobInset.top;
|
||||
|
||||
_partRects[CPScrollerDecrementPage] = CGRectMake(0.0, effectiveDecrementLineHeight, width, knobLocation - effectiveDecrementLineHeight);
|
||||
_partRects[CPScrollerKnob] = CGRectMake(knobInset.left, knobLocation, knobWidth, knobHeight);
|
||||
@@ -432,9 +410,10 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
effectiveIncrementLineWidth = incrementLineSize.width + trackInset.right,
|
||||
slotSize = width - effectiveDecrementLineWidth - effectiveIncrementLineWidth,
|
||||
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
|
||||
knobWidth = MAX(minimumKnobLength, (slotSize * _knobProportion)),
|
||||
knobHorizontalInset = knobInset.left + knobInset.right,
|
||||
knobWidth = MAX(minimumKnobLength, ((slotSize - knobHorizontalInset) * _knobProportion)),
|
||||
knobHeight = height - knobInset.top - knobInset.bottom,
|
||||
knobLocation = effectiveDecrementLineWidth + (slotSize - knobWidth) * [self floatValue];
|
||||
knobLocation = effectiveDecrementLineWidth + (slotSize - knobWidth - knobHorizontalInset) * [self floatValue] + knobInset.left;
|
||||
|
||||
_partRects[CPScrollerDecrementPage] = CGRectMake(effectiveDecrementLineWidth, 0.0, knobLocation - effectiveDecrementLineWidth, height);
|
||||
_partRects[CPScrollerKnob] = CGRectMake(knobLocation, knobInset.top, knobWidth, knobHeight);
|
||||
@@ -483,9 +462,6 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
*/
|
||||
- (void)fadeOut
|
||||
{
|
||||
if ([self hasThemeState:CPThemeStateScrollViewLegacy])
|
||||
return;
|
||||
|
||||
[_animationScroller startAnimation];
|
||||
}
|
||||
|
||||
@@ -733,7 +709,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
var themeState = _themeState;
|
||||
|
||||
if (NAMES_FOR_PARTS[_hitPart] + "-color" !== anAttributeName)
|
||||
themeState &= ~CPThemeStateHighlighted;
|
||||
themeState = themeState.without(CPThemeStateHighlighted);
|
||||
|
||||
return [self valueForThemeAttribute:anAttributeName inState:themeState];
|
||||
}
|
||||
@@ -788,7 +764,10 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
if (_timerFadeOut)
|
||||
[_timerFadeOut invalidate];
|
||||
|
||||
_timerFadeOut = [CPTimer scheduledTimerWithTimeInterval:1.2 target:self selector:@selector(_performFadeOut:) userInfo:nil repeats:NO];
|
||||
if ([self hasThemeState:CPThemeStateScrollViewLegacy])
|
||||
[self unsetThemeState:CPThemeStateSelected];
|
||||
else
|
||||
_timerFadeOut = [CPTimer scheduledTimerWithTimeInterval:1.2 target:self selector:@selector(_performFadeOut:) userInfo:nil repeats:NO];
|
||||
}
|
||||
|
||||
|
||||
@@ -802,8 +781,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
|
||||
|
||||
@end
|
||||
|
||||
var CPScrollerControlSizeKey = @"CPScrollerControlSize",
|
||||
CPScrollerIsVerticalKey = @"CPScrollerIsVerticalKey",
|
||||
var CPScrollerIsVerticalKey = @"CPScrollerIsVerticalKey",
|
||||
CPScrollerKnobProportionKey = @"CPScrollerKnobProportion",
|
||||
CPScrollerStyleKey = @"CPScrollerStyleKey";
|
||||
|
||||
@@ -813,10 +791,6 @@ var CPScrollerControlSizeKey = @"CPScrollerControlSize",
|
||||
{
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
{
|
||||
_controlSize = CPRegularControlSize;
|
||||
if ([aCoder containsValueForKey:CPScrollerControlSizeKey])
|
||||
_controlSize = [aCoder decodeIntForKey:CPScrollerControlSizeKey];
|
||||
|
||||
_knobProportion = 1.0;
|
||||
|
||||
if ([aCoder containsValueForKey:CPScrollerKnobProportionKey])
|
||||
@@ -851,7 +825,6 @@ var CPScrollerControlSizeKey = @"CPScrollerControlSize",
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeInt:_controlSize forKey:CPScrollerControlSizeKey];
|
||||
[aCoder encodeInt:_isVertical forKey:CPScrollerIsVerticalKey];
|
||||
[aCoder encodeFloat:_knobProportion forKey:CPScrollerKnobProportionKey];
|
||||
[aCoder encodeInt:_style forKey:CPScrollerStyleKey];
|
||||
|
||||
+168
-49
@@ -36,8 +36,6 @@ CPSearchFieldNoRecentsMenuItemTag = 1003;
|
||||
|
||||
var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotification";
|
||||
|
||||
var RECENT_SEARCH_PREFIX = @" ";
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPSearchField
|
||||
@@ -73,10 +71,21 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
@"image-search": [CPNull null],
|
||||
@"image-find": [CPNull null],
|
||||
@"image-cancel": [CPNull null],
|
||||
@"image-cancel-pressed": [CPNull null]
|
||||
@"image-cancel-pressed": [CPNull null],
|
||||
@"image-search-inset" : CGInsetMake(0, 0, 0, 5),
|
||||
@"image-cancel-inset" : CGInsetMake(0, 5, 0, 0),
|
||||
@"search-right-margin": 2
|
||||
};
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding === CPPredicateBinding)
|
||||
return [_CPSearchFieldPredicateBinder class];
|
||||
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame])
|
||||
@@ -87,10 +96,6 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
_recentsAutosaveName = nil;
|
||||
|
||||
[self _init];
|
||||
#if PLATFORM(DOM)
|
||||
_cancelButton._DOMElement.style.cursor = "default";
|
||||
_searchButton._DOMElement.style.cursor = "default";
|
||||
#endif
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -119,16 +124,28 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
_canResignFirstResponder = YES;
|
||||
}
|
||||
|
||||
- (void)viewWillMoveToSuperview:(CPView)aView
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Override observers
|
||||
|
||||
- (void)_removeObservers
|
||||
{
|
||||
[super viewWillMoveToSuperview:aView];
|
||||
if (!_isObserving)
|
||||
return;
|
||||
|
||||
[super _removeObservers];
|
||||
|
||||
// First we remove any observer that may have been in place to avoid memory leakage.
|
||||
[[CPNotificationCenter defaultCenter] removeObserver:self name:CPControlTextDidChangeNotification object:self];
|
||||
}
|
||||
|
||||
// Register the observe here if we need to.
|
||||
if (aView)
|
||||
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_searchFieldTextDidChange:) name:CPControlTextDidChangeNotification object:self];
|
||||
- (void)_addObservers
|
||||
{
|
||||
if (_isObserving)
|
||||
return;
|
||||
|
||||
[super _addObservers];
|
||||
|
||||
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_searchFieldTextDidChange:) name:CPControlTextDidChangeNotification object:self];
|
||||
}
|
||||
|
||||
// Managing Buttons
|
||||
@@ -165,7 +182,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
- (void)resetSearchButton
|
||||
{
|
||||
var button = [self searchButton],
|
||||
searchButtonImage = (_searchMenuTemplate === nil) ? [self valueForThemeAttribute:@"image-search"] : [self valueForThemeAttribute:@"image-find"];
|
||||
searchButtonImage = (_searchMenuTemplate === nil) ? [self currentValueForThemeAttribute:@"image-search"] : [self currentValueForThemeAttribute:@"image-find"];
|
||||
|
||||
[button setBordered:NO];
|
||||
[button setImageScaling:CPImageScaleAxesIndependently];
|
||||
@@ -234,8 +251,9 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
|
||||
if (_searchButton)
|
||||
{
|
||||
var searchBounds = [self searchButtonRectForBounds:bounds];
|
||||
leftOffset = CGRectGetMaxX(searchBounds) + 2;
|
||||
var searchBounds = [self searchButtonRectForBounds:bounds],
|
||||
rightMargin = [self currentValueForThemeAttribute:@"search-right-margin"];
|
||||
leftOffset = CGRectGetMaxX(searchBounds) + rightMargin;
|
||||
}
|
||||
|
||||
if (_cancelButton)
|
||||
@@ -254,9 +272,10 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
*/
|
||||
- (CGRect)searchButtonRectForBounds:(CGRect)rect
|
||||
{
|
||||
var size = [[self valueForThemeAttribute:@"image-search"] size] || CGSizeMakeZero();
|
||||
var size = [[self currentValueForThemeAttribute:@"image-search"] size] || CGSizeMakeZero(),
|
||||
inset = [self currentValueForThemeAttribute:@"image-search-inset"];
|
||||
|
||||
return CGRectMake(5, (CGRectGetHeight(rect) - size.height) / 2, size.width, size.height);
|
||||
return CGRectMake(inset.left - inset.right, inset.top - inset.bottom + (CGRectGetHeight(rect) - size.height) / 2, size.width, size.height);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -266,9 +285,10 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
*/
|
||||
- (CGRect)cancelButtonRectForBounds:(CGRect)rect
|
||||
{
|
||||
var size = [[self valueForThemeAttribute:@"image-cancel"] size] || CGSizeMakeZero();
|
||||
var size = [[self currentValueForThemeAttribute:@"image-cancel"] size] || CGSizeMakeZero(),
|
||||
inset = [self currentValueForThemeAttribute:@"image-cancel-inset"];
|
||||
|
||||
return CGRectMake(CGRectGetWidth(rect) - size.width - 5, (CGRectGetHeight(rect) - size.width) / 2, size.height, size.height);
|
||||
return CGRectMake(CGRectGetWidth(rect) - size.width + inset.left - inset.right, inset.top - inset.bottom + (CGRectGetHeight(rect) - size.width) / 2, size.height, size.height);
|
||||
}
|
||||
|
||||
// Managing Menu Templates
|
||||
@@ -372,9 +392,9 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
*/
|
||||
- (void)setRecentSearches:(CPArray)searches
|
||||
{
|
||||
var max = MIN([self maximumRecents], [searches count]),
|
||||
searches = [searches subarrayWithRange:CPMakeRange(0, max)];
|
||||
var max = MIN([self maximumRecents], [searches count]);
|
||||
|
||||
searches = [searches subarrayWithRange:CPMakeRange(0, max)];
|
||||
_recentSearches = searches;
|
||||
[self _autosaveRecentSearchList];
|
||||
}
|
||||
@@ -517,19 +537,16 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
}
|
||||
|
||||
/*!
|
||||
Provides the common case items for a recent searches menu. If there are not recent searches,
|
||||
displays a single disabled item:
|
||||
|
||||
No Recent Searches
|
||||
Provides the common case items for a recent searches menu.
|
||||
|
||||
If there are 1 more recent searches, it displays:
|
||||
|
||||
Recent Searches
|
||||
recent search 1
|
||||
recent search 2
|
||||
etc.
|
||||
Clear
|
||||
---------------------
|
||||
Clear Recent Searches
|
||||
Recent Searches
|
||||
recent search 1
|
||||
recent search 2
|
||||
etc.
|
||||
|
||||
If you wish to add items before or after the template, you can. If you put items
|
||||
before, a separator will automatically be placed before the default template item.
|
||||
@@ -554,6 +571,13 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
var template = [[CPMenu alloc] init],
|
||||
item;
|
||||
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"Clear"
|
||||
action:@selector(_searchFieldClearRecents:)
|
||||
keyEquivalent:@""];
|
||||
[item setTag:CPSearchFieldClearRecentsMenuItemTag];
|
||||
[item setTarget:self];
|
||||
[template addItem:item];
|
||||
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"Recent Searches"
|
||||
action:nil
|
||||
keyEquivalent:@""];
|
||||
@@ -568,20 +592,6 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
[item setTarget:self];
|
||||
[template addItem:item];
|
||||
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"Clear Recent Searches"
|
||||
action:@selector(_searchFieldClearRecents:)
|
||||
keyEquivalent:@""];
|
||||
[item setTag:CPSearchFieldClearRecentsMenuItemTag];
|
||||
[item setTarget:self];
|
||||
[template addItem:item];
|
||||
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"No Recent Searches"
|
||||
action:nil
|
||||
keyEquivalent:@""];
|
||||
[item setTag:CPSearchFieldNoRecentsMenuItemTag];
|
||||
[item setEnabled:NO];
|
||||
[template addItem:item];
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
@@ -594,6 +604,8 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
countOfRecents = [_recentSearches count],
|
||||
numberOfItems = [_searchMenuTemplate numberOfItems];
|
||||
|
||||
[menu setAutoenablesItems:NO];
|
||||
|
||||
for (var i = 0; i < numberOfItems; i++)
|
||||
{
|
||||
var item = [[_searchMenuTemplate itemAtIndex:i] copy];
|
||||
@@ -614,8 +626,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
|
||||
for (var recentIndex = 0; recentIndex < countOfRecents; ++recentIndex)
|
||||
{
|
||||
// RECENT_SEARCH_PREFIX is a hack until CPMenuItem -setIndentationLevel works
|
||||
var recentItem = [[CPMenuItem alloc] initWithTitle:RECENT_SEARCH_PREFIX + [_recentSearches objectAtIndex:recentIndex]
|
||||
var recentItem = [[CPMenuItem alloc] initWithTitle:[_recentSearches objectAtIndex:recentIndex]
|
||||
action:itemAction
|
||||
keyEquivalent:[item keyEquivalent]];
|
||||
[item setTarget:self];
|
||||
@@ -675,7 +686,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
|
||||
- (void)_showMenu
|
||||
{
|
||||
if (_searchMenu === nil || [_searchMenu numberOfItems] === 0 || ![self isEnabled])
|
||||
if (_searchMenu === nil || [_searchMenu numberOfItems] === 0 || ![self isEnabled] || ([_recentSearches count] === 0))
|
||||
return;
|
||||
|
||||
var aFrame = [[self superview] convertRect:[self frame] toView:nil],
|
||||
@@ -703,7 +714,7 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
|
||||
- (void)_searchFieldSearch:(id)sender
|
||||
{
|
||||
var searchString = [[sender title] substringFromIndex:[RECENT_SEARCH_PREFIX length]];
|
||||
var searchString = [sender title];
|
||||
|
||||
if ([sender tag] != CPSearchFieldRecentsMenuItemTag)
|
||||
[self _addStringToRecentSearches:searchString];
|
||||
@@ -757,8 +768,75 @@ var RECENT_SEARCH_PREFIX = @" ";
|
||||
_recentSearches = list;
|
||||
}
|
||||
|
||||
- (void)unbind:(CPString)aBinding
|
||||
{
|
||||
[super unbind:aBinding];
|
||||
|
||||
// our CPPredicateBinding binder adds a binding to the value.
|
||||
// this private binding has to be also removed
|
||||
if (aBinding === CPPredicateBinding)
|
||||
[[[self class] _binderClassForBinding:aBinding] unbind:CPValueBinding forObject:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation CPSearchField (CPTrackingArea)
|
||||
{
|
||||
CPTrackingArea _searchButtonTrackingArea;
|
||||
CPTrackingArea _cancelButtonTrackingArea;
|
||||
}
|
||||
|
||||
- (void)updateTrackingAreas
|
||||
{
|
||||
if (_searchButtonTrackingArea)
|
||||
{
|
||||
[self removeTrackingArea:_searchButtonTrackingArea];
|
||||
_searchButtonTrackingArea = nil;
|
||||
}
|
||||
|
||||
if (_cancelButtonTrackingArea)
|
||||
{
|
||||
[self removeTrackingArea:_cancelButtonTrackingArea];
|
||||
_cancelButtonTrackingArea = nil;
|
||||
}
|
||||
|
||||
if (_searchButton)
|
||||
{
|
||||
_searchButtonTrackingArea = [[CPTrackingArea alloc] initWithRect:[_searchButton frame]
|
||||
options:CPTrackingCursorUpdate | CPTrackingActiveInKeyWindow
|
||||
owner:self
|
||||
userInfo:@{ @"isButton": YES }];
|
||||
|
||||
[self addTrackingArea:_searchButtonTrackingArea];
|
||||
}
|
||||
|
||||
if (_cancelButton)
|
||||
{
|
||||
_cancelButtonTrackingArea = [[CPTrackingArea alloc] initWithRect:[_cancelButton frame]
|
||||
options:CPTrackingCursorUpdate | CPTrackingActiveInKeyWindow
|
||||
owner:self
|
||||
userInfo:@{ @"isButton": YES }];
|
||||
|
||||
[self addTrackingArea:_cancelButtonTrackingArea];
|
||||
}
|
||||
|
||||
[super updateTrackingAreas];
|
||||
}
|
||||
|
||||
- (void)cursorUpdate:(CPEvent)anEvent
|
||||
{
|
||||
if ([[[anEvent trackingArea] userInfo] objectForKey:@"isButton"])
|
||||
[[CPCursor arrowCursor] set];
|
||||
else
|
||||
[super cursorUpdate:anEvent];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
|
||||
CPSendsWholeSearchStringKey = @"CPSendsWholeSearchStringKey",
|
||||
CPSendsSearchStringImmediatelyKey = @"CPSendsSearchStringImmediatelyKey",
|
||||
@@ -811,3 +889,44 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPSearchFieldPredicateBinder : CPBinder
|
||||
{
|
||||
CPArrayController _controller;
|
||||
CPString _predicateFormat;
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding === CPPredicateBinding)
|
||||
{
|
||||
var options = [_info objectForKey:CPOptionsKey];
|
||||
|
||||
_controller = [_info objectForKey:CPObservedObjectKey];
|
||||
_predicateFormat = [options objectForKey:"CPPredicateFormat"];
|
||||
[_source bind:CPValueBinding toObject:self withKeyPath:"searchFieldValue" options:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setSearchFieldValue:(CPString)aValue
|
||||
{
|
||||
var destination = [_info objectForKey:CPObservedObjectKey],
|
||||
keyPath = [_info objectForKey:CPObservedKeyPathKey];
|
||||
|
||||
var formatString = _predicateFormat.replace(/\$value/g, "%@");
|
||||
[self suppressSpecificNotificationFromObject:destination keyPath:keyPath];
|
||||
|
||||
if (aValue)
|
||||
[_controller setFilterPredicate:[CPPredicate predicateWithFormat:formatString, aValue]];
|
||||
else
|
||||
[_controller setFilterPredicate:nil];
|
||||
|
||||
[self unsuppressSpecificNotificationFromObject:destination keyPath:keyPath];
|
||||
}
|
||||
- (CPString)searchFieldValue
|
||||
{
|
||||
return [_source stringValue];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
+355
-247
@@ -25,9 +25,11 @@
|
||||
@import "CPControl.j"
|
||||
@import "CPWindow_Constants.j"
|
||||
@import "_CPImageAndTextView.j"
|
||||
@import "CPMenu.j"
|
||||
|
||||
@global CPApp
|
||||
|
||||
@typedef CPSegmentSwitchTracking
|
||||
CPSegmentSwitchTrackingSelectOne = 0;
|
||||
CPSegmentSwitchTrackingSelectAny = 1;
|
||||
CPSegmentSwitchTrackingMomentary = 2;
|
||||
@@ -40,7 +42,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
@implementation CPSegmentedControl : CPControl
|
||||
{
|
||||
CPArray _segments;
|
||||
CPArray _segments @accessors(getter=segments);
|
||||
CPArray _themeStates;
|
||||
|
||||
int _selectedSegment;
|
||||
@@ -70,23 +72,9 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
@"center-segment-bezel-color": [CPNull null],
|
||||
@"divider-bezel-color": [CPNull null],
|
||||
@"divider-thickness": 1.0,
|
||||
@"default-height": 24.0,
|
||||
};
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if ([self _isSelectionBinding:aBinding])
|
||||
return [_CPSegmentedControlBinder class];
|
||||
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
+ (BOOL)_isSelectionBinding:(CPString)aBinding
|
||||
{
|
||||
return (aBinding === CPSelectedIndexBinding || aBinding === CPSelectedLabelBinding || aBinding === CPSelectedTagBinding);
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aRect
|
||||
{
|
||||
_segments = [];
|
||||
@@ -99,22 +87,21 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
_selectedSegment = -1;
|
||||
|
||||
_trackingMode = CPSegmentSwitchTrackingSelectOne;
|
||||
_trackingHighlighted = NO;
|
||||
_trackingSegment = -1;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options
|
||||
/*!
|
||||
Sets the control's size.
|
||||
@param aControlSize the control's size
|
||||
*/
|
||||
- (void)setControlSize:(CPControlSize)aControlSize
|
||||
{
|
||||
if ([[self class] _isSelectionBinding:aBinding] && _trackingMode !== CPSegmentSwitchTrackingSelectOne)
|
||||
CPLog.warn("Binding " + aBinding + " needs CPSegmentSwitchTrackingSelectOne tracking mode");
|
||||
else
|
||||
[super bind:aBinding toObject:anObject withKeyPath:aKeyPath options:options];
|
||||
}
|
||||
|
||||
- (void)_reverseSetBinding
|
||||
{
|
||||
[_CPSegmentedControlBinder reverseSetValueForObject:self];
|
||||
[super setControlSize:aControlSize];
|
||||
[self _sizeToControlSize];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -122,7 +109,54 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (int)selectedTag
|
||||
{
|
||||
return [_segments[_selectedSegment] tag];
|
||||
return [[_segments objectAtIndex:_selectedSegment] tag];
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (void)setSegments:(CPArray)segments
|
||||
{
|
||||
[self removeSegmentsAtIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self segmentCount])]];
|
||||
|
||||
[self insertSegments:segments atIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [segments count])]];
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (void)insertSegments:(CPArray)segments atIndexes:(CPIndexSet)indices
|
||||
{
|
||||
if ([segments count] == 0)
|
||||
return;
|
||||
|
||||
var newStates = @[],
|
||||
count = [indices count];
|
||||
|
||||
while (count--)
|
||||
[newStates addObject:CPThemeStateNormal];
|
||||
|
||||
[_segments insertObjects:segments atIndexes:indices];
|
||||
[_themeStates insertObjects:newStates atIndexes:indices];
|
||||
|
||||
if (_selectedSegment >= [indices firstIndex])
|
||||
_selectedSegment += [indices count];
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (void)removeSegmentsAtIndexes:(CPIndexSet)indices
|
||||
{
|
||||
if ([indices count] == 0)
|
||||
return;
|
||||
|
||||
[indices enumerateIndexesUsingBlock:function(idx, stop)
|
||||
{
|
||||
[[_segments objectAtIndex:idx] setSelected:NO];
|
||||
}];
|
||||
|
||||
if ([indices containsIndex:_selectedSegment])
|
||||
_selectedSegment = -1;
|
||||
else if ([indices lastIndex] < _selectedSegment)
|
||||
_selectedSegment -= [indices count];
|
||||
|
||||
[_segments removeObjectsAtIndexes:indices];
|
||||
[_themeStates removeObjectsAtIndexes:indices];
|
||||
}
|
||||
|
||||
// Specifying the number of segments
|
||||
@@ -132,41 +166,32 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setSegmentCount:(unsigned)aCount
|
||||
{
|
||||
if (_segments.length == aCount)
|
||||
var prevCount = [_segments count];
|
||||
|
||||
if (aCount == prevCount)
|
||||
return;
|
||||
|
||||
var height = CGRectGetHeight([self bounds]),
|
||||
dividersBefore = MAX(0, _segments.length - 1),
|
||||
dividersAfter = MAX(0, aCount - 1);
|
||||
|
||||
if (_segments.length < aCount)
|
||||
if (aCount > prevCount)
|
||||
{
|
||||
for (var index = _segments.length; index < aCount; ++index)
|
||||
{
|
||||
_segments[index] = [[_CPSegmentItem alloc] init];
|
||||
_themeStates[index] = CPThemeStateNormal;
|
||||
}
|
||||
}
|
||||
else if (aCount < _segments.length)
|
||||
{
|
||||
_segments.length = aCount;
|
||||
_themeStates.length = aCount;
|
||||
}
|
||||
var count = aCount - prevCount,
|
||||
segments = @[];
|
||||
|
||||
if (_selectedSegment >= _segments.length)
|
||||
while (count--)
|
||||
[segments addObject:[[_CPSegmentItem alloc] init]];
|
||||
|
||||
[self insertSegments:segments atIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(prevCount, aCount - prevCount)]];
|
||||
}
|
||||
else
|
||||
[self removeSegmentsAtIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(aCount, prevCount - aCount)]];
|
||||
|
||||
[self _updateSelectionIfNeeded];
|
||||
[self tileWithChangedSegment:MAX(MIN(prevCount, aCount) - 1, 0)];
|
||||
}
|
||||
|
||||
- (void)_updateSelectionIfNeeded
|
||||
{
|
||||
if (_selectedSegment >= [self segmentCount])
|
||||
_selectedSegment = -1;
|
||||
|
||||
var thickness = [self currentValueForThemeAttribute:@"divider-thickness"],
|
||||
frame = [self frame],
|
||||
widthOfAllSegments = 0,
|
||||
dividerExtraSpace = ([_segments count] - 1) * thickness;
|
||||
|
||||
for (var i = 0; i < [_segments count]; i++)
|
||||
widthOfAllSegments += [_segments[i] width];
|
||||
|
||||
[self setFrameSize:CGSizeMake(widthOfAllSegments + dividerExtraSpace, frame.size.height)];
|
||||
|
||||
[self tileWithChangedSegment:0];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -174,7 +199,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (unsigned)segmentCount
|
||||
{
|
||||
return _segments.length;
|
||||
return [_segments count];
|
||||
}
|
||||
|
||||
// Specifying Selected Segment
|
||||
@@ -186,7 +211,20 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
- (void)setSelectedSegment:(unsigned)aSegment
|
||||
{
|
||||
// setSelected:forSegment throws the exception for us (if necessary)
|
||||
[self setSelected:YES forSegment:aSegment];
|
||||
if (_selectedSegment == aSegment)
|
||||
return;
|
||||
|
||||
if (aSegment == -1)
|
||||
{
|
||||
var count = [self segmentCount];
|
||||
|
||||
while (count--)
|
||||
[self setSelected:NO forSegment:count];
|
||||
|
||||
_selectedSegment = -1;
|
||||
}
|
||||
else
|
||||
[self setSelected:YES forSegment:aSegment];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -204,8 +242,8 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
{
|
||||
var index = 0;
|
||||
|
||||
for (; index < _segments.length; ++index)
|
||||
if (_segments[index].tag == aTag)
|
||||
for (; index < [_segments count]; ++index)
|
||||
if ([[_segments objectAtIndex:index] tag] == aTag)
|
||||
{
|
||||
[self setSelectedSegment:index];
|
||||
|
||||
@@ -219,8 +257,8 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
{
|
||||
var index = 0;
|
||||
|
||||
for (; index < _segments.length; ++index)
|
||||
if (_segments[index].label == aLabel)
|
||||
for (; index < [_segments count]; ++index)
|
||||
if ([[_segments objectAtIndex:index] label] == aLabel)
|
||||
{
|
||||
[self setSelectedSegment:index];
|
||||
|
||||
@@ -231,7 +269,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
}
|
||||
|
||||
// Specifying Tracking Mode
|
||||
|
||||
/*! @ignore */
|
||||
- (BOOL)isTracking
|
||||
{
|
||||
|
||||
@@ -249,7 +287,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
var index = 0,
|
||||
selected = NO;
|
||||
|
||||
for (; index < _segments.length; ++index)
|
||||
for (; index < [self segmentCount]; ++index)
|
||||
if ([_segments[index] selected])
|
||||
if (selected)
|
||||
[self setSelected:NO forSegment:index];
|
||||
@@ -261,7 +299,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
{
|
||||
var index = 0;
|
||||
|
||||
for (; index < _segments.length; ++index)
|
||||
for (; index < [self segmentCount]; ++index)
|
||||
if ([_segments[index] selected])
|
||||
[self setSelected:NO forSegment:index];
|
||||
}
|
||||
@@ -284,8 +322,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setWidth:(float)aWidth forSegment:(unsigned)aSegment
|
||||
{
|
||||
[_segments[aSegment] setWidth:aWidth];
|
||||
|
||||
[[_segments objectAtIndex:aSegment] setWidth:aWidth];
|
||||
[self tileWithChangedSegment:aSegment];
|
||||
}
|
||||
|
||||
@@ -296,7 +333,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (float)widthForSegment:(unsigned)aSegment
|
||||
{
|
||||
return [_segments[aSegment] width];
|
||||
return [[_segments objectAtIndex:aSegment] width];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -307,7 +344,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setImage:(CPImage)anImage forSegment:(unsigned)aSegment
|
||||
{
|
||||
[_segments[aSegment] setImage:anImage];
|
||||
[[_segments objectAtIndex:aSegment] setImage:anImage];
|
||||
|
||||
[self tileWithChangedSegment:aSegment];
|
||||
}
|
||||
@@ -319,7 +356,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (CPImage)imageForSegment:(unsigned)aSegment
|
||||
{
|
||||
return [_segments[aSegment] image];
|
||||
return [[_segments objectAtIndex:aSegment] image];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -330,7 +367,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setLabel:(CPString)aLabel forSegment:(unsigned)aSegment
|
||||
{
|
||||
[_segments[aSegment] setLabel:aLabel];
|
||||
[[_segments objectAtIndex:aSegment] setLabel:aLabel];
|
||||
|
||||
[self tileWithChangedSegment:aSegment];
|
||||
}
|
||||
@@ -342,7 +379,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (CPString)labelForSegment:(unsigned)aSegment
|
||||
{
|
||||
return [_segments[aSegment] label];
|
||||
return [[_segments objectAtIndex:aSegment] label];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -353,7 +390,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setMenu:(CPMenu)aMenu forSegment:(unsigned)aSegment
|
||||
{
|
||||
[_segments[aSegment] setMenu:aMenu];
|
||||
[[_segments objectAtIndex:aSegment] setMenu:aMenu];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -363,7 +400,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (CPMenu)menuForSegment:(unsigned)aSegment
|
||||
{
|
||||
return [_segments[aSegment] menu];
|
||||
return [[_segments objectAtIndex:aSegment] menu];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -375,7 +412,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setSelected:(BOOL)isSelected forSegment:(unsigned)aSegment
|
||||
{
|
||||
var segment = _segments[aSegment];
|
||||
var segment = [_segments objectAtIndex:aSegment];
|
||||
|
||||
// If we're already in this state, bail.
|
||||
if ([segment selected] == isSelected)
|
||||
@@ -392,7 +429,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
_selectedSegment = aSegment;
|
||||
|
||||
if (_trackingMode == CPSegmentSwitchTrackingSelectOne && oldSelectedSegment != aSegment && oldSelectedSegment != -1)
|
||||
if (_trackingMode == CPSegmentSwitchTrackingSelectOne && oldSelectedSegment != aSegment && oldSelectedSegment != -1 && oldSelectedSegment < _segments.length)
|
||||
{
|
||||
[_segments[oldSelectedSegment] setSelected:NO];
|
||||
_themeStates[oldSelectedSegment] = CPThemeStateNormal;
|
||||
@@ -415,7 +452,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (BOOL)isSelectedForSegment:(unsigned)aSegment
|
||||
{
|
||||
return [_segments[aSegment] selected];
|
||||
return [[_segments objectAtIndex:aSegment] selected];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -426,15 +463,17 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setEnabled:(BOOL)shouldBeEnabled forSegment:(unsigned)aSegment
|
||||
{
|
||||
if ([_segments[aSegment] enabled] === shouldBeEnabled)
|
||||
var segment = [_segments objectAtIndex:aSegment];
|
||||
|
||||
if ([segment enabled] === shouldBeEnabled)
|
||||
return;
|
||||
|
||||
[_segments[aSegment] setEnabled:shouldBeEnabled];
|
||||
[segment setEnabled:shouldBeEnabled];
|
||||
|
||||
if (shouldBeEnabled)
|
||||
_themeStates[aSegment] &= ~CPThemeStateDisabled;
|
||||
_themeStates[aSegment] = _themeStates[aSegment].without(CPThemeStateDisabled);
|
||||
else
|
||||
_themeStates[aSegment] |= CPThemeStateDisabled;
|
||||
_themeStates[aSegment] = _themeStates[aSegment].and(CPThemeStateDisabled);
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
@@ -447,7 +486,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (BOOL)isEnabledForSegment:(unsigned)aSegment
|
||||
{
|
||||
return [_segments[aSegment] enabled];
|
||||
return [[_segments objectAtIndex:aSegment] enabled];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -457,7 +496,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setTag:(int)aTag forSegment:(unsigned)aSegment
|
||||
{
|
||||
[_segments[aSegment] setTag:aTag];
|
||||
[[_segments objectAtIndex:aSegment] setTag:aTag];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -466,7 +505,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (int)tagForSegment:(unsigned)aSegment
|
||||
{
|
||||
return [_segments[aSegment] tag];
|
||||
return [[_segments objectAtIndex:aSegment] tag];
|
||||
}
|
||||
|
||||
// Drawings
|
||||
@@ -477,10 +516,13 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)drawSegmentBezel:(int)aSegment highlight:(BOOL)shouldHighlight
|
||||
{
|
||||
if (shouldHighlight)
|
||||
_themeStates[aSegment] |= CPThemeStateHighlighted;
|
||||
else
|
||||
_themeStates[aSegment] &= ~CPThemeStateHighlighted;
|
||||
if (aSegment < _themeStates.length)
|
||||
{
|
||||
if (shouldHighlight)
|
||||
_themeStates[aSegment] = _themeStates[aSegment].and(CPThemeStateHighlighted);
|
||||
else
|
||||
_themeStates[aSegment] = _themeStates[aSegment].without(CPThemeStateHighlighted);
|
||||
}
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
@@ -488,14 +530,12 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
- (float)_leftOffsetForSegment:(unsigned)segment
|
||||
{
|
||||
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
|
||||
|
||||
if (segment == 0)
|
||||
return bezelInset.left;
|
||||
return [self currentValueForThemeAttribute:@"bezel-inset"].left;
|
||||
|
||||
var thickness = [self currentValueForThemeAttribute:@"divider-thickness"];
|
||||
|
||||
return [self _leftOffsetForSegment:segment - 1] + [self widthForSegment:segment - 1] + thickness;
|
||||
return [self _leftOffsetForSegment:segment - 1] + CGRectGetWidth([self frameForSegment:segment - 1]) + thickness;
|
||||
}
|
||||
|
||||
- (unsigned)_indexOfLastSegment
|
||||
@@ -510,7 +550,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
var height = [self currentValueForThemeAttribute:@"default-height"],
|
||||
var height = [self currentValueForThemeAttribute:@"min-size"].height,
|
||||
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||
bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"],
|
||||
bounds = [self bounds];
|
||||
@@ -529,7 +569,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
else if (aName.indexOf("segment-bezel") === 0)
|
||||
{
|
||||
var segment = parseInt(aName.substring("segment-bezel-".length), 10),
|
||||
frame = CGRectCreateCopy([_segments[segment] frame]);
|
||||
frame = CGRectCreateCopy([self frameForSegment:segment]);
|
||||
|
||||
if (segment === 0)
|
||||
{
|
||||
@@ -537,7 +577,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
frame.size.width -= contentInset.left;
|
||||
}
|
||||
|
||||
if (segment === _segments.length - 1)
|
||||
if (segment === [self segmentCount] - 1)
|
||||
frame.size.width = CGRectGetWidth([self bounds]) - contentInset.right - frame.origin.x;
|
||||
|
||||
return frame;
|
||||
@@ -545,7 +585,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
else if (aName.indexOf("divider-bezel") === 0)
|
||||
{
|
||||
var segment = parseInt(aName.substring("divider-bezel-".length), 10),
|
||||
width = [self widthForSegment:segment],
|
||||
width = CGRectGetWidth([self frameForSegment:segment]),
|
||||
left = [self _leftOffsetForSegment:segment],
|
||||
thickness = [self currentValueForThemeAttribute:@"divider-thickness"];
|
||||
|
||||
@@ -564,19 +604,32 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
if ([aName hasPrefix:@"segment-content"])
|
||||
return [[_CPImageAndTextView alloc] initWithFrame:CGRectMakeZero()];
|
||||
{
|
||||
var view = [[_CPImageAndTextView alloc] initWithFrame:CGRectMakeZero()];
|
||||
[view _setUsesSingleLineMode:YES];
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
return [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
if (_segments.length <= 0)
|
||||
if ([self segmentCount] <= 0)
|
||||
return;
|
||||
|
||||
var themeState = _themeStates[0];
|
||||
var themeState = _themeStates[0],
|
||||
isDisabled = [self hasThemeState:CPThemeStateDisabled],
|
||||
isControlSizeSmall = [self hasThemeState:CPThemeStateControlSizeSmall],
|
||||
isControlSizeMini = [self hasThemeState:CPThemeStateControlSizeMini];
|
||||
|
||||
themeState |= _themeState & CPThemeStateDisabled;
|
||||
themeState = isDisabled ? themeState.and(CPThemeStateDisabled) : themeState;
|
||||
|
||||
if (isControlSizeSmall)
|
||||
themeState = themeState.and(CPThemeStateControlSizeSmall);
|
||||
else if (isControlSizeMini)
|
||||
themeState = themeState.and(CPThemeStateControlSizeMini);
|
||||
|
||||
var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
|
||||
inState:themeState],
|
||||
@@ -589,7 +642,12 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
var themeState = _themeStates[_themeStates.length - 1];
|
||||
|
||||
themeState |= _themeState & CPThemeStateDisabled;
|
||||
themeState = isDisabled ? themeState.and(CPThemeStateDisabled) : themeState;
|
||||
|
||||
if (isControlSizeSmall)
|
||||
themeState = themeState.and(CPThemeStateControlSizeSmall);
|
||||
else if (isControlSizeMini)
|
||||
themeState = themeState.and(CPThemeStateControlSizeMini);
|
||||
|
||||
var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color"
|
||||
inState:themeState],
|
||||
@@ -604,7 +662,12 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
{
|
||||
var themeState = _themeStates[i];
|
||||
|
||||
themeState |= _themeState & CPThemeStateDisabled;
|
||||
themeState = isDisabled ? themeState.and(CPThemeStateDisabled) : themeState;
|
||||
|
||||
if (isControlSizeSmall)
|
||||
themeState = themeState.and(CPThemeStateControlSizeSmall);
|
||||
else if (isControlSizeMini)
|
||||
themeState = themeState.and(CPThemeStateControlSizeMini);
|
||||
|
||||
var bezelColor = [self valueForThemeAttribute:@"center-segment-bezel-color"
|
||||
inState:themeState],
|
||||
@@ -615,7 +678,6 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
[bezelView setBackgroundColor:bezelColor];
|
||||
|
||||
|
||||
// layout image/title views
|
||||
var segment = _segments[i],
|
||||
contentView = [self layoutEphemeralSubviewNamed:@"segment-content-" + i
|
||||
@@ -642,11 +704,15 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
if (i == count - 1)
|
||||
continue;
|
||||
|
||||
var borderState = _themeStates[i] | _themeStates[i + 1];
|
||||
|
||||
borderState = (borderState & CPThemeStateSelected & ~CPThemeStateHighlighted) ? CPThemeStateSelected : CPThemeStateNormal;
|
||||
var borderState = _themeStates[i].and(_themeStates[i + 1]);
|
||||
|
||||
borderState |= _themeState & CPThemeStateDisabled;
|
||||
borderState = isDisabled ? borderState.and(CPThemeStateDisabled) : borderState;
|
||||
|
||||
if (isControlSizeSmall)
|
||||
borderState = borderState.and(CPThemeStateControlSizeSmall);
|
||||
else if (isControlSizeMini)
|
||||
borderState = borderState.and(CPThemeStateControlSizeMini);
|
||||
|
||||
var borderColor = [self valueForThemeAttribute:@"divider-bezel-color"
|
||||
inState:borderState],
|
||||
@@ -669,61 +735,33 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
{
|
||||
}
|
||||
|
||||
- (void)tileWithChangedSegment:(unsigned)aSegment
|
||||
/*! @ignore */
|
||||
- (void)tile
|
||||
{
|
||||
if (aSegment >= _segments.length)
|
||||
[self tileWithChangedSegment:0];
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (void)tileWithChangedSegment:(CPInteger)aSegment
|
||||
{
|
||||
var segmentCount = [self segmentCount];
|
||||
|
||||
// Corner case: when segmentCount == 0 and aSegment == 0, we do not return here because we still need to set the new frameSize bellow.
|
||||
if (aSegment < 0 || (segmentCount > 0 && aSegment >= segmentCount))
|
||||
return;
|
||||
|
||||
var segment = _segments[aSegment],
|
||||
segmentWidth = [segment width],
|
||||
themeState = _themeStates[aSegment] | (_themeState & CPThemeStateDisabled),
|
||||
contentInset = [self valueForThemeAttribute:@"content-inset" inState:themeState],
|
||||
font = [self font];
|
||||
var width = 0;
|
||||
|
||||
if (!segmentWidth)
|
||||
if (segmentCount > 0)
|
||||
{
|
||||
if ([segment image] && [segment label])
|
||||
segmentWidth = [[segment label] sizeWithFont:font].width + [[segment image] size].width + contentInset.left + contentInset.right;
|
||||
else if (segment.image)
|
||||
segmentWidth = [[segment image] size].width + contentInset.left + contentInset.right;
|
||||
else if (segment.label)
|
||||
segmentWidth = [[segment label] sizeWithFont:font].width + contentInset.left + contentInset.right;
|
||||
else
|
||||
segmentWidth = 0.0;
|
||||
// Invalidate frames for segments on the right. They will be lazily computed by -frameForSegment:.
|
||||
for (var i = aSegment; i < segmentCount; i++)
|
||||
[_segments[i] setFrame:CGRectMakeZero()];
|
||||
|
||||
width = CGRectGetMaxX([self frameForSegment:(segmentCount - 1)]);
|
||||
}
|
||||
|
||||
var delta = segmentWidth - CGRectGetWidth([segment frame]);
|
||||
|
||||
if (!delta)
|
||||
{
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Update control size
|
||||
var frame = [self frame];
|
||||
|
||||
[self setFrameSize:CGSizeMake(CGRectGetWidth(frame) + delta, CGRectGetHeight(frame))];
|
||||
|
||||
// Update segment width
|
||||
[segment setWidth:segmentWidth];
|
||||
[segment setFrame:[self frameForSegment:aSegment]];
|
||||
|
||||
// Update following segments widths
|
||||
var index = aSegment + 1;
|
||||
|
||||
for (; index < _segments.length; ++index)
|
||||
{
|
||||
[_segments[index] frame].origin.x += delta;
|
||||
|
||||
[self drawSegmentBezel:index highlight:NO];
|
||||
[self drawSegment:index highlight:NO];
|
||||
}
|
||||
|
||||
[self drawSegmentBezel:aSegment highlight:NO];
|
||||
[self drawSegment:aSegment highlight:NO];
|
||||
[self setFrameSize:CGSizeMake(width, CGRectGetHeight([self frame]))];
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
@@ -735,29 +773,57 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (CGRect)frameForSegment:(unsigned)aSegment
|
||||
{
|
||||
return [self bezelFrameForSegment:aSegment];
|
||||
var segment = [_segments objectAtIndex:aSegment],
|
||||
frame = [segment frame];
|
||||
|
||||
if (CGRectEqualToRect(frame, CGRectMakeZero()))
|
||||
{
|
||||
frame = [self bezelFrameForSegment:aSegment];
|
||||
[segment setFrame:frame];
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
- (CGRect)bezelFrameForSegment:(unsigned)aSegment
|
||||
{
|
||||
var height = [self currentValueForThemeAttribute:@"default-height"],
|
||||
bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"],
|
||||
var left = [self _leftOffsetForSegment:aSegment],
|
||||
top = [self currentValueForThemeAttribute:@"bezel-inset"].top,
|
||||
width = [self widthForSegment:aSegment],
|
||||
left = [self _leftOffsetForSegment:aSegment];
|
||||
height = [self currentValueForThemeAttribute:@"min-size"].height;
|
||||
|
||||
return CGRectMake(left, bezelInset.top, width, height);
|
||||
if (width == 0)
|
||||
{
|
||||
var themeState = _themeState.hasThemeState(CPThemeStateDisabled) ? _themeStates[aSegment].and(CPThemeStateDisabled) : _themeStates[aSegment],
|
||||
contentInset = [self valueForThemeAttribute:@"content-inset" inState:themeState],
|
||||
contentInsetWidth = contentInset.left + contentInset.right,
|
||||
|
||||
segment = _segments[aSegment],
|
||||
label = [segment label],
|
||||
image = [segment image];
|
||||
|
||||
width = (label ? [label sizeWithFont:[self font]].width : 4.0) + (image ? [image size].width : 0) + contentInsetWidth;
|
||||
}
|
||||
|
||||
return CGRectMake(left, top, width, height);
|
||||
}
|
||||
|
||||
- (CGRect)contentFrameForSegment:(unsigned)aSegment
|
||||
{
|
||||
var height = [self currentValueForThemeAttribute:@"default-height"],
|
||||
var height = [self currentValueForThemeAttribute:@"min-size"].height,
|
||||
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||
width = [self widthForSegment:aSegment],
|
||||
width = CGRectGetWidth([self frameForSegment:aSegment]),
|
||||
left = [self _leftOffsetForSegment:aSegment];
|
||||
|
||||
return CGRectMake(left + contentInset.left, contentInset.top, width - contentInset.left - contentInset.right, height - contentInset.top - contentInset.bottom);
|
||||
}
|
||||
|
||||
- (CGSize)_minimumFrameSize
|
||||
{
|
||||
// The current width is always the minimum width.
|
||||
return CGSizeMake(CGRectGetWidth([self frame]), [self currentValueForThemeAttribute:@"min-size"].height);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the segment that is hit by the specified point.
|
||||
@param aPoint the point to test for a segment hit
|
||||
@@ -766,19 +832,19 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
- (unsigned)testSegment:(CGPoint)aPoint
|
||||
{
|
||||
var location = [self convertPoint:aPoint fromView:nil],
|
||||
count = _segments.length;
|
||||
count = [self segmentCount];
|
||||
|
||||
while (count--)
|
||||
if (CGRectContainsPoint([_segments[count] frame], aPoint))
|
||||
if (CGRectContainsPoint([self frameForSegment:count], aPoint))
|
||||
return count;
|
||||
|
||||
if (_segments.length)
|
||||
if ([self segmentCount])
|
||||
{
|
||||
var adjustedLastFrame = CGRectCreateCopy([_segments[_segments.length - 1] frame]);
|
||||
var adjustedLastFrame = CGRectCreateCopy([self frameForSegment:(_segments.length - 1)]);
|
||||
adjustedLastFrame.size.width = CGRectGetWidth([self bounds]) - adjustedLastFrame.origin.x;
|
||||
|
||||
if (CGRectContainsPoint(adjustedLastFrame, aPoint))
|
||||
return _segments.length - 1;
|
||||
return [self segmentCount] - 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
@@ -806,64 +872,68 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
var type = [anEvent type],
|
||||
location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
|
||||
if (type == CPLeftMouseUp)
|
||||
switch (type)
|
||||
{
|
||||
if (_trackingSegment == -1)
|
||||
case CPLeftMouseUp:
|
||||
|
||||
if (_trackingSegment === CPNotFound)
|
||||
return;
|
||||
|
||||
if (_trackingSegment === [self testSegment:location])
|
||||
{
|
||||
if (_trackingMode == CPSegmentSwitchTrackingSelectAny)
|
||||
{
|
||||
[self setSelected:![self isSelectedForSegment:_trackingSegment] forSegment:_trackingSegment];
|
||||
|
||||
// With ANY, _selectedSegment means last pressed.
|
||||
_selectedSegment = _trackingSegment;
|
||||
}
|
||||
else
|
||||
[self setSelected:YES forSegment:_trackingSegment];
|
||||
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
|
||||
if (_trackingMode == CPSegmentSwitchTrackingMomentary)
|
||||
{
|
||||
[self setSelected:NO forSegment:_trackingSegment];
|
||||
|
||||
_selectedSegment = CPNotFound;
|
||||
}
|
||||
}
|
||||
|
||||
[self drawSegmentBezel:_trackingSegment highlight:NO];
|
||||
|
||||
_trackingSegment = CPNotFound;
|
||||
|
||||
return;
|
||||
|
||||
if (_trackingSegment === [self testSegment:location])
|
||||
{
|
||||
if (_trackingMode == CPSegmentSwitchTrackingSelectAny)
|
||||
case CPLeftMouseDown:
|
||||
|
||||
var trackingSegment = [self testSegment:location];
|
||||
if (trackingSegment > CPNotFound && [self isEnabledForSegment:trackingSegment])
|
||||
{
|
||||
[self setSelected:![self isSelectedForSegment:_trackingSegment] forSegment:_trackingSegment];
|
||||
|
||||
// With ANY, _selectedSegment means last pressed.
|
||||
_selectedSegment = _trackingSegment;
|
||||
_trackingHighlighted = YES;
|
||||
_trackingSegment = trackingSegment;
|
||||
[self drawSegmentBezel:_trackingSegment highlight:YES];
|
||||
}
|
||||
else
|
||||
[self setSelected:YES forSegment:_trackingSegment];
|
||||
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
break;
|
||||
|
||||
if (_trackingMode == CPSegmentSwitchTrackingMomentary)
|
||||
case CPLeftMouseDragged:
|
||||
|
||||
if (_trackingSegment === CPNotFound)
|
||||
return;
|
||||
|
||||
var highlighted = [self testSegment:location] === _trackingSegment;
|
||||
|
||||
if (highlighted != _trackingHighlighted)
|
||||
{
|
||||
[self setSelected:NO forSegment:_trackingSegment];
|
||||
_trackingHighlighted = highlighted;
|
||||
|
||||
_selectedSegment = -1;
|
||||
[self drawSegmentBezel:_trackingSegment highlight:_trackingHighlighted];
|
||||
}
|
||||
}
|
||||
|
||||
[self drawSegmentBezel:_trackingSegment highlight:NO];
|
||||
|
||||
_trackingSegment = -1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == CPLeftMouseDown)
|
||||
{
|
||||
var trackingSegment = [self testSegment:location];
|
||||
if (trackingSegment > -1 && [self isEnabledForSegment:trackingSegment])
|
||||
{
|
||||
_trackingHighlighted = YES;
|
||||
_trackingSegment = trackingSegment;
|
||||
[self drawSegmentBezel:_trackingSegment highlight:YES];
|
||||
}
|
||||
}
|
||||
|
||||
else if (type == CPLeftMouseDragged)
|
||||
{
|
||||
if (_trackingSegment == -1)
|
||||
return;
|
||||
|
||||
var highlighted = [self testSegment:location] === _trackingSegment;
|
||||
|
||||
if (highlighted != _trackingHighlighted)
|
||||
{
|
||||
_trackingHighlighted = highlighted;
|
||||
|
||||
[self drawSegmentBezel:_trackingSegment highlight:_trackingHighlighted];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackSegment:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
@@ -873,7 +943,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
{
|
||||
[super setFont:aFont];
|
||||
|
||||
[self tileWithChangedSegment:0];
|
||||
[self tile];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -905,28 +975,49 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
|
||||
if ([aCoder containsValueForKey:CPSegmentedControlSelectedKey])
|
||||
_selectedSegment = [aCoder decodeIntForKey:CPSegmentedControlSelectedKey];
|
||||
else
|
||||
_selectedSegment = -1;
|
||||
_selectedSegment = CPNotFound;
|
||||
|
||||
if ([aCoder containsValueForKey:CPSegmentedControlTrackingModeKey])
|
||||
_trackingMode = [aCoder decodeIntForKey:CPSegmentedControlTrackingModeKey];
|
||||
else
|
||||
_trackingMode = CPSegmentSwitchTrackingSelectOne;
|
||||
|
||||
// HACK
|
||||
|
||||
for (var i = 0; i < _segments.length; i++)
|
||||
{
|
||||
// Here we update the themeStates array for each segments to know if there are selected or not
|
||||
for (var i = 0; i < [self segmentCount]; i++)
|
||||
_themeStates[i] = [_segments[i] selected] ? CPThemeStateSelected : CPThemeStateNormal;
|
||||
[self tileWithChangedSegment:i];
|
||||
|
||||
[self tile];
|
||||
|
||||
var thickness = [self currentValueForThemeAttribute:@"divider-thickness"],
|
||||
dividerExtraSpace = ([_segments count] - 1) * thickness,
|
||||
difference = MAX(originalWidth - [self frame].size.width - dividerExtraSpace, 0.0),
|
||||
remainingWidth = FLOOR(difference / [self segmentCount]),
|
||||
widthOfAllSegments = 0;
|
||||
|
||||
// We do this in a second loop because it relies on all the themeStates being set first
|
||||
for (var i = 0; i < [self segmentCount]; i++)
|
||||
{
|
||||
var frame = [_segments[i] frame];
|
||||
frame.size.width += remainingWidth;
|
||||
|
||||
widthOfAllSegments += CGRectGetWidth(frame);
|
||||
}
|
||||
|
||||
var difference = MAX(originalWidth - [self frame].size.width, 0.0),
|
||||
remainingWidth = FLOOR(difference / _segments.length);
|
||||
// Here we handle the leftovers pixel, and we will add one pixel to each segment cell till we have the same size as the originalSize.
|
||||
// This is needed to have a perfect/same alignment between our application and xCode.
|
||||
var leftOversPixel = originalWidth - (widthOfAllSegments + dividerExtraSpace);
|
||||
|
||||
for (var i = 0; i < _segments.length; i++)
|
||||
[self setWidth:[_segments[i] width] + remainingWidth forSegment:i];
|
||||
// Make sure we don't make an out of range
|
||||
if (leftOversPixel < [self segmentCount] - 1)
|
||||
{
|
||||
for (var i = 0; i < leftOversPixel; i++)
|
||||
{
|
||||
[_segments[i] frame].size.width += 1;
|
||||
}
|
||||
}
|
||||
|
||||
[self tileWithChangedSegment:0];
|
||||
[self setFrameSize:CGSizeMake(originalWidth, CGRectGetHeight([self frame]))];
|
||||
[self tile];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -944,31 +1035,48 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
|
||||
|
||||
@end
|
||||
|
||||
var CPSegmentedControlBindersMap = {},
|
||||
CPSegmentedControlNoSelectionPlaceholder = "CPSegmentedControlNoSelectionPlaceholder";
|
||||
@implementation CPSegmentedControl (BindingSupport)
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if ([self _isSelectionBinding:aBinding])
|
||||
return [_CPSegmentedControlBinder class];
|
||||
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
+ (BOOL)_isSelectionBinding:(CPString)aBinding
|
||||
{
|
||||
return (aBinding === CPSelectedIndexBinding || aBinding === CPSelectedLabelBinding || aBinding === CPSelectedTagBinding);
|
||||
}
|
||||
|
||||
+ (BOOL)isBindingExclusive:(CPString)aBinding
|
||||
{
|
||||
return [self _isSelectionBinding:aBinding];
|
||||
}
|
||||
|
||||
- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options
|
||||
{
|
||||
if ([[self class] _isSelectionBinding:aBinding] && _trackingMode !== CPSegmentSwitchTrackingSelectOne)
|
||||
{
|
||||
CPLog.warn("Binding " + aBinding + " needs CPSegmentSwitchTrackingSelectOne tracking mode");
|
||||
return;
|
||||
}
|
||||
|
||||
[super bind:aBinding toObject:anObject withKeyPath:aKeyPath options:options];
|
||||
}
|
||||
|
||||
- (void)_reverseSetBinding
|
||||
{
|
||||
[_CPSegmentedControlBinder _reverseSetValueFromExclusiveBinderForObject:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPSegmentedControlNoSelectionPlaceholder = "CPSegmentedControlNoSelectionPlaceholder";
|
||||
|
||||
@implementation _CPSegmentedControlBinder : CPBinder
|
||||
{
|
||||
CPString _selectionBinding @accessors(readonly, getter=selectionBinding);
|
||||
}
|
||||
|
||||
+ (void)reverseSetValueForObject:(id)aSource
|
||||
{
|
||||
var binder = CPSegmentedControlBindersMap[[aSource UID]];
|
||||
[binder reverseSetValueFor:[binder selectionBinding]];
|
||||
}
|
||||
|
||||
- (id)initWithBinding:(CPString)aBinding name:(CPString)aName to:(id)aDestination keyPath:(CPString)aKeyPath options:(CPDictionary)options from:(id)aSource
|
||||
{
|
||||
self = [super initWithBinding:aBinding name:aName to:aDestination keyPath:aKeyPath options:options from:aSource];
|
||||
|
||||
if (self)
|
||||
{
|
||||
CPSegmentedControlBindersMap[[aSource UID]] = self;
|
||||
_selectionBinding = aName;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
||||
|
||||
+5
-2
@@ -22,6 +22,9 @@
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
@import "CGGeometry.j"
|
||||
@import "CPColor.j"
|
||||
@import "CPGraphicsContext.j"
|
||||
|
||||
/*!
|
||||
@deprecated
|
||||
@@ -31,9 +34,9 @@
|
||||
*/
|
||||
@implementation CPShadow : CPObject
|
||||
{
|
||||
CGSize _offset @accessors(property=shadowOffset);
|
||||
CGSize _offset @accessors(property=shadowOffset);
|
||||
float _blurRadius @accessors(property=shadowBlurRadius);
|
||||
CPColor _color @accessors(property=shadowColor);
|
||||
CPColor _color @accessors(property=shadowColor);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
@import "CPImage.j"
|
||||
@import "CPView.j"
|
||||
|
||||
|
||||
@typedef CPShadowWeight
|
||||
CPLightShadow = 0;
|
||||
CPHeavyShadow = 1;
|
||||
|
||||
|
||||
+50
-2
@@ -23,6 +23,18 @@
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPRunLoop.j>
|
||||
|
||||
@typedef HTMLAudioElement
|
||||
|
||||
@protocol CPSoundDelegate <CPObject>
|
||||
|
||||
@optional
|
||||
- (void)sound:(CPSound)aSound didFinishPlaying:(BOOL)finishedLoading;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPSoundDelegate_sound_didFinishPlaying_ = 1 << 1;
|
||||
|
||||
CPSoundLoadStateEmpty = 0;
|
||||
CPSoundLoadStateLoading = 1;
|
||||
CPSoundLoadStateCanBePlayed = 2;
|
||||
@@ -50,6 +62,7 @@ CPSoundPlayBackStatePause = 2;
|
||||
HTMLAudioElement _audioTag;
|
||||
int _loadStatus;
|
||||
int _playBackStatus;
|
||||
unsigned _implementedDelegateMethods;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
@@ -133,6 +146,25 @@ CPSoundPlayBackStatePause = 2;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Delegate methods
|
||||
|
||||
/*!
|
||||
Sets the sound's delegate.
|
||||
@param aDelegate the new delegate
|
||||
*/
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
{
|
||||
if (_delegate === aDelegate)
|
||||
return;
|
||||
|
||||
_delegate = aDelegate;
|
||||
_implementedDelegateMethods = 0;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(sound:didFinishPlaying:)])
|
||||
_implementedDelegateMethods |= CPSoundDelegate_sound_didFinishPlaying_;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Events listener
|
||||
|
||||
@@ -207,8 +239,7 @@ CPSoundPlayBackStatePause = 2;
|
||||
_audioTag.currentTime = 0.0;
|
||||
_playBackStatus = CPSoundPlayBackStateStop;
|
||||
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(sound:didFinishPlaying:)])
|
||||
[_delegate sound:self didFinishPlaying:YES];
|
||||
[self _sendDelegateSoundDidFinishPlaying:YES];
|
||||
|
||||
return YES;
|
||||
}
|
||||
@@ -316,3 +347,20 @@ CPSoundPlayBackStatePause = 2;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation CPSound (CPSoundDelegate)
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call delegate sound:didFinishPlaying:
|
||||
*/
|
||||
- (void)_sendDelegateSoundDidFinishPlaying:(BOOL)finishedPlaying
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPSoundDelegate_sound_didFinishPlaying_))
|
||||
return;
|
||||
|
||||
[_delegate sound:self didFinishPlaying:finishedPlaying];
|
||||
}
|
||||
|
||||
@end
|
||||
+400
-173
@@ -26,10 +26,40 @@
|
||||
@import "CPImage.j"
|
||||
@import "CPView.j"
|
||||
@import "CPCursor.j"
|
||||
@import "CPTrackingArea.j"
|
||||
|
||||
@class CPUserDefaults
|
||||
@global CPApp
|
||||
|
||||
@protocol CPSplitViewDelegate <CPObject>
|
||||
|
||||
@optional
|
||||
- (BOOL)splitView:(CPSplitView)splitView canCollapseSubview:(CPView)subview;
|
||||
- (BOOL)splitView:(CPSplitView)splitView shouldAdjustSizeOfSubview:(CPView)subview;
|
||||
- (BOOL)splitView:(CPSplitView)splitView shouldCollapseSubview:(CPView)subview forDoubleClickOnDividerAtIndex:(CPInteger)dividerIndex;
|
||||
- (CGRect)splitView:(CPSplitView)splitView additionalEffectiveRectOfDividerAtIndex:(CPInteger)dividerIndex;
|
||||
- (CGRect)splitView:(CPSplitView)splitView effectiveRect:(CGRect)proposedEffectiveRect forDrawnRect:(CGRect)drawnRect ofDividerAtIndex:(CPInteger)dividerIndex;
|
||||
- (float)splitView:(CPSplitView)splitView constrainMaxCoordinate:(float)proposedMax ofSubviewAt:(CPInteger)dividerIndex;
|
||||
- (float)splitView:(CPSplitView)splitView constrainMinCoordinate:(float)proposedMin ofSubviewAt:(CPInteger)dividerIndex;
|
||||
- (float)splitView:(CPSplitView)splitView constrainSplitPosition:(float)proposedPosition ofSubviewAt:(CPInteger)dividerIndex;
|
||||
- (void)splitView:(CPSplitView)splitView resizeSubviewsWithOldSize:(CGSize)oldSize;
|
||||
- (void)splitViewDidResizeSubviews:(CPNotification)aNotification;
|
||||
- (void)splitViewWillResizeSubviews:(CPNotification)aNotification;
|
||||
|
||||
@end
|
||||
|
||||
var CPSplitViewDelegate_splitView_canCollapseSubview_ = 1 << 0,
|
||||
CPSplitViewDelegate_splitView_shouldAdjustSizeOfSubview_ = 1 << 1,
|
||||
CPSplitViewDelegate_splitView_shouldCollapseSubview_forDoubleClickOnDividerAtIndex_ = 1 << 2,
|
||||
CPSplitViewDelegate_splitView_additionalEffectiveRectOfDividerAtIndex_ = 1 << 3,
|
||||
CPSplitViewDelegate_splitView_effectiveRect_forDrawnRect_ofDividerAtIndex_ = 1 << 4,
|
||||
CPSplitViewDelegate_splitView_constrainMaxCoordinate_ofSubviewAt_ = 1 << 5,
|
||||
CPSplitViewDelegate_splitView_constrainMinCoordinate_ofSubviewAt_ = 1 << 6,
|
||||
CPSplitViewDelegate_splitView_constrainSplitPosition_ofSubviewAt_ = 1 << 7,
|
||||
CPSplitViewDelegate_splitView_resizeSubviewsWithOldSize_ = 1 << 8,
|
||||
CPSplitViewDelegate_splitViewDidResizeSubviews_ = 1 << 9,
|
||||
CPSplitViewDelegate_splitViewWillResizeSubviews_ = 1 << 10;
|
||||
|
||||
#define SPLIT_VIEW_MAYBE_POST_WILL_RESIZE() \
|
||||
if ((_suppressResizeNotificationsMask & DidPostWillResizeNotification) === 0) \
|
||||
{ \
|
||||
@@ -73,29 +103,32 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
|
||||
@implementation CPSplitView : CPView
|
||||
{
|
||||
id _delegate;
|
||||
BOOL _isVertical;
|
||||
BOOL _isPaneSplitter;
|
||||
id <CPSplitViewDelegate> _delegate;
|
||||
BOOL _isVertical;
|
||||
BOOL _isPaneSplitter;
|
||||
|
||||
int _currentDivider;
|
||||
float _initialOffset;
|
||||
CPDictionary _preCollapsePositions;
|
||||
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 _isTracking;
|
||||
|
||||
CPString _autosaveName;
|
||||
BOOL _shouldAutosave;
|
||||
CGSize _shouldRestoreFromAutosaveUnlessFrameSize;
|
||||
CPString _autosaveName;
|
||||
BOOL _shouldAutosave;
|
||||
CGSize _shouldRestoreFromAutosaveUnlessFrameSize;
|
||||
|
||||
BOOL _needsResizeSubviews;
|
||||
int _suppressResizeNotificationsMask;
|
||||
BOOL _needsResizeSubviews;
|
||||
int _suppressResizeNotificationsMask;
|
||||
|
||||
CPArray _buttonBars;
|
||||
CPArray _buttonBars;
|
||||
|
||||
unsigned _implementedDelegateMethods;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
@@ -126,6 +159,7 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
_buttonBars = [];
|
||||
|
||||
_shouldAutosave = YES;
|
||||
_isTracking = NO;
|
||||
|
||||
[self _setVertical:YES];
|
||||
}
|
||||
@@ -181,6 +215,9 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
[_subviews[index] setFrame:CGRectMake(0, ROUND((eachSize + dividerThickness) * index), frame.size.width, eachSize)];
|
||||
}
|
||||
|
||||
if (_DOMDividerElements[_drawingDivider])
|
||||
[self _setupDOMDivider];
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
[self _postNotificationDidResize];
|
||||
|
||||
@@ -331,9 +368,9 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundRepeat = "repeat";
|
||||
|
||||
CPDOMDisplayServerAppendChild(_DOMElement, _DOMDividerElements[_drawingDivider]);
|
||||
[self _setupDOMDivider];
|
||||
}
|
||||
|
||||
[self _setupDOMDivider];
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMDividerElements[_drawingDivider], NULL, CGRectGetMinX(aRect), CGRectGetMinY(aRect));
|
||||
CPDOMDisplayServerSetStyleSize(_DOMDividerElements[_drawingDivider], CGRectGetWidth(aRect), CGRectGetHeight(aRect));
|
||||
#endif
|
||||
@@ -406,11 +443,8 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
buttonBarRect.origin = [self convertPoint:buttonBarRect.origin fromView:buttonBar];
|
||||
}
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitView:effectiveRect:forDrawnRect:ofDividerAtIndex:)])
|
||||
effectiveRect = [_delegate splitView:self effectiveRect:effectiveRect forDrawnRect:effectiveRect ofDividerAtIndex:anIndex];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitView:additionalEffectiveRectOfDividerAtIndex:)])
|
||||
additionalRect = [_delegate splitView:self additionalEffectiveRectOfDividerAtIndex:anIndex];
|
||||
effectiveRect = [self _sendDelegateSplitViewEffectiveRect:effectiveRect forDrawnRect:effectiveRect ofDividerAtIndex:anIndex];
|
||||
additionalRect = [self _sendDelegateSplitViewAdditionalEffectiveRectOfDividerAtIndex:anIndex];
|
||||
|
||||
return CGRectContainsPoint(effectiveRect, aPoint) ||
|
||||
(additionalRect && CGRectContainsPoint(additionalRect, aPoint)) ||
|
||||
@@ -423,17 +457,26 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
return nil;
|
||||
|
||||
var point = [self convertPoint:aPoint fromView:[self superview]],
|
||||
count = [_subviews count] - 1;
|
||||
dividerIndex = [self _dividerAtPoint:point];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
if ([self cursorAtPoint:point hitDividerAtIndex:i])
|
||||
return self;
|
||||
}
|
||||
if (dividerIndex !== CPNotFound)
|
||||
return self;
|
||||
|
||||
return [super hitTest:aPoint];
|
||||
}
|
||||
|
||||
- (CPInteger)_dividerAtPoint:(CGPoint)aPoint
|
||||
{
|
||||
var count = [_subviews count] - 1;
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
if ([self cursorAtPoint:aPoint hitDividerAtIndex:i])
|
||||
return i;
|
||||
}
|
||||
|
||||
return CPNotFound;
|
||||
}
|
||||
/*
|
||||
Tracks the divider.
|
||||
@param anEvent the input event
|
||||
@@ -444,12 +487,13 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
|
||||
if (type == CPLeftMouseUp)
|
||||
{
|
||||
// We disabled autosaving during tracking.
|
||||
_shouldAutosave = YES;
|
||||
|
||||
if (_currentDivider != CPNotFound)
|
||||
if ([anEvent clickCount] == 2 || (_isTracking && _currentDivider != CPNotFound))
|
||||
{
|
||||
// We disabled autosaving during tracking.
|
||||
_shouldAutosave = YES;
|
||||
_currentDivider = CPNotFound;
|
||||
_isTracking = NO;
|
||||
|
||||
[self _autosave];
|
||||
[self _updateResizeCursor:anEvent];
|
||||
}
|
||||
@@ -459,59 +503,55 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
|
||||
if (type == CPLeftMouseDown)
|
||||
{
|
||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||
count = [_subviews count] - 1;
|
||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
_currentDivider = [self _dividerAtPoint:point];
|
||||
|
||||
_currentDivider = CPNotFound;
|
||||
var frame = [_subviews[_currentDivider] frame],
|
||||
startPosition = frame.origin[_originComponent] + frame.size[_sizeComponent];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
if ([anEvent clickCount] == 2 &&
|
||||
[self _delegateRespondsToSplitViewCanCollapseSubview] &&
|
||||
[self _delegateRespondsToSplitViewshouldCollapseSubviewForDoubleClickOnDividerAtIndex])
|
||||
{
|
||||
var frame = [_subviews[i] frame],
|
||||
startPosition = frame.origin[_originComponent] + frame.size[_sizeComponent];
|
||||
var minPosition = [self minPossiblePositionOfDividerAtIndex:_currentDivider],
|
||||
maxPosition = [self maxPossiblePositionOfDividerAtIndex:_currentDivider],
|
||||
preCollapsePosition = [_preCollapsePositions objectForKey:"" + _currentDivider] || 0;
|
||||
|
||||
if ([self cursorAtPoint:point hitDividerAtIndex:i])
|
||||
if ([self _sendDelegateSplitViewCanCollapseSubview:_subviews[_currentDivider]] && [self _sendDelegateSplitViewShouldCollapseSubview:_subviews[_currentDivider] forDoubleClickOnDividerAtIndex:_currentDivider])
|
||||
{
|
||||
if ([anEvent clickCount] == 2 &&
|
||||
[_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)] &&
|
||||
[_delegate respondsToSelector:@selector(splitView:shouldCollapseSubview:forDoubleClickOnDividerAtIndex:)])
|
||||
{
|
||||
var minPosition = [self minPossiblePositionOfDividerAtIndex: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])
|
||||
{
|
||||
if ([self isSubviewCollapsed:_subviews[i]])
|
||||
[self setPosition:preCollapsePosition ? preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
|
||||
else
|
||||
[self setPosition:minPosition ofDividerAtIndex:i];
|
||||
}
|
||||
else if ([_delegate splitView:self canCollapseSubview:_subviews[i + 1]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i + 1] forDoubleClickOnDividerAtIndex:i])
|
||||
{
|
||||
if ([self isSubviewCollapsed:_subviews[i + 1]])
|
||||
[self setPosition:preCollapsePosition ? preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
|
||||
else
|
||||
[self setPosition:maxPosition ofDividerAtIndex:i];
|
||||
}
|
||||
}
|
||||
if ([self isSubviewCollapsed:_subviews[_currentDivider]])
|
||||
[self setPosition:preCollapsePosition ? preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:_currentDivider];
|
||||
else
|
||||
{
|
||||
_currentDivider = i;
|
||||
_initialOffset = startPosition - point[_originComponent];
|
||||
|
||||
// Don't autosave during a resize. We'll wait until it's done.
|
||||
_shouldAutosave = NO;
|
||||
[self _postNotificationWillResize];
|
||||
}
|
||||
[self setPosition:minPosition ofDividerAtIndex:_currentDivider];
|
||||
}
|
||||
else if ([self _sendDelegateSplitViewCanCollapseSubview:_subviews[_currentDivider + 1]] && [self _sendDelegateSplitViewShouldCollapseSubview:_subviews[_currentDivider + 1] forDoubleClickOnDividerAtIndex:_currentDivider])
|
||||
{
|
||||
if ([self isSubviewCollapsed:_subviews[_currentDivider + 1]])
|
||||
[self setPosition:preCollapsePosition ? preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:_currentDivider];
|
||||
else
|
||||
[self setPosition:maxPosition ofDividerAtIndex:_currentDivider];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_initialOffset = startPosition - point[_originComponent];
|
||||
// Don't autosave during a resize. We'll wait until it's done.
|
||||
_shouldAutosave = NO;
|
||||
[self _postNotificationWillResize];
|
||||
}
|
||||
|
||||
if (_currentDivider === CPNotFound)
|
||||
return;
|
||||
}
|
||||
|
||||
else if (type == CPLeftMouseDragged && _currentDivider != CPNotFound)
|
||||
{
|
||||
if (!_isTracking)
|
||||
{
|
||||
// Don't autosave during a resize. We'll wait until it's done.
|
||||
_shouldAutosave = NO;
|
||||
[self _postNotificationWillResize];
|
||||
|
||||
_isTracking = YES;
|
||||
}
|
||||
|
||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
|
||||
[self setPosition:(point[_originComponent] + _initialOffset) ofDividerAtIndex:_currentDivider];
|
||||
@@ -524,8 +564,11 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
// FIXME: This should not trap events if not on a divider!
|
||||
[self trackDivider:anEvent];
|
||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||
dividerIndex = [self _dividerAtPoint:point];
|
||||
|
||||
if (dividerIndex !== CPNotFound)
|
||||
[self trackDivider:anEvent];
|
||||
}
|
||||
|
||||
- (void)viewDidMoveToWindow
|
||||
@@ -534,26 +577,6 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
//[[self window] setAcceptsMouseMovedEvents:YES];
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(CPEvent)anEvent
|
||||
{
|
||||
// Tracking code handles cursor by itself.
|
||||
if (_currentDivider == CPNotFound)
|
||||
[self _updateResizeCursor:anEvent];
|
||||
}
|
||||
|
||||
- (void)mouseMoved:(CPEvent)anEvent
|
||||
{
|
||||
if (_currentDivider == CPNotFound)
|
||||
[self _updateResizeCursor:anEvent];
|
||||
}
|
||||
|
||||
- (void)mouseExited:(CPEvent)anEvent
|
||||
{
|
||||
if (_currentDivider == CPNotFound)
|
||||
// FIXME: we should use CPCursor push/pop (if previous currentCursor != arrow).
|
||||
[[CPCursor arrowCursor] set];
|
||||
}
|
||||
|
||||
- (void)_updateResizeCursor:(CPEvent)anEvent
|
||||
{
|
||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
@@ -580,12 +603,8 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
|
||||
if (sizeA === 0)
|
||||
canGrow = YES; // Subview is collapsed.
|
||||
else if (!canShrink &&
|
||||
[_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)] &&
|
||||
[_delegate splitView:self canCollapseSubview:_subviews[i]])
|
||||
{
|
||||
else if (!canShrink && [self _sendDelegateSplitViewCanCollapseSubview:_subviews[i]])
|
||||
canShrink = YES; // Subview is collapsible.
|
||||
}
|
||||
|
||||
if (sizeB === 0)
|
||||
{
|
||||
@@ -594,9 +613,7 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
// 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]])
|
||||
else if (!canGrow && [self _sendDelegateSplitViewCanCollapseSubview:_subviews[i + 1]])
|
||||
{
|
||||
canGrow = YES; // Right/lower subview is collapsible.
|
||||
}
|
||||
@@ -657,53 +674,38 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
- (int)_realPositionForPosition:(float)position ofDividerAtIndex:(int)dividerIndex
|
||||
{
|
||||
// not sure where this should override other positions?
|
||||
if ([_delegate respondsToSelector:@selector(splitView:constrainSplitPosition:ofSubviewAt:)])
|
||||
{
|
||||
var proposedPosition = [_delegate splitView:self constrainSplitPosition:position ofSubviewAt:dividerIndex];
|
||||
var proposedPosition = [self _sendDelegateSplitViewConstrainSplitPosition: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;
|
||||
}
|
||||
// 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],
|
||||
actualMax = proposedMax,
|
||||
actualMin = proposedMin;
|
||||
actualMin = proposedMin,
|
||||
proposedActualMin = [self _sendDelegateSplitViewConstrainMinCoordinate:proposedMin ofSubviewAt:dividerIndex],
|
||||
proposedActualMax = [self _sendDelegateSplitViewConstrainMaxCoordinate:proposedMax ofSubviewAt:dividerIndex];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitView:constrainMinCoordinate:ofSubviewAt:)])
|
||||
{
|
||||
var proposedActualMin = [_delegate splitView:self constrainMinCoordinate:proposedMin ofSubviewAt:dividerIndex];
|
||||
if (_IS_NUMERIC(proposedActualMin))
|
||||
actualMin = proposedActualMin;
|
||||
|
||||
if (_IS_NUMERIC(proposedActualMin))
|
||||
actualMin = proposedActualMin;
|
||||
}
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitView:constrainMaxCoordinate:ofSubviewAt:)])
|
||||
{
|
||||
var proposedActualMax = [_delegate splitView:self constrainMaxCoordinate:proposedMax ofSubviewAt:dividerIndex];
|
||||
|
||||
if (_IS_NUMERIC(proposedActualMax))
|
||||
actualMax = proposedActualMax;
|
||||
}
|
||||
if (_IS_NUMERIC(proposedActualMax))
|
||||
actualMax = proposedActualMax;
|
||||
|
||||
var viewA = _subviews[dividerIndex],
|
||||
viewB = _subviews[dividerIndex + 1],
|
||||
realPosition = MAX(MIN(position, actualMax), actualMin);
|
||||
|
||||
// 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;
|
||||
if ((position < proposedMin + (actualMin - proposedMin) / 2) && [self _sendDelegateSplitViewCanCollapseSubview: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;
|
||||
if ((position > proposedMax - (proposedMax - actualMax) / 2) && [self _sendDelegateSplitViewCanCollapseSubview:viewB])
|
||||
realPosition = proposedMax;
|
||||
|
||||
return realPosition;
|
||||
}
|
||||
@@ -787,9 +789,9 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
|
||||
- (void)resizeSubviewsWithOldSize:(CGSize)oldSize
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(splitView:resizeSubviewsWithOldSize:)])
|
||||
if ([self _delegateRespondsToSplitViewResizeSubviewsWithOldSize])
|
||||
{
|
||||
[_delegate splitView:self resizeSubviewsWithOldSize:oldSize];
|
||||
[self _sendDelegateSplitViewResizeSubviewsWithOldSize:oldSize];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -815,8 +817,7 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
oldFlexibleSpace = 0,
|
||||
totalSizablePanes = 0,
|
||||
isSizableMap = {},
|
||||
viewSizes = [],
|
||||
delegateRespondsToShouldAdjust = [_delegate respondsToSelector:@selector(splitView:shouldAdjustSizeOfSubview:)];
|
||||
viewSizes = [];
|
||||
|
||||
// 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
|
||||
@@ -832,7 +833,7 @@ var ShouldSuppressResizeNotifications = 1,
|
||||
for (index = 0; index < count; ++index)
|
||||
{
|
||||
var view = _subviews[index],
|
||||
isSizable = !delegateRespondsToShouldAdjust || [_delegate splitView:self shouldAdjustSizeOfSubview:view],
|
||||
isSizable = [self _sendDelegateSplitViewShouldAdjustSizeOfSubview:view],
|
||||
size = [view frame].size[_sizeComponent];
|
||||
|
||||
isSizableMap[index] = isSizable;
|
||||
@@ -958,25 +959,47 @@ The sum of the views and the sum of the dividers should be equal to the size of
|
||||
|
||||
@param delegate - The delegate of the splitview.
|
||||
*/
|
||||
- (void)setDelegate:(id)delegate
|
||||
- (void)setDelegate:(id <CPSplitViewDelegate>)aDelegate
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(splitViewDidResizeSubviews:)])
|
||||
[[CPNotificationCenter defaultCenter] removeObserver:_delegate name:CPSplitViewDidResizeSubviewsNotification object:self];
|
||||
if (_delegate === aDelegate)
|
||||
return;
|
||||
|
||||
_delegate = aDelegate;
|
||||
_implementedDelegateMethods = 0;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitViewWillResizeSubviews:)])
|
||||
[[CPNotificationCenter defaultCenter] removeObserver:_delegate name:CPSplitViewWillResizeSubviewsNotification object:self];
|
||||
_implementedDelegateMethods |= CPSplitViewDelegate_splitViewWillResizeSubviews_;
|
||||
|
||||
_delegate = delegate;
|
||||
if ([_delegate respondsToSelector:@selector(splitViewDidResizeSubviews:)])
|
||||
_implementedDelegateMethods |= CPSplitViewDelegate_splitViewDidResizeSubviews_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)])
|
||||
_implementedDelegateMethods |= CPSplitViewDelegate_splitView_canCollapseSubview_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitView:shouldAdjustSizeOfSubview:)])
|
||||
_implementedDelegateMethods |= CPSplitViewDelegate_splitView_shouldAdjustSizeOfSubview_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitView:shouldCollapseSubview:forDoubleClickOnDividerAtIndex:)])
|
||||
_implementedDelegateMethods |= CPSplitViewDelegate_splitView_shouldCollapseSubview_forDoubleClickOnDividerAtIndex_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitView:additionalEffectiveRectOfDividerAtIndex:)])
|
||||
_implementedDelegateMethods |= CPSplitViewDelegate_splitView_additionalEffectiveRectOfDividerAtIndex_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitView:effectiveRect:forDrawnRect:ofDividerAtIndex:)])
|
||||
_implementedDelegateMethods |= CPSplitViewDelegate_splitView_effectiveRect_forDrawnRect_ofDividerAtIndex_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitView:constrainMaxCoordinate:ofSubviewAt:)])
|
||||
_implementedDelegateMethods |= CPSplitViewDelegate_splitView_constrainMaxCoordinate_ofSubviewAt_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitView:constrainMinCoordinate:ofSubviewAt:)])
|
||||
_implementedDelegateMethods |= CPSplitViewDelegate_splitView_constrainMinCoordinate_ofSubviewAt_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitView:constrainSplitPosition:ofSubviewAt:)])
|
||||
_implementedDelegateMethods |= CPSplitViewDelegate_splitView_constrainSplitPosition_ofSubviewAt_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitView:resizeSubviewsWithOldSize:)])
|
||||
_implementedDelegateMethods |= CPSplitViewDelegate_splitView_resizeSubviewsWithOldSize_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(splitViewDidResizeSubviews:)])
|
||||
[[CPNotificationCenter defaultCenter] addObserver:_delegate
|
||||
selector:@selector(splitViewDidResizeSubviews:)
|
||||
name:CPSplitViewDidResizeSubviewsNotification
|
||||
object:self];
|
||||
if ([_delegate respondsToSelector:@selector(splitViewWillResizeSubviews:)])
|
||||
[[CPNotificationCenter defaultCenter] addObserver:_delegate
|
||||
selector:@selector(splitViewWillResizeSubviews:)
|
||||
name:CPSplitViewWillResizeSubviewsNotification
|
||||
object:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1026,27 +1049,12 @@ The sum of the views and the sum of the dividers should be equal to the size of
|
||||
|
||||
- (void)_postNotificationWillResize
|
||||
{
|
||||
var userInfo = nil;
|
||||
|
||||
if (_currentDivider !== CPNotFound)
|
||||
userInfo = @{ @"CPSplitViewDividerIndex": _currentDivider };
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPSplitViewWillResizeSubviewsNotification
|
||||
object:self
|
||||
userInfo:userInfo];
|
||||
[self _sendDelegateSplitViewWillResizeSubviews];
|
||||
}
|
||||
|
||||
- (void)_postNotificationDidResize
|
||||
{
|
||||
var userInfo = nil;
|
||||
|
||||
if (_currentDivider !== CPNotFound)
|
||||
userInfo = @{ @"CPSplitViewDividerIndex": _currentDivider };
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPSplitViewDidResizeSubviewsNotification
|
||||
object:self
|
||||
userInfo:userInfo];
|
||||
|
||||
[self _sendDelegateSplitViewDidResizeSubviews];
|
||||
|
||||
// TODO Cocoa always autosaves on "viewDidEndLiveResize". If Cappuccino adds support for this we
|
||||
// should do the same.
|
||||
@@ -1192,6 +1200,224 @@ The sum of the views and the sum of the dividers should be equal to the size of
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPSplitView (CPTrackingArea)
|
||||
{
|
||||
CPMutableArray _splitViewTrackingAreas;
|
||||
}
|
||||
|
||||
- (void)updateTrackingAreas
|
||||
{
|
||||
if (_splitViewTrackingAreas)
|
||||
{
|
||||
for (var i = 0, count = [_splitViewTrackingAreas count]; i < count; i++)
|
||||
[self removeTrackingArea:_splitViewTrackingAreas[i]];
|
||||
|
||||
_splitViewTrackingAreas = nil;
|
||||
}
|
||||
|
||||
var options = CPTrackingCursorUpdate | CPTrackingActiveInKeyWindow;
|
||||
|
||||
_splitViewTrackingAreas = @[];
|
||||
|
||||
for (var i = 0; i < _subviews.length - 1; i++)
|
||||
{
|
||||
[_splitViewTrackingAreas addObject:[[CPTrackingArea alloc] initWithRect:[self effectiveRectOfDividerAtIndex:i]
|
||||
options:options
|
||||
owner:self
|
||||
userInfo:nil]];
|
||||
|
||||
[self addTrackingArea:_splitViewTrackingAreas[i]];
|
||||
}
|
||||
|
||||
[super updateTrackingAreas];
|
||||
}
|
||||
|
||||
- (void)cursorUpdate:(CPEvent)anEvent
|
||||
{
|
||||
if (_currentDivider === CPNotFound)
|
||||
[self _updateResizeCursor:anEvent];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation CPSplitView (CPSplitViewDelegate)
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Return YES if the delegate implements splitView:resizeSubviewsWithOldSize:
|
||||
*/
|
||||
- (BOOL)_delegateRespondsToSplitViewResizeSubviewsWithOldSize
|
||||
{
|
||||
return _implementedDelegateMethods & CPSplitViewDelegate_splitView_resizeSubviewsWithOldSize_;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Return YES if the delegate implements splitView:canCollapseSubview:
|
||||
*/
|
||||
- (BOOL)_delegateRespondsToSplitViewCanCollapseSubview
|
||||
{
|
||||
return _implementedDelegateMethods & CPSplitViewDelegate_splitView_canCollapseSubview_;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Return YES if the delegate implements splitView:shouldCollapseSubview:forDoubleClickOnDividerAtIndex
|
||||
*/
|
||||
- (BOOL)_delegateRespondsToSplitViewshouldCollapseSubviewForDoubleClickOnDividerAtIndex
|
||||
{
|
||||
return _implementedDelegateMethods & CPSplitViewDelegate_splitView_shouldCollapseSubview_forDoubleClickOnDividerAtIndex_;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call the delegate splitView:canCollapseSubview:
|
||||
*/
|
||||
- (BOOL)_sendDelegateSplitViewCanCollapseSubview:(CPView)aView
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPSplitViewDelegate_splitView_canCollapseSubview_))
|
||||
return NO;
|
||||
|
||||
return [_delegate splitView:self canCollapseSubview:aView];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call the delegate splitView:shouldAdjustSizeOfSubview:
|
||||
*/
|
||||
- (BOOL)_sendDelegateSplitViewShouldAdjustSizeOfSubview:(CPView)aView
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPSplitViewDelegate_splitView_shouldAdjustSizeOfSubview_))
|
||||
return YES;
|
||||
|
||||
return [_delegate splitView:self shouldAdjustSizeOfSubview:aView];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call the delegate splitView:shouldCollapseSubview:forDoubleClickOnDividerAtIndex:
|
||||
*/
|
||||
- (BOOL)_sendDelegateSplitViewShouldCollapseSubview:(CPView)aView forDoubleClickOnDividerAtIndex:(int)anIndex
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPSplitViewDelegate_splitView_shouldCollapseSubview_forDoubleClickOnDividerAtIndex_))
|
||||
return NO;
|
||||
|
||||
return [_delegate splitView:self shouldCollapseSubview:aView forDoubleClickOnDividerAtIndex:anIndex];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call the delegate splitView:additionalEffectiveRectOfDividerAtIndex:
|
||||
*/
|
||||
- (CGRect)_sendDelegateSplitViewAdditionalEffectiveRectOfDividerAtIndex:(int)anIndex
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPSplitViewDelegate_splitView_additionalEffectiveRectOfDividerAtIndex_))
|
||||
return nil;
|
||||
|
||||
return [_delegate splitView:self additionalEffectiveRectOfDividerAtIndex:anIndex];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call the delegate splitView:effectiveRect:forDrawnRect:ofDividerAtIndex:
|
||||
*/
|
||||
- (CGRect)_sendDelegateSplitViewEffectiveRect:(CGRect)proposedEffectiveRect forDrawnRect:(CGRect)drawnRect ofDividerAtIndex:(CPInteger)dividerIndex
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPSplitViewDelegate_splitView_effectiveRect_forDrawnRect_ofDividerAtIndex_))
|
||||
return proposedEffectiveRect;
|
||||
|
||||
return [_delegate splitView:self effectiveRect:proposedEffectiveRect forDrawnRect:drawnRect ofDividerAtIndex:dividerIndex];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call the delegate splitView:constrainMaxCoordinate:ofSubviewAt:
|
||||
*/
|
||||
- (float)_sendDelegateSplitViewConstrainMaxCoordinate:(float)proposedMax ofSubviewAt:(CPInteger)dividerIndex
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPSplitViewDelegate_splitView_constrainMaxCoordinate_ofSubviewAt_))
|
||||
return nil;
|
||||
|
||||
return [_delegate splitView:self constrainMaxCoordinate:proposedMax ofSubviewAt:dividerIndex];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call the delegate splitView:constrainMinCoordinate:ofSubviewAt:
|
||||
*/
|
||||
- (float)_sendDelegateSplitViewConstrainMinCoordinate:(float)proposedMin ofSubviewAt:(CPInteger)dividerIndex
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPSplitViewDelegate_splitView_constrainMinCoordinate_ofSubviewAt_))
|
||||
return nil;
|
||||
|
||||
return [_delegate splitView:self constrainMinCoordinate:proposedMin ofSubviewAt:dividerIndex];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call the delegate splitView:constrainSplitPosition:ofSubviewAt:
|
||||
*/
|
||||
- (float)_sendDelegateSplitViewConstrainSplitPosition:(float)proposedMax ofSubviewAt:(CPInteger)dividerIndex
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPSplitViewDelegate_splitView_constrainSplitPosition_ofSubviewAt_))
|
||||
return nil;
|
||||
|
||||
return [_delegate splitView:self constrainSplitPosition:proposedMax ofSubviewAt:dividerIndex];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call the delegate splitView:resizeSubviewsWithOldSize:
|
||||
*/
|
||||
- (void)_sendDelegateSplitViewResizeSubviewsWithOldSize:(CGSize)oldSize
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPSplitViewDelegate_splitView_resizeSubviewsWithOldSize_))
|
||||
return;
|
||||
|
||||
[_delegate splitView:self resizeSubviewsWithOldSize:oldSize];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call the delegate splitViewWillResizeSubviews:
|
||||
*/
|
||||
- (void)_sendDelegateSplitViewWillResizeSubviews
|
||||
{
|
||||
var userInfo = nil;
|
||||
|
||||
if (_currentDivider !== CPNotFound)
|
||||
userInfo = @{ @"CPSplitViewDividerIndex": _currentDivider };
|
||||
|
||||
if (_implementedDelegateMethods & CPSplitViewDelegate_splitViewWillResizeSubviews_)
|
||||
[_delegate splitViewWillResizeSubviews:[[CPNotification alloc] initWithName:CPSplitViewWillResizeSubviewsNotification object:self userInfo:userInfo]];
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPSplitViewWillResizeSubviewsNotification object:self userInfo:userInfo];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call the delegate splitViewDidResizeSubviews:
|
||||
*/
|
||||
- (void)_sendDelegateSplitViewDidResizeSubviews
|
||||
{
|
||||
var userInfo = nil;
|
||||
|
||||
if (_currentDivider !== CPNotFound)
|
||||
userInfo = @{ @"CPSplitViewDividerIndex": _currentDivider };
|
||||
|
||||
if (_implementedDelegateMethods & CPSplitViewDelegate_splitViewDidResizeSubviews_)
|
||||
[_delegate splitViewDidResizeSubviews:[[CPNotification alloc] initWithName:CPSplitViewDidResizeSubviewsNotification object:self userInfo:userInfo]];
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPSplitViewDidResizeSubviewsNotification object:self userInfo:userInfo];
|
||||
|
||||
[self updateTrackingAreas];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
|
||||
CPSplitViewIsVerticalKey = "CPSplitViewIsVerticalKey",
|
||||
CPSplitViewIsPaneSplitterKey = "CPSplitViewIsPaneSplitterKey",
|
||||
@@ -1243,6 +1469,7 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
|
||||
|
||||
_currentDivider = CPNotFound;
|
||||
_shouldAutosave = YES;
|
||||
_isTracking = NO;
|
||||
|
||||
_DOMDividerElements = [];
|
||||
|
||||
|
||||
+28
-21
@@ -25,7 +25,6 @@
|
||||
@import "CPTextField.j"
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
CPStepper is an implementation of Cocoa NSStepper.
|
||||
|
||||
@@ -53,9 +52,9 @@
|
||||
@param maxValue the maximal acceptable value of the stepper
|
||||
@return Initialized CPStepper
|
||||
*/
|
||||
+ (CPStepper)stepperWithInitialValue:(float)aValue minValue:(float)aMinValue maxValue:(float)aMaxValue
|
||||
+ (id)stepperWithInitialValue:(float)aValue minValue:(float)aMinValue maxValue:(float)aMaxValue
|
||||
{
|
||||
var stepper = [[CPStepper alloc] initWithFrame:CGRectMakeZero()];
|
||||
var stepper = [[self alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[stepper setDoubleValue:aValue];
|
||||
[stepper setMinValue:aMinValue];
|
||||
@@ -75,14 +74,14 @@
|
||||
|
||||
@return Initialized CPStepper
|
||||
*/
|
||||
+ (CPStepper)stepper
|
||||
+ (id)stepper
|
||||
{
|
||||
return [CPStepper stepperWithInitialValue:0.0 minValue:0.0 maxValue:59.0];
|
||||
}
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding == CPValueBinding || aBinding == CPMinValueBinding || aBinding == CPMaxValueBinding)
|
||||
if (aBinding === CPValueBinding || aBinding === CPMinValueBinding || aBinding === CPMaxValueBinding)
|
||||
return [_CPStepperValueBinder class];
|
||||
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
@@ -90,7 +89,7 @@
|
||||
|
||||
- (CPString)_replacementKeyPathForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding == CPValueBinding)
|
||||
if (aBinding === CPValueBinding)
|
||||
return @"doubleValue";
|
||||
|
||||
return [super _replacementKeyPathForBinding:aBinding];
|
||||
@@ -138,9 +137,16 @@
|
||||
[self setContinuous:_autorepeat];
|
||||
[self addSubview:_buttonDown];
|
||||
|
||||
[self _sizeToFit];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)setControlSize:(CPControlSize)aControlSize
|
||||
{
|
||||
[super setControlSize:aControlSize];
|
||||
[self _sizeToFit];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Superclass overrides
|
||||
|
||||
@@ -159,8 +165,8 @@
|
||||
|
||||
- (void)setFrame:(CGRect)aFrame
|
||||
{
|
||||
var upSize = [self valueForThemeAttribute:@"up-button-size"],
|
||||
downSize = [self valueForThemeAttribute:@"down-button-size"],
|
||||
var upSize = [self currentValueForThemeAttribute:@"up-button-size"],
|
||||
downSize = [self currentValueForThemeAttribute:@"down-button-size"],
|
||||
minSize = CGSizeMake(upSize.width, upSize.height + downSize.height),
|
||||
frame = CGRectMakeCopy(aFrame);
|
||||
|
||||
@@ -172,21 +178,22 @@
|
||||
/*! @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);
|
||||
var controlSizeThemeState = [self _controlSizeThemeState],
|
||||
aFrame = [self frame],
|
||||
upSize = [self valueForThemeAttribute:@"up-button-size" inState:controlSizeThemeState],
|
||||
downSize = [self valueForThemeAttribute:@"down-button-size" inState:controlSizeThemeState],
|
||||
upFrame = CGRectMake(0, 0, upSize.width, upSize.height),
|
||||
downFrame = CGRectMake(0, 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];
|
||||
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inState:CPThemeStateBordered] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered];
|
||||
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inState:CPThemeStateBordered | CPThemeStateDisabled] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateDisabled];
|
||||
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inState:CPThemeStateBordered | CPThemeStateHighlighted] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateHighlighted];
|
||||
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inStates:[controlSizeThemeState, CPThemeStateBordered]] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered];
|
||||
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inStates:[controlSizeThemeState, CPThemeStateBordered, CPThemeStateDisabled]] forThemeAttribute:@"bezel-color" inStates:[CPThemeStateBordered, CPThemeStateDisabled]];
|
||||
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inStates:[controlSizeThemeState, CPThemeStateBordered, CPThemeStateHighlighted]] forThemeAttribute:@"bezel-color" inStates:[CPThemeStateBordered, CPThemeStateHighlighted]];
|
||||
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inStates:[controlSizeThemeState, CPThemeStateBordered]] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered];
|
||||
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inStates:[controlSizeThemeState, CPThemeStateBordered, CPThemeStateDisabled]] forThemeAttribute:@"bezel-color" inStates:[CPThemeStateBordered, CPThemeStateDisabled]];
|
||||
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inStates:[controlSizeThemeState, CPThemeStateBordered, CPThemeStateHighlighted]] forThemeAttribute:@"bezel-color" inStates:[CPThemeStateBordered, CPThemeStateHighlighted]];
|
||||
}
|
||||
|
||||
- (void)_sizeToFit
|
||||
@@ -232,7 +239,7 @@
|
||||
if (![self isEnabled])
|
||||
return;
|
||||
|
||||
if (aSender == _buttonUp)
|
||||
if (aSender === _buttonUp)
|
||||
[self setDoubleValue:([self doubleValue] + _increment)];
|
||||
else
|
||||
[self setDoubleValue:([self doubleValue] - _increment)];
|
||||
@@ -285,7 +292,7 @@
|
||||
|
||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options forBinding:(CPString)aBinding
|
||||
{
|
||||
var placeholder = (aBinding == CPMaxValueBinding) ? [_source maxValue] : [_source minValue];
|
||||
var placeholder = (aBinding === CPMaxValueBinding) ? [_source maxValue] : [_source minValue];
|
||||
|
||||
[super _updatePlaceholdersWithOptions:options];
|
||||
|
||||
|
||||
@@ -24,9 +24,13 @@
|
||||
|
||||
@import "CGGeometry.j"
|
||||
@import "CPPlatformString.j"
|
||||
@import "CPFont.j"
|
||||
@import "CPCompatibility.j"
|
||||
|
||||
|
||||
var CPStringSizeWithFontInWidthCache = {};
|
||||
var CPStringSizeWithFontInWidthCache = [],
|
||||
CPStringSizeWithFontHeightCache = [],
|
||||
CPStringSizeMeasuringContext;
|
||||
|
||||
CPStringSizeCachingEnabled = YES;
|
||||
|
||||
@@ -53,21 +57,67 @@ CPStringSizeCachingEnabled = YES;
|
||||
return [self sizeWithFont:aFont inWidth:NULL];
|
||||
}
|
||||
|
||||
- (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth
|
||||
+ (void) initialize
|
||||
{
|
||||
if ([self class] != [CPString class])
|
||||
return;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
if (CPFeatureIsCompatible(CPHTMLCanvasFeature) && !CPStringSizeMeasuringContext)
|
||||
CPStringSizeMeasuringContext = CGBitmapGraphicsContextCreate();
|
||||
#endif
|
||||
}
|
||||
|
||||
- (CGSize)_sizeWithFont:(CPFont)aFont inWidth:(float)aWidth
|
||||
{
|
||||
var size;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
if (!CPStringSizeCachingEnabled)
|
||||
return [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
|
||||
|
||||
var cacheKey = self + [aFont cssString] + aWidth,
|
||||
size = CPStringSizeWithFontInWidthCache[cacheKey];
|
||||
var sizeCacheForFont = CPStringSizeWithFontInWidthCache[self];
|
||||
|
||||
if (size === undefined)
|
||||
{
|
||||
if (sizeCacheForFont === undefined)
|
||||
sizeCacheForFont = CPStringSizeWithFontInWidthCache[self] = [];
|
||||
|
||||
if (!aWidth)
|
||||
aWidth = '0';
|
||||
|
||||
var cssString = [aFont cssString],
|
||||
cacheKey = cssString + '_' + aWidth;
|
||||
|
||||
size = sizeCacheForFont[cacheKey];
|
||||
|
||||
if (size !== undefined && sizeCacheForFont.hasOwnProperty(cacheKey))
|
||||
return CGSizeMakeCopy(size);
|
||||
|
||||
if (!CPFeatureIsCompatible(CPHTMLCanvasFeature) || aWidth > 0)
|
||||
size = [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
|
||||
CPStringSizeWithFontInWidthCache[cacheKey] = size;
|
||||
else
|
||||
{
|
||||
if (CPPlatformHasBug(CPTextSizingAlwaysNeedsSetFontBug) || CPStringSizeMeasuringContext.font !== cssString)
|
||||
CPStringSizeMeasuringContext.font = cssString;
|
||||
|
||||
var fontHeight = CPStringSizeWithFontHeightCache[cssString];
|
||||
|
||||
if (fontHeight === undefined)
|
||||
fontHeight = CPStringSizeWithFontHeightCache[cssString] = [aFont defaultLineHeightForFont];
|
||||
|
||||
size = CGSizeMake(CPStringSizeMeasuringContext.measureText(self).width, fontHeight);
|
||||
}
|
||||
|
||||
sizeCacheForFont[cacheKey] = size;
|
||||
#else
|
||||
size = CGSizeMake(0, 0);
|
||||
#endif
|
||||
return CGSizeMakeCopy(size);
|
||||
}
|
||||
|
||||
- (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth
|
||||
{
|
||||
var size = [self _sizeWithFont:aFont inWidth:aWidth];
|
||||
return CGSizeMake(CEIL(size.width), size.height);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+506
-107
@@ -25,6 +25,7 @@
|
||||
@import "CPTabViewItem.j"
|
||||
@import "CPView.j"
|
||||
|
||||
@typedef CPTabViewType
|
||||
CPTopTabsBezelBorder = 0;
|
||||
//CPLeftTabsBezelBorder = 1;
|
||||
CPBottomTabsBezelBorder = 2;
|
||||
@@ -33,10 +34,25 @@ CPNoTabsBezelBorder = 4; //Displays no tabs and has a bezeled border.
|
||||
CPNoTabsLineBorder = 5; //Has no tabs and displays a line border.
|
||||
CPNoTabsNoBorder = 6; //Displays no tabs and no border.
|
||||
|
||||
var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
CPTabViewShouldSelectTabViewItemSelector = 2,
|
||||
CPTabViewWillSelectTabViewItemSelector = 4,
|
||||
CPTabViewDidChangeNumberOfTabViewItemsSelector = 8;
|
||||
@class _CPTabViewBox
|
||||
@class _CPSegmentedControl
|
||||
|
||||
var CPTabViewDidSelectTabViewItemSelector = 1 << 1,
|
||||
CPTabViewShouldSelectTabViewItemSelector = 1 << 2,
|
||||
CPTabViewWillSelectTabViewItemSelector = 1 << 3,
|
||||
CPTabViewDidChangeNumberOfTabViewItemsSelector = 1 << 4;
|
||||
|
||||
|
||||
@protocol CPTabViewDelegate <CPObject>
|
||||
|
||||
@optional
|
||||
- (BOOL)tabView:(CPTabView)tabView shouldSelectTabViewItem:(CPTabViewItem)tabViewItem;
|
||||
- (void)tabView:(CPTabView)tabView didSelectTabViewItem:(CPTabViewItem)tabViewItem;
|
||||
- (void)tabView:(CPTabView)tabView willSelectTabViewItem:(CPTabViewItem)tabViewItem;
|
||||
- (void)tabViewDidChangeNumberOfTabViewItems:(CPTabView)tabView;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -48,27 +64,27 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
@implementation CPTabView : CPView
|
||||
{
|
||||
CPArray _items;
|
||||
CPArray _items;
|
||||
|
||||
CPSegmentedControl _tabs;
|
||||
CPBox _box;
|
||||
_CPSegmentedControl _tabs;
|
||||
_CPTabViewBox _box;
|
||||
CPView _placeholderView @accessors;
|
||||
|
||||
CPNumber _selectedIndex;
|
||||
CPTabViewItem _selectedTabViewItem;
|
||||
|
||||
CPTabViewType _type;
|
||||
CPFont _font;
|
||||
CPTabViewType _type;
|
||||
CPFont _font;
|
||||
|
||||
id _delegate;
|
||||
unsigned _delegateSelectors;
|
||||
id <CPTabViewDelegate> _delegate;
|
||||
unsigned _delegateSelectors;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
_items = [CPArray array];
|
||||
|
||||
[self _init];
|
||||
_selectedTabViewItem = nil;
|
||||
[self setTabViewType:CPTopTabsBezelBorder];
|
||||
}
|
||||
|
||||
@@ -77,19 +93,26 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_selectedIndex = CPNotFound;
|
||||
_tabs = [[_CPSegmentedControl alloc] initWithFrame:CGRectMakeZero()];
|
||||
[_tabs setTabView:self];
|
||||
[_tabs setSegments:[CPArray array]];
|
||||
|
||||
_tabs = [[CPSegmentedControl alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
|
||||
[_tabs setHitTests:NO];
|
||||
|
||||
var height = [_tabs valueForThemeAttribute:@"default-height"];
|
||||
var height = [_tabs valueForThemeAttribute:@"min-size"].height;
|
||||
[_tabs setFrameSize:CGSizeMake(0, height)];
|
||||
|
||||
_box = [[CPBox alloc] initWithFrame:[self bounds]];
|
||||
_box = [[_CPTabViewBox alloc] initWithFrame:[self bounds]];
|
||||
[_box setTabView:self];
|
||||
[self setBackgroundColor:[CPColor colorWithCalibratedWhite:0.95 alpha:1.0]];
|
||||
|
||||
[self addSubview:_box];
|
||||
[self addSubview:_tabs];
|
||||
|
||||
_placeholderView = nil;
|
||||
}
|
||||
|
||||
- (CPArray)items
|
||||
{
|
||||
return [_tabs segments];
|
||||
}
|
||||
|
||||
// Adding and Removing Tabs
|
||||
@@ -99,7 +122,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)addTabViewItem:(CPTabViewItem)aTabViewItem
|
||||
{
|
||||
[self insertTabViewItem:aTabViewItem atIndex:[_items count]];
|
||||
[self insertTabViewItem:aTabViewItem atIndex:[self numberOfTabViewItems]];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -109,15 +132,24 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)insertTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(CPUInteger)anIndex
|
||||
{
|
||||
[_items insertObject:aTabViewItem atIndex:anIndex];
|
||||
[self _insertTabViewItems:[aTabViewItem] atIndexes:[CPIndexSet indexSetWithIndex:anIndex]];
|
||||
}
|
||||
|
||||
[self _updateItems];
|
||||
[self _repositionTabs];
|
||||
- (void)_insertTabViewItems:(CPArray)tabViewItems atIndexes:(CPIndexSet)indexes
|
||||
{
|
||||
var prevItemsCount = [self numberOfTabViewItems];
|
||||
|
||||
[aTabViewItem _setTabView:self];
|
||||
[_tabs insertSegments:tabViewItems atIndexes:indexes];
|
||||
[tabViewItems makeObjectsPerformSelector:@selector(_setTabView:) withObject:self];
|
||||
|
||||
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
|
||||
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
|
||||
[self tileWithChangedItem:[tabViewItems firstObject]];
|
||||
[self _reverseSetContent];
|
||||
|
||||
[self _sendDelegateTabViewDidChangeNumberOfTabViewItems];
|
||||
|
||||
// Do not allow empty selection if selection bindings are not enabled.
|
||||
if (prevItemsCount == 0 && [self numberOfTabViewItems] > 0 && ![self _isSelectionBinded])
|
||||
[self _selectTabViewItemAtIndex:0];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -126,23 +158,39 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)removeTabViewItem:(CPTabViewItem)aTabViewItem
|
||||
{
|
||||
var count = [_items count];
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
if ([_items objectAtIndex:i] === aTabViewItem)
|
||||
{
|
||||
[_items removeObjectAtIndex:i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
var idx = [[self items] indexOfObjectIdenticalTo:aTabViewItem];
|
||||
|
||||
[self _updateItems];
|
||||
[self _repositionTabs];
|
||||
if (idx == CPNotFound)
|
||||
return;
|
||||
|
||||
[_tabs removeSegmentsAtIndexes:[CPIndexSet indexSetWithIndex:idx]];
|
||||
[aTabViewItem _setTabView:nil];
|
||||
|
||||
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
|
||||
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
|
||||
[self tileWithChangedItem:nil];
|
||||
[self _didRemoveTabViewItem:aTabViewItem atIndex:idx];
|
||||
[self _reverseSetContent];
|
||||
|
||||
[self _sendDelegateTabViewDidChangeNumberOfTabViewItems];
|
||||
}
|
||||
|
||||
- (void)_didRemoveTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(CPInteger)idx
|
||||
{
|
||||
// If the selection is managed by bindings, let the binder do that.
|
||||
if ([self _isSelectionBinded])
|
||||
return;
|
||||
|
||||
if (_selectedTabViewItem == aTabViewItem)
|
||||
{
|
||||
var didSelect = NO;
|
||||
|
||||
if (idx > 0)
|
||||
didSelect = [self selectTabViewItemAtIndex:idx - 1];
|
||||
else if ([self numberOfTabViewItems] > 0)
|
||||
didSelect = [self selectTabViewItemAtIndex:0];
|
||||
|
||||
if (didSelect == NO)
|
||||
_selectedTabViewItem == nil;
|
||||
}
|
||||
}
|
||||
|
||||
// Accessing Tabs
|
||||
@@ -153,7 +201,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (int)indexOfTabViewItem:(CPTabViewItem)aTabViewItem
|
||||
{
|
||||
return [_items indexOfObjectIdenticalTo:aTabViewItem];
|
||||
return [[self items] indexOfObjectIdenticalTo:aTabViewItem];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -163,11 +211,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (int)indexOfTabViewItemWithIdentifier:(CPString)anIdentifier
|
||||
{
|
||||
for (var index = [_items count]; index >= 0; index--)
|
||||
if ([[_items[index] identifier] isEqual:anIdentifier])
|
||||
return index;
|
||||
|
||||
return CPNotFound;
|
||||
return [[self items] indexOfObjectPassingTest:function(item, idx, stop)
|
||||
{
|
||||
return [[item identifier] isEqual:anIdentifier];
|
||||
}];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -176,7 +223,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (unsigned)numberOfTabViewItems
|
||||
{
|
||||
return [_items count];
|
||||
return [[self items] count];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -185,7 +232,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (CPTabViewItem)tabViewItemAtIndex:(CPUInteger)anIndex
|
||||
{
|
||||
return [_items objectAtIndex:anIndex];
|
||||
return [[self items] objectAtIndex:anIndex];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -194,7 +241,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (CPArray)tabViewItems
|
||||
{
|
||||
return [_items copy]; // Copy?
|
||||
return [[self items] copy]; // Copy?
|
||||
}
|
||||
|
||||
// Selecting a Tab
|
||||
@@ -204,7 +251,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)selectFirstTabViewItem:(id)aSender
|
||||
{
|
||||
if ([_items count] === 0)
|
||||
if ([self numberOfTabViewItems] === 0)
|
||||
return; // throw?
|
||||
|
||||
[self selectTabViewItemAtIndex:0];
|
||||
@@ -216,10 +263,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)selectLastTabViewItem:(id)aSender
|
||||
{
|
||||
if ([_items count] === 0)
|
||||
if ([self numberOfTabViewItems] === 0)
|
||||
return; // throw?
|
||||
|
||||
[self selectTabViewItemAtIndex:[_items count] - 1];
|
||||
[self selectTabViewItemAtIndex:[self numberOfTabViewItems] - 1];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -228,12 +275,12 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)selectNextTabViewItem:(id)aSender
|
||||
{
|
||||
if (_selectedIndex === CPNotFound)
|
||||
if (_selectedTabViewItem === nil)
|
||||
return;
|
||||
|
||||
var nextIndex = _selectedIndex + 1;
|
||||
var nextIndex = [self indexOfTabViewItem:_selectedTabViewItem] + 1;
|
||||
|
||||
if (nextIndex === [_items count])
|
||||
if (nextIndex === [self numberOfTabViewItems])
|
||||
// does nothing. According to spec at (http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Reference/ApplicationKit/Classes/NSTabView_Class/Reference/Reference.html#//apple_ref/occ/instm/NSTabView/selectNextTabViewItem:)
|
||||
return;
|
||||
|
||||
@@ -246,10 +293,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)selectPreviousTabViewItem:(id)aSender
|
||||
{
|
||||
if (_selectedIndex === CPNotFound)
|
||||
if (_selectedTabViewItem === nil)
|
||||
return;
|
||||
|
||||
var previousIndex = _selectedIndex - 1;
|
||||
var previousIndex = [self indexOfTabViewItem:_selectedTabViewItem] - 1;
|
||||
|
||||
if (previousIndex < 0)
|
||||
return; // does nothing. See above.
|
||||
@@ -272,36 +319,70 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (BOOL)selectTabViewItemAtIndex:(CPUInteger)anIndex
|
||||
{
|
||||
if (anIndex === _selectedIndex)
|
||||
return;
|
||||
|
||||
var aTabViewItem = [self tabViewItemAtIndex:anIndex];
|
||||
|
||||
if ((_delegateSelectors & CPTabViewShouldSelectTabViewItemSelector) && ![_delegate tabView:self shouldSelectTabViewItem:aTabViewItem])
|
||||
if (![self _selectTabViewItemAtIndex:anIndex])
|
||||
return NO;
|
||||
|
||||
if (_delegateSelectors & CPTabViewWillSelectTabViewItemSelector)
|
||||
[_delegate tabView:self willSelectTabViewItem:aTabViewItem];
|
||||
|
||||
[_tabs selectSegmentWithTag:anIndex];
|
||||
[self _setSelectedIndex:anIndex];
|
||||
|
||||
if (_delegateSelectors & CPTabViewDidSelectTabViewItemSelector)
|
||||
[_delegate tabView:self didSelectTabViewItem:aTabViewItem];
|
||||
[self _reverseSetSelectedIndex];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
// Like selectTabViewItemAtIndex: but without bindings interaction
|
||||
- (BOOL)_selectTabViewItemAtIndex:(CPUInteger)anIndex
|
||||
{
|
||||
var aTabViewItem = [self tabViewItemAtIndex:anIndex];
|
||||
|
||||
if (aTabViewItem == _selectedTabViewItem)
|
||||
return NO;
|
||||
|
||||
if (![self _sendDelegateShouldSelectTabViewItem:aTabViewItem])
|
||||
return NO;
|
||||
|
||||
[self _sendDelegateWillSelectTabViewItem:aTabViewItem];
|
||||
|
||||
[_tabs setSelectedSegment:anIndex];
|
||||
_selectedTabViewItem = aTabViewItem;
|
||||
[self _loadTabViewItem:aTabViewItem];
|
||||
|
||||
[self _sendDelegateDidSelectTabViewItem:aTabViewItem];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)_loadTabViewItem:(CPTabViewItem)aTabViewItem
|
||||
{
|
||||
var controller = [aTabViewItem viewController];
|
||||
|
||||
if (controller !== nil && ![controller isViewLoaded])
|
||||
{
|
||||
[controller loadViewWithCompletionHandler:function(view, error)
|
||||
{
|
||||
if (error !== nil)
|
||||
{
|
||||
CPLog.warn("Could not load the view for item " + aTabViewItem + ". " + error);
|
||||
}
|
||||
else if (view !== nil)
|
||||
{
|
||||
[aTabViewItem setView:view];
|
||||
|
||||
if ([self selectedTabViewItem] == aTabViewItem)
|
||||
[self _displayItemView:view];
|
||||
}
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self _displayItemView:[aTabViewItem view]];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the current item being displayed.
|
||||
@return the tab view item currenly being displayed by the receiver
|
||||
*/
|
||||
- (CPTabViewItem)selectedTabViewItem
|
||||
{
|
||||
if (_selectedIndex != CPNotFound)
|
||||
return [_items objectAtIndex:_selectedIndex];
|
||||
|
||||
return nil;
|
||||
return _selectedTabViewItem;
|
||||
}
|
||||
|
||||
// Modifying the font
|
||||
@@ -362,6 +443,14 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)tileWithChangedItem:(CPTabViewItem)aTabViewItem
|
||||
{
|
||||
var segment = aTabViewItem ? [self indexOfTabViewItem:aTabViewItem] : 0;
|
||||
[_tabs tileWithChangedSegment:segment];
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
// Even if CPTabView's autoresizesSubviews is NO, _tabs and _box has to be laid out.
|
||||
@@ -405,7 +494,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
Sets the delegate for this tab view.
|
||||
@param aDelegate the tab view's delegate
|
||||
*/
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
- (void)setDelegate:(id <CPTabViewDelegate>)aDelegate
|
||||
{
|
||||
if (_delegate == aDelegate)
|
||||
return;
|
||||
@@ -437,14 +526,6 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
return [_box backgroundColor];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
var segmentIndex = [_tabs testSegment:[_tabs convertPoint:[anEvent locationInWindow] fromView:nil]];
|
||||
|
||||
if (segmentIndex != CPNotFound && [self selectTabViewItemAtIndex:segmentIndex])
|
||||
[_tabs trackSegment:anEvent];
|
||||
}
|
||||
|
||||
- (void)_repositionTabs
|
||||
{
|
||||
var horizontalCenterOfSelf = CGRectGetWidth([self bounds]) / 2,
|
||||
@@ -456,30 +537,243 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
[_tabs setCenter:CGPointMake(horizontalCenterOfSelf, verticalCenterOfTabs)];
|
||||
}
|
||||
|
||||
- (void)_setSelectedIndex:(CPNumber)index
|
||||
- (void)_displayItemView:(CPView)aView
|
||||
{
|
||||
_selectedIndex = index;
|
||||
[self _setContentViewFromItem:[_items objectAtIndex:_selectedIndex]];
|
||||
[_box setContentView:aView];
|
||||
}
|
||||
|
||||
- (void)_setContentViewFromItem:(CPTabViewItem)anItem
|
||||
// DELEGATE METHODS
|
||||
|
||||
- (BOOL)_sendDelegateShouldSelectTabViewItem:(CPTabViewItem)aTabViewItem
|
||||
{
|
||||
[_box setContentView:[anItem view]];
|
||||
if (_delegateSelectors & CPTabViewShouldSelectTabViewItemSelector)
|
||||
return [_delegate tabView:self shouldSelectTabViewItem:aTabViewItem];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)_updateItems
|
||||
- (void)_sendDelegateWillSelectTabViewItem:(CPTabViewItem)aTabViewItem
|
||||
{
|
||||
var count = [_items count];
|
||||
[_tabs setSegmentCount:count];
|
||||
if (_delegateSelectors & CPTabViewWillSelectTabViewItemSelector)
|
||||
[_delegate tabView:self willSelectTabViewItem:aTabViewItem];
|
||||
}
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
- (void)_sendDelegateDidSelectTabViewItem:(CPTabViewItem)aTabViewItem
|
||||
{
|
||||
if (_delegateSelectors & CPTabViewDidSelectTabViewItemSelector)
|
||||
[_delegate tabView:self didSelectTabViewItem:aTabViewItem];
|
||||
}
|
||||
|
||||
- (void)_sendDelegateTabViewDidChangeNumberOfTabViewItems
|
||||
{
|
||||
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
|
||||
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPTabView (BindingSupport)
|
||||
|
||||
+ (Class)_binderClassForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding == CPContentBinding)
|
||||
return [_CPTabViewContentBinder class];
|
||||
else if (aBinding == CPSelectionIndexesBinding || aBinding == CPSelectedIndexBinding)
|
||||
return [_CPTabViewSelectionBinder class];
|
||||
|
||||
return [super _binderClassForBinding:aBinding];
|
||||
}
|
||||
|
||||
+ (BOOL)isBindingExclusive:(CPString)aBinding
|
||||
{
|
||||
return (aBinding == CPSelectionIndexesBinding || aBinding == CPSelectedIndexBinding);
|
||||
}
|
||||
|
||||
- (void)_reverseSetContent
|
||||
{
|
||||
var theBinder = [self binderForBinding:CPContentBinding];
|
||||
[theBinder reverseSetValueFor:@"items"];
|
||||
}
|
||||
|
||||
- (void)_reverseSetSelectedIndex
|
||||
{
|
||||
var theBinder = [self binderForBinding:CPSelectionIndexesBinding];
|
||||
|
||||
if (theBinder !== nil)
|
||||
[theBinder reverseSetValueFor:@"selectionIndexes"];
|
||||
else
|
||||
{
|
||||
[_tabs setLabel:[[_items objectAtIndex:i] label] forSegment:i];
|
||||
[_tabs setTag:i forSegment:i];
|
||||
theBinder = [self binderForBinding:CPSelectedIndexBinding];
|
||||
[theBinder reverseSetValueFor:@"selectedIndex"];
|
||||
}
|
||||
}
|
||||
|
||||
- (CPBinder)binderForBinding:(CPString)aBinding
|
||||
{
|
||||
var cls = [[self class] _binderClassForBinding:aBinding];
|
||||
return [cls getBinding:aBinding forObject:self];
|
||||
}
|
||||
|
||||
- (BOOL)_isSelectionBinded
|
||||
{
|
||||
return [self binderForBinding:CPSelectionIndexesBinding] || [self binderForBinding:CPSelectedIndexBinding];
|
||||
}
|
||||
|
||||
- (void)setItems:(CPArray)tabViewItems
|
||||
{
|
||||
if ([tabViewItems isEqualToArray:[_tabs segments]])
|
||||
return;
|
||||
|
||||
[[self items] makeObjectsPerformSelector:@selector(_setTabView:) withObject:nil];
|
||||
[_tabs setSegments:tabViewItems];
|
||||
[tabViewItems makeObjectsPerformSelector:@selector(_setTabView:) withObject:self];
|
||||
|
||||
[self tileWithChangedItem:nil];
|
||||
|
||||
// Update the selection because setSegments: did remove all previous segments AND the selection.
|
||||
[_tabs setSelectedSegment:[self indexOfTabViewItem:_selectedTabViewItem]];
|
||||
|
||||
// should we send delegate methods in bindings mode ?
|
||||
//[self _delegateTabViewDidChangeNumberOfTabViewItems:self];
|
||||
}
|
||||
|
||||
- (void)_deselectAll
|
||||
{
|
||||
[_tabs setSelectedSegment:-1];
|
||||
_selectedTabViewItem = nil;
|
||||
}
|
||||
|
||||
- (void)_displayPlaceholder:(CPString)aPlaceholder
|
||||
{
|
||||
if (_placeholderView == nil)
|
||||
{
|
||||
_placeholderView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
var textField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||
[textField setTag:1000];
|
||||
[textField setTextColor:[CPColor whiteColor]];
|
||||
[textField setFont:[CPFont boldFontWithName:@"Geneva" size:18 italic:YES]];
|
||||
[_placeholderView addSubview:textField];
|
||||
}
|
||||
|
||||
if (_selectedIndex === CPNotFound)
|
||||
[self selectFirstTabViewItem:self];
|
||||
var textField = [_placeholderView viewWithTag:1000];
|
||||
[textField setStringValue:aPlaceholder];
|
||||
[textField sizeToFit];
|
||||
|
||||
var boxBounds = [_box bounds],
|
||||
textFieldBounds = [textField bounds],
|
||||
origin = CGPointMake(CGRectGetWidth(boxBounds)/2 - CGRectGetWidth(textFieldBounds)/2, CGRectGetHeight(boxBounds)/2 - CGRectGetHeight(textFieldBounds));
|
||||
|
||||
[textField setFrameOrigin:origin];
|
||||
|
||||
[self _displayItemView:_placeholderView];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Override
|
||||
|
||||
/*!
|
||||
Enabled controls accept first mouse by default.
|
||||
*/
|
||||
- (BOOL)acceptsFirstMouse:(CPEvent)anEvent
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var _CPTabViewContentBinderNull = @"NO CONTENT";
|
||||
|
||||
@implementation _CPTabViewContentBinder : CPBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
||||
{
|
||||
[super _updatePlaceholdersWithOptions:options];
|
||||
[self _setPlaceholder:_CPTabViewContentBinderNull forMarker:CPNullMarker isDefault:YES];
|
||||
}
|
||||
|
||||
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||
{
|
||||
[_source setItems:@[]];
|
||||
[_source _setPlaceholderView:aValue];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
[_source setItems:aValue];
|
||||
}
|
||||
|
||||
- (id)valueForBinding:(CPString)aBinding
|
||||
{
|
||||
return [_source items];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var _CPTabViewSelectionBinderMultipleValues = @"Multiple Selection",
|
||||
_CPTabViewSelectionBinderNoSelection = @"No Selection";
|
||||
|
||||
@implementation _CPTabViewSelectionBinder : CPBinder
|
||||
{
|
||||
}
|
||||
|
||||
- (void)_updatePlaceholdersWithOptions:(CPDictionary)options
|
||||
{
|
||||
[super _updatePlaceholdersWithOptions:options];
|
||||
|
||||
[self _setPlaceholder:_CPTabViewSelectionBinderMultipleValues forMarker:CPMultipleValuesMarker isDefault:YES];
|
||||
[self _setPlaceholder:_CPTabViewSelectionBinderNoSelection forMarker:CPNoSelectionMarker isDefault:YES];
|
||||
}
|
||||
|
||||
- (void)setPlaceholderValue:(id)aValue withMarker:(CPString)aMarker forBinding:(CPString)aBinding
|
||||
{
|
||||
if (aMarker == CPNoSelectionMarker || aMarker == CPNullMarker)
|
||||
[_source _deselectAll];
|
||||
|
||||
[_source _displayPlaceholder:aValue];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding == CPSelectionIndexesBinding)
|
||||
{
|
||||
if (aValue == nil || [aValue count] == 0)
|
||||
{
|
||||
[_source _deselectAll];
|
||||
[_source _displayPlaceholder:_CPTabViewSelectionBinderNoSelection];
|
||||
}
|
||||
else if ([aValue count] > 1)
|
||||
[_source _displayPlaceholder:_CPTabViewSelectionBinderMultipleValues];
|
||||
else if ([aValue firstIndex] < [_source numberOfTabViewItems])
|
||||
[_source _selectTabViewItemAtIndex:[aValue firstIndex]];
|
||||
}
|
||||
else if (aBinding == CPSelectedIndexBinding)
|
||||
{
|
||||
if (aValue == CPNotFound)
|
||||
{
|
||||
[_source _deselectAll];
|
||||
[_source _displayPlaceholder:_CPTabViewSelectionBinderNoSelection];
|
||||
}
|
||||
else if (aValue < [_source numberOfTabViewItems])
|
||||
[_source _selectTabViewItemAtIndex:aValue];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)valueForBinding:(CPString)aBinding
|
||||
{
|
||||
if (aBinding == CPSelectionIndexesBinding)
|
||||
{
|
||||
var result = [CPIndexSet indexSet],
|
||||
idx = [_source indexOfTabViewItem:[_source selectedTabViewItem]];
|
||||
|
||||
if (idx !== CPNotFound)
|
||||
[result addIndex:idx];
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (aBinding == CPSelectedIndexBinding)
|
||||
return [_source indexOfTabViewItem:[_source selectedTabViewItem]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -501,12 +795,13 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
||||
_font = [aCoder decodeObjectForKey:CPTabViewFontKey];
|
||||
[_tabs setFont:_font];
|
||||
|
||||
_items = [aCoder decodeObjectForKey:CPTabViewItemsKey];
|
||||
[_items makeObjectsPerformSelector:@selector(_setTabView:) withObject:self];
|
||||
var items = [aCoder decodeObjectForKey:CPTabViewItemsKey] || [CPArray array];
|
||||
[self _insertTabViewItems:items atIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [items count])]];
|
||||
|
||||
[self setDelegate:[aCoder decodeObjectForKey:CPTabViewDelegateKey]];
|
||||
|
||||
self.selectOnAwake = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
|
||||
_selectedTabViewItem = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
|
||||
|
||||
_type = [aCoder decodeIntForKey:CPTabViewTypeKey];
|
||||
}
|
||||
|
||||
@@ -515,14 +810,23 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
||||
|
||||
- (void)awakeFromCib
|
||||
{
|
||||
[super awakeFromCib];
|
||||
|
||||
// This cannot be run in initWithCoder because it might call selectTabViewItem:, which is
|
||||
// not safe to call before the views of the tab views items are fully decoded.
|
||||
[self _updateItems];
|
||||
|
||||
if (self.selectOnAwake)
|
||||
if (_selectedTabViewItem)
|
||||
{
|
||||
[self selectTabViewItem:self.selectOnAwake];
|
||||
delete self.selectOnAwake;
|
||||
var idx = [self indexOfTabViewItem:_selectedTabViewItem];
|
||||
|
||||
if (idx !== CPNotFound)
|
||||
{
|
||||
// Temporarily set the selected item to not selected.
|
||||
// It allows the initial selection to be made correctly.
|
||||
_selectedTabViewItem = nil;
|
||||
|
||||
[self selectTabViewItemAtIndex:idx];
|
||||
}
|
||||
}
|
||||
|
||||
var type = _type;
|
||||
@@ -544,9 +848,7 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
||||
|
||||
[aCoder encodeObject:_items forKey:CPTabViewItemsKey];
|
||||
|
||||
var selected = [self selectedTabViewItem];
|
||||
if (selected)
|
||||
[aCoder encodeObject:selected forKey:CPTabViewSelectedItemKey];
|
||||
[aCoder encodeConditionalObject:_selectedTabViewItem forKey:CPTabViewSelectedItemKey];
|
||||
|
||||
[aCoder encodeInt:_type forKey:CPTabViewTypeKey];
|
||||
[aCoder encodeObject:_font forKey:CPTabViewFontKey];
|
||||
@@ -555,3 +857,100 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPTabViewBox : CPBox
|
||||
{
|
||||
CPTabView _tabView @accessors(property=tabView);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Override
|
||||
|
||||
- (CPView)hitTest:(CGPoint)aPoint
|
||||
{
|
||||
// Here we check if we have clicked on the segmentedControl of the tabView or not
|
||||
// If YES, the CPBox should not handle the click
|
||||
var segmentIndex = [_tabView._tabs testSegment:[_tabView._tabs convertPoint:aPoint fromView:[self superview]]];
|
||||
|
||||
if (segmentIndex != CPNotFound)
|
||||
return nil;
|
||||
|
||||
return [super hitTest:aPoint];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
# pragma mark -
|
||||
|
||||
// This subclass of CPSegmentedControl implements specific behaviour needed by CPTabView, which
|
||||
// differs in some ways from normal CPSegmentedControl habits :
|
||||
//
|
||||
// - all items are enabled
|
||||
// - when you select a tab (mouse down, holding) and drag upon another tab, the second one reacts
|
||||
// (showing a pushed state) and can then be selected by releasing the mouse over it.
|
||||
// - a delegate has the opportunity to accept or not the selection of an item
|
||||
|
||||
@implementation _CPSegmentedControl : CPSegmentedControl
|
||||
{
|
||||
CPTabView _tabView @accessors(property=tabView);
|
||||
}
|
||||
|
||||
- (void)trackSegment:(CPEvent)anEvent
|
||||
{
|
||||
var type = [anEvent type],
|
||||
location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||
currentSegment = [self testSegment:location];
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CPLeftMouseUp:
|
||||
|
||||
if (_trackingSegment === CPNotFound)
|
||||
return;
|
||||
|
||||
if ((_trackingSegment !== _selectedSegment) &&
|
||||
[_tabView _sendDelegateShouldSelectTabViewItem:[_tabView tabViewItemAtIndex:_trackingSegment]])
|
||||
{
|
||||
[self setSelected:YES forSegment:_trackingSegment];
|
||||
_selectedSegment = _trackingSegment;
|
||||
[_tabView selectTabViewItemAtIndex:_selectedSegment];
|
||||
}
|
||||
|
||||
[self drawSegmentBezel:_trackingSegment highlight:NO];
|
||||
|
||||
_trackingSegment = CPNotFound;
|
||||
|
||||
return;
|
||||
|
||||
case CPLeftMouseDown:
|
||||
|
||||
if (currentSegment > CPNotFound)
|
||||
{
|
||||
_trackingSegment = currentSegment;
|
||||
[self drawSegmentBezel:_trackingSegment highlight:YES];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CPLeftMouseDragged:
|
||||
|
||||
if (_trackingSegment !== currentSegment)
|
||||
{
|
||||
if (_trackingSegment > CPNotFound)
|
||||
[self drawSegmentBezel:_trackingSegment highlight:NO];
|
||||
|
||||
_trackingSegment = currentSegment;
|
||||
|
||||
if (_trackingSegment > CPNotFound)
|
||||
[self drawSegmentBezel:_trackingSegment highlight:YES];
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackSegment:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
+103
-10
@@ -23,7 +23,8 @@
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
@import "CPView.j"
|
||||
|
||||
@class CPTabView
|
||||
@class CPViewController
|
||||
|
||||
/*
|
||||
The tab is currently selected.
|
||||
@@ -53,14 +54,34 @@ CPPressedTab = 2;
|
||||
*/
|
||||
@implementation CPTabViewItem : CPObject
|
||||
{
|
||||
id _identifier;
|
||||
CPString _label;
|
||||
id _identifier;
|
||||
CPString _label;
|
||||
CPInteger _tag @accessors(property=tag);
|
||||
|
||||
CPView _view;
|
||||
CPView _auxiliaryView;
|
||||
CPView _view;
|
||||
CPView _auxiliaryView;
|
||||
|
||||
CPTabView _tabView;
|
||||
unsigned _tabState; // Looks like it is not yet implemented
|
||||
CPTabView _tabView;
|
||||
unsigned _tabState; // Looks like it is not yet implemented
|
||||
|
||||
CPImage _image @accessors(property=image);
|
||||
CPViewController _viewController @accessors(getter=viewController);
|
||||
|
||||
BOOL _enabled @accessors(property=enabled);
|
||||
BOOL _selected @accessors(property=selected);
|
||||
CGRect _tabRect @accessors(property=frame);
|
||||
float _width @accessors(property=width);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
*/
|
||||
+ (CPTabViewItem)tabViewItemWithViewController:(CPViewController)aViewController
|
||||
{
|
||||
var item = [[CPTabViewItem alloc] init];
|
||||
[item setViewController:aViewController];
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
@@ -68,6 +89,19 @@ CPPressedTab = 2;
|
||||
return [self initWithIdentifier:@""];
|
||||
}
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_tag = 0;
|
||||
_viewController = nil;
|
||||
_image = nil;
|
||||
_tabState = 0;
|
||||
_tabView = nil;
|
||||
_enabled = YES;
|
||||
_selected = NO;
|
||||
_tabRect = CGRectMakeZero();
|
||||
_width = 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Initializes the tab view item with the specified identifier.
|
||||
@return the initialized CPTabViewItem
|
||||
@@ -76,8 +110,12 @@ CPPressedTab = 2;
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
_identifier = anIdentifier;
|
||||
[self _init];
|
||||
|
||||
_identifier = anIdentifier;
|
||||
_label = nil;
|
||||
_view = nil;
|
||||
//_auxiliaryView = nil;
|
||||
|
||||
return self;
|
||||
}
|
||||
@@ -89,7 +127,11 @@ CPPressedTab = 2;
|
||||
*/
|
||||
- (void)setLabel:(CPString)aLabel
|
||||
{
|
||||
if ([aLabel isEqualToString:_label])
|
||||
return;
|
||||
|
||||
_label = aLabel;
|
||||
[_tabView tileWithChangedItem:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -100,6 +142,28 @@ CPPressedTab = 2;
|
||||
return _label;
|
||||
}
|
||||
|
||||
// Working With Images
|
||||
/*!
|
||||
Sets the CPTabViewItem's image.
|
||||
@param anImage the image for the item
|
||||
*/
|
||||
- (void)setImage:(CPImage)anImage
|
||||
{
|
||||
if ([anImage isEqual:_image])
|
||||
return;
|
||||
|
||||
_image = anImage;
|
||||
[_tabView tileWithChangedItem:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the CPTabViewItem's image
|
||||
*/
|
||||
- (CPImage)image
|
||||
{
|
||||
return _image;
|
||||
}
|
||||
|
||||
// Checking the Tab Display State
|
||||
/*!
|
||||
Returns the tab's current state.
|
||||
@@ -139,7 +203,7 @@ CPPressedTab = 2;
|
||||
_view = aView;
|
||||
|
||||
if ([_tabView selectedTabViewItem] == self)
|
||||
[_tabView _setContentViewFromItem:self];
|
||||
[_tabView _displayItemView:_view];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -147,6 +211,9 @@ CPPressedTab = 2;
|
||||
*/
|
||||
- (CPView)view
|
||||
{
|
||||
if (!_view && _viewController)
|
||||
return [_viewController view]; // The view controller loads here.
|
||||
|
||||
return _view;
|
||||
}
|
||||
|
||||
@@ -185,10 +252,32 @@ CPPressedTab = 2;
|
||||
_tabView = aView;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the specified view controller for the tab view item.
|
||||
@param aViewController an instance of CPViewController.
|
||||
*/
|
||||
- (void)setViewController:(CPViewController)aViewController
|
||||
{
|
||||
_viewController = aViewController;
|
||||
|
||||
var identifier = [aViewController cibName],
|
||||
title = [_viewController title];
|
||||
|
||||
if (identifier)
|
||||
_identifier = identifier;
|
||||
|
||||
if (title)
|
||||
[self setLabel:title];
|
||||
|
||||
if ([_tabView selectedTabViewItem] == self)
|
||||
[_tabView _loadTabViewItem:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPTabViewItemIdentifierKey = "CPTabViewItemIdentifierKey",
|
||||
CPTabViewItemLabelKey = "CPTabViewItemLabelKey",
|
||||
CPTabViewItemImageKey = "CPTabViewItemImageKey",
|
||||
CPTabViewItemViewKey = "CPTabViewItemViewKey",
|
||||
CPTabViewItemAuxViewKey = "CPTabViewItemAuxViewKey";
|
||||
|
||||
@@ -201,8 +290,11 @@ var CPTabViewItemIdentifierKey = "CPTabViewItemIdentifierKey",
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self _init];
|
||||
|
||||
_identifier = [aCoder decodeObjectForKey:CPTabViewItemIdentifierKey];
|
||||
_label = [aCoder decodeObjectForKey:CPTabViewItemLabelKey];
|
||||
_image = [aCoder decodeObjectForKey:CPTabViewItemImageKey];
|
||||
|
||||
_view = [aCoder decodeObjectForKey:CPTabViewItemViewKey];
|
||||
_auxiliaryView = [aCoder decodeObjectForKey:CPTabViewItemAuxViewKey];
|
||||
@@ -215,6 +307,7 @@ var CPTabViewItemIdentifierKey = "CPTabViewItemIdentifierKey",
|
||||
{
|
||||
[aCoder encodeObject:_identifier forKey:CPTabViewItemIdentifierKey];
|
||||
[aCoder encodeObject:_label forKey:CPTabViewItemLabelKey];
|
||||
[aCoder encodeObject:_image forKey:CPTabViewItemImageKey];
|
||||
|
||||
[aCoder encodeObject:_view forKey:CPTabViewItemViewKey];
|
||||
[aCoder encodeObject:_auxiliaryView forKey:CPTabViewItemAuxViewKey];
|
||||
|
||||
+25
-20
@@ -28,9 +28,8 @@
|
||||
|
||||
@import "CPTextField.j"
|
||||
|
||||
@global CPTableViewColumnDidResizeNotification
|
||||
|
||||
@class _CPTableColumnHeaderView
|
||||
@class CPTableView
|
||||
|
||||
CPTableColumnNoResizing = 0;
|
||||
CPTableColumnAutoresizingMask = 1 << 0;
|
||||
@@ -181,11 +180,11 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
columns = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(index, [tableView._exposedColumns lastIndex] - index + 1)];
|
||||
|
||||
// FIXME: Would be faster with some sort of -setNeedsDisplayInColumns: that updates a dirtyTableColumnForDisplay cache; then marked columns would relayout their data views at display time.
|
||||
[tableView _layoutDataViewsInRows:rows columns:columns];
|
||||
[tableView _layoutViewsForRowIndexes:rows columnIndexes:columns];
|
||||
[tableView tile];
|
||||
|
||||
if (!_disableResizingPosting)
|
||||
[self _postDidResizeNotificationWithOldWidth:oldWidth];
|
||||
[[self tableView] _didResizeTableColumn:self oldWidth:oldWidth];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,7 +287,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
if (width < [self minWidth])
|
||||
[self setMinWidth:width];
|
||||
else if (width > [self maxWidth])
|
||||
[self setMaxWidth:width]
|
||||
[self setMaxWidth:width];
|
||||
|
||||
if (_width !== width)
|
||||
[self setWidth:width];
|
||||
@@ -394,8 +393,8 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
*/
|
||||
- (void)setDataView:(CPView)aView
|
||||
{
|
||||
if (_dataView)
|
||||
_dataViewData = nil;
|
||||
if (_dataView === aView)
|
||||
return;
|
||||
|
||||
[aView setThemeState:CPThemeStateTableDataView];
|
||||
|
||||
@@ -500,7 +499,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
*/
|
||||
- (void)setHidden:(BOOL)shouldBeHidden
|
||||
{
|
||||
shouldBeHidden = !!shouldBeHidden
|
||||
shouldBeHidden = !!shouldBeHidden;
|
||||
|
||||
if (_isHidden === shouldBeHidden)
|
||||
return;
|
||||
@@ -541,14 +540,9 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (void)_postDidResizeNotificationWithOldWidth:(float)oldWidth
|
||||
- (CPString)description
|
||||
{
|
||||
[[self tableView] _didResizeTableColumn:self];
|
||||
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPTableViewColumnDidResizeNotification
|
||||
object:[self tableView]
|
||||
userInfo:@{ @"CPTableColumn": self, @"CPOldWidth": oldWidth }];
|
||||
return [CPString stringWithFormat:"<%@ 0x%@ identifier=%@>", [self className], [CPString stringWithHash:[self UID]], [self identifier]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -560,11 +554,22 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
- (void)setValueFor:(CPString)aBinding
|
||||
{
|
||||
var tableView = [_source tableView],
|
||||
column = [[tableView tableColumns] indexOfObjectIdenticalTo:_source],
|
||||
rowIndexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [tableView numberOfRows])],
|
||||
columnIndexes = [CPIndexSet indexSetWithIndex:column];
|
||||
newNumberOfRows = [tableView _numberOfRows];
|
||||
|
||||
[tableView reloadDataForRowIndexes:rowIndexes columnIndexes:columnIndexes];
|
||||
if ([tableView numberOfRows] == newNumberOfRows)
|
||||
{
|
||||
var rowIndexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, newNumberOfRows)],
|
||||
column = [[tableView tableColumns] indexOfObjectIdenticalTo:_source],
|
||||
columnIndexes = [CPIndexSet indexSetWithIndex:column];
|
||||
|
||||
// Reloads objectValues only, not the views.
|
||||
// FIXME: reload data for all rows or just rows intersecting exposed rows ?
|
||||
[tableView _reloadDataForRowIndexes:rowIndexes columnIndexes:columnIndexes];
|
||||
}
|
||||
else
|
||||
{
|
||||
[tableView reloadData];
|
||||
}
|
||||
}
|
||||
|
||||
- (CPSortDescriptor)_defaultSortDescriptorPrototype
|
||||
@@ -604,7 +609,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
}
|
||||
|
||||
/*!
|
||||
Binds the receiver to an object.
|
||||
Binds the receiver to an object. Note that unlike Cocoa, this works only *after* the receiver has been added to a \c CPTableView.
|
||||
|
||||
@param CPString aBinding - The binding you wish to make. Typically CPValueBinding.
|
||||
@param id anObject - The object to bind the receiver to.
|
||||
|
||||
+413
-364
File diff suppressed because it is too large
Load Diff
+1098
-831
File diff suppressed because it is too large
Load Diff
+321
-1
@@ -5,6 +5,13 @@
|
||||
* Created by Alexander Ljungberg.
|
||||
* Copyright 2010, WireLoad, LLC.
|
||||
*
|
||||
* additions from
|
||||
*
|
||||
* Daniel Boehringer on 8/02/2014.
|
||||
* Copyright Daniel Boehringer on 8/02/2014.
|
||||
*
|
||||
*
|
||||
*
|
||||
* 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,6 +27,30 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/Foundation.j>
|
||||
|
||||
@import "CPPasteboard.j"
|
||||
@import "CPView.j"
|
||||
|
||||
@global CPStringPboardType
|
||||
@global _CPSmartPboardType
|
||||
|
||||
@class CPAttributedString
|
||||
@class _CPRTFParser
|
||||
|
||||
@protocol CPTextDelegate <CPObject>
|
||||
|
||||
@optional
|
||||
- (BOOL)textShouldBeginEditing:(CPText)aTextObject;
|
||||
- (BOOL)textShouldEndEditing:(CPText)aTextObject;
|
||||
- (void)textDidBeginEditing:(CPNotification)aNotification;
|
||||
- (void)textDidChange:(CPNotification)aNotification;
|
||||
- (void)textDidEndEditing:(CPNotification)aNotification;
|
||||
|
||||
@end
|
||||
|
||||
CPParagraphSeparatorCharacter = 0x2029;
|
||||
CPLineSeparatorCharacter = 0x2028;
|
||||
CPEnterCharacter = "\u0003";
|
||||
CPBackspaceCharacter = "\u0008";
|
||||
CPTabCharacter = "\u0009";
|
||||
@@ -29,6 +60,7 @@ CPCarriageReturnCharacter = "\u000d";
|
||||
CPBackTabCharacter = "\u0019";
|
||||
CPDeleteCharacter = "\u007f";
|
||||
|
||||
@typedef CPTextMovement
|
||||
CPIllegalTextMovement = 0;
|
||||
CPOtherTextMovement = 0;
|
||||
CPReturnTextMovement = 16;
|
||||
@@ -38,4 +70,292 @@ CPLeftTextMovement = 19;
|
||||
CPRightTextMovement = 20;
|
||||
CPUpTextMovement = 21;
|
||||
CPDownTextMovement = 22;
|
||||
CPCancelTextMovement = 23;
|
||||
CPCancelTextMovement = 23;
|
||||
|
||||
@typedef CPWritingDirection
|
||||
CPWritingDirectionNatural = -1;
|
||||
CPWritingDirectionLeftToRight = 0;
|
||||
CPWritingDirectionRightToLeft = 1;
|
||||
|
||||
@typedef CPTextAlignment
|
||||
CPLeftTextAlignment = 0;
|
||||
CPRightTextAlignment = 1;
|
||||
CPCenterTextAlignment = 2;
|
||||
CPJustifiedTextAlignment = 3;
|
||||
CPNaturalTextAlignment = 4;
|
||||
|
||||
/*
|
||||
CPText notifications
|
||||
*/
|
||||
CPTextDidBeginEditingNotification = @"CPTextDidBeginEditingNotification";
|
||||
CPTextDidChangeNotification = @"CPTextDidChangeNotification";
|
||||
CPTextDidEndEditingNotification = @"CPTextDidEndEditingNotification";
|
||||
|
||||
/*
|
||||
CPTextView Notifications
|
||||
*/
|
||||
CPTextViewDidChangeSelectionNotification = @"CPTextViewDidChangeSelectionNotification";
|
||||
CPTextViewDidChangeTypingAttributesNotification = @"CPTextViewDidChangeTypingAttributesNotification";
|
||||
|
||||
/*
|
||||
FIXME: move these to CPAttributed string
|
||||
Make use of attributed keys in AppKit
|
||||
*/
|
||||
CPFontAttributeName = @"CPFontAttributeName";
|
||||
CPForegroundColorAttributeName = @"CPForegroundColorAttributeName";
|
||||
CPBackgroundColorAttributeName = @"CPBackgroundColorAttributeName";
|
||||
CPShadowAttributeName = @"CPShadowAttributeName";
|
||||
CPUnderlineStyleAttributeName = @"CPUnderlineStyleAttributeName";
|
||||
CPSuperscriptAttributeName = @"CPSuperscriptAttributeName";
|
||||
CPBaselineOffsetAttributeName = @"CPBaselineOffsetAttributeName";
|
||||
CPAttachmentAttributeName = @"CPAttachmentAttributeName";
|
||||
CPLigatureAttributeName = @"CPLigatureAttributeName";
|
||||
CPKernAttributeName = @"CPKernAttributeName";
|
||||
|
||||
@implementation CPText : CPView
|
||||
{
|
||||
BOOL _isEditable @accessors(getter=isEditable, setter=setEditable:);
|
||||
BOOL _isSelectable @accessors(getter=isSelectable, setter=setSelectable:);
|
||||
BOOL _isRichText @accessors(getter=isRichText, setter=setRichText:);
|
||||
}
|
||||
|
||||
- (void)setSelectable:(BOOL)flag
|
||||
{
|
||||
[self willChangeValueForKey:@"selectable"];
|
||||
_isSelectable = flag;
|
||||
[self didChangeValueForKey:@"selectable"];
|
||||
|
||||
if (!flag)
|
||||
[self setEditable:flag];
|
||||
}
|
||||
|
||||
- (void)setEditable:(BOOL)flag
|
||||
{
|
||||
[self willChangeValueForKey:@"editable"];
|
||||
_isEditable = flag;
|
||||
[self didChangeValueForKey:@"editable"];
|
||||
|
||||
if (flag)
|
||||
[self setSelectable:flag];
|
||||
}
|
||||
|
||||
- (void)changeFont:(id)sender
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
}
|
||||
|
||||
- (void)copy:(id)sender
|
||||
{
|
||||
var selectedRange = [self selectedRange];
|
||||
|
||||
if (selectedRange.length < 1)
|
||||
return;
|
||||
|
||||
var pasteboard = [CPPasteboard generalPasteboard];
|
||||
|
||||
// put plain representation on the pasteboad unconditionally
|
||||
[pasteboard declareTypes:[CPStringPboardType] owner:nil];
|
||||
[pasteboard setString:[[self stringValue] substringWithRange:selectedRange] forType:CPStringPboardType];
|
||||
}
|
||||
|
||||
- (id)_plainStringForPasting
|
||||
{
|
||||
return [[CPPasteboard generalPasteboard] stringForType:CPStringPboardType];
|
||||
}
|
||||
|
||||
- (id)_stringForPasting
|
||||
{
|
||||
var pasteboard = [CPPasteboard generalPasteboard],
|
||||
dataForPasting = [pasteboard stringForType:CPRTFPboardType],
|
||||
stringForPasting = [pasteboard stringForType:CPStringPboardType];
|
||||
|
||||
if (dataForPasting || [stringForPasting hasPrefix:"{\\rtf1\\ansi"])
|
||||
stringForPasting = [[_CPRTFParser new] parseRTF:dataForPasting ? dataForPasting : stringForPasting];
|
||||
|
||||
if (![self isRichText] && [stringForPasting isKindOfClass:[CPAttributedString class]])
|
||||
stringForPasting = stringForPasting._string;
|
||||
|
||||
return stringForPasting;
|
||||
}
|
||||
|
||||
- (BOOL)_shouldUseSmartPasting
|
||||
{
|
||||
return parseInt([[CPPasteboard generalPasteboard] stringForType:_CPSmartPboardType], 10) > 0 || NO;
|
||||
}
|
||||
|
||||
- (void)paste:(id)sender
|
||||
{
|
||||
var stringForPasting = [self _stringForPasting];
|
||||
|
||||
if (stringForPasting)
|
||||
[self insertText:stringForPasting];
|
||||
}
|
||||
|
||||
- (void)copyFont:(id)sender
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
}
|
||||
|
||||
- (void)delete:(id)sender
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
}
|
||||
|
||||
- (CPFont)font:(CPFont)aFont
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)isHorizontallyResizable
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isRulerVisible
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isVerticallyResizable
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (CGSize)maxSize
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
|
||||
return CGSizeMake(0,0);
|
||||
}
|
||||
|
||||
- (CGSize)minSize
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
return CGSizeMake(0,0);
|
||||
}
|
||||
|
||||
- (void)pasteFont:(id)sender
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
}
|
||||
|
||||
- (void)replaceCharactersInRange:(CPRange)aRange withString:(CPString)aString
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
}
|
||||
|
||||
- (void)scrollRangeToVisible:(CPRange)aRange
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
}
|
||||
|
||||
- (void)selectedAll:(id)sender
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
}
|
||||
|
||||
- (CPRange)selectedRange
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
|
||||
return CPMakeRange(CPNotFound, 0);
|
||||
}
|
||||
|
||||
- (void)setFont:(CPFont)aFont
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
}
|
||||
|
||||
- (void)setFont:(CPFont)aFont range:(CPRange)aRange
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
}
|
||||
|
||||
- (void)setHorizontallyResizable:(BOOL)flag
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
}
|
||||
|
||||
- (void)setMaxSize:(CGSize)aSize
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
}
|
||||
|
||||
- (void)setMinSize:(CGSize)aSize
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
}
|
||||
|
||||
- (void)setString:(CPString)aString
|
||||
{
|
||||
[self replaceCharactersInRange:CPMakeRange(0, [[self string] length]) withString:aString];
|
||||
}
|
||||
|
||||
- (void)setUsesFontPanel:(BOOL)flag
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
}
|
||||
|
||||
- (void)setVerticallyResizable:(BOOL)flag
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
}
|
||||
|
||||
- (CPString)string
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)underline:(id)sender
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
}
|
||||
|
||||
- (BOOL)usesFontPanel
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPTextViewIsEditableKey = @"CPTextViewIsEditableKey",
|
||||
CPTextViewIsSelectableKey = @"CPTextViewIsSelectableKey",
|
||||
CPTextViewIsRichTextKey = @"CPTextViewIsRichTextKey";
|
||||
|
||||
@implementation CPText (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self setSelectable:[aCoder decodeBoolForKey:CPTextViewIsSelectableKey]];
|
||||
[self setEditable:[aCoder decodeBoolForKey:CPTextViewIsEditableKey]];
|
||||
[self setRichText:[aCoder decodeBoolForKey:CPTextViewIsRichTextKey]];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
[aCoder encodeBool:_isEditable forKey:CPTextViewIsEditableKey];
|
||||
[aCoder encodeBool:_isSelectable forKey:CPTextViewIsSelectableKey];
|
||||
[aCoder encodeBool:_isRichText forKey:CPTextViewIsRichTextKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+544
-253
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* CPFontDescriptor.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Emmanuel Maillard on 07/03/10.
|
||||
* Copyright Emmanuel Maillard 2010.
|
||||
*
|
||||
* 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>
|
||||
/*
|
||||
Font descriptor dictionary keys
|
||||
*/
|
||||
|
||||
/*
|
||||
CPFontNameAttribute contains a CPString that specified the font name
|
||||
(may be an name list like: 'Marker Felt, Lucida Grande, Helvetica')
|
||||
*/
|
||||
CPFontNameAttribute = @"CPFontNameAttribute";
|
||||
/*
|
||||
CPFontSizeAttribute contains a CPString that specified the font size
|
||||
(as a float value)
|
||||
*/
|
||||
CPFontSizeAttribute = @"CPFontSizeAttribute";
|
||||
/*
|
||||
CPFontTraitsAttribute a CPDictionary that contains font traits keys
|
||||
(CPFontSymbolicTrait or CPFontWeightTrait)
|
||||
*/
|
||||
CPFontTraitsAttribute = @"CPFontTraitsAttribute";
|
||||
|
||||
// Font traits dictionary keys
|
||||
/*
|
||||
CPFontSymbolicTrait a CPNumber that contains CPFontFamilyClass and
|
||||
typeface information flags.
|
||||
*/
|
||||
CPFontSymbolicTrait = @"CPFontSymbolicTrait";
|
||||
|
||||
/*
|
||||
CPFontWeightTrait
|
||||
We use CPString with CSS string values for font weight
|
||||
(normal | bold | bolder | lighter | 100 | 200 | 300 | 400
|
||||
| 500 | 600 | 700 | 800 | 900)
|
||||
NOTE: Cocoa compatibility issue: NSFontWeightTrait are NSNumber for
|
||||
font weight (from -1.0 to 1.0, 0.0 for normal weight).
|
||||
*/
|
||||
CPFontWeightTrait = @"CPFontWeightTrait";
|
||||
|
||||
/*
|
||||
CPFontFamilyClass
|
||||
*/
|
||||
CPFontUnknownClass = 0 << 28;
|
||||
CPFontOldStyleSerifsClass = 1 << 28;
|
||||
CPFontTransitionalSerifsClass = 2 << 28;
|
||||
CPFontModernSerifsClass = 3 << 28;
|
||||
CPFontClarendonSerifsClass = 4 << 28;
|
||||
CPFontSlabSerifsClass = 5 << 28;
|
||||
CPFontFreeformSerifsClass = 7 << 28;
|
||||
CPFontSansSerifClass = 8 << 28;
|
||||
|
||||
CPFontSerifClass = (CPFontOldStyleSerifsClass | CPFontTransitionalSerifsClass |
|
||||
CPFontModernSerifsClass | CPFontClarendonSerifsClass |
|
||||
CPFontSlabSerifsClass | CPFontFreeformSerifsClass);
|
||||
|
||||
CPFontFamilyClassMask = 0xF0000000;
|
||||
|
||||
/*
|
||||
Typeface information
|
||||
*/
|
||||
CPFontItalicTrait = 1 << 0;
|
||||
CPFontBoldTrait = 1 << 1;
|
||||
CPFontExpandedTrait = 1 << 5; /* TODO: CCS 3 font-stretch */
|
||||
CPFontCondensedTrait = 1 << 6;
|
||||
CPFontSmallCapsTrait = 1 << 7;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPFontDescriptor
|
||||
*/
|
||||
@implementation CPFontDescriptor : CPObject
|
||||
{
|
||||
CPDictionary _attributes;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a font descriptor with the specified attributes.
|
||||
|
||||
@param attributes a dictionary that describe the desired font descriptor
|
||||
@return the requested font descriptor
|
||||
*/
|
||||
+ (CPFontDescriptor)fontDescriptorWithFontAttributes:(CPDictionary)attributes
|
||||
{
|
||||
return [[CPFontDescriptor alloc] initWithFontAttributes:attributes];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a font descriptor with the specified name and size.
|
||||
|
||||
@param fontName the name of the font
|
||||
@param aSize the size of the font (in points)
|
||||
@return the requested font descriptor
|
||||
*/
|
||||
+ (CPFontDescriptor)fontDescriptorWithName:(CPString)fontName size:(float)size
|
||||
{
|
||||
return [[CPFontDescriptor alloc] initWithFontAttributes:[CPDictionary dictionaryWithObjects:[fontName, [CPString stringWithString:size + '']] forKeys:[CPFontNameAttribute,CPFontSizeAttribute]]];
|
||||
}
|
||||
|
||||
/*!
|
||||
Initialize a font descriptor with the specified attributes.
|
||||
|
||||
@param attributes a dictionary that describe the desired font descriptor
|
||||
@return the requested font descriptor
|
||||
*/
|
||||
- (id)initWithFontAttributes:(CPDictionary)attributes
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_attributes = [[CPMutableDictionary alloc] init];
|
||||
|
||||
if (attributes)
|
||||
[_attributes addEntriesFromDictionary:attributes];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a new font descriptor that is the same as the receiver but with the
|
||||
specified attributes taking precedence over the existing ones.
|
||||
|
||||
@param attributes a dictionary that describe the desired font descriptor
|
||||
@return the new font descriptor
|
||||
*/
|
||||
- (CPFontDescriptor)fontDescriptorByAddingAttributes:(CPDictionary)attributes
|
||||
{
|
||||
var attrib = [_attributes copy];
|
||||
|
||||
[attrib addEntriesFromDictionary:attributes];
|
||||
|
||||
return [[CPFontDescriptor alloc] initWithFontAttributes:attrib];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a new font descriptor that is the same as the receiver but with the specified size taking precedence over the existing ones.
|
||||
|
||||
@param aSize the new size
|
||||
@return the new font descriptor
|
||||
*/
|
||||
- (CPFontDescriptor)fontDescriptorWithSize:(float)aSize
|
||||
{
|
||||
var attrib = [_attributes copy];
|
||||
|
||||
[attrib setObject:[CPString stringWithString:aSize + ''] forKey:CPFontSizeAttribute];
|
||||
|
||||
return [[CPFontDescriptor alloc] initWithFontAttributes:attrib];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a new font descriptor that is the same as the receiver but with
|
||||
the specified symbolic traits taking precedence over the existing ones.
|
||||
|
||||
@param symbolicTraits the desired new symbolic traits
|
||||
@return the new font descriptor
|
||||
*/
|
||||
- (CPFontDescriptor)fontDescriptorWithSymbolicTraits:(CPFontSymbolicTraits)symbolicTraits
|
||||
{
|
||||
var attrib = [_attributes copy];
|
||||
|
||||
if ([attrib objectForKey:CPFontTraitsAttribute])
|
||||
[[attrib objectForKey:CPFontTraitsAttribute] setObject:[CPNumber numberWithUnsignedInt:symbolicTraits]
|
||||
forKey:CPFontSymbolicTrait];
|
||||
else
|
||||
[attrib setObject:[CPDictionary dictionaryWithObject:[CPNumber numberWithUnsignedInt:symbolicTraits]
|
||||
forKey:CPFontSymbolicTrait] forKey:CPFontTraitsAttribute];
|
||||
|
||||
return [[CPFontDescriptor alloc] initWithFontAttributes:attrib];
|
||||
}
|
||||
|
||||
- (id)objectForKey:(id)aKey
|
||||
{
|
||||
return [_attributes objectForKey:aKey];
|
||||
}
|
||||
|
||||
- (CPDictionary)fontAttributes
|
||||
{
|
||||
return _attributes;
|
||||
}
|
||||
|
||||
- (float)pointSize
|
||||
{
|
||||
var value = [_attributes objectForKey:CPFontSizeAttribute];
|
||||
|
||||
return value ? [value floatValue] : 0.0;
|
||||
}
|
||||
|
||||
- (CPFontSymbolicTraits)symbolicTraits
|
||||
{
|
||||
var traits = [_attributes objectForKey:CPFontTraitsAttribute];
|
||||
|
||||
return (traits && [traits objectForKey:CPFontSymbolicTrait]) ? [[traits objectForKey:CPFontSymbolicTrait] unsignedIntValue] : 0;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPFontDescriptorAttributesKey = @"CPFontDescriptorAttributesKey";
|
||||
|
||||
@implementation CPFontDescriptor (CPCoding)
|
||||
|
||||
/*!
|
||||
Initializes the font descriptor from a coder.
|
||||
|
||||
@param aCoder the coder from which to read the font descriptor data
|
||||
@return the initialized font
|
||||
*/
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
return [self initWithFontAttributes:[aCoder decodeObjectForKey:CPFontDescriptorAttributesKey]];
|
||||
}
|
||||
|
||||
/*!
|
||||
Writes the font descriptor to a coder.
|
||||
|
||||
@param aCoder the coder to which the data will be written
|
||||
*/
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeObject:_attributes forKey:CPFontDescriptorAttributesKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var _wrapNameRegEx = new RegExp(/(\w+\s+\w+)(,*)/g);
|
||||
|
||||
/*
|
||||
Helper methods to CPFont for generating CSS font style
|
||||
*/
|
||||
@implementation CPFontDescriptor (CPFontCSSHelper)
|
||||
|
||||
- (CPString)fontStyleCSSString
|
||||
{
|
||||
return [self symbolicTraits] & CPFontItalicTrait ? @"italic" : @"normal";
|
||||
}
|
||||
|
||||
- (CPString)fontWeightCSSString
|
||||
{
|
||||
var traitsAttributes = [_attributes objectForKey:CPFontTraitsAttribute];
|
||||
|
||||
if (traitsAttributes)
|
||||
{
|
||||
/* give preference to CPFontWeightTrait */
|
||||
if ([traitsAttributes objectForKey:CPFontWeightTrait])
|
||||
return [traitsAttributes objectForKey:CPFontWeightTrait];
|
||||
/* else fallback to facetype symbolic traits */
|
||||
if ([self symbolicTraits] & CPFontBoldTrait)
|
||||
return @"bold";
|
||||
}
|
||||
|
||||
return @"normal";
|
||||
}
|
||||
|
||||
- (CPString)fontSizeCSSString
|
||||
{
|
||||
return [_attributes objectForKey:CPFontSizeAttribute] ? [[_attributes objectForKey:CPFontSizeAttribute] intValue] + "px" : @"";
|
||||
}
|
||||
|
||||
- (CPString)fontFamilyCSSString
|
||||
{
|
||||
var aName = @"";
|
||||
|
||||
if ([_attributes objectForKey:CPFontNameAttribute])
|
||||
aName += [_attributes objectForKey:CPFontNameAttribute].replace(_wrapNameRegEx, '"$1"$2');
|
||||
|
||||
var symbolicTraits = [self symbolicTraits];
|
||||
|
||||
if (symbolicTraits)
|
||||
{
|
||||
if ((symbolicTraits & CPFontFamilyClassMask) & CPFontSansSerifClass)
|
||||
aName += @", sans-serif";
|
||||
else if ((symbolicTraits & CPFontFamilyClassMask) & CPFontSerifClass)
|
||||
aName += @", serif";
|
||||
}
|
||||
|
||||
return aName;
|
||||
}
|
||||
|
||||
- (CPString)fontVariantCSSString
|
||||
{
|
||||
if ([self symbolicTraits] & CPFontSmallCapsTrait)
|
||||
return @"small-caps";
|
||||
|
||||
return @"normal";
|
||||
}
|
||||
|
||||
- (CPString)cssString
|
||||
{
|
||||
return [CPString stringWithString:[self fontStyleCSSString] + " "
|
||||
+ [self fontVariantCSSString] + " "
|
||||
+ [self fontWeightCSSString] + " "
|
||||
+ [self fontSizeCSSString] + " "
|
||||
+ [self fontFamilyCSSString]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
* CPFontPanel.j
|
||||
* AppKit
|
||||
*
|
||||
* TODOs:
|
||||
* 1. make browser-width for size smaller and fix columns
|
||||
* 2. add all the missing features from the MacOS X counterpart (sampleview)
|
||||
*
|
||||
*
|
||||
* Created by Daniel Boehringer on 2/JAN/2014.
|
||||
* All modifications copyright Daniel Boehringer 2013.
|
||||
* Extensive code formatting and review by Andrew Hankinson
|
||||
* Based on original work by
|
||||
* Created by Emmanuel Maillard on 06/03/2010.
|
||||
* Copyright Emmanuel Maillard 2010.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
@import "CPPanel.j"
|
||||
@import "CPColorWell.j"
|
||||
@import "CPColorPanel.j"
|
||||
@import "CPBrowser.j"
|
||||
@import "CPText.j"
|
||||
@import "CPFontManager.j"
|
||||
|
||||
|
||||
@class CPTextStorage
|
||||
@class CPLayoutManager
|
||||
@class CPTextContainer
|
||||
@class CPFontManager
|
||||
|
||||
/*
|
||||
Collection indexes
|
||||
*/
|
||||
var kTypefaceIndex_Normal = 0,
|
||||
kTypefaceIndex_Italic = 1,
|
||||
kTypefaceIndex_Bold = 2,
|
||||
kTypefaceIndex_BoldItalic = 3,
|
||||
kToolbarHeight = 32,
|
||||
kBorderSpacing = 6,
|
||||
kInnerSpacing = 2,
|
||||
kNothingChanged = 0,
|
||||
kFontNameChanged = 1,
|
||||
kTypefaceChanged = 2,
|
||||
kSizeChanged = 3,
|
||||
kTextColorChanged = 4,
|
||||
kBackgroundColorChanged = 5,
|
||||
kUnderlineChanged = 6,
|
||||
kWeightChanged = 7,
|
||||
_sharedFontPanel;
|
||||
|
||||
// FIXME<!> Locale support
|
||||
var _availableTraits= [@"Normal", @"Italic", @"Bold", @"Bold Italic"],
|
||||
_availableSizes = [@"9", @"10", @"11", @"12", @"13", @"14", @"18", @"24", @"36", @"48", @"72", @"96"];
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPFontPanel
|
||||
*/
|
||||
@implementation CPFontPanel : CPPanel
|
||||
{
|
||||
id _fontBrowser;
|
||||
id _traitBrowser;
|
||||
id _sizeBrowser;
|
||||
CPArray _availableFonts;
|
||||
id _textColorWell;
|
||||
CPColor _textColor;
|
||||
int _currentColorButtonTag;
|
||||
BOOL _setupDone;
|
||||
int _fontChanges;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Class methods
|
||||
|
||||
/*!
|
||||
Check if the shared Font panel exists.
|
||||
*/
|
||||
+ (BOOL)sharedFontPanelExists
|
||||
{
|
||||
return _sharedFontPanel !== nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the shared Font panel.
|
||||
*/
|
||||
+ (CPFontPanel)sharedFontPanel
|
||||
{
|
||||
if (!_sharedFontPanel)
|
||||
_sharedFontPanel = [[CPFontPanel alloc] init];
|
||||
|
||||
return _sharedFontPanel;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Init methods
|
||||
|
||||
/*! @ignore */
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super initWithContentRect:CGRectMake(100, 90, 450, 394) styleMask:(CPTitledWindowMask | CPClosableWindowMask /*| CPResizableWindowMask*/ )])
|
||||
{
|
||||
[[self contentView] setBackgroundColor:[CPColor colorWithWhite:0.95 alpha:1.0]];
|
||||
[self setTitle:@"Font Panel"];
|
||||
[self setLevel:CPFloatingWindowLevel];
|
||||
[self setFloatingPanel:YES];
|
||||
[self setBecomesKeyOnlyIfNeeded:YES];
|
||||
[self setMinSize:CGSizeMake(378, 394)];
|
||||
|
||||
_availableFonts = [[CPFontManager sharedFontManager] availableFonts];
|
||||
_textColor = [CPColor blackColor];
|
||||
_setupDone = NO;
|
||||
_fontChanges = kNothingChanged;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*! @ignore */
|
||||
- (void)_setupToolbarView
|
||||
{
|
||||
_toolbarView = [[CPView alloc] initWithFrame:CGRectMake(0, kBorderSpacing, CGRectGetWidth([self frame]), kToolbarHeight)];
|
||||
[_toolbarView setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
// Text color
|
||||
_textColorWell = [[CPColorWell alloc] initWithFrame:CGRectMake(10, 0, 25, 25)];
|
||||
[_textColorWell setColor:_textColor];
|
||||
[_toolbarView addSubview:_textColorWell];
|
||||
}
|
||||
|
||||
- (void)_setupBrowser:(CPBrowser)aBrowser
|
||||
{
|
||||
[aBrowser setTarget:self];
|
||||
[aBrowser setAction:@selector(browserClicked:)];
|
||||
[aBrowser setDoubleAction:@selector(dblClicked:)];
|
||||
[aBrowser setAllowsEmptySelection:NO];
|
||||
[aBrowser setAllowsMultipleSelection:NO];
|
||||
[aBrowser setDelegate:self];
|
||||
[[self contentView] addSubview:aBrowser];
|
||||
}
|
||||
|
||||
- (void)_setupContents
|
||||
{
|
||||
if (_setupDone)
|
||||
return;
|
||||
|
||||
_setupDone = YES;
|
||||
|
||||
[self _setupToolbarView];
|
||||
|
||||
var contentView = [self contentView],
|
||||
label = [CPTextField labelWithTitle:@"Font name"],
|
||||
contentBounds = [contentView bounds],
|
||||
upperView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(contentBounds), CGRectGetHeight(contentBounds) - (kBorderSpacing + kToolbarHeight + kInnerSpacing))];
|
||||
|
||||
[contentView addSubview:_toolbarView];
|
||||
|
||||
_fontBrowser = [[CPBrowser alloc] initWithFrame:CGRectMake(10, 35, 150, 350)];
|
||||
_traitBrowser = [[CPBrowser alloc] initWithFrame:CGRectMake(155, 35, 150, 350)];
|
||||
_sizeBrowser = [[CPBrowser alloc] initWithFrame:CGRectMake(300, 35, 140, 350)];
|
||||
|
||||
[self _setupBrowser:_fontBrowser];
|
||||
[self _setupBrowser:_traitBrowser];
|
||||
[self _setupBrowser:_sizeBrowser];
|
||||
|
||||
[[CPNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(textViewDidChangeSelection:)
|
||||
name:CPTextViewDidChangeSelectionNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)textViewDidChangeSelection:(CPNotification)notification
|
||||
{
|
||||
[self _refreshWithTextView:[notification object]];
|
||||
|
||||
}
|
||||
|
||||
- (void)_refreshWithTextView:(CPTextView)textView
|
||||
{
|
||||
if (![self isVisible])
|
||||
return;
|
||||
|
||||
var attribs = [textView _attributesForFontPanel],
|
||||
font = [attribs objectForKey:CPFontAttributeName] || [[textView textStorage] font] || [CPFont systemFontOfSize:12.0],
|
||||
color = [attribs objectForKey:CPForegroundColorAttributeName];
|
||||
|
||||
if (!font)
|
||||
return;
|
||||
|
||||
var trait = kTypefaceIndex_Normal;
|
||||
|
||||
if ([font isItalic] && [font isBold])
|
||||
trait = kTypefaceIndex_BoldItalic;
|
||||
else if ([font isItalic])
|
||||
trait = kTypefaceIndex_Italic;
|
||||
else if ([font isBold])
|
||||
trait = kTypefaceIndex_Bold;
|
||||
|
||||
[self setCurrentFont:font];
|
||||
[self setCurrentTrait:trait];
|
||||
[self setCurrentSize:[font size] + ""]; //cast to string
|
||||
|
||||
if (!color)
|
||||
return;
|
||||
|
||||
[_textColorWell setColor:color];
|
||||
}
|
||||
|
||||
- (void)orderFront:(id)sender
|
||||
{
|
||||
[self _setupContents];
|
||||
[super orderFront:sender];
|
||||
[self _refreshWithTextView:[[CPApp keyWindow] firstResponder]];
|
||||
}
|
||||
|
||||
- (void)reloadDefaultFontFamilies
|
||||
{
|
||||
_availableFonts = [[CPFontManager sharedFontManager] availableFonts];
|
||||
}
|
||||
|
||||
- (BOOL)worksWhenModal
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
@param aFont the font to convert.
|
||||
@return The converted font or \c aFont if failed to convert.
|
||||
*/
|
||||
- (CPFont)panelConvertFont:(CPFont)aFont
|
||||
{
|
||||
var newFont = aFont,
|
||||
index = 0;
|
||||
|
||||
switch (_fontChanges)
|
||||
{
|
||||
case kFontNameChanged:
|
||||
newFont = [CPFont fontWithDescriptor:[[aFont fontDescriptor] fontDescriptorByAddingAttributes:
|
||||
[CPDictionary dictionaryWithObject:[self currentFont] forKey:CPFontNameAttribute]] size:0.0];
|
||||
break;
|
||||
|
||||
case kTypefaceChanged:
|
||||
index = [self currentTrait];
|
||||
if (index == kTypefaceIndex_BoldItalic)
|
||||
newFont = [[CPFontManager sharedFontManager] convertFont:aFont toHaveTrait:CPBoldFontMask | CPItalicFontMask];
|
||||
else if (index == kTypefaceIndex_Bold)
|
||||
newFont = [[CPFontManager sharedFontManager] convertFont:aFont toHaveTrait:CPBoldFontMask];
|
||||
else if (index == kTypefaceIndex_Italic)
|
||||
newFont = [[CPFontManager sharedFontManager] convertFont:aFont toHaveTrait:CPItalicFontMask];
|
||||
else
|
||||
newFont = [[CPFontManager sharedFontManager] convertFont:aFont toNotHaveTrait:CPBoldFontMask | CPItalicFontMask];
|
||||
break;
|
||||
|
||||
case kSizeChanged:
|
||||
newFont = [[CPFontManager sharedFontManager] convertFont:aFont toSize:[self currentSize]];
|
||||
break;
|
||||
|
||||
case kNothingChanged:
|
||||
break;
|
||||
|
||||
default:
|
||||
CPLog.trace(@"FIXME: -[" + [self className] + " " + _cmd + "] unhandled _fontChanges: " + _fontChanges);
|
||||
break;
|
||||
}
|
||||
|
||||
return newFont;
|
||||
}
|
||||
|
||||
- (void)setCurrentSize:(CGSize)aSize
|
||||
{
|
||||
[_sizeBrowser selectRow:[_availableSizes indexOfObject:aSize] inColumn:0];
|
||||
}
|
||||
|
||||
- (CPString)currentSize
|
||||
{
|
||||
return [_sizeBrowser selectedItem];
|
||||
}
|
||||
|
||||
- (void)setCurrentFont:(CPFont)aFont
|
||||
{
|
||||
[_fontBrowser selectRow:[_availableFonts indexOfObject:[aFont familyName]] inColumn:0];
|
||||
}
|
||||
|
||||
- (CPString)currentFont
|
||||
{
|
||||
return [_fontBrowser selectedItem];
|
||||
}
|
||||
|
||||
- (void)setCurrentTrait:(unsigned)aTrait
|
||||
{
|
||||
var row = 0;
|
||||
|
||||
switch (aTrait)
|
||||
{
|
||||
case kTypefaceIndex_Italic:
|
||||
row = 1;
|
||||
break;
|
||||
|
||||
case kTypefaceIndex_Bold:
|
||||
row = 2;
|
||||
break;
|
||||
|
||||
case kTypefaceIndex_BoldItalic:
|
||||
row = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
[_traitBrowser selectRow:row inColumn:0];
|
||||
}
|
||||
|
||||
// FIXME<!> Locale support
|
||||
- (unsigned)currentTrait
|
||||
{
|
||||
var sel = [_traitBrowser selectedItem];
|
||||
|
||||
if (sel === "Italic")
|
||||
return kTypefaceIndex_Italic;
|
||||
|
||||
if (sel === "Bold")
|
||||
return kTypefaceIndex_Bold;
|
||||
|
||||
if (sel === "Bold Italic")
|
||||
return kTypefaceIndex_BoldItalic;
|
||||
|
||||
return kTypefaceIndex_Normal;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the selected font in Font panel.
|
||||
@param font the selected font
|
||||
@param flag if \c the current selection have multiple fonts.
|
||||
*/
|
||||
- (void)setPanelFont:(CPFont)font isMultiple:(BOOL)flag
|
||||
{
|
||||
[self _setupContents];
|
||||
|
||||
if ([self currentFont] !== [font familyName])
|
||||
[self setCurrentFont:[font familyName]];
|
||||
|
||||
if ([self currentSize] != [font size])
|
||||
[self setCurrentSize:[font size]];
|
||||
|
||||
var typefaceIndex = kTypefaceIndex_Normal,
|
||||
symbolicTraits = [[font fontDescriptor] symbolicTraits];
|
||||
|
||||
if ((symbolicTraits & CPFontItalicTrait) && (symbolicTraits & CPFontBoldTrait))
|
||||
typefaceIndex = kTypefaceIndex_BoldItalic;
|
||||
else if (symbolicTraits & CPFontItalicTrait)
|
||||
typefaceIndex = kTypefaceIndex_Italic;
|
||||
else if (symbolicTraits & CPFontBoldTrait)
|
||||
typefaceIndex = kTypefaceIndex_Bold;
|
||||
|
||||
if ([self currentTrait] != typefaceIndex)
|
||||
[self setCurrentTrait:typefaceIndex ];
|
||||
|
||||
_fontChanges = kNothingChanged;
|
||||
}
|
||||
|
||||
- (void)changeColor:(id)sender
|
||||
{
|
||||
_textColor = [sender color];
|
||||
_fontChanges = kTextColorChanged;
|
||||
[[CPFontManager sharedFontManager] modifyFontViaPanel:self];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// TODO: ask CPFontManager for traits //
|
||||
- (void)browserClicked:(id)aBrowser
|
||||
{
|
||||
if (aBrowser === _fontBrowser)
|
||||
{
|
||||
_fontChanges = kFontNameChanged;
|
||||
[[CPFontManager sharedFontManager] modifyFontViaPanel:self];
|
||||
}
|
||||
else if (aBrowser === _traitBrowser)
|
||||
{
|
||||
_fontChanges = kTypefaceChanged;
|
||||
[[CPFontManager sharedFontManager] modifyFontViaPanel:self];
|
||||
}
|
||||
else if (aBrowser === _sizeBrowser)
|
||||
{
|
||||
_fontChanges = kSizeChanged;
|
||||
[[CPFontManager sharedFontManager] modifyFontViaPanel:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dblClicked:(id)sender
|
||||
{
|
||||
// alert("DOUBLE");
|
||||
}
|
||||
|
||||
- (id)browser:(id)aBrowser numberOfChildrenOfItem:(id)anItem
|
||||
{
|
||||
if (aBrowser === _fontBrowser)
|
||||
return [_availableFonts count];
|
||||
|
||||
if (aBrowser === _traitBrowser)
|
||||
return [_availableTraits count];
|
||||
|
||||
return [_availableSizes count]
|
||||
}
|
||||
|
||||
- (id)browser:(id)aBrowser child:(int)index ofItem:(id)anItem
|
||||
{
|
||||
if (aBrowser === _fontBrowser)
|
||||
return [_availableFonts objectAtIndex:index];
|
||||
|
||||
if (aBrowser === _traitBrowser)
|
||||
return [_availableTraits objectAtIndex:index];
|
||||
|
||||
return [_availableSizes objectAtIndex:index];
|
||||
}
|
||||
|
||||
- (id)browser:(id)aBrowser objectValueForItem:(id)anItem
|
||||
{
|
||||
return anItem;
|
||||
}
|
||||
|
||||
- (BOOL)browser:(id)aBrowser isLeafItem:(id)anItem
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
[CPFontManager setFontPanelFactory:[CPFontPanel class]];
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* CPParagraphStyle.j
|
||||
* AppKit
|
||||
*
|
||||
* FIXME
|
||||
* This is basically a stub.
|
||||
* We need to store all the spacing informations as well as writing direction (among others)
|
||||
*
|
||||
* Created by Daniel Boehringer on 11/01/2014
|
||||
* Copyright Daniel Boehringer 2014.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPArray.j>
|
||||
|
||||
@import "CPText.j"
|
||||
|
||||
CPLeftTabStopType = 0;
|
||||
|
||||
CPParagraphStyleAttributeName = @"CPParagraphStyleAttributeName";
|
||||
|
||||
var _sharedDefaultParagraphStyle,
|
||||
_defaultTabStopArray;
|
||||
|
||||
@implementation CPParagraphStyle : CPObject
|
||||
{
|
||||
CPArray _tabStops @accessors(property=tabStops);
|
||||
CPTextAlignment _alignment @accessors(property=alignment);
|
||||
unsigned _firstLineHeadIndent @accessors(property=firstLineHeadIndent);
|
||||
unsigned _headIndent @accessors(property=headIndent);
|
||||
unsigned _tailIndent @accessors(property=tailIndent);
|
||||
unsigned _paragraphSpacing @accessors(property=paragraphSpacing);
|
||||
unsigned _minimumLineHeight @accessors(property=minimumLineHeight);
|
||||
unsigned _maximumLineHeight @accessors(property=maximumLineHeight);
|
||||
unsigned _lineSpacing @accessors(property=lineSpacing);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Class methods
|
||||
|
||||
+ (CPParagraphStyle)defaultParagraphStyle
|
||||
{
|
||||
if (!_sharedDefaultParagraphStyle)
|
||||
_sharedDefaultParagraphStyle = [self new];
|
||||
|
||||
return _sharedDefaultParagraphStyle;
|
||||
}
|
||||
|
||||
+ (CPArray)_defaultTabStops
|
||||
{
|
||||
if (!_defaultTabStopArray)
|
||||
{
|
||||
var i;
|
||||
_defaultTabStopArray = [];
|
||||
|
||||
// <!> FIXME: Define constants for these magic numbers: 13, 28
|
||||
for (i = 1; i < 16 ; i++)
|
||||
{
|
||||
_defaultTabStopArray.push([[CPTextTab alloc] initWithType:CPLeftTabStopType location:i * 28]);
|
||||
}
|
||||
}
|
||||
|
||||
return _defaultTabStopArray;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Init methods
|
||||
|
||||
- (id)init
|
||||
{
|
||||
[self _initWithDefaults];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPParagraphStyle)initWithParagraphStyle:(CPParagraphStyle)other
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
_tabStops = [other._tabStops copy];
|
||||
_alignment = other._alignment;
|
||||
_firstLineHeadIndent = other._firstLineHeadIndent;
|
||||
_headIndent = other._headIndent;
|
||||
_tailIndent = other._tailIndent;
|
||||
_paragraphSpacing = other._paragraphSpacing;
|
||||
_minimumLineHeight = other._minimumLineHeight;
|
||||
_maximumLineHeight = other._maximumLineHeight;
|
||||
_lineSpacing = other._lineSpacing;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_initWithDefaults
|
||||
{
|
||||
_alignment = CPLeftTextAlignment;
|
||||
_tabStops = [[[self class] _defaultTabStops] copy];
|
||||
}
|
||||
|
||||
- (void)addTabStop:(CPTextTab)aStop
|
||||
{
|
||||
_tabStops.push(aStop);
|
||||
}
|
||||
|
||||
- (id)copy
|
||||
{
|
||||
var other = [[self class] alloc];
|
||||
|
||||
return [other initWithParagraphStyle:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPParagraphStyleTabStopsKey = @"CPParagraphStyleTabStopsKey",
|
||||
CPParagraphStyleAlignmentKey = @"CPParagraphStyleAlignmentKey",
|
||||
CPParagraphStyleFirstLineHeadIndentKey = @"CPParagraphStyleFirstLineHeadIndentKey",
|
||||
CPParagraphStyleHeadIndentKey = @"CPParagraphStyleHeadIndentKey",
|
||||
CPParagraphStyleTailIndentKey = @"CPParagraphStyleTailIndentKey",
|
||||
CPParagraphStyleParagraphSpacingKey = @"CPParagraphStyleParagraphSpacingKey",
|
||||
CPParagraphStyleMinimumLineHeightKey = @"CPParagraphStyleMinimumLineHeightKey",
|
||||
CPParagraphStyleMaximumLineHeightKey = @"CPParagraphStyleMaximumLineHeightKey",
|
||||
CPParagraphStyleLineSpacingKey = @"CPParagraphStyleLineSpacingKey";
|
||||
|
||||
@implementation CPParagraphStyle (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(id)aCoder
|
||||
{
|
||||
self = [self init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_tabStops = [aCoder decodeObjectForKey:"CPParagraphStyleTabStopsKey"];
|
||||
_alignment = [aCoder decodeIntForKey:"CPParagraphStyleAlignmentKey"];
|
||||
_firstLineHeadIndent = [aCoder decodeIntForKey:"CPParagraphStyleFirstLineHeadIndentKey"];
|
||||
_headIndent = [aCoder decodeIntForKey:"CPParagraphStyleHeadIndentKey"];
|
||||
_tailIndent = [aCoder decodeIntForKey:"CPParagraphStyleTailIndentKey"];
|
||||
_paragraphSpacing = [aCoder decodeIntForKey:"CPParagraphStyleParagraphSpacingKey"];
|
||||
_minimumLineHeight = [aCoder decodeIntForKey:"CPParagraphStyleMinimumLineHeightKey"];
|
||||
_maximumLineHeight = [aCoder decodeIntForKey:"CPParagraphStyleMaximumLineHeightKey"];
|
||||
_lineSpacing = [aCoder decodeIntForKey:"CPParagraphStyleLineSpacingKey"];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(id)aCoder
|
||||
{
|
||||
[aCoder encodeInt:_alignment forKey:"CPParagraphStyleAlignmentKey"];
|
||||
[aCoder encodeObject:_tabStops forKey:"CPParagraphStyleTabStopsKey"];
|
||||
[aCoder encodeInt:_firstLineHeadIndent forKey:"CPParagraphStyleFirstLineHeadIndentKey"];
|
||||
[aCoder encodeInt:_headIndent forKey:"CPParagraphStyleHeadIndentKey"];
|
||||
[aCoder encodeInt:_tailIndent forKey:"CPParagraphStyleTailIndentKey"];
|
||||
[aCoder encodeInt:_paragraphSpacing forKey:"CPParagraphStyleParagraphSpacingKey"];
|
||||
[aCoder encodeInt:_minimumLineHeight forKey:"CPParagraphStyleMinimumLineHeightKey"];
|
||||
[aCoder encodeInt:_maximumLineHeight forKey:"CPParagraphStyleMaximumLineHeightKey"];
|
||||
[aCoder encodeInt:_lineSpacing forKey:"CPParagraphStyleLineSpacingKey"];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation CPTextTab : CPObject
|
||||
{
|
||||
int _type @accessors(property = tabStopType);
|
||||
double _location @accessors(property = location);
|
||||
}
|
||||
|
||||
- (id)initWithType:(CPTabStopType) aType location:(double) aLocation
|
||||
{
|
||||
if ([self = [super init]])
|
||||
{
|
||||
_type = aType;
|
||||
_location = aLocation;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPTextTabTypeKey = @"CPTextTabTypeKey",
|
||||
CPTextTabLocationKey = @"CPTextTabLocationKey";
|
||||
|
||||
@implementation CPTextTab (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(id)aCoder
|
||||
{
|
||||
self = [self init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_type = [aCoder decodeIntForKey:"CPTextTabTypeKey"];
|
||||
_location = [aCoder decodeDoubleForKey:"CPTextTabLocationKey"];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(id)aCoder
|
||||
{
|
||||
[aCoder encodeInt:_type forKey:"CPTextTabTypeKey"];
|
||||
[aCoder encodeDouble:_location forKey:"CPTextTabLocationKey"];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* CPTextContainer.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Emmanuel Maillard on 27/02/2010.
|
||||
* Copyright Emmanuel Maillard 2010.
|
||||
*
|
||||
* 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/CPGeometry.j>
|
||||
@import "CPLayoutManager.j"
|
||||
|
||||
@class CPTextView
|
||||
@class CPLayoutManager
|
||||
|
||||
/*
|
||||
@global
|
||||
@group CPLineSweepDirection
|
||||
*/
|
||||
CPLineSweepLeft = 0;
|
||||
/*
|
||||
@global
|
||||
@group CPLineSweepDirection
|
||||
*/
|
||||
CPLineSweepRight = 1;
|
||||
/*
|
||||
@global
|
||||
@group CPLineSweepDirection
|
||||
*/
|
||||
CPLineSweepDown = 2;
|
||||
/*
|
||||
@global
|
||||
@group CPLineSweepDirection
|
||||
*/
|
||||
CPLineSweepUp = 3;
|
||||
|
||||
/*
|
||||
@global
|
||||
@group CPLineMovementDirection
|
||||
*/
|
||||
CPLineDoesntMoves = 0;
|
||||
/*
|
||||
@global
|
||||
@group CPLineMovementDirection
|
||||
*/
|
||||
CPLineMovesLeft = 1;
|
||||
/*
|
||||
@global
|
||||
@group CPLineMovementDirection
|
||||
*/
|
||||
CPLineMovesRight = 2;
|
||||
/*
|
||||
@global
|
||||
@group CPLineMovementDirection
|
||||
*/
|
||||
CPLineMovesDown = 3;
|
||||
/*
|
||||
@global
|
||||
@group CPLineMovementDirection
|
||||
*/
|
||||
CPLineMovesUp = 4;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPTextContainer
|
||||
*/
|
||||
@implementation CPTextContainer : CPObject
|
||||
{
|
||||
float _lineFragmentPadding @accessors(property=lineFragmentPadding);
|
||||
CGSize _size @accessors(property=containerSize);
|
||||
CPLayoutManager _layoutManager @accessors(property=layoutManager);
|
||||
CPTextView _textView @accessors(property=textView);
|
||||
BOOL _inResizing;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Init methods
|
||||
|
||||
- (id)initWithContainerSize:(CGSize)aSize
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_size = aSize;
|
||||
[self _init];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
return [self initWithContainerSize:CPMakeSize(1e7, 1e7)];
|
||||
}
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_lineFragmentPadding = 0.0;
|
||||
|
||||
_layoutManager = [[CPLayoutManager alloc] init];
|
||||
[_layoutManager addTextContainer:self];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Setter methods
|
||||
|
||||
- (void)setContainerSize:(CGSize)someSize
|
||||
{
|
||||
var oldSize = _size;
|
||||
|
||||
_size = CGSizeMakeCopy(someSize);
|
||||
|
||||
if (oldSize.width != _size.width)
|
||||
{
|
||||
_inResizing = YES;
|
||||
[_layoutManager invalidateLayoutForCharacterRange:CPMakeRange(0, [[_layoutManager textStorage] length])
|
||||
isSoft:NO
|
||||
actualCharacterRange:NULL];
|
||||
|
||||
[_layoutManager _validateLayoutAndGlyphs];
|
||||
[_textView sizeToFit]; // this is necessary to adopt the height of CPTextView in case of rewrapping
|
||||
_inResizing = NO;
|
||||
}
|
||||
}
|
||||
|
||||
// Controls whether the receiver adjusts the width of its bounding rectangle when its text view is resized.
|
||||
- (void)setWidthTracksTextView:(BOOL)flag
|
||||
{
|
||||
[_textView setPostsFrameChangedNotifications:flag];
|
||||
|
||||
if (flag)
|
||||
{
|
||||
[[CPNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(textViewFrameChanged:)
|
||||
name:CPViewFrameDidChangeNotification
|
||||
object:_textView];
|
||||
}
|
||||
else
|
||||
{
|
||||
[[CPNotificationCenter defaultCenter] removeObserver:self
|
||||
name:CPViewFrameDidChangeNotification
|
||||
object:_textView];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)textViewFrameChanged:(CPNotification)aNotification
|
||||
{
|
||||
var newSize = CGSizeMake([_textView frame].size.width, _size.height);
|
||||
|
||||
[self setContainerSize:newSize];
|
||||
}
|
||||
|
||||
- (void)setTextView:(CPTextView)aTextView
|
||||
{
|
||||
if (_textView)
|
||||
[_textView setTextContainer:nil];
|
||||
|
||||
_textView = aTextView;
|
||||
|
||||
if (_textView)
|
||||
[_textView setTextContainer:self];
|
||||
|
||||
[_layoutManager textContainerChangedTextView:self];
|
||||
}
|
||||
|
||||
- (BOOL)containsPoint:(CGPoint)aPoint
|
||||
{
|
||||
return CGRectContainsPoint(CGRectMake(0, 0, _size.width, _size.height), aPoint);
|
||||
}
|
||||
|
||||
- (BOOL)isSimpleRectangularTextContainer
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CGRect)lineFragmentRectForProposedRect:(CGRect)proposedRect
|
||||
sweepDirection:(CPLineSweepDirection)sweep
|
||||
movementDirection:(CPLineMovementDirection)movement
|
||||
remainingRect:(CGRectPointer)remainingRect
|
||||
{
|
||||
var resultRect = CGRectCreateCopy(proposedRect);
|
||||
|
||||
if (sweep != CPLineSweepRight || movement != CPLineMovesDown)
|
||||
{
|
||||
CPLog.trace(@"FIXME: unsupported sweep (" + sweep + ") or movement (" + movement + ")");
|
||||
return CGRectMakeZero();
|
||||
}
|
||||
|
||||
if (resultRect.origin.x + resultRect.size.width > _size.width)
|
||||
resultRect.size.width = _size.width - resultRect.origin.x;
|
||||
|
||||
if (resultRect.size.width < 0)
|
||||
resultRect = CGRectMakeZero();
|
||||
|
||||
if (remainingRect)
|
||||
{
|
||||
remainingRect.origin.x = resultRect.origin.x + resultRect.size.width;
|
||||
remainingRect.origin.y = resultRect.origin.y;
|
||||
remainingRect.size.height = resultRect.size.height;
|
||||
remainingRect.size.width = _size.width - (resultRect.origin.x + resultRect.size.width);
|
||||
}
|
||||
|
||||
return resultRect;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPTextContainerSizeKey = @"CPTextContainerSizeKey",
|
||||
CPTextContainerLayoutManagerKey = @"CPTextContainerLayoutManagerKey";
|
||||
|
||||
@implementation CPTextContainer (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self _init];
|
||||
|
||||
_size = [aCoder decodeSizeForKey:CPTextContainerSizeKey];
|
||||
|
||||
_layoutManager = [aCoder decodeObjectForKey:CPTextContainerLayoutManagerKey];
|
||||
[_layoutManager addTextContainer:self];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeSize:_size forKey:CPTextContainerSizeKey];
|
||||
[aCoder encodeObject:_layoutManager forKey:CPTextContainerLayoutManagerKey];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* CPTextStorage.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Emmanuel Maillard on 27/02/2010.
|
||||
* Copyright Emmanuel Maillard 2010.
|
||||
*
|
||||
* 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/CPNotificationCenter.j>
|
||||
@import <Foundation/CPAttributedString.j>
|
||||
|
||||
@import "CPText.j"
|
||||
@import "CPFont.j"
|
||||
|
||||
@class CPLayoutManager;
|
||||
|
||||
CPTextStorageEditedAttributes = 1;
|
||||
CPTextStorageEditedCharacters = 2;
|
||||
|
||||
CPTextStorageWillProcessEditingNotification = @"CPTextStorageWillProcessEditingNotification";
|
||||
CPTextStorageDidProcessEditingNotification = @"CPTextStorageDidProcessEditingNotification";
|
||||
|
||||
@protocol CPTextStorageDelegate <CPObject>
|
||||
|
||||
- (void)textStorageWillProcessEditing:(CPNotification)aNotification;
|
||||
- (void)textStorageDidProcessEditing:(CPNotification)aNotification;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPTextStorageDelegate_textStorageWillProcessEditing_ = 1 << 1,
|
||||
CPTextStorageDelegate_textStorageDidProcessEditing_ = 1 << 2;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPTextStorage
|
||||
*/
|
||||
@implementation CPTextStorage : CPMutableAttributedString
|
||||
{
|
||||
CPColor _foregroundColor @accessors(property=foregroundColor);
|
||||
CPFont _font @accessors(property=font);
|
||||
CPMutableArray _layoutManagers @accessors(getter=layoutManagers);
|
||||
CPRange _editedRange @accessors(getter=editedRange);
|
||||
id <CPTextStorageDelegate> _delegate @accessors(property=delegate);
|
||||
int _changeInLength @accessors(property=changeInLength);
|
||||
unsigned _editedMask @accessors(property=editedMask);
|
||||
|
||||
int _editCount; // {begin,end}Editing counter
|
||||
unsigned _implementedDelegateMethods;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Init methods
|
||||
|
||||
- (id)initWithString:(CPString)aString attributes:(CPDictionary)attributes
|
||||
{
|
||||
self = [super initWithString:aString attributes:attributes];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_layoutManagers = [[CPMutableArray alloc] init];
|
||||
_editedRange = CPMakeRange(CPNotFound, 0);
|
||||
_changeInLength = 0;
|
||||
_editedMask = 0;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithString:(CPString)aString
|
||||
{
|
||||
return [self initWithString:aString attributes:nil];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
return [self initWithString:@"" attributes:nil];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Delegate methods
|
||||
|
||||
- (void)setDelegate:(id <CPTextStorageDelegate>)aDelegate
|
||||
{
|
||||
if (_delegate === aDelegate)
|
||||
return;
|
||||
|
||||
_implementedDelegateMethods = 0;
|
||||
_delegate = aDelegate;
|
||||
|
||||
if (_delegate)
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(textStorageWillProcessEditing:)])
|
||||
_implementedDelegateMethods |= CPTextStorageDelegate_textStorageWillProcessEditing_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(textStorageDidProcessEditing:)])
|
||||
_implementedDelegateMethods |= CPTextStorageDelegate_textStorageDidProcessEditing_;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Layout manager methods
|
||||
|
||||
- (void)addLayoutManager:(CPLayoutManager)aManager
|
||||
{
|
||||
if ([_layoutManagers containsObject:aManager])
|
||||
return
|
||||
|
||||
[aManager setTextStorage:self];
|
||||
[_layoutManagers addObject:aManager];
|
||||
}
|
||||
|
||||
- (void)removeLayoutManager:(CPLayoutManager)aManager
|
||||
{
|
||||
if (![_layoutManagers containsObject:aManager])
|
||||
return
|
||||
|
||||
[aManager setTextStorage:nil];
|
||||
[_layoutManagers removeObject:aManager];
|
||||
}
|
||||
|
||||
- (void)invalidateAttributesInRange:(CPRange)aRange
|
||||
{
|
||||
/* FIXME: stub */
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Editing methods
|
||||
|
||||
- (void)processEditing
|
||||
{
|
||||
[self _sendDelegateWillProcessEditingNotification];
|
||||
[self invalidateAttributesInRange:[self editedRange]];
|
||||
[self _sendDelegateDidProcessEditingNotification];
|
||||
|
||||
var c = [_layoutManagers count];
|
||||
|
||||
for (var i = 0; i < c; i++)
|
||||
{
|
||||
[[_layoutManagers objectAtIndex:i] textStorage:self
|
||||
edited:_editedMask
|
||||
range:_editedRange
|
||||
changeInLength:_changeInLength
|
||||
invalidatedRange:_editedRange];
|
||||
}
|
||||
|
||||
_editedRange.location = CPNotFound;
|
||||
_editedMask = 0;
|
||||
_changeInLength = 0;
|
||||
}
|
||||
|
||||
- (void)beginEditing
|
||||
{
|
||||
if (_editCount == 0)
|
||||
_editedRange = CPMakeRange(CPNotFound, 0);
|
||||
|
||||
_editCount++;
|
||||
}
|
||||
|
||||
- (void)endEditing
|
||||
{
|
||||
_editCount--;
|
||||
|
||||
if (_editCount == 0)
|
||||
[self processEditing];
|
||||
}
|
||||
|
||||
- (void)edited:(unsigned)editedMask range:(CPRange)aRange changeInLength:(int)lengthChange
|
||||
{
|
||||
var copyRange = CPMakeRangeCopy(aRange);
|
||||
|
||||
if (_editCount == 0) // used outside a beginEditing/endEditing
|
||||
{
|
||||
_editedMask = editedMask;
|
||||
_changeInLength = lengthChange;
|
||||
copyRange.length += lengthChange;
|
||||
_editedRange = copyRange;
|
||||
[self processEditing];
|
||||
}
|
||||
else
|
||||
{
|
||||
_editedMask |= editedMask;
|
||||
_changeInLength += lengthChange;
|
||||
copyRange.length += lengthChange;
|
||||
|
||||
if (_editedRange.location == CPNotFound)
|
||||
_editedRange = copyRange;
|
||||
else
|
||||
_editedRange = CPUnionRange(_editedRange,copyRange);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeAttribute:(CPString)anAttribute range:(CPRange)aRange
|
||||
{
|
||||
[self beginEditing];
|
||||
[super removeAttribute:anAttribute range:aRange];
|
||||
[self edited:CPTextStorageEditedAttributes range:aRange changeInLength:0];
|
||||
[self endEditing];
|
||||
}
|
||||
|
||||
- (void)addAttributes:(CPDictionary)aDictionary range:(CPRange)aRange
|
||||
{
|
||||
[self beginEditing];
|
||||
[super addAttributes:aDictionary range:aRange];
|
||||
[self edited:CPTextStorageEditedAttributes range:aRange changeInLength:0];
|
||||
[self endEditing];
|
||||
}
|
||||
|
||||
- (void)deleteCharactersInRange:(CPRange)aRange
|
||||
{
|
||||
[self beginEditing];
|
||||
[super deleteCharactersInRange:aRange];
|
||||
[self edited:CPTextStorageEditedCharacters range:aRange changeInLength:-aRange.length];
|
||||
[self endEditing];
|
||||
}
|
||||
|
||||
- (void)replaceCharactersInRange:(CPRange)aRange withString:(CPString)aString
|
||||
{
|
||||
[self beginEditing];
|
||||
[super replaceCharactersInRange:aRange withString:aString];
|
||||
[self edited:CPTextStorageEditedCharacters range:aRange changeInLength:([aString length] - aRange.length)];
|
||||
[self endEditing];
|
||||
}
|
||||
|
||||
- (void)replaceCharactersInRange:(CPRange)aRange withAttributedString:(CPAttributedString)aString
|
||||
{
|
||||
[self beginEditing];
|
||||
[super replaceCharactersInRange:aRange withAttributedString:aString];
|
||||
[self edited:(CPTextStorageEditedAttributes | CPTextStorageEditedCharacters) range:aRange changeInLength:([aString length] - aRange.length)];
|
||||
[self endEditing];
|
||||
}
|
||||
|
||||
- (CPAttributedString)attributedSubstringFromRange:(CPRange)aRange
|
||||
{
|
||||
if (!aRange.length)
|
||||
return [CPAttributedString new];
|
||||
|
||||
return [super attributedSubstringFromRange:aRange];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation CPTextStorage (CPTextStorageDelegate)
|
||||
|
||||
- (void)_sendDelegateWillProcessEditingNotification
|
||||
{
|
||||
if (_implementedDelegateMethods & CPTextStorageDelegate_textStorageWillProcessEditing_)
|
||||
[_delegate textStorageWillProcessEditing:[[CPNotification alloc] initWithName:CPTextStorageWillProcessEditingNotification object:self userInfo:nil]];
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPTextStorageWillProcessEditingNotification object:self];
|
||||
}
|
||||
|
||||
- (void)_sendDelegateDidProcessEditingNotification
|
||||
{
|
||||
if (_implementedDelegateMethods & CPTextStorageDelegate_textStorageDidProcessEditing_)
|
||||
[_delegate textStorageWillProcessEditing:[[CPNotification alloc] initWithName:CPTextStorageDidProcessEditingNotification object:self userInfo:nil]];
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPTextStorageDidProcessEditingNotification object:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation CPTextStorage (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
}
|
||||
|
||||
@end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
* CPTypesetter.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Daniel Boehringer on 27/12/2013.
|
||||
* All modifications copyright Daniel Boehringer 2013.
|
||||
* Extensive code formatting and review by Andrew Hankinson
|
||||
* Based on original work by
|
||||
* Emmanuel Maillard on 27/02/2010.
|
||||
* Copyright Emmanuel Maillard 2010.
|
||||
*
|
||||
* 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 "CPParagraphStyle.j"
|
||||
@import "CPTextStorage.j"
|
||||
@import "CPFont.j"
|
||||
|
||||
// forward declare these classes for type matching
|
||||
@class CPLayoutManager
|
||||
@class CPTextContainer
|
||||
@class CPTextView
|
||||
|
||||
/*
|
||||
CPTypesetterControlCharacterAction
|
||||
*/
|
||||
CPTypesetterZeroAdvancementAction = 1 << 0;
|
||||
CPTypesetterWhitespaceAction = 1 << 1;
|
||||
CPSTypesetterHorizontalTabAction = 1 << 2;
|
||||
CPTypesetterLineBreakAction = 1 << 3;
|
||||
CPTypesetterParagraphBreakAction = 1 << 4;
|
||||
CPTypesetterContainerBreakAction = 1 << 5;
|
||||
|
||||
var CPSystemTypesetterFactory,
|
||||
_sharedSimpleTypesetter;
|
||||
|
||||
@implementation CPTypesetter : CPObject
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Class methods
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
[CPTypesetter _setSystemTypesetterFactory:[CPSimpleTypesetter class]];
|
||||
}
|
||||
|
||||
+ (id)sharedSystemTypesetter
|
||||
{
|
||||
return [CPSystemTypesetterFactory sharedInstance];
|
||||
}
|
||||
|
||||
+ (void)_setSystemTypesetterFactory:(Class)aClass
|
||||
{
|
||||
CPSystemTypesetterFactory = aClass;
|
||||
}
|
||||
|
||||
- (CPTypesetterControlCharacterAction)actionForControlCharacterAtIndex:(unsigned)charIndex
|
||||
{
|
||||
return CPTypesetterZeroAdvancementAction;
|
||||
}
|
||||
|
||||
- (CPLayoutManager)layoutManager
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CPTextContainer)currentTextContainer
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CPArray)textContainers
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)layoutGlyphsInLayoutManager:(CPLayoutManager)layoutManager
|
||||
startingAtGlyphIndex:(unsigned)startGlyphIndex
|
||||
maxNumberOfLineFragments:(unsigned)maxNumLines
|
||||
nextGlyphIndex:(UIntegerReference)nextGlyph
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CPSimpleTypesetter : CPTypesetter
|
||||
{
|
||||
CPLayoutManager _layoutManager @accessors(property=layoutManager);
|
||||
CPTextContainer _currentTextContainer @accessors(property=currentTextContainer);
|
||||
CPTextStorage _textStorage;
|
||||
|
||||
CPRange _attributesRange;
|
||||
CPDictionary _currentAttributes;
|
||||
CPParagraphStyle _currentParagraph;
|
||||
|
||||
float _lineHeight;
|
||||
float _lineBase;
|
||||
float _lineWidth;
|
||||
|
||||
unsigned _indexOfCurrentContainer;
|
||||
|
||||
CPArray _lineFragments;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Class methods
|
||||
|
||||
+ (id)sharedInstance
|
||||
{
|
||||
if (!_sharedSimpleTypesetter)
|
||||
_sharedSimpleTypesetter = [[CPSimpleTypesetter alloc] init];
|
||||
|
||||
return _sharedSimpleTypesetter;
|
||||
}
|
||||
|
||||
- (CPArray)textContainers
|
||||
{
|
||||
return [_layoutManager textContainers];
|
||||
}
|
||||
|
||||
- (CPTextTab)textTabForWidth:(double)aWidth writingDirection:(CPWritingDirection)direction
|
||||
{
|
||||
var tabStops = [_currentParagraph tabStops];
|
||||
|
||||
if (!tabStops)
|
||||
tabStops = [CPParagraphStyle _defaultTabStops];
|
||||
|
||||
var l = tabStops.length;
|
||||
|
||||
if (aWidth > tabStops[l - 1]._location)
|
||||
return nil;
|
||||
|
||||
for (var i = l - 1; i >= 0; i--)
|
||||
{
|
||||
if (aWidth > tabStops[i]._location)
|
||||
{
|
||||
if (i + 1 < l)
|
||||
return tabStops[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
if (i === -1)
|
||||
return tabStops[0];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)_flushRange:(CPRange)lineRange
|
||||
lineOrigin:(CGPoint)lineOrigin
|
||||
currentContainer:(CPTextContainer)aContainer
|
||||
advancements:(CPArray)advancements
|
||||
lineCount:(unsigned)lineCount
|
||||
sameLine:(BOOL)sameLine
|
||||
{
|
||||
var myX = 0,
|
||||
rect = CGRectMake(lineOrigin.x, lineOrigin.y, _lineWidth, _lineHeight),
|
||||
containerSize = aContainer._size;
|
||||
|
||||
[_layoutManager _appendNewLineFragmentInTextContainer:_currentTextContainer forGlyphRange:lineRange];
|
||||
|
||||
var fragment = [_layoutManager._lineFragments lastObject];
|
||||
fragment._isLast = !sameLine;
|
||||
_lineFragments.push(fragment);
|
||||
|
||||
[_layoutManager setLineFragmentRect:rect forGlyphRange:lineRange usedRect:rect];
|
||||
|
||||
switch ([_currentParagraph alignment])
|
||||
{
|
||||
case CPLeftTextAlignment:
|
||||
myX = 0;
|
||||
break;
|
||||
|
||||
case CPCenterTextAlignment:
|
||||
myX = (containerSize.width - _lineWidth) / 2;
|
||||
break;
|
||||
|
||||
case CPRightTextAlignment:
|
||||
myX = containerSize.width - _lineWidth;
|
||||
break;
|
||||
}
|
||||
|
||||
[_layoutManager setLocation:CGPointMake(myX, _lineBase) forStartOfGlyphRange:lineRange];
|
||||
[_layoutManager _setAdvancements:advancements forGlyphRange:lineRange];
|
||||
|
||||
if (!sameLine) //fix the _lineFragments when fontsizes differ
|
||||
{
|
||||
var l = _lineFragments.length;
|
||||
|
||||
for (var i = 0 ; i < l ; i++)
|
||||
[_lineFragments[i] _adjustForHeight:_lineHeight];
|
||||
}
|
||||
|
||||
if (!lineCount) // do not rescue on first line
|
||||
return NO;
|
||||
|
||||
if (aContainer._inResizing)
|
||||
return NO;
|
||||
|
||||
return ([_layoutManager _rescuingInvalidFragmentsWasPossibleForGlyphRange:lineRange]);
|
||||
}
|
||||
|
||||
- (void)layoutGlyphsInLayoutManager:(CPLayoutManager)layoutManager
|
||||
startingAtGlyphIndex:(unsigned)glyphIndex
|
||||
maxNumberOfLineFragments:(unsigned)maxNumLines
|
||||
nextGlyphIndex:(UIntegerReference)nextGlyph
|
||||
{
|
||||
var textContainers = [layoutManager textContainers],
|
||||
textContainersCount = [textContainers count];
|
||||
|
||||
_layoutManager = layoutManager;
|
||||
_textStorage = [_layoutManager textStorage];
|
||||
_indexOfCurrentContainer = MAX(0, [textContainers
|
||||
indexOfObject:[_layoutManager textContainerForGlyphAtIndex:glyphIndex effectiveRange:nil withoutAdditionalLayout:YES]
|
||||
inRange:CPMakeRange(0, textContainersCount)]);
|
||||
|
||||
_currentTextContainer = textContainers[_indexOfCurrentContainer];
|
||||
|
||||
_attributesRange = CPMakeRange(0, 0);
|
||||
_lineHeight = 0;
|
||||
_lineBase = 0;
|
||||
_lineWidth = 0;
|
||||
|
||||
var containerSize = [_currentTextContainer containerSize],
|
||||
containerSizeWidth = containerSize.width,
|
||||
containerSizeHeight = containerSize.height,
|
||||
lineRange = CPMakeRange(glyphIndex, 0),
|
||||
wrapRange = CPMakeRange(0, 0),
|
||||
wrapWidth = 0,
|
||||
isNewline = NO,
|
||||
isTabStop = NO,
|
||||
isWordWrapped = NO,
|
||||
numberOfGlyphs= [_textStorage length],
|
||||
leading,
|
||||
numLines = 0,
|
||||
theString = [_textStorage string],
|
||||
lineOrigin,
|
||||
ascent,
|
||||
descent,
|
||||
advancements = [],
|
||||
prevRangeWidth = 0,
|
||||
measuringRange = CPMakeRange(glyphIndex, 0),
|
||||
currentAnchor = 0,
|
||||
currentFont,
|
||||
currentFontLineHeight,
|
||||
previousFont,
|
||||
currentParagraphMinimumLineHeight,
|
||||
currentParagraphMaximumLineHeight,
|
||||
currentParagraphLineSpacing;
|
||||
|
||||
if (glyphIndex > 0)
|
||||
lineOrigin = CGPointCreateCopy([_layoutManager lineFragmentRectForGlyphAtIndex:glyphIndex effectiveRange:nil].origin);
|
||||
else if ([_layoutManager extraLineFragmentTextContainer])
|
||||
lineOrigin = CGPointMake(0, [_layoutManager extraLineFragmentUsedRect].origin.y);
|
||||
else
|
||||
lineOrigin = CGPointMake(0, 0);
|
||||
|
||||
[_layoutManager _removeInvalidLineFragments];
|
||||
|
||||
if (![_textStorage length])
|
||||
return;
|
||||
|
||||
_lineFragments = [];
|
||||
|
||||
for (; numLines != maxNumLines && glyphIndex < numberOfGlyphs; glyphIndex++)
|
||||
{
|
||||
// check whether there any change in the attributes from here on
|
||||
if (!CPLocationInRange(glyphIndex, _attributesRange))
|
||||
{
|
||||
_currentAttributes = [_textStorage attributesAtIndex:glyphIndex effectiveRange:_attributesRange];
|
||||
currentFont = [_currentAttributes objectForKey:CPFontAttributeName];
|
||||
_currentParagraph = [_currentAttributes objectForKey:CPParagraphStyleAttributeName] || [CPParagraphStyle defaultParagraphStyle];
|
||||
currentParagraphMinimumLineHeight = [_currentParagraph minimumLineHeight];
|
||||
currentParagraphMaximumLineHeight = [_currentParagraph maximumLineHeight];
|
||||
currentParagraphLineSpacing = [_currentParagraph lineSpacing];
|
||||
|
||||
if (!currentFont)
|
||||
currentFont = [_textStorage font] || [CPFont systemFontOfSize:12.0];
|
||||
|
||||
ascent = [currentFont ascender];
|
||||
descent = [currentFont descender];
|
||||
leading = (ascent - descent) * 0.2; // FAKE leading
|
||||
|
||||
currentFontLineHeight = ascent - descent + leading;
|
||||
|
||||
if (previousFont !== currentFont)
|
||||
{
|
||||
measuringRange = CPMakeRange(glyphIndex, 0);
|
||||
currentAnchor = prevRangeWidth;
|
||||
previousFont = currentFont;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (currentFontLineHeight > _lineHeight)
|
||||
_lineHeight = currentFontLineHeight;
|
||||
|
||||
if (ascent > _lineBase)
|
||||
_lineBase = ascent;
|
||||
|
||||
lineRange.length++;
|
||||
measuringRange.length++;
|
||||
|
||||
var currentCharCode = theString.charCodeAt(glyphIndex), // use pure javascript methods for performance reasons
|
||||
rangeWidth = [theString.substr(measuringRange.location, measuringRange.length) _sizeWithFont:currentFont inWidth:NULL].width + currentAnchor;
|
||||
|
||||
switch (currentCharCode) // faster than sending actionForControlCharacterAtIndex: called for each char.
|
||||
{
|
||||
case 9: // '\t'
|
||||
{
|
||||
var nextTab = [self textTabForWidth:rangeWidth + lineOrigin.x writingDirection:0];
|
||||
|
||||
isTabStop = YES;
|
||||
|
||||
if (nextTab)
|
||||
rangeWidth = nextTab._location - lineOrigin.x;
|
||||
else
|
||||
rangeWidth += 28; //FIXME
|
||||
} // fallthrough intentional
|
||||
case 32: // ' '
|
||||
wrapRange = CPMakeRangeCopy(lineRange);
|
||||
wrapWidth = rangeWidth;
|
||||
wrapRange._height = _lineHeight;
|
||||
wrapRange._base = _lineBase;
|
||||
break;
|
||||
|
||||
case 10:
|
||||
case 13:
|
||||
isNewline = YES;
|
||||
}
|
||||
|
||||
advancements.push({width: rangeWidth - prevRangeWidth, height: ascent, descent: descent});
|
||||
|
||||
prevRangeWidth = _lineWidth = rangeWidth;
|
||||
|
||||
if (lineOrigin.x + rangeWidth > containerSizeWidth)
|
||||
{
|
||||
if (wrapWidth)
|
||||
{
|
||||
lineRange = wrapRange;
|
||||
_lineWidth = wrapWidth;
|
||||
_lineHeight = wrapRange._height;
|
||||
_lineBase = wrapRange._base;
|
||||
}
|
||||
|
||||
isNewline = YES;
|
||||
isWordWrapped = YES;
|
||||
glyphIndex = CPMaxRange(lineRange) - 1; // start the line starts directly at current character
|
||||
}
|
||||
|
||||
if (isNewline || isTabStop)
|
||||
{
|
||||
if ([self _flushRange:lineRange lineOrigin:lineOrigin currentContainer:_currentTextContainer advancements:advancements lineCount:numLines sameLine:!isNewline])
|
||||
return;
|
||||
|
||||
if (isTabStop)
|
||||
{
|
||||
lineOrigin.x += rangeWidth;
|
||||
isTabStop = NO;
|
||||
}
|
||||
|
||||
if (isNewline)
|
||||
{
|
||||
if (currentParagraphMinimumLineHeight && currentParagraphMinimumLineHeight > _lineHeight)
|
||||
_lineHeight = currentParagraphMinimumLineHeight;
|
||||
|
||||
if (currentParagraphMaximumLineHeight && currentParagraphMaximumLineHeight < _lineHeight)
|
||||
_lineHeight = currentParagraphMaximumLineHeight;
|
||||
|
||||
lineOrigin.y += _lineHeight;
|
||||
|
||||
if (currentParagraphLineSpacing)
|
||||
lineOrigin.y += currentParagraphLineSpacing;
|
||||
|
||||
if (lineOrigin.y > containerSizeHeight && _indexOfCurrentContainer < textContainersCount - 1)
|
||||
{
|
||||
_currentTextContainer = textContainers[++_indexOfCurrentContainer];
|
||||
containerSize = [_currentTextContainer containerSize];
|
||||
containerSizeWidth = containerSize.width;
|
||||
containerSizeHeight = containerSize.height;
|
||||
}
|
||||
|
||||
lineOrigin.x = 0;
|
||||
numLines++;
|
||||
isNewline = NO;
|
||||
_lineFragments = [];
|
||||
_lineHeight = 0;
|
||||
_lineBase = ascent;
|
||||
}
|
||||
|
||||
_lineWidth = 0;
|
||||
advancements = [];
|
||||
currentAnchor = 0;
|
||||
prevRangeWidth = 0;
|
||||
lineRange = CPMakeRange(glyphIndex + 1, 0);
|
||||
measuringRange = CPMakeRange(glyphIndex + 1, 0);
|
||||
wrapRange = CPMakeRange(0, 0);
|
||||
wrapWidth = 0;
|
||||
isWordWrapped = NO;
|
||||
}
|
||||
}
|
||||
|
||||
// this is to "flush" the remaining characters
|
||||
if (lineRange.length)
|
||||
{
|
||||
[self _flushRange:lineRange lineOrigin:lineOrigin currentContainer:_currentTextContainer advancements:advancements lineCount:numLines sameLine:NO];
|
||||
}
|
||||
|
||||
var rect = CGRectMake(0, lineOrigin.y, containerSizeWidth, [_layoutManager._lineFragments lastObject]._usedRect.size.height - descent);
|
||||
[_layoutManager setExtraLineFragmentRect:rect usedRect:rect textContainer:_currentTextContainer];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,793 @@
|
||||
/* RTFParser.j
|
||||
|
||||
Parse a RTF string into a CPAttributedString
|
||||
|
||||
Copyright (C) 2014 Daniel Boehringer
|
||||
|
||||
FIXME: this class should be redone using a 'real' parser
|
||||
|
||||
* all paragraph spacing information is currently not parsed
|
||||
|
||||
|
||||
* 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/CPAttributedString.j>
|
||||
@import <Foundation/CPGeometry.j>
|
||||
@import "CPFontManager.j"
|
||||
@import "CPParagraphStyle.j"
|
||||
|
||||
@global CPLeftTextAlignment
|
||||
@global CPRightTextAlignment
|
||||
@global CPCenterTextAlignment
|
||||
@global CPJustifiedTextAlignment
|
||||
@global CPNaturalTextAlignment
|
||||
|
||||
@global CPFontAttributeName
|
||||
@global CPForegroundColorAttributeName
|
||||
|
||||
var hexTable = [];
|
||||
|
||||
// Hold the attributes of the current run
|
||||
@implementation _RTFAttribute : CPObject
|
||||
{
|
||||
CPRange _range;
|
||||
CPParagraphStyle paragraph;
|
||||
CPColor fgColour;
|
||||
CPColor bgColour;
|
||||
CPColor ulColour;
|
||||
CPString fontName;
|
||||
unsigned fontSize;
|
||||
BOOL bold;
|
||||
BOOL italic;
|
||||
BOOL underline;
|
||||
BOOL strikethrough;
|
||||
BOOL script;
|
||||
BOOL _tabChanged;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
[self resetFont];
|
||||
[self resetParagraphStyle];
|
||||
_range = CPMakeRange(0, 0);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)copy
|
||||
{
|
||||
var mynew = [_RTFAttribute new];
|
||||
|
||||
mynew.paragraph = [paragraph copy];
|
||||
mynew.fontName = fontName;
|
||||
mynew.fgColour = fgColour;
|
||||
mynew.bgColour = bgColour;
|
||||
mynew.ulColour = ulColour;
|
||||
|
||||
return mynew;
|
||||
}
|
||||
|
||||
- (CPFont)currentFont
|
||||
{
|
||||
var font = [CPFont _fontWithName:fontName size:fontSize bold:bold italic:italic];
|
||||
|
||||
if (font)
|
||||
return font;
|
||||
|
||||
//Before giving up and using a default font, we try if this is
|
||||
//not the case of a font with a composite name, such as
|
||||
//'Helvetica-Light'. In that case, even if we don't have
|
||||
//exactly an 'Helvetica-Light' font family, we might have an
|
||||
//'Helvetica' one.
|
||||
var range = [fontName rangeOfString:@"-"];
|
||||
|
||||
if (range.location != CPNotFound)
|
||||
{
|
||||
var fontFamily = [fontName substringToIndex: range.location];
|
||||
|
||||
font = [CPFont fontWithName:fontFamily size:fontSize];
|
||||
}
|
||||
|
||||
/* Last resort, default font. :-( */
|
||||
if (font == nil)
|
||||
font = [CPFont systemFontOfSize:fontSize];
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
- (CPNumber)script
|
||||
{
|
||||
return [CPNumber numberWithInt:script];
|
||||
}
|
||||
|
||||
- (CPNumber)underline
|
||||
{
|
||||
if (underline != 0)
|
||||
return [CPNumber numberWithInt:underline];
|
||||
else
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CPNumber)strikethrough
|
||||
{
|
||||
if (strikethrough != 0)
|
||||
return [CPNumber numberWithInt:strikethrough];
|
||||
else
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)resetParagraphStyle
|
||||
{
|
||||
paragraph = [[CPParagraphStyle defaultParagraphStyle] copy];
|
||||
}
|
||||
|
||||
- (void)resetFont
|
||||
{
|
||||
var font = [CPFont systemFontOfSize:12];
|
||||
|
||||
fontName = [font familyName];
|
||||
fontSize = 12.0;
|
||||
italic = NO;
|
||||
bold = NO;
|
||||
underline = 0;
|
||||
strikethrough = 0;
|
||||
script = 0;
|
||||
}
|
||||
|
||||
- (void)addTab:(float)location type:(CPTextTabType)type
|
||||
{
|
||||
var tab = [[CPTextTab alloc] initWithType:CPLeftTabStopType
|
||||
location:location];
|
||||
|
||||
if (!_tabChanged)
|
||||
{
|
||||
[paragraph setTabStops:[tab]];
|
||||
_tabChanged = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
[paragraph addTabStop: tab];
|
||||
}
|
||||
}
|
||||
|
||||
- (CPDictionary)dictionary
|
||||
{
|
||||
var ret = @{};
|
||||
[ret setObject:[self currentFont] forKey:CPFontAttributeName];
|
||||
[ret setObject:paragraph forKey:CPParagraphStyleAttributeName];
|
||||
|
||||
if (fgColour)
|
||||
[ret setObject:fgColour forKey:CPForegroundColorAttributeName];
|
||||
|
||||
return ret;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
// based on https://github.com/lazygyu/RTF-parser
|
||||
|
||||
var kRTFParserType_char = 0,
|
||||
kRTFParserType_dest = 1,
|
||||
kRTFParserType_prop = 2,
|
||||
kRTFParserType_spec = 3;
|
||||
|
||||
// Keyword descriptions
|
||||
var kRgsymRtf = {
|
||||
// keyword dflt fPassDflt kwd idx
|
||||
"b" : [ "b", 1, false, kRTFParserType_prop, "propBold"],
|
||||
"ul" : [ "ul", 1, false, kRTFParserType_prop, "propUnderline"],
|
||||
"i" : [ "i", 1, false, kRTFParserType_prop, "propItalic"],
|
||||
"li" : [ "li", 0, false, kRTFParserType_prop, "propPgnFormat"],
|
||||
"pgnucltr" : [ "pgnucltr", "pgULtr", true, kRTFParserType_prop, "propPgnFormat"],
|
||||
"pgnlcltr" : [ "pgnlcltr", "pgLLtr", true, kRTFParserType_prop, "propPgnFormat"],
|
||||
"qc" : [ "qc", "justC", true, kRTFParserType_prop, "propJust"],
|
||||
"ql" : [ "ql", "justL", true, kRTFParserType_prop, "propJust"],
|
||||
"qr" : [ "qr", "justR", true, kRTFParserType_prop, "propJust"],
|
||||
"qj" : [ "qj", "justF", true, kRTFParserType_prop, "propJust"],
|
||||
"paperw" : [ "paperw", 12240, false, kRTFParserType_prop, "propXaPage"],
|
||||
"paperh" : [ "paperh", 15480, false, kRTFParserType_prop, "propYaPage"],
|
||||
"margl" : [ "margl", 1800, false, kRTFParserType_prop, "propXaLeft"],
|
||||
"margr" : [ "margr", 1800, false, kRTFParserType_prop, "propXaRight"],
|
||||
"margt" : [ "margt", 1440, false, kRTFParserType_prop, "propYaTop"],
|
||||
"margb" : [ "margb", 1440, false, kRTFParserType_prop, "propYaBottom"],
|
||||
"pgnstart" : [ "pgnstart", 1, true, kRTFParserType_prop, "propPgnStart"],
|
||||
"facingp" : [ "facingp", 1, true, kRTFParserType_prop, "propFacingp"],
|
||||
"landscape" : [ "landscape",1, true, kRTFParserType_prop, "propLandscape"],
|
||||
"par" : [ "par", 0, false, kRTFParserType_char, "\n"],
|
||||
"pard" : [ "pard", 0, false, kRTFParserType_prop, "propDefaultPara"],
|
||||
"\0x0a" : [ "\0x0a", 0, false, kRTFParserType_char, "\n"],
|
||||
"\0x0d" : [ "\0x0d", 0, false, kRTFParserType_char, ""],
|
||||
"tab" : [ "tab", 0, false, kRTFParserType_char, "\t"],
|
||||
"ldblquote" : [ "ldblquote",0, false, kRTFParserType_char, '"'],
|
||||
"rdblquote" : [ "rdblquote",0, false, kRTFParserType_char, '"'],
|
||||
"bin" : [ "bin", 0, false, kRTFParserType_spec, "ipfnBin"],
|
||||
"*" : [ "*", 0, false, kRTFParserType_spec, "ipfnDestSkip"],
|
||||
"'" : [ "'", 0, false, kRTFParserType_spec, "ipfnHex"],
|
||||
"author" : [ "author", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"buptim" : [ "buptim", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"colortbl" : [ "colortbl", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"comment" : [ "comment", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"creatim" : [ "creatim", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"doccomm" : [ "doccomm", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"fonttbl" : [ "fonttbl", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"footer" : [ "footer", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"footerf" : [ "footerf", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"footerl" : [ "footerl", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"footerr" : [ "footerr", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"footnote" : [ "footnote", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"ftncn" : [ "ftncn", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"ftnsep" : [ "ftnsep", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"ftnsepc" : [ "ftnsepc", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"fprq" : [ "fprq", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
// "fcharset" : [ "fcharset", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"rquote" : [ "rquote", 0, false, kRTFParserType_char, "'"],
|
||||
// "s" : [ "s", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"header" : [ "header", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"headerf" : [ "headerf", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"headerl" : [ "headerl", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"headerr" : [ "headerr", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"info" : [ "info", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"keywords" : [ "keywords", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"operator" : [ "operator", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"pict" : [ "pict", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"printim" : [ "printim", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"private1" : [ "private1", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"revtim" : [ "revtim", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"rxe" : [ "rxe", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"stylesheet" : [ "stylesheet",0, false, kRTFParserType_dest, "destSkip"],
|
||||
"subject" : [ "subject", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"tc" : [ "tc", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"title" : [ "title", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"txe" : [ "txe", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"xe" : [ "xe", 0, false, kRTFParserType_dest, "destSkip"],
|
||||
"[" : [ "[", 0, false, kRTFParserType_char, '['],
|
||||
" " : [ " ", 0, false, kRTFParserType_char, ' '],
|
||||
"]" : [ "]", 0, false, kRTFParserType_char, ']'],
|
||||
"{" : [ "{", 0, false, kRTFParserType_char, '{'],
|
||||
"}" : [ "}", 0, false, kRTFParserType_char, '}'],
|
||||
"\\" : [ "\\", 0, false, kRTFParserType_char, '\\']
|
||||
};
|
||||
|
||||
@implementation _CPRTFParser : CPObject
|
||||
{
|
||||
CPString _codePage;
|
||||
CGSize _paper;
|
||||
CPString _rtf;
|
||||
unsigned _curState;
|
||||
CPArray _states;
|
||||
unsigned _currentParseIndex;
|
||||
BOOL _hexreturn;
|
||||
_RTFAttribute _currentRun;
|
||||
CPAttributedString _result;
|
||||
CPArray _colorArray;
|
||||
CPArray _fontArray;
|
||||
CPString _freename;
|
||||
BOOL _parsingFontTable;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_paper = CPMakeSize(0, 0);
|
||||
_rtf = "";
|
||||
_curState = 0; // 0 = normal, 1 = skip
|
||||
_states = [];
|
||||
_currentParseIndex = 0;
|
||||
_hexreturn = NO;
|
||||
_result = [CPAttributedString new];
|
||||
_colorArray = [];
|
||||
_fontArray = ['Arial']; // FIXME: should be name of system font
|
||||
_freename = "";
|
||||
_parsingFontTable = NO;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPString)_checkChar:(CPArray)sym parameter:(CPString)ch
|
||||
{
|
||||
switch (_curState)
|
||||
{
|
||||
case 0:
|
||||
if (sym && sym[4])
|
||||
return sym[4];
|
||||
|
||||
case 1:
|
||||
// CPLogConsole("skipped : " + sym[4]);
|
||||
return '';
|
||||
|
||||
default:
|
||||
if (sym && sym[4])
|
||||
return sym[4];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)pushState
|
||||
{
|
||||
_states.push["group"];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)popState
|
||||
{
|
||||
_states.pop();
|
||||
|
||||
if (_curState > 0)
|
||||
_curState--;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CPString)_parseSpec:(CPArray)sym parameter:(CPString)v
|
||||
{
|
||||
var ch = '';
|
||||
|
||||
switch (sym[4])
|
||||
{
|
||||
case "ipfnDestSkip":
|
||||
_curState++;
|
||||
return '';
|
||||
|
||||
case "ipfnHex":
|
||||
ch = _rtf.charAt(++_currentParseIndex);
|
||||
|
||||
var hex = '';
|
||||
|
||||
while (new RegExp("[a-fA-F0-9\\']").test(ch))
|
||||
{
|
||||
if (ch == "'")
|
||||
{
|
||||
_currentParseIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
hex += (ch + '');
|
||||
ch = _rtf.charAt(++_currentParseIndex);
|
||||
}
|
||||
//ch = parseInt(ch, 16);
|
||||
//console.log("hex : " + hex);
|
||||
_hexreturn = YES;
|
||||
_currentParseIndex--;
|
||||
|
||||
if (_curState !== 0)
|
||||
return '';
|
||||
else
|
||||
return hex;
|
||||
break;
|
||||
|
||||
case "codePage":
|
||||
ch = _rtf.charAt(++_currentParseIndex);
|
||||
|
||||
var code = '';
|
||||
|
||||
while (new RegExp("[0-9]").test(ch))
|
||||
{
|
||||
code += (ch + '');
|
||||
ch = _rtf.charAt(++_currentParseIndex);
|
||||
}
|
||||
|
||||
_codePage = code;
|
||||
_currentParseIndex--;
|
||||
break;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
- (void)_flushCurrentRun
|
||||
{
|
||||
var newOffset = 0;
|
||||
|
||||
if (_currentRun)
|
||||
{
|
||||
if ([_result length] == _currentRun._range.location)
|
||||
return;
|
||||
|
||||
_currentRun._range.length = [_result length] - _currentRun._range.location;
|
||||
newOffset = CPMaxRange(_currentRun._range);
|
||||
|
||||
var dict = [_currentRun dictionary];
|
||||
|
||||
[_result setAttributes:dict range:_currentRun._range]; // flush previous run
|
||||
_currentRun.fgColour = [CPColor blackColor];
|
||||
}
|
||||
else
|
||||
_currentRun = [_RTFAttribute new];
|
||||
|
||||
_currentRun._range = CPMakeRange(newOffset, 0); // open a new one
|
||||
}
|
||||
|
||||
- (CPString)_applyPropChange:sym parameter:param
|
||||
{
|
||||
//console.log("prop : " + sym[0] + " / param : " + param+ ' ');
|
||||
|
||||
switch (sym[0])
|
||||
{
|
||||
case "pard":
|
||||
[self _flushCurrentRun];
|
||||
break;
|
||||
|
||||
case "b": // bold
|
||||
if (param === 0)
|
||||
{
|
||||
if (_currentRun && _currentRun.bold)
|
||||
[self _flushCurrentRun];
|
||||
|
||||
_currentRun.bold = NO
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_currentRun && !_currentRun.bold)
|
||||
[self _flushCurrentRun];
|
||||
|
||||
_currentRun.bold = YES;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "i": // italic
|
||||
if (param === 0)
|
||||
{
|
||||
if (_currentRun && _currentRun.italic)
|
||||
[self _flushCurrentRun];
|
||||
|
||||
_currentRun.italic = NO
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_currentRun && !_currentRun.italic)
|
||||
[self _flushCurrentRun];
|
||||
|
||||
_currentRun.italic = YES;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "qc": // paragraph center
|
||||
[_currentRun.paragraph setAlignment:CPCenterTextAlignment];
|
||||
break;
|
||||
|
||||
case "paperw":
|
||||
_paper.width = param;
|
||||
break;
|
||||
|
||||
case "paperh":
|
||||
_paper.height = param;
|
||||
break;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
- (CPString)_changeDest:(CPArray)sym
|
||||
{
|
||||
switch (sym[0])
|
||||
{
|
||||
case "colortbl":
|
||||
_colorArray.push([CPColor blackColor]);
|
||||
break;
|
||||
|
||||
case "fonttbl":
|
||||
_parsingFontTable = YES;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sym[4] == "destSkip")
|
||||
{
|
||||
CPLogConsole("Dest skip start : [" + sym[0] + "]");
|
||||
_curState++;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
- (CPString)_translateKeyword:(CPString)keyword parameter:(CPString)param fParameter:(BOOL)fParam
|
||||
{
|
||||
if (kRgsymRtf[keyword] !== undefined)
|
||||
{
|
||||
var sym = kRgsymRtf[keyword];
|
||||
|
||||
switch (sym[3])
|
||||
{
|
||||
case kRTFParserType_prop:
|
||||
if (sym[2] || !fParam)
|
||||
param = sym[1];
|
||||
|
||||
return [self _applyPropChange:sym parameter:param];
|
||||
|
||||
case kRTFParserType_char:
|
||||
if((param + '') !== 'NaN' && (param + '') !== 'null' && (param + '').length)
|
||||
_currentParseIndex -= (param + '').length;
|
||||
|
||||
return [self _checkChar:sym parameter:param];
|
||||
|
||||
case kRTFParserType_dest:
|
||||
return [self _changeDest:sym];
|
||||
|
||||
case kRTFParserType_spec:
|
||||
return [self _parseSpec:sym parameter:param];
|
||||
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (keyword)
|
||||
{
|
||||
case "red":
|
||||
var oldColor = [_colorArray lastObject],
|
||||
green = [oldColor greenComponent],
|
||||
blue = [oldColor blueComponent];
|
||||
|
||||
_colorArray.pop();
|
||||
_colorArray.push([CPColor colorWithRed:parseInt(param) / 255 green:green blue:blue alpha:1.0]);
|
||||
break;
|
||||
|
||||
case "green":
|
||||
var oldColor = [_colorArray lastObject],
|
||||
red = [oldColor redComponent],
|
||||
blue = [oldColor blueComponent];
|
||||
|
||||
_colorArray.pop();
|
||||
_colorArray.push([CPColor colorWithRed:red green: parseInt(param) / 255 blue:blue alpha:1.0]);
|
||||
break;
|
||||
|
||||
case "blue":
|
||||
var oldColor = [_colorArray lastObject],
|
||||
green = [oldColor greenComponent],
|
||||
red = [oldColor redComponent];
|
||||
|
||||
_colorArray.pop();
|
||||
_colorArray.push([CPColor colorWithRed:red green:green blue:parseInt(param) / 255 alpha:1.0]);
|
||||
_colorArray.push([CPColor blackColor]); // placeholder for next color
|
||||
break;
|
||||
|
||||
case "cf": // change foreground color
|
||||
[self _flushCurrentRun];
|
||||
var fontIndex = parseInt(param) - 1;
|
||||
|
||||
if (_currentRun && fontIndex >= 0)
|
||||
_currentRun.fgColour = _colorArray[fontIndex];
|
||||
|
||||
break;
|
||||
|
||||
case "f": // change font
|
||||
[self _flushCurrentRun];
|
||||
var fontIndex = parseInt(param);
|
||||
|
||||
if (_currentRun && fontIndex >= 0 && fontIndex < _fontArray.length)
|
||||
_currentRun.fontName = _fontArray[fontIndex];
|
||||
break;
|
||||
|
||||
case "fs": // change font size
|
||||
[self _flushCurrentRun];
|
||||
_currentRun.fontSize = parseInt(param) / 2;
|
||||
break;
|
||||
|
||||
case "tx": // tabstop
|
||||
var location = parseInt(param) / 20;
|
||||
|
||||
if (_currentRun)
|
||||
[_currentRun addTab:location type:CPLeftTabStopType];
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
CPLogConsole("skip : " + keyword + " param: " + param);
|
||||
|
||||
}
|
||||
|
||||
if (_states.length > 0)
|
||||
_curState = 1;
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
- (CPString)_parseKeyword:(CPString)rtf length:(unsigned)len
|
||||
{
|
||||
var ch = '',
|
||||
fParam = false,
|
||||
fNeg = false,
|
||||
keyword = '',
|
||||
param = '';
|
||||
|
||||
_rtf = rtf;
|
||||
|
||||
if (++_currentParseIndex >= len)
|
||||
return len;
|
||||
|
||||
ch = rtf.charAt(_currentParseIndex);
|
||||
|
||||
if (!/[a-zA-Z]/.test(ch))
|
||||
return [self _translateKeyword:ch parameter:nil fParameter:fParam];
|
||||
|
||||
while (new RegExp("[a-zA-Z]").test(ch))
|
||||
{
|
||||
keyword += ch;
|
||||
ch = rtf.charAt(++_currentParseIndex);
|
||||
}
|
||||
|
||||
if (ch == '-')
|
||||
{
|
||||
fNeg = true;
|
||||
ch = rtf.charAt(++_currentParseIndex);
|
||||
}
|
||||
|
||||
fParam = true;
|
||||
|
||||
while (new RegExp("[0-9]").test(ch))
|
||||
{
|
||||
param += (ch + '');
|
||||
ch = rtf.charAt(++_currentParseIndex);
|
||||
}
|
||||
|
||||
_currentParseIndex--;
|
||||
param = parseInt(param);
|
||||
|
||||
if (fNeg)
|
||||
param *= -1;
|
||||
|
||||
return [self _translateKeyword:keyword parameter:param fParameter:fParam];
|
||||
}
|
||||
|
||||
- (void)_appendPlainString:(CPString) aString
|
||||
{
|
||||
[_result replaceCharactersInRange:CPMakeRange([_result length], 0) withString:aString];
|
||||
|
||||
}
|
||||
- (CPAttributedString)parseRTF:(CPString)rtf
|
||||
{
|
||||
rtf = rtf.replace(/\\\n/g, "\\par\n");
|
||||
|
||||
if (rtf.length == 0)
|
||||
return '';
|
||||
|
||||
_currentParseIndex = -1;
|
||||
|
||||
var len = rtf.length,
|
||||
tmp = '',
|
||||
ch = '',
|
||||
hex = '',
|
||||
lastchar = 0;
|
||||
|
||||
while (_currentParseIndex < len)
|
||||
{
|
||||
tmp = rtf.charAt(++_currentParseIndex);
|
||||
|
||||
if (tmp !== "\\" && hex.length > 0)
|
||||
{
|
||||
[self _appendPlainString: String.fromCharCode(parseInt((hex), 16))];
|
||||
hex = '';
|
||||
}
|
||||
|
||||
switch (tmp)
|
||||
{
|
||||
case " ":
|
||||
if (lastchar == 1)
|
||||
{
|
||||
lastchar = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_freename += tmp;
|
||||
[self _appendPlainString:tmp];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "{":
|
||||
if ([self pushState])
|
||||
CPLogConsole("push");
|
||||
|
||||
break;
|
||||
|
||||
case "}":
|
||||
if ([self popState])
|
||||
CPLogConsole("pop");
|
||||
|
||||
if (_freename)
|
||||
{
|
||||
CPLogConsole(_freename);
|
||||
|
||||
if (_parsingFontTable)
|
||||
{
|
||||
_fontArray.push(_freename);
|
||||
_parsingFontTable = NO;
|
||||
}
|
||||
|
||||
_freename = "";
|
||||
}
|
||||
|
||||
[self _flushCurrentRun];
|
||||
break;
|
||||
|
||||
case "\\":
|
||||
_freename = '';
|
||||
ch = [self _parseKeyword:rtf length:len];
|
||||
|
||||
if (!_hexreturn && ch.length == 0)
|
||||
lastchar = 1;
|
||||
else
|
||||
lastchar = 0;
|
||||
|
||||
if (_hexreturn)
|
||||
{
|
||||
if (ch.length > 0)
|
||||
{
|
||||
if (parseInt(ch, 16) & 0x80)
|
||||
{
|
||||
hex += ch.toUpperCase();
|
||||
}
|
||||
else
|
||||
{
|
||||
[self _appendPlainString: String.fromCharCode(parseInt((hex + ch), 16))];
|
||||
hex = '';
|
||||
}
|
||||
|
||||
if (hex.length == 4)
|
||||
{
|
||||
var temp = parseInt(hex, 16);
|
||||
|
||||
if (hexTable && hexTable[hex.toUpperCase()] !== undefined)
|
||||
temp = parseInt(hexTable[hex.toUpperCase()], 16);
|
||||
|
||||
[self _appendPlainString: String.fromCharCode(temp)];
|
||||
hex = '';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CPLogConsole("hex skipped");
|
||||
}
|
||||
|
||||
_hexreturn = NO;
|
||||
}
|
||||
else if (ch !== undefined && _curState === 0)
|
||||
{
|
||||
[self _appendPlainString:ch];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0x0d:
|
||||
case 0x0a:
|
||||
case '\n':
|
||||
case '\r':
|
||||
break;
|
||||
|
||||
default:
|
||||
lastchar = 0;
|
||||
|
||||
if (_curState == 0)
|
||||
[self _appendPlainString:tmp];
|
||||
else if (tmp !== ';')
|
||||
_freename += tmp;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return _result;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,613 @@
|
||||
/*
|
||||
_CPRTFProducer.j
|
||||
|
||||
Serialize CPAttributedString to a RTF String
|
||||
|
||||
Copyright (C) 2014 Daniel Boehringer
|
||||
This file is based on the RTFProducer from GNUStep
|
||||
(which i co-authored with Fred Kiefer in 1999)
|
||||
|
||||
* 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/CPAttributedString.j>
|
||||
@import "CPParagraphStyle.j"
|
||||
@import "CPColor.j"
|
||||
@import "CPGraphics.j"
|
||||
@import "CPFontManager.j"
|
||||
|
||||
@global CPForegroundColorAttributeName
|
||||
@global CPBackgroundColorAttributeName
|
||||
@global CPUnderlineStyleAttributeName
|
||||
@global CPSuperscriptAttributeName
|
||||
@global CPBaselineOffsetAttributeName
|
||||
@global CPAttachmentAttributeName
|
||||
@global CPLigatureAttributeName
|
||||
@global CPKernAttributeName
|
||||
|
||||
@global CPLeftTextAlignment
|
||||
@global CPRightTextAlignment
|
||||
@global CPCenterTextAlignment
|
||||
@global CPJustifiedTextAlignment
|
||||
@global CPNaturalTextAlignment
|
||||
|
||||
var PAPERSIZE = @"PaperSize",
|
||||
LEFTMARGIN = @"LeftMargin",
|
||||
RIGHTMARGIN = @"RightMargin",
|
||||
TOPMARGIN = @"TopMargin",
|
||||
BUTTOMMARGIN = @"ButtomMargin";
|
||||
|
||||
function _points2twips(a) { return (a) * 20.0; }
|
||||
|
||||
@implementation _CPRTFProducer : CPObject
|
||||
{
|
||||
CPAttributedString text;
|
||||
CPMutableDictionary fontDict;
|
||||
CPMutableDictionary colorDict;
|
||||
CPDictionary docDict;
|
||||
CPMutableArray attachments;
|
||||
CPFont currentFont;
|
||||
CPColor fgColor;
|
||||
CPColor bgColor;
|
||||
CPColor ulColor;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Class methods
|
||||
|
||||
|
||||
+ (CPString)produceRTF:(CPAttributedString)aText documentAttributes:(CPDictionary)dict
|
||||
{
|
||||
var mynew = [self new];
|
||||
|
||||
return [mynew RTFDStringFromAttributedString:aText documentAttributes:dict];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark init methods
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
// maintain a dictionary for the used colours
|
||||
// (for rtf-header generation)
|
||||
colorDict = [CPMutableDictionary new];
|
||||
|
||||
//maintain a dictionary for the used fonts
|
||||
//(for rtf-header generation)
|
||||
fontDict = [CPMutableDictionary new];
|
||||
|
||||
fgColor = [CPColor blackColor];
|
||||
bgColor= [CPColor whiteColor];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// private stuff follows
|
||||
- (CPString)fontTable
|
||||
{
|
||||
if (![fontDict count])
|
||||
return @"";
|
||||
|
||||
var fontlistString = "",
|
||||
fontEnum,
|
||||
currFont,
|
||||
keyArray;
|
||||
|
||||
keyArray = [fontDict allKeys];
|
||||
keyArray = [keyArray sortedArrayUsingSelector:@selector(compare:)];
|
||||
fontEnum = [keyArray objectEnumerator];
|
||||
|
||||
while ((currFont = [fontEnum nextObject]) !== nil)
|
||||
{
|
||||
var fontFamily,
|
||||
detail;
|
||||
|
||||
if ([currFont isEqualToString:@"Symbol"])
|
||||
fontFamily = @"tech";
|
||||
else if ([currFont isEqualToString:@"Helvetica"])
|
||||
fontFamily = @"swiss";
|
||||
else if ([currFont isEqualToString:@"Arial"])
|
||||
fontFamily = @"swiss";
|
||||
else if ([currFont isEqualToString:@"Courier"])
|
||||
fontFamily = @"modern";
|
||||
else if ([currFont isEqualToString:@"Times"])
|
||||
fontFamily = @"roman";
|
||||
else fontFamily = @"nil";
|
||||
|
||||
detail = [CPString stringWithFormat:@"%@\\f%@ %@;", [fontDict objectForKey:currFont], fontFamily, currFont];
|
||||
fontlistString += detail;
|
||||
}
|
||||
|
||||
return [CPString stringWithFormat:@"{\\fonttbl%@}\n", fontlistString];
|
||||
}
|
||||
|
||||
- (CPString)colorTable
|
||||
{
|
||||
if (![colorDict count])
|
||||
return @"";
|
||||
|
||||
var result,
|
||||
count = [colorDict count],
|
||||
list = [CPMutableArray arrayWithCapacity:count],
|
||||
keyEnum = [colorDict keyEnumerator],
|
||||
next,
|
||||
i;
|
||||
|
||||
while ((next = [keyEnum nextObject]) !== nil)
|
||||
{
|
||||
var cn = [colorDict objectForKey:next];
|
||||
[list insertObject:[CPColor colorWithCSSString:next] atIndex:[cn intValue]-1];
|
||||
}
|
||||
|
||||
result = [CPString stringWithString:@"{\\colortbl;"];
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
var color = [[list objectAtIndex:i]
|
||||
colorUsingColorSpaceName:CPCalibratedRGBColorSpace];
|
||||
|
||||
result += [CPString stringWithFormat:@"\\red%d\\green%d\\blue%d;",
|
||||
([color redComponent] * 255),
|
||||
([color greenComponent] * 255),
|
||||
([color blueComponent] * 255)];
|
||||
}
|
||||
|
||||
result += @"}\n";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (CPString)documentAttributes
|
||||
{
|
||||
if (!docDict)
|
||||
return @"";
|
||||
|
||||
var result,
|
||||
detail,
|
||||
val,
|
||||
num;
|
||||
|
||||
result = [CPString string];
|
||||
|
||||
val = [docDict objectForKey:PAPERSIZE];
|
||||
|
||||
if (val)
|
||||
{
|
||||
detail = [CPString stringWithFormat:@"\\paperw%d \\paperh%d",
|
||||
_points2twips(val.width),
|
||||
_points2twips(val.height)];
|
||||
|
||||
result += detail;
|
||||
}
|
||||
|
||||
num = [docDict objectForKey:LEFTMARGIN];
|
||||
|
||||
if (num)
|
||||
{
|
||||
var f = [num floatValue];
|
||||
|
||||
detail = [CPString stringWithFormat:@"\\margl%d", _points2twips(f)];
|
||||
result += detail;
|
||||
}
|
||||
|
||||
num = [docDict objectForKey:RIGHTMARGIN];
|
||||
|
||||
if (num)
|
||||
{
|
||||
var f = [num floatValue];
|
||||
|
||||
detail = [CPString stringWithFormat:@"\\margr%d", _points2twips(f)];
|
||||
result += detail;
|
||||
}
|
||||
|
||||
num = [docDict objectForKey:TOPMARGIN];
|
||||
|
||||
if (num)
|
||||
{
|
||||
var f = [num floatValue];
|
||||
|
||||
detail = [CPString stringWithFormat:@"\\margt%d", _points2twips(f)];
|
||||
result += detail;
|
||||
}
|
||||
|
||||
num = [docDict objectForKey:BUTTOMMARGIN];
|
||||
|
||||
if (num)
|
||||
{
|
||||
var f = [num floatValue];
|
||||
|
||||
detail = [CPString stringWithFormat:@"\\margb%d", _points2twips(f)];
|
||||
result += detail;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (CPString)headerString
|
||||
{
|
||||
var result;
|
||||
|
||||
result = [CPString stringWithString:@"{\\rtf1\\ansi"];
|
||||
result += [self fontTable];
|
||||
result += [self colorTable];
|
||||
result += [self documentAttributes];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (CPString)trailerString
|
||||
{
|
||||
return @"}";
|
||||
}
|
||||
|
||||
- (CPString)fontToken:(CPString) fontName
|
||||
{
|
||||
var fCount = [fontDict objectForKey:fontName];
|
||||
|
||||
if (fCount == nil)
|
||||
{
|
||||
var count = [fontDict count];
|
||||
|
||||
fCount = [CPString stringWithFormat:@"\\f%d", count];
|
||||
[fontDict setObject:fCount forKey:fontName];
|
||||
}
|
||||
|
||||
return fCount;
|
||||
}
|
||||
|
||||
- (int)numberForColor:(CPColor)color
|
||||
{
|
||||
var num = [colorDict objectForKey:[color cssString]];
|
||||
|
||||
if (!num)
|
||||
[colorDict setObject:num = [CPNumber numberWithInt:[colorDict count] + 1]
|
||||
forKey:[color cssString]];
|
||||
|
||||
return [num intValue];
|
||||
}
|
||||
|
||||
- (CPString)paragraphStyle:(CPParagraphStyle)paraStyle
|
||||
{
|
||||
var headerString = [CPString stringWithString:@"\\pard"],
|
||||
twips;
|
||||
|
||||
if (paraStyle == nil)
|
||||
return headerString;
|
||||
|
||||
switch ([paraStyle alignment])
|
||||
{
|
||||
case CPRightTextAlignment:
|
||||
headerString += @"\\qr";
|
||||
break;
|
||||
|
||||
case CPCenterTextAlignment:
|
||||
headerString += @"\\qc";
|
||||
break;
|
||||
|
||||
case CPLeftTextAlignment:
|
||||
headerString += @"\\ql";
|
||||
break;
|
||||
|
||||
case CPJustifiedTextAlignment:
|
||||
headerString += @"\\qj";
|
||||
break;
|
||||
|
||||
default:
|
||||
headerString += @"\\ql";
|
||||
break;
|
||||
}
|
||||
|
||||
// write first line indent and left indent
|
||||
var twips = _points2twips([paraStyle firstLineHeadIndent]);
|
||||
|
||||
if (twips != 0.0)
|
||||
headerString += [CPString stringWithFormat:@"\\fi%d", twips];
|
||||
|
||||
twips = _points2twips([paraStyle headIndent]);
|
||||
|
||||
if (twips != 0.0)
|
||||
headerString += [CPString stringWithFormat:@"\\li%d", twips];
|
||||
|
||||
twips = _points2twips([paraStyle tailIndent]);
|
||||
|
||||
if (twips != 0.0)
|
||||
headerString += [CPString stringWithFormat:@"\\ri%d", twips];
|
||||
|
||||
twips = _points2twips([paraStyle paragraphSpacing]);
|
||||
|
||||
if (twips != 0.0)
|
||||
headerString += [CPString stringWithFormat:@"\\sa%d", twips];
|
||||
|
||||
twips = _points2twips([paraStyle minimumLineHeight]);
|
||||
|
||||
if (twips != 0.0)
|
||||
headerString += [CPString stringWithFormat:@"\\sl%d", twips];
|
||||
|
||||
twips = _points2twips([paraStyle maximumLineHeight]);
|
||||
|
||||
if (twips != 0.0)
|
||||
headerString += [CPString stringWithFormat:@"\\sl-%d", twips];
|
||||
|
||||
var enumerator,
|
||||
tab;
|
||||
|
||||
enumerator = [[paraStyle tabStops] objectEnumerator];
|
||||
|
||||
while ((tab = [enumerator nextObject]))
|
||||
{
|
||||
switch ([tab tabStopType])
|
||||
{
|
||||
case CPLeftTabStopType:
|
||||
// no tabkind emission needed
|
||||
break;
|
||||
/* case NSRightTabStopType:
|
||||
headerString += @"\\tqr";
|
||||
break;
|
||||
case NSCenterTabStopType:
|
||||
headerString += @"\\tqc";
|
||||
break;
|
||||
case NSDecimalTabStopType:
|
||||
headerString += @"\\tqdec";
|
||||
break;
|
||||
default:
|
||||
NSLog(@"Unknown tab stop type.");
|
||||
*/
|
||||
}
|
||||
|
||||
headerString += [CPString stringWithFormat:@"\\tx%d",_points2twips([tab location])];
|
||||
}
|
||||
|
||||
return headerString;
|
||||
}
|
||||
|
||||
- (CPString)runStringForString:(CPString) substring
|
||||
attributes:(CPDictionary) attributes
|
||||
paragraphStart:(BOOL) first
|
||||
{
|
||||
var result = "",
|
||||
headerString = "",
|
||||
trailerString = "",
|
||||
attribEnum,
|
||||
currAttrib;
|
||||
|
||||
if (first)
|
||||
{
|
||||
var paraStyle = [attributes objectForKey:CPParagraphStyleAttributeName];
|
||||
headerString += [self paragraphStyle:paraStyle];
|
||||
}
|
||||
|
||||
/*
|
||||
* analyze attributes of current run
|
||||
*
|
||||
* FIXME: All the character attributes should be output relative to the font
|
||||
* attributes of the paragraph. So if the paragraph has underline on it should
|
||||
* still be possible to switch it off for some characters, which currently is
|
||||
* not possible.
|
||||
*/
|
||||
attribEnum = [attributes keyEnumerator];
|
||||
|
||||
while ((currAttrib = [attribEnum nextObject]) != nil)
|
||||
{
|
||||
if ([currAttrib isEqualToString:CPFontAttributeName])
|
||||
{
|
||||
/*
|
||||
* handle fonts
|
||||
*/
|
||||
var font,
|
||||
fontName,
|
||||
traits;
|
||||
|
||||
font = [attributes objectForKey:CPFontAttributeName];
|
||||
fontName = [font familyName];
|
||||
traits = [[CPFontManager sharedFontManager] traitsOfFont:font];
|
||||
|
||||
/*
|
||||
* font name
|
||||
*/
|
||||
if (currentFont == nil || ![fontName isEqualToString:[currentFont familyName]])
|
||||
headerString += [self fontToken:fontName];
|
||||
|
||||
/*
|
||||
* font size
|
||||
*/
|
||||
if (currentFont == nil || [font size] != [currentFont size])
|
||||
{
|
||||
var points = [font size] * 2,
|
||||
pString;
|
||||
|
||||
pString = [CPString stringWithFormat:@"\\fs%d", points];
|
||||
headerString += pString;
|
||||
}
|
||||
/*
|
||||
* font attributes
|
||||
*/
|
||||
if (traits & CPItalicFontMask)
|
||||
{
|
||||
headerString += @"\\i";
|
||||
trailerString += @"\\i0";
|
||||
}
|
||||
|
||||
if (traits & CPBoldFontMask)
|
||||
{
|
||||
headerString += @"\\b";
|
||||
trailerString += @"\\b0";
|
||||
}
|
||||
|
||||
if (first)
|
||||
currentFont = font;
|
||||
}
|
||||
else if ([currAttrib isEqualToString:CPForegroundColorAttributeName])
|
||||
{
|
||||
var color = [attributes objectForKey:CPForegroundColorAttributeName];
|
||||
|
||||
if (![color isEqual:fgColor])
|
||||
{
|
||||
headerString += [CPString stringWithFormat:@"\\cf%d", [self numberForColor:color]];
|
||||
trailerString += @"\\cf0";
|
||||
}
|
||||
}
|
||||
else if ([currAttrib isEqualToString:CPBackgroundColorAttributeName])
|
||||
{
|
||||
var color = [attributes objectForKey:CPBackgroundColorAttributeName];
|
||||
|
||||
if (![color isEqual:bgColor])
|
||||
{
|
||||
headerString += [CPString stringWithFormat:@"\\cb%d", [self numberForColor:color]];
|
||||
trailerString += @"\\cb0";
|
||||
}
|
||||
}
|
||||
else if ([currAttrib isEqualToString:CPUnderlineStyleAttributeName])
|
||||
{
|
||||
headerString += @"\\ul";
|
||||
trailerString += @"\\ulnone";
|
||||
}
|
||||
else if ([currAttrib isEqualToString:CPSuperscriptAttributeName])
|
||||
{
|
||||
var value = [attributes objectForKey:CPSuperscriptAttributeName],
|
||||
svalue = [value intValue] * 6;
|
||||
|
||||
if (svalue > 0)
|
||||
{
|
||||
headerString += [CPString stringWithFormat:@"\\up%d", svalue];
|
||||
trailerString += @"\\up0";
|
||||
}
|
||||
else if (svalue < 0)
|
||||
{
|
||||
headerString += [CPString stringWithFormat:@"\\dn-%d", svalue];
|
||||
trailerString += @"\\dn0";
|
||||
}
|
||||
}
|
||||
else if ([currAttrib isEqualToString:CPBaselineOffsetAttributeName])
|
||||
{
|
||||
var value = [attributes objectForKey:CPBaselineOffsetAttributeName],
|
||||
svalue = [value floatValue] * 2;
|
||||
|
||||
if (svalue > 0)
|
||||
{
|
||||
headerString += [CPString stringWithFormat:@"\\up%d", svalue];
|
||||
trailerString += @"\\up0";
|
||||
}
|
||||
else if (svalue < 0)
|
||||
{
|
||||
headerString += [CPString stringWithFormat:@"\\dn-%d", svalue];
|
||||
trailerString += @"\\dn0";
|
||||
}
|
||||
}
|
||||
else if ([currAttrib isEqualToString:CPAttachmentAttributeName])
|
||||
{
|
||||
}
|
||||
else if ([currAttrib isEqualToString:CPLigatureAttributeName])
|
||||
{
|
||||
}
|
||||
else if ([currAttrib isEqualToString:CPKernAttributeName])
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
substring = substring.replace(/\\/g, '\\\\');
|
||||
substring = substring.replace(/\n/g, '\\par\n');
|
||||
substring = substring.replace(/\t/g, '\\tab');
|
||||
substring = substring.replace(/{/g, '\\{');
|
||||
substring = substring.replace(/}/g, '\\}');
|
||||
// FIXME: All characters not in the standard encoding must be
|
||||
// replaced by \'xx
|
||||
|
||||
if (!first)
|
||||
{
|
||||
var braces;
|
||||
|
||||
if ([headerString length])
|
||||
braces = [CPString stringWithFormat:@"{%@ %@}", headerString, substring];
|
||||
else
|
||||
braces = substring;
|
||||
|
||||
result += braces;
|
||||
}
|
||||
else
|
||||
{
|
||||
var nobraces;
|
||||
|
||||
if ([headerString length])
|
||||
nobraces = [CPString stringWithFormat:@"%@ %@", headerString, substring];
|
||||
else
|
||||
nobraces = substring;
|
||||
|
||||
result += nobraces;
|
||||
}
|
||||
|
||||
return result + trailerString;
|
||||
}
|
||||
|
||||
- (CPString)bodyString
|
||||
{
|
||||
var string = [text string],
|
||||
result = "",
|
||||
loc = 0,
|
||||
length = [string length],
|
||||
currRange = CPMakeRange(loc, 0),
|
||||
completeRange = CPMakeRange(0, length),
|
||||
first = YES;
|
||||
|
||||
// FIXME <!> split along newline characters and run as outer loop
|
||||
while (CPMaxRange(currRange) < CPMaxRange(completeRange)) // save all "runs"
|
||||
{
|
||||
var attributes,
|
||||
substring,
|
||||
runString;
|
||||
|
||||
attributes = [text attributesAtIndex:CPMaxRange(currRange)
|
||||
longestEffectiveRange:currRange
|
||||
inRange:completeRange];
|
||||
substring = [string substringWithRange:currRange];
|
||||
runString = [self runStringForString:substring
|
||||
attributes:attributes
|
||||
paragraphStart:YES];
|
||||
|
||||
result += runString;
|
||||
first = NO;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
- (CPString)RTFDStringFromAttributedString:(CPAttributedString)aText
|
||||
documentAttributes:(CPDictionary)dict
|
||||
{
|
||||
var output = [CPString string],
|
||||
headerString,
|
||||
trailerString,
|
||||
bodyString;
|
||||
|
||||
text = aText;
|
||||
docDict = dict;
|
||||
|
||||
/*
|
||||
* do not change order! (esp. body has to be generated first; builds context)
|
||||
*/
|
||||
bodyString = [self bodyString];
|
||||
trailerString = [self trailerString];
|
||||
headerString = [self headerString];
|
||||
|
||||
output += headerString;
|
||||
output += bodyString;
|
||||
output += trailerString;
|
||||
return output;
|
||||
}
|
||||
@end
|
||||
+398
-195
@@ -24,8 +24,12 @@
|
||||
@import <Foundation/CPMutableArray.j>
|
||||
@import <Foundation/CPString.j>
|
||||
@import <Foundation/CPKeyedUnarchiver.j>
|
||||
@import <Foundation/CPBundle.j>
|
||||
|
||||
@class CPView
|
||||
@class _CPThemeAttribute
|
||||
@class CPImage
|
||||
@class CPColor
|
||||
|
||||
var CPThemesByName = { },
|
||||
CPThemeDefaultTheme = nil,
|
||||
@@ -35,7 +39,6 @@ var CPThemesByName = { },
|
||||
/*!
|
||||
@ingroup appkit
|
||||
*/
|
||||
|
||||
@implementation CPTheme : CPObject
|
||||
{
|
||||
CPString _name;
|
||||
@@ -141,20 +144,19 @@ var CPThemesByName = { },
|
||||
|
||||
if (!className)
|
||||
{
|
||||
if ([aClass isKindOfClass:[CPView class]])
|
||||
if ([aClass respondsToSelector:@selector(defaultThemeClass)])
|
||||
{
|
||||
if ([aClass respondsToSelector:@selector(defaultThemeClass)])
|
||||
className = [aClass defaultThemeClass];
|
||||
else if ([aClass respondsToSelector:@selector(themeClass)])
|
||||
{
|
||||
CPLog.warn(@"%@ themeClass is deprecated in favor of defaultThemeClass", CPStringFromClass(aClass));
|
||||
className = [aClass themeClass];
|
||||
}
|
||||
else
|
||||
return nil;
|
||||
className = [aClass defaultThemeClass];
|
||||
}
|
||||
else if ([aClass respondsToSelector:@selector(themeClass)])
|
||||
{
|
||||
CPLog.warn(@"%@ themeClass is deprecated in favor of defaultThemeClass", CPStringFromClass(aClass));
|
||||
className = [aClass themeClass];
|
||||
}
|
||||
else
|
||||
[CPException raise:CPInvalidArgumentException reason:@"aClass must be a class object or a string."];
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
return [_attributes objectForKey:className];
|
||||
@@ -240,7 +242,7 @@ var CPThemesByName = { },
|
||||
@param aClass The themed class in which to look for the attribute
|
||||
@return A value or nil
|
||||
*/
|
||||
- (id)valueForAttributeWithName:(CPString)aName inState:(CPThemeState)aState forClass:(id)aClass
|
||||
- (id)valueForAttributeWithName:(CPString)aName inState:(ThemeState)aState forClass:(id)aClass
|
||||
{
|
||||
var attribute = [self attributeWithName:aName forClass:aClass];
|
||||
|
||||
@@ -314,6 +316,278 @@ var CPThemeNameKey = @"CPThemeNameKey",
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark CSS Theming
|
||||
|
||||
// The code below adds support for CSS theming with 100% compatibility with current theming system.
|
||||
// The idea is to extend CPColor and CPImage with CSS components and adapt low level UI components to
|
||||
// support this new kind of CPColor/CPImage. See CPImageView, CPView and _CPImageAndTextView.
|
||||
//
|
||||
// To be considered and treated as CSS based, a theme must set to YES the attribute "css-based" for CPView
|
||||
// in the theDescriptor (default value is NO), like in the example below :
|
||||
//
|
||||
// + (CPView)themedView
|
||||
// {
|
||||
// var view = [[CPView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
|
||||
//
|
||||
// [self registerThemeValues:[[@"css-based", YES]] forView:view];
|
||||
//
|
||||
// return view;
|
||||
// }
|
||||
//
|
||||
// You can use the method -(BOOL)isCSSBased on a theme to determine how to cope with it in your own code.
|
||||
//
|
||||
// The method -(void)setCSSResourcesPath is meant to be used only by CPThemeBlend during theme loading in order to
|
||||
// replace the special path "%%" in CSS components (like in url(%%packed.png) ) with the path to the theme blend resources folder.
|
||||
|
||||
@implementation CPTheme (CSSTheming)
|
||||
|
||||
- (void)setCSSResourcesPath:(CPString)pathToResources
|
||||
{
|
||||
[_attributes enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
|
||||
{
|
||||
[anObject enumerateKeysAndObjectsUsingBlock:function(aKey2, anObject2, stop2)
|
||||
{
|
||||
// anObject2 is now a _CPThemeAttribute
|
||||
|
||||
[[anObject2 values] enumerateKeysAndObjectsUsingBlock:function(aKey3, anObject3, stop3)
|
||||
{
|
||||
if (anObject3.isa && ([anObject3 isKindOfClass:CPImage] || [anObject3 isKindOfClass:CPColor]) && [anObject3 cssDictionary])
|
||||
{
|
||||
// We have a CSS defined image or color
|
||||
[self _fixPathInCSSDictionary:[anObject3 cssDictionary] withPathToResources:pathToResources];
|
||||
[self _fixPathInCSSDictionary:[anObject3 cssBeforeDictionary] withPathToResources:pathToResources];
|
||||
[self _fixPathInCSSDictionary:[anObject3 cssAfterDictionary] withPathToResources:pathToResources];
|
||||
}
|
||||
}];
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)_fixPathInCSSDictionary:(CPDictionary)aDictionary withPathToResources:(CPString)pathToResources
|
||||
{
|
||||
[aDictionary enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
|
||||
{
|
||||
[aDictionary setObject:[anObject stringByReplacingOccurrencesOfString:@"%%" withString:pathToResources] forKey:aKey];
|
||||
}];
|
||||
}
|
||||
|
||||
- (BOOL)isCSSBased
|
||||
{
|
||||
return !![self valueForAttributeWithName:@"css-based" forClass:[CPView class]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
/*!
|
||||
* ThemeStates are immutable objects representing a particular ThemeState. Applications should never be creating
|
||||
* ThemeStates directly but should instead use the CPThemeState function.
|
||||
*/
|
||||
function ThemeState(stateNames)
|
||||
{
|
||||
var stateNameKeys = [];
|
||||
this._stateNames = {};
|
||||
|
||||
for (var key in stateNames)
|
||||
{
|
||||
if (!stateNames.hasOwnProperty(key))
|
||||
continue;
|
||||
|
||||
if (key !== 'normal')
|
||||
{
|
||||
this._stateNames[key] = true;
|
||||
stateNameKeys.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (stateNameKeys.length === 0)
|
||||
{
|
||||
stateNameKeys.push('normal');
|
||||
this._stateNames['normal'] = true;
|
||||
}
|
||||
|
||||
stateNameKeys.sort();
|
||||
this._stateNameString = stateNameKeys[0];
|
||||
|
||||
var stateNameLength = stateNameKeys.length;
|
||||
|
||||
for (var stateIndex = 1; stateIndex < stateNameLength; stateIndex++)
|
||||
this._stateNameString = this._stateNameString + "+" + stateNameKeys[stateIndex];
|
||||
|
||||
this._stateNameCount = stateNameLength;
|
||||
}
|
||||
|
||||
ThemeState.prototype.toString = function()
|
||||
{
|
||||
return this._stateNameString;
|
||||
}
|
||||
|
||||
ThemeState.prototype.hasThemeState = function(aState)
|
||||
{
|
||||
if (!aState || !aState._stateNames)
|
||||
return false;
|
||||
|
||||
// We can do this in O(n) because both states have their stateNames already sorted.
|
||||
for (var stateName in aState._stateNames)
|
||||
{
|
||||
if (!aState._stateNames.hasOwnProperty(stateName))
|
||||
continue;
|
||||
|
||||
if (!this._stateNames[stateName])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ThemeState.prototype.isSubsetOf = function(aState)
|
||||
{
|
||||
if (aState._stateNameCount < this._stateNameCount)
|
||||
return false;
|
||||
|
||||
for (var key in this._stateNames)
|
||||
{
|
||||
if (!this._stateNames.hasOwnProperty(key))
|
||||
continue;
|
||||
|
||||
if (!aState._stateNames[key])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ThemeState.prototype.without = function(aState)
|
||||
{
|
||||
if (!aState || aState === [CPNull null])
|
||||
return this;
|
||||
|
||||
var firstTransform = CPThemeWithoutTransform[this._stateNameString],
|
||||
result;
|
||||
|
||||
if (firstTransform)
|
||||
{
|
||||
result = firstTransform[aState._stateNameString];
|
||||
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
|
||||
var newStates = {};
|
||||
|
||||
for (var stateName in this._stateNames)
|
||||
{
|
||||
if (!this._stateNames.hasOwnProperty(stateName))
|
||||
continue;
|
||||
|
||||
if (!aState._stateNames[stateName])
|
||||
newStates[stateName] = true;
|
||||
}
|
||||
|
||||
result = ThemeState._cacheThemeState(new ThemeState(newStates));
|
||||
|
||||
if (!firstTransform)
|
||||
firstTransform = CPThemeWithoutTransform[this._stateNameString] = {};
|
||||
|
||||
firstTransform[aState._stateNameString] = result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ThemeState.prototype.and = function(aState)
|
||||
{
|
||||
var firstTransform = CPThemeAndTransform[this._stateNameString],
|
||||
result;
|
||||
|
||||
if (firstTransform)
|
||||
{
|
||||
result = firstTransform[aState._stateNameString];
|
||||
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
|
||||
result = CPThemeState(this, aState);
|
||||
|
||||
if (!firstTransform)
|
||||
firstTransform = CPThemeAndTransform[this._stateNameString] = {};
|
||||
|
||||
firstTransform[aState._stateNameString] = result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var CPThemeStates = {},
|
||||
CPThemeWithoutTransform = {},
|
||||
CPThemeAndTransform = {};
|
||||
|
||||
ThemeState._cacheThemeState = function(aState)
|
||||
{
|
||||
// We do this caching so themeState equality works. Basically, doing CPThemeState('foo+bar') === CPThemeState('bar', 'foo') will return true.
|
||||
var themeState = CPThemeStates[String(aState)];
|
||||
|
||||
if (themeState === undefined)
|
||||
{
|
||||
themeState = aState;
|
||||
CPThemeStates[String(themeState)] = themeState;
|
||||
}
|
||||
|
||||
return themeState;
|
||||
}
|
||||
|
||||
/*!
|
||||
* This method can be called in multiple ways:
|
||||
* CPThemeState('state1') - creates a new CPThemeState that corresponds to the string 'state1'
|
||||
* CPThemeState('state1', 'state2') - creates a new composite CPThemeState made up of both 'state1' or 'state2'
|
||||
* CPThemeState('state1+state2') - The same as CPThemeState('state1', 'state2')
|
||||
* CPThemeState(state1, state2) - creates a new composite CPThemeState made up of state1 and state2
|
||||
* where state1 and state2 are not strings but are themselves CPThemeStates.
|
||||
*/
|
||||
function CPThemeState()
|
||||
{
|
||||
if (arguments.length < 1)
|
||||
throw "CPThemeState() must be called with at least one string argument";
|
||||
|
||||
var themeState;
|
||||
|
||||
if (arguments.length === 1 && typeof arguments[0] === 'string')
|
||||
{
|
||||
themeState = CPThemeStates[arguments[0]];
|
||||
|
||||
if (themeState !== undefined)
|
||||
return themeState;
|
||||
}
|
||||
|
||||
var stateNames = {};
|
||||
|
||||
for (var argIndex = 0; argIndex < arguments.length; argIndex++)
|
||||
{
|
||||
if (arguments[argIndex] === [CPNull null] || !arguments[argIndex])
|
||||
continue;
|
||||
|
||||
if (typeof arguments[argIndex] === 'object')
|
||||
{
|
||||
for (var stateName in arguments[argIndex]._stateNames)
|
||||
{
|
||||
if (!arguments[argIndex]._stateNames.hasOwnProperty(stateName))
|
||||
continue;
|
||||
|
||||
stateNames[stateName] = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var allNames = arguments[argIndex].split('+');
|
||||
|
||||
for (var nameIndex = 0; nameIndex < allNames.length; nameIndex++)
|
||||
stateNames[allNames[nameIndex]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
themeState = ThemeState._cacheThemeState(new ThemeState(stateNames));
|
||||
return themeState;
|
||||
}
|
||||
|
||||
@implementation _CPThemeKeyedUnarchiver : CPKeyedUnarchiver
|
||||
{
|
||||
CPBundle _bundle;
|
||||
@@ -341,88 +615,31 @@ var CPThemeNameKey = @"CPThemeNameKey",
|
||||
|
||||
@end
|
||||
|
||||
var CPThemeStates = {},
|
||||
CPThemeStateNames = {},
|
||||
CPThemeStateCount = 0;
|
||||
CPThemeStateNormal = CPThemeState("normal");
|
||||
CPThemeStateDisabled = CPThemeState("disabled");
|
||||
CPThemeStateHovered = CPThemeState("hovered");
|
||||
CPThemeStateHighlighted = CPThemeState("highlighted");
|
||||
CPThemeStateSelected = CPThemeState("selected");
|
||||
CPThemeStateTableDataView = CPThemeState("tableDataView");
|
||||
CPThemeStateSelectedDataView = CPThemeState("selectedTableDataView");
|
||||
CPThemeStateGroupRow = CPThemeState("CPThemeStateGroupRow");
|
||||
CPThemeStateBezeled = CPThemeState("bezeled");
|
||||
CPThemeStateBordered = CPThemeState("bordered");
|
||||
CPThemeStateEditable = CPThemeState("editable");
|
||||
CPThemeStateEditing = CPThemeState("editing");
|
||||
CPThemeStateVertical = CPThemeState("vertical");
|
||||
CPThemeStateDefault = CPThemeState("default");
|
||||
CPThemeStateCircular = CPThemeState("circular");
|
||||
CPThemeStateAutocompleting = CPThemeState("autocompleting");
|
||||
CPThemeStateFirstResponder = CPThemeState("firstResponder");
|
||||
CPThemeStateMainWindow = CPThemeState("mainWindow");
|
||||
CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
CPThemeStateControlSizeRegular = CPThemeState("controlSizeRegular");
|
||||
CPThemeStateControlSizeSmall = CPThemeState("controlSizeSmall");
|
||||
CPThemeStateControlSizeMini = CPThemeState("controlSizeMini");
|
||||
|
||||
function CPThemeState(aStateName)
|
||||
{
|
||||
var state = CPThemeStates[aStateName];
|
||||
CPThemeStateNormalString = String(CPThemeStateNormal);
|
||||
|
||||
if (state === undefined)
|
||||
{
|
||||
if (aStateName.indexOf('+') === -1)
|
||||
state = 1 << CPThemeStateCount++;
|
||||
else
|
||||
{
|
||||
var state = 0,
|
||||
states = aStateName.split('+'),
|
||||
count = states.length;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var stateName = states[count],
|
||||
individualState = CPThemeStates[stateName];
|
||||
|
||||
if (individualState === undefined)
|
||||
{
|
||||
individualState = 1 << CPThemeStateCount++;
|
||||
CPThemeStates[stateName] = individualState;
|
||||
CPThemeStateNames[individualState] = stateName;
|
||||
}
|
||||
|
||||
state |= individualState;
|
||||
}
|
||||
}
|
||||
|
||||
CPThemeStates[aStateName] = state;
|
||||
CPThemeStateNames[state] = aStateName;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
function CPThemeStateName(aState)
|
||||
{
|
||||
var name = CPThemeStateNames[aState];
|
||||
|
||||
if (name !== undefined)
|
||||
return name;
|
||||
|
||||
if (!(aState & (aState - 1)))
|
||||
return "";
|
||||
|
||||
var state = 1,
|
||||
name = "";
|
||||
|
||||
for (; state < aState; state <<= 1)
|
||||
if (aState & state)
|
||||
name += (name.length === 0 ? '' : '+') + CPThemeStateNames[state];
|
||||
|
||||
CPThemeStateNames[aState] = name;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
CPThemeStateNames[0] = "normal";
|
||||
CPThemeStateNormal = CPThemeStates["normal"] = 0;
|
||||
CPThemeStateDisabled = CPThemeState("disabled");
|
||||
CPThemeStateHovered = CPThemeState("hovered");
|
||||
CPThemeStateHighlighted = CPThemeState("highlighted");
|
||||
CPThemeStateSelected = CPThemeState("selected");
|
||||
CPThemeStateTableDataView = CPThemeState("tableDataView");
|
||||
CPThemeStateSelectedDataView = CPThemeState("selectedTableDataView");
|
||||
CPThemeStateGroupRow = CPThemeState("CPThemeStateGroupRow");
|
||||
CPThemeStateBezeled = CPThemeState("bezeled");
|
||||
CPThemeStateBordered = CPThemeState("bordered");
|
||||
CPThemeStateEditable = CPThemeState("editable");
|
||||
CPThemeStateEditing = CPThemeState("editing");
|
||||
CPThemeStateVertical = CPThemeState("vertical");
|
||||
CPThemeStateDefault = CPThemeState("default");
|
||||
CPThemeStateCircular = CPThemeState("circular");
|
||||
CPThemeStateAutocompleting = CPThemeState("autocompleting");
|
||||
CPThemeStateMainWindow = CPThemeState("mainWindow");
|
||||
CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
|
||||
@implementation _CPThemeAttribute : CPObject
|
||||
{
|
||||
@@ -434,7 +651,7 @@ CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
_CPThemeAttribute _themeDefaultAttribute;
|
||||
}
|
||||
|
||||
- (id)initWithName:(CPString)aName defaultValue:(id)aDefaultValue
|
||||
- (id)initWithName:(CPString)aName defaultValue:(id)aDefaultValue defaultAttribute:(_CPThemeAttribute)aDefaultAttribute
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
@@ -443,7 +660,9 @@ CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
_cache = { };
|
||||
_name = aName;
|
||||
_defaultValue = aDefaultValue;
|
||||
_values = @{};
|
||||
|
||||
if (aDefaultAttribute)
|
||||
_themeDefaultAttribute = aDefaultAttribute;
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -464,29 +683,41 @@ CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
return [_values count] > 0;
|
||||
}
|
||||
|
||||
- (BOOL)isTrivial
|
||||
- (_CPThemeAttribute)attributeBySettingValue:(id)aValue
|
||||
{
|
||||
return ([_values count] === 1) && (Number([_values allKeys][0]) === CPThemeStateNormal);
|
||||
var attribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue defaultAttribute:_themeDefaultAttribute];
|
||||
|
||||
if (aValue !== undefined && aValue !== nil)
|
||||
attribute._values = @{ CPThemeStateNormalString: aValue };
|
||||
|
||||
return attribute;
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue
|
||||
- (_CPThemeAttribute)attributeBySettingValue:(id)aValue forState:(ThemeState)aState
|
||||
{
|
||||
_cache = {};
|
||||
var shouldRemoveValue = aValue === undefined || aValue === nil,
|
||||
attribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue defaultAttribute:_themeDefaultAttribute],
|
||||
values = _values;
|
||||
|
||||
if (aValue === undefined || aValue === nil)
|
||||
_values = @{};
|
||||
else
|
||||
_values = @{ String(CPThemeStateNormal): aValue };
|
||||
}
|
||||
if (values != null)
|
||||
{
|
||||
values = [values copy];
|
||||
|
||||
- (void)setValue:(id)aValue forState:(CPThemeState)aState
|
||||
{
|
||||
_cache = { };
|
||||
if (shouldRemoveValue)
|
||||
[values removeObjectForKey:String(aState)];
|
||||
else
|
||||
[values setObject:aValue forKey:String(aState)];
|
||||
|
||||
if ((aValue === undefined) || (aValue === nil))
|
||||
[_values removeObjectForKey:String(aState)];
|
||||
else
|
||||
[_values setObject:aValue forKey:String(aState)];
|
||||
attribute._values = values;
|
||||
}
|
||||
else if (!shouldRemoveValue)
|
||||
{
|
||||
values = [[CPDictionary alloc] init];
|
||||
[values setObject:aValue forKey:String(aState)];
|
||||
attribute._values = values;
|
||||
}
|
||||
|
||||
return attribute;
|
||||
}
|
||||
|
||||
- (id)value
|
||||
@@ -494,44 +725,34 @@ CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
return [self valueForState:CPThemeStateNormal];
|
||||
}
|
||||
|
||||
- (id)valueForState:(CPThemeState)aState
|
||||
- (id)valueForState:(ThemeState)aState
|
||||
{
|
||||
var value = _cache[aState];
|
||||
var stateName = String(aState),
|
||||
value = _cache[stateName];
|
||||
|
||||
// This can be nil.
|
||||
if (value !== undefined)
|
||||
return value;
|
||||
|
||||
value = [_values objectForKey:String(aState)];
|
||||
value = [_values objectForKey:stateName];
|
||||
|
||||
// If we don't have a value, and we have a non-normal state...
|
||||
if ((value === undefined || value === nil) && aState !== CPThemeStateNormal)
|
||||
if (value === undefined || value === nil)
|
||||
{
|
||||
// If this is a composite state (not a power of 2), find the closest partial subset match.
|
||||
if (aState & (aState - 1))
|
||||
// If this is a composite state, find the closest partial subset match.
|
||||
if (aState._stateNameCount > 1)
|
||||
{
|
||||
var highestOneCount = 0,
|
||||
states = [_values allKeys],
|
||||
count = states.length;
|
||||
var states = [_values allKeys],
|
||||
count = states ? states.length : 0,
|
||||
largestThemeState = 0;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
// states[count] is a string!
|
||||
var state = Number(states[count]);
|
||||
var stateObject = CPThemeState(states[count]);
|
||||
|
||||
// A & B = A iff A < B
|
||||
if ((state & aState) === state)
|
||||
if (stateObject.isSubsetOf(aState) && stateObject._stateNameCount > largestThemeState)
|
||||
{
|
||||
var oneCount = cachedNumberOfOnes[state];
|
||||
|
||||
if (oneCount === undefined)
|
||||
oneCount = numberOfOnes(state);
|
||||
|
||||
if (oneCount > highestOneCount)
|
||||
{
|
||||
highestOneCount = oneCount;
|
||||
value = [_values objectForKey:String(state)];
|
||||
}
|
||||
value = [_values objectForKey:states[count]];
|
||||
largestThemeState = stateObject._stateNameCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -554,32 +775,46 @@ CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
value = nil;
|
||||
}
|
||||
|
||||
_cache[aState] = value;
|
||||
_cache[stateName] = value;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
- (void)setParentAttribute:(_CPThemeAttribute)anAttribute
|
||||
- (_CPThemeAttribute)attributeBySettingParentAttribute:(_CPThemeAttribute)anAttribute
|
||||
{
|
||||
if (_themeDefaultAttribute === anAttribute)
|
||||
return;
|
||||
return self;
|
||||
|
||||
_cache = { };
|
||||
_themeDefaultAttribute = anAttribute;
|
||||
var attribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue defaultAttribute:anAttribute];
|
||||
|
||||
attribute._values = [_values copy];
|
||||
|
||||
return attribute;
|
||||
}
|
||||
|
||||
- (_CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
|
||||
{
|
||||
var mergedAttribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue];
|
||||
var mergedAttribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue defaultAttribute:_themeDefaultAttribute];
|
||||
|
||||
mergedAttribute._values = [_values copy];
|
||||
[mergedAttribute._values addEntriesFromDictionary:anAttribute._values];
|
||||
|
||||
if (anAttribute._values)
|
||||
mergedAttribute._values ? [mergedAttribute._values addEntriesFromDictionary:anAttribute._values] : [anAttribute._values copy];
|
||||
|
||||
return mergedAttribute;
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
return [super description] + @" Name: " + _name + @", defaultAttribute: " + _themeDefaultAttribute + @", defaultValue: " + _defaultValue + @", values: " + _values;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
// This is used to pass 'parrentAttribute' to the coder
|
||||
var ParentAttributeForCoder = nil;
|
||||
|
||||
@implementation _CPThemeAttribute (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
@@ -593,13 +828,16 @@ CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
_name = [aCoder decodeObjectForKey:@"name"];
|
||||
_defaultValue = [aCoder decodeObjectForKey:@"defaultValue"];
|
||||
_values = @{};
|
||||
_themeDefaultAttribute = ParentAttributeForCoder;
|
||||
|
||||
if ([aCoder containsValueForKey:@"value"])
|
||||
{
|
||||
var state = CPThemeStateNormal;
|
||||
var state;
|
||||
|
||||
if ([aCoder containsValueForKey:@"state"])
|
||||
state = CPThemeState([aCoder decodeObjectForKey:@"state"]);
|
||||
state = [aCoder decodeObjectForKey:@"state"];
|
||||
else
|
||||
state = CPThemeStateNormalString;
|
||||
|
||||
[_values setObject:[aCoder decodeObjectForKey:"value"] forKey:state];
|
||||
}
|
||||
@@ -613,7 +851,7 @@ CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
{
|
||||
var key = keys[count];
|
||||
|
||||
[_values setObject:[encodedValues objectForKey:key] forKey:CPThemeState(key)];
|
||||
[_values setObject:[encodedValues objectForKey:key] forKey:key];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -627,14 +865,14 @@ CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
[aCoder encodeObject:_defaultValue forKey:@"defaultValue"];
|
||||
|
||||
var keys = [_values allKeys],
|
||||
count = keys.length;
|
||||
count = keys ? keys.length : 0;
|
||||
|
||||
if (count === 1)
|
||||
{
|
||||
var onlyKey = keys[0];
|
||||
|
||||
if (Number(onlyKey) !== CPThemeStateNormal)
|
||||
[aCoder encodeObject:CPThemeStateName(Number(onlyKey)) forKey:@"state"];
|
||||
if (onlyKey !== String(CPThemeStateNormal))
|
||||
[aCoder encodeObject:onlyKey forKey:@"state"];
|
||||
|
||||
[aCoder encodeObject:[_values objectForKey:onlyKey] forKey:@"value"];
|
||||
}
|
||||
@@ -646,7 +884,7 @@ CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
{
|
||||
var key = keys[count];
|
||||
|
||||
[encodedValues setObject:[_values objectForKey:key] forKey:CPThemeStateName(Number(key))];
|
||||
[encodedValues setObject:[_values objectForKey:key] forKey:key];
|
||||
}
|
||||
|
||||
[aCoder encodeObject:encodedValues forKey:@"values"];
|
||||
@@ -655,35 +893,6 @@ CPThemeStateKeyWindow = CPThemeState("keyWindow");
|
||||
|
||||
@end
|
||||
|
||||
var cachedNumberOfOnes = [ 0 /*000000*/, 1 /*000001*/, 1 /*000010*/, 2 /*000011*/, 1 /*000100*/, 2 /*000101*/, 2 /*000110*/,
|
||||
3 /*000111*/, 1 /*001000*/, 2 /*001001*/, 2 /*001010*/, 3 /*001011*/, 2 /*001100*/, 3 /*001101*/,
|
||||
3 /*001110*/, 4 /*001111*/, 1 /*010000*/, 2 /*010001*/, 2 /*010010*/, 3 /*010011*/, 2 /*010100*/,
|
||||
3 /*010101*/, 3 /*010110*/, 4 /*010111*/, 2 /*011000*/, 3 /*011001*/, 3 /*011010*/, 4 /*011011*/,
|
||||
3 /*011100*/, 4 /*011101*/, 4 /*011110*/, 5 /*011111*/, 1 /*100000*/, 2 /*100001*/, 2 /*100010*/,
|
||||
3 /*100011*/, 2 /*100100*/, 3 /*100101*/, 3 /*100110*/, 4 /*100111*/, 2 /*101000*/, 3 /*101001*/,
|
||||
3 /*101010*/, 4 /*101011*/, 3 /*101100*/, 4 /*101101*/, 4 /*101110*/, 5 /*101111*/, 2 /*110000*/,
|
||||
3 /*110001*/, 3 /*110010*/, 4 /*110011*/, 3 /*110100*/, 4 /*110101*/, 4 /*110110*/, 5 /*110111*/,
|
||||
3 /*111000*/, 4 /*111001*/, 4 /*111010*/, 5 /*111011*/, 4 /*111100*/, 5 /*111101*/, 5 /*111110*/,
|
||||
6 /*111111*/ ];
|
||||
|
||||
var numberOfOnes = function(aNumber)
|
||||
{
|
||||
var count = 0,
|
||||
slot = aNumber;
|
||||
|
||||
while (aNumber)
|
||||
{
|
||||
++count;
|
||||
aNumber &= (aNumber - 1);
|
||||
}
|
||||
|
||||
cachedNumberOfOnes[slot] = count;
|
||||
|
||||
return count;
|
||||
};
|
||||
|
||||
numberOfOnes.displayName = "numberOfOnes";
|
||||
|
||||
function CPThemeAttributeEncode(aCoder, aThemeAttribute)
|
||||
{
|
||||
var values = aThemeAttribute._values,
|
||||
@@ -694,7 +903,7 @@ function CPThemeAttributeEncode(aCoder, aThemeAttribute)
|
||||
{
|
||||
var state = [values allKeys][0];
|
||||
|
||||
if (Number(state) === 0)
|
||||
if (state === CPThemeStateNormalString)
|
||||
{
|
||||
[aCoder encodeObject:[values objectForKey:state] forKey:key];
|
||||
|
||||
@@ -712,30 +921,24 @@ function CPThemeAttributeEncode(aCoder, aThemeAttribute)
|
||||
return NO;
|
||||
}
|
||||
|
||||
function CPThemeAttributeDecode(aCoder, anAttributeName, aDefaultValue, aTheme, aClass)
|
||||
function CPThemeAttributeDecode(aCoder, attribute)
|
||||
{
|
||||
var key = "$a" + anAttributeName;
|
||||
var key = "$a" + attribute._name;
|
||||
|
||||
if (![aCoder containsValueForKey:key])
|
||||
var attribute = [[_CPThemeAttribute alloc] initWithName:anAttributeName defaultValue:aDefaultValue];
|
||||
|
||||
else
|
||||
if ([aCoder containsValueForKey:key])
|
||||
{
|
||||
var attribute = [aCoder decodeObjectForKey:key];
|
||||
ParentAttributeForCoder = attribute._themeDefaultAttribute;
|
||||
|
||||
if (!attribute.isa || ![attribute isKindOfClass:[_CPThemeAttribute class]])
|
||||
{
|
||||
var themeAttribute = [[_CPThemeAttribute alloc] initWithName:anAttributeName defaultValue:aDefaultValue];
|
||||
var decodedAttribute = [aCoder decodeObjectForKey:key];
|
||||
|
||||
[themeAttribute setValue:attribute];
|
||||
ParentAttributeForCoder = nil;
|
||||
|
||||
attribute = themeAttribute;
|
||||
}
|
||||
if (!decodedAttribute || !decodedAttribute.isa || ![decodedAttribute isKindOfClass:[_CPThemeAttribute class]])
|
||||
attribute = [attribute attributeBySettingValue:decodedAttribute];
|
||||
else
|
||||
attribute = decodedAttribute;
|
||||
}
|
||||
|
||||
if (aTheme && aClass)
|
||||
[attribute setParentAttribute:[aTheme attributeWithName:anAttributeName forClass:aClass]];
|
||||
|
||||
return attribute;
|
||||
}
|
||||
|
||||
|
||||
+15
-6
@@ -64,12 +64,10 @@
|
||||
*/
|
||||
- (CPArray)themeNames
|
||||
{
|
||||
var names = [];
|
||||
|
||||
for (var i = 0; i < _themes.length; ++i)
|
||||
names.push(_themes[i].substring(0, _themes[i].indexOf(".keyedtheme")));
|
||||
|
||||
return names;
|
||||
return [_themes arrayByApplyingBlock:function(theme)
|
||||
{
|
||||
return theme.substring(0, theme.indexOf(".keyedtheme"));
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)loadWithDelegate:(id)aDelegate
|
||||
@@ -97,6 +95,17 @@
|
||||
[unarchiver finishDecoding];
|
||||
}
|
||||
|
||||
// CSS Theming
|
||||
|
||||
for (var i = 0, nb = [_themes count], allThemes = [self themeNames], aThemeName, aTheme; i < nb; i++)
|
||||
{
|
||||
aThemeName = allThemes[i];
|
||||
aTheme = [CPTheme themeNamed:aThemeName];
|
||||
|
||||
if ([aTheme isCSSBased])
|
||||
[aTheme setCSSResourcesPath:[aBundle resourcePath]];
|
||||
}
|
||||
|
||||
[_loadDelegate blendDidFinishLoading:self];
|
||||
}
|
||||
|
||||
|
||||
+140
-48
@@ -33,10 +33,35 @@
|
||||
@import "CPTextField.j"
|
||||
@import "CPWindow_Constants.j"
|
||||
|
||||
@class _CPTokenFieldTokenCloseButton
|
||||
@class _CPTokenFieldTokenDisclosureButton
|
||||
|
||||
@global CPApp
|
||||
@global CPTextFieldDidFocusNotification
|
||||
@global CPTextFieldDidBlurNotification
|
||||
|
||||
|
||||
// TODO: should be conform to protocol CPTextFieldDelegate
|
||||
@protocol CPTokenFieldDelegate <CPObject>
|
||||
|
||||
@optional
|
||||
- (BOOL)tokenField:(CPTokenField)tokenField hasMenuForRepresentedObject:(id)representedObject;
|
||||
- (CPArray)tokenField:(CPTokenField)tokenField completionsForSubstring:(CPString)substring indexOfToken:(CPInteger)tokenIndex indexOfSelectedItem:(CPInteger)selectedIndex;
|
||||
- (CPArray)tokenField:(CPTokenField)tokenField shouldAddObjects:(CPArray)tokens atIndex:(CPUInteger)index;
|
||||
- (CPMenu)tokenField:(CPTokenField)tokenField menuForRepresentedObject:(id)representedObject;
|
||||
- (CPString )tokenField:(CPTokenField)tokenField displayStringForRepresentedObject:(id)representedObject;
|
||||
- (id)tokenField:(CPTokenField)tokenField representedObjectForEditingString:(CPString)editingString;
|
||||
|
||||
@end
|
||||
|
||||
var CPTokenFieldDelegate_tokenField_hasMenuForRepresentedObject_ = 1 << 1,
|
||||
CPTokenFieldDelegate_tokenField_completionsForSubstring_indexOfToken_indexOfSelectedItem_ = 1 << 2,
|
||||
CPTokenFieldDelegate_tokenField_shouldAddObjects_atIndex_ = 1 << 3,
|
||||
CPTokenFieldDelegate_tokenField_menuForRepresentedObject_ = 1 << 4,
|
||||
CPTokenFieldDelegate_tokenField_displayStringForRepresentedObject_ = 1 << 5,
|
||||
CPTokenFieldDelegate_tokenField_representedObjectForEditingString_ = 1 << 6;
|
||||
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var CPTokenFieldDOMInputElement = nil,
|
||||
@@ -64,23 +89,26 @@ CPTokenFieldDeleteButtonType = 1;
|
||||
|
||||
@implementation CPTokenField : CPTextField
|
||||
{
|
||||
CPScrollView _tokenScrollView;
|
||||
int _shouldScrollTo;
|
||||
CPScrollView _tokenScrollView;
|
||||
int _shouldScrollTo;
|
||||
|
||||
CPRange _selectedRange;
|
||||
CPRange _selectedRange;
|
||||
|
||||
_CPAutocompleteMenu _autocompleteMenu;
|
||||
CGRect _inputFrame;
|
||||
_CPAutocompleteMenu _autocompleteMenu;
|
||||
CGRect _inputFrame;
|
||||
|
||||
CPTimeInterval _completionDelay;
|
||||
CPTimeInterval _completionDelay;
|
||||
|
||||
CPCharacterSet _tokenizingCharacterSet @accessors(property=tokenizingCharacterSet);
|
||||
CPCharacterSet _tokenizingCharacterSet @accessors(property=tokenizingCharacterSet);
|
||||
|
||||
CPEvent _mouseDownEvent;
|
||||
CPEvent _mouseDownEvent;
|
||||
|
||||
BOOL _shouldNotifyTarget;
|
||||
BOOL _shouldNotifyTarget;
|
||||
|
||||
int _buttonType @accessors(property=buttonType);
|
||||
int _buttonType @accessors(property=buttonType);
|
||||
|
||||
id <CPTokenFieldDelegate> _tokenFieldDelegate;
|
||||
unsigned _implementedTokenFieldDelegateMethods;
|
||||
}
|
||||
|
||||
+ (CPCharacterSet)defaultTokenizingCharacterSet
|
||||
@@ -140,6 +168,41 @@ CPTokenFieldDeleteButtonType = 1;
|
||||
[self addSubview:_tokenScrollView];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Delegate methods
|
||||
|
||||
/*!
|
||||
Set the delegate of the receiver
|
||||
*/
|
||||
- (void)setDelegate:(id <CPTokenFieldDelegate>)aDelegate
|
||||
{
|
||||
if (_tokenFieldDelegate === aDelegate)
|
||||
return;
|
||||
|
||||
_tokenFieldDelegate = aDelegate;
|
||||
_implementedTokenFieldDelegateMethods = 0;
|
||||
|
||||
if ([_tokenFieldDelegate respondsToSelector:@selector(tokenField:hasMenuForRepresentedObject:)])
|
||||
_implementedTokenFieldDelegateMethods |= CPTokenFieldDelegate_tokenField_hasMenuForRepresentedObject_;
|
||||
|
||||
if ([_tokenFieldDelegate respondsToSelector:@selector(tokenField:completionsForSubstring:indexOfToken:indexOfSelectedItem:)])
|
||||
_implementedTokenFieldDelegateMethods |= CPTokenFieldDelegate_tokenField_completionsForSubstring_indexOfToken_indexOfSelectedItem_;
|
||||
|
||||
if ([_tokenFieldDelegate respondsToSelector:@selector(tokenField:shouldAddObjects:atIndex:)])
|
||||
_implementedTokenFieldDelegateMethods |= CPTokenFieldDelegate_tokenField_shouldAddObjects_atIndex_;
|
||||
|
||||
if ([_tokenFieldDelegate respondsToSelector:@selector(tokenField:menuForRepresentedObject:)])
|
||||
_implementedTokenFieldDelegateMethods |= CPTokenFieldDelegate_tokenField_menuForRepresentedObject_;
|
||||
|
||||
if ([_tokenFieldDelegate respondsToSelector:@selector(tokenField:displayStringForRepresentedObject:)])
|
||||
_implementedTokenFieldDelegateMethods |= CPTokenFieldDelegate_tokenField_displayStringForRepresentedObject_;
|
||||
|
||||
if ([_tokenFieldDelegate respondsToSelector:@selector(tokenField:representedObjectForEditingString:)])
|
||||
_implementedTokenFieldDelegateMethods |= CPTokenFieldDelegate_tokenField_representedObjectForEditingString_;
|
||||
|
||||
[super setDelegate:_tokenFieldDelegate];
|
||||
}
|
||||
|
||||
- (_CPAutocompleteMenu)_autocompleteMenu
|
||||
{
|
||||
if (!_autocompleteMenu)
|
||||
@@ -321,6 +384,9 @@ CPTokenFieldDeleteButtonType = 1;
|
||||
|
||||
- (BOOL)becomeFirstResponder
|
||||
{
|
||||
if (![super becomeFirstResponder])
|
||||
return NO;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
if (CPTokenFieldInputOwner && [CPTokenFieldInputOwner window] !== [self window])
|
||||
[[CPTokenFieldInputOwner window] makeFirstResponder:nil];
|
||||
@@ -382,21 +448,27 @@ CPTokenFieldDeleteButtonType = 1;
|
||||
element.style.width = CGRectGetWidth(contentRect) + "px";
|
||||
element.style.height = [font defaultLineHeightForFont] + "px";
|
||||
|
||||
window.setTimeout(function()
|
||||
[[CPRunLoop mainRunLoop] performBlock:function()
|
||||
{
|
||||
[_tokenScrollView documentView]._DOMElement.appendChild(element);
|
||||
|
||||
//post CPControlTextDidBeginEditingNotification
|
||||
[self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
|
||||
|
||||
window.setTimeout(function()
|
||||
[[CPRunLoop mainRunLoop] performBlock:function()
|
||||
{
|
||||
// This will prevent to jump to the focused element
|
||||
var previousScrollingOrigin = [self _scrollToVisibleRectAndReturnPreviousOrigin];
|
||||
|
||||
element.focus();
|
||||
|
||||
[self _restorePreviousScrollingOrigin:previousScrollingOrigin];
|
||||
|
||||
CPTokenFieldInputOwner = self;
|
||||
}, 0.0);
|
||||
} argument:nil order:0 modes:[CPDefaultRunLoopMode]];
|
||||
|
||||
[self textDidFocus:[CPNotification notificationWithName:CPTextFieldDidFocusNotification object:self userInfo:nil]];
|
||||
}, 0.0);
|
||||
} argument:nil order:0 modes:[CPDefaultRunLoopMode]];
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
@@ -451,17 +523,25 @@ CPTokenFieldDeleteButtonType = 1;
|
||||
var element = [self _inputElement];
|
||||
|
||||
CPTokenFieldInputResigning = YES;
|
||||
element.blur();
|
||||
|
||||
if (CPTokenFieldInputIsActive)
|
||||
element.blur();
|
||||
|
||||
if (!CPTokenFieldInputDidBlur)
|
||||
CPTokenFieldBlurHandler();
|
||||
|
||||
CPTokenFieldInputDidBlur = NO;
|
||||
CPTokenFieldInputResigning = NO;
|
||||
|
||||
if (element.parentNode == [_tokenScrollView documentView]._DOMElement)
|
||||
element.parentNode.removeChild(element);
|
||||
|
||||
// Previosly, we unflagged CPTokenFieldInputDidBlur and CPTokenFieldInputResigning before
|
||||
// the call to removeChild. This may result in DOM exceptions in Chrome under certain conditions.
|
||||
// See https://stackoverflow.com/questions/21926083/failed-to-execute-removechild-on-node
|
||||
// for why we need to unflag CPTokenFieldInputDidBlur and CPTokenFieldInputResigning
|
||||
// only after removing the element.
|
||||
|
||||
CPTokenFieldInputDidBlur = NO;
|
||||
CPTokenFieldInputResigning = NO;
|
||||
|
||||
CPTokenFieldInputIsActive = NO;
|
||||
|
||||
if (document.attachEvent)
|
||||
@@ -469,7 +549,7 @@ CPTokenFieldDeleteButtonType = 1;
|
||||
CPTokenFieldCachedSelectStartFunction = nil;
|
||||
CPTokenFieldCachedDragFunction = nil;
|
||||
|
||||
document.body.ondrag = CPTokenFieldCachedDragFunction
|
||||
document.body.ondrag = CPTokenFieldCachedDragFunction;
|
||||
document.body.onselectstart = CPTokenFieldCachedSelectStartFunction
|
||||
}
|
||||
|
||||
@@ -967,6 +1047,21 @@ CPTokenFieldDeleteButtonType = 1;
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
}
|
||||
|
||||
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
|
||||
{
|
||||
var characters = [anEvent characters];
|
||||
|
||||
// Here we handle the event when getting a CPNewlineCharacter or CPCarriageReturnCharacter when the menu is open
|
||||
// We don't want that the application dispatches the event to the other controls
|
||||
if ([self hasThemeState:CPThemeStateAutocompleting] && (characters === CPNewlineCharacter || characters === CPCarriageReturnCharacter))
|
||||
{
|
||||
[self keyDown:anEvent];
|
||||
return YES;
|
||||
}
|
||||
|
||||
return [super performKeyEquivalent:anEvent];
|
||||
}
|
||||
|
||||
- (void)textDidChange:(CPNotification)aNotification
|
||||
{
|
||||
if ([aNotification object] !== self)
|
||||
@@ -1152,7 +1247,7 @@ CPTokenFieldDeleteButtonType = 1;
|
||||
var scrollToToken = _shouldScrollTo;
|
||||
|
||||
if (scrollToToken === CPScrollDestinationLeft)
|
||||
scrollToToken = tokens[_selectedRange.location]
|
||||
scrollToToken = tokens[_selectedRange.location];
|
||||
else if (scrollToToken === CPScrollDestinationRight)
|
||||
scrollToToken = tokens[MAX(0, CPMaxRange(_selectedRange) - 1)];
|
||||
[self _scrollTokenViewToVisible:scrollToToken];
|
||||
@@ -1185,12 +1280,10 @@ CPTokenFieldDeleteButtonType = 1;
|
||||
*/
|
||||
- (CPArray)_completionsForSubstring:(CPString)substring indexOfToken:(int)tokenIndex indexOfSelectedItem:(int)selectedIndex
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(tokenField:completionsForSubstring:indexOfToken:indexOfSelectedItem:)])
|
||||
{
|
||||
return [[self delegate] tokenField:self completionsForSubstring:substring indexOfToken:tokenIndex indexOfSelectedItem:selectedIndex];
|
||||
}
|
||||
if (!(_implementedTokenFieldDelegateMethods & CPTokenFieldDelegate_tokenField_completionsForSubstring_indexOfToken_indexOfSelectedItem_))
|
||||
return [];
|
||||
|
||||
return [];
|
||||
return [_tokenFieldDelegate tokenField:self completionsForSubstring:substring indexOfToken:tokenIndex indexOfSelectedItem:selectedIndex];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1199,6 +1292,7 @@ CPTokenFieldDeleteButtonType = 1;
|
||||
- (CGPoint)_completionOrigin:(_CPAutocompleteMenu)anAutocompleteMenu
|
||||
{
|
||||
var relativeFrame = _inputFrame ? [[_tokenScrollView documentView] convertRect:_inputFrame toView:self ] : [self bounds];
|
||||
|
||||
return CGPointMake(CGRectGetMinX(relativeFrame), CGRectGetMaxY(relativeFrame));
|
||||
}
|
||||
|
||||
@@ -1212,13 +1306,12 @@ CPTokenFieldDeleteButtonType = 1;
|
||||
*/
|
||||
- (CPString)_displayStringForRepresentedObject:(id)representedObject
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(tokenField:displayStringForRepresentedObject:)])
|
||||
if (_implementedTokenFieldDelegateMethods & CPTokenFieldDelegate_tokenField_displayStringForRepresentedObject_)
|
||||
{
|
||||
var stringForRepresentedObject = [[self delegate] tokenField:self displayStringForRepresentedObject:representedObject];
|
||||
var stringForRepresentedObject = [_tokenFieldDelegate tokenField:self displayStringForRepresentedObject:representedObject];
|
||||
|
||||
if (stringForRepresentedObject !== nil)
|
||||
{
|
||||
return stringForRepresentedObject;
|
||||
}
|
||||
}
|
||||
|
||||
return representedObject;
|
||||
@@ -1235,10 +1328,10 @@ CPTokenFieldDeleteButtonType = 1;
|
||||
*/
|
||||
- (CPArray)_shouldAddObjects:(CPArray)tokens atIndex:(int)index
|
||||
{
|
||||
var delegate = [self delegate];
|
||||
if ([delegate respondsToSelector:@selector(tokenField:shouldAddObjects:atIndex:)])
|
||||
if (_implementedTokenFieldDelegateMethods & CPTokenFieldDelegate_tokenField_shouldAddObjects_atIndex_)
|
||||
{
|
||||
var approvedObjects = [delegate tokenField:self shouldAddObjects:tokens atIndex:index];
|
||||
var approvedObjects = [_tokenFieldDelegate tokenField:self shouldAddObjects:tokens atIndex:index];
|
||||
|
||||
if (approvedObjects !== nil)
|
||||
return approvedObjects;
|
||||
}
|
||||
@@ -1257,10 +1350,10 @@ CPTokenFieldDeleteButtonType = 1;
|
||||
*/
|
||||
- (id)_representedObjectForEditingString:(CPString)aString
|
||||
{
|
||||
var delegate = [self delegate];
|
||||
if ([delegate respondsToSelector:@selector(tokenField:representedObjectForEditingString:)])
|
||||
if (_implementedTokenFieldDelegateMethods & CPTokenFieldDelegate_tokenField_representedObjectForEditingString_)
|
||||
{
|
||||
var token = [delegate tokenField:self representedObjectForEditingString:aString];
|
||||
var token = [_tokenFieldDelegate tokenField:self representedObjectForEditingString:aString];
|
||||
|
||||
if (token !== nil && token !== undefined)
|
||||
return token;
|
||||
// If nil was returned, assume the string is the represented object. The alternative would have been
|
||||
@@ -1272,23 +1365,22 @@ CPTokenFieldDeleteButtonType = 1;
|
||||
|
||||
- (BOOL)_hasMenuForRepresentedObject:(id)aRepresentedObject
|
||||
{
|
||||
var delegate = [self delegate];
|
||||
if ([delegate respondsToSelector:@selector(tokenField:hasMenuForRepresentedObject:)] &&
|
||||
[delegate respondsToSelector:@selector(tokenField:menuForRepresentedObject:)])
|
||||
return [delegate tokenField:self hasMenuForRepresentedObject:aRepresentedObject];
|
||||
if ((_implementedTokenFieldDelegateMethods & CPTokenFieldDelegate_tokenField_hasMenuForRepresentedObject_) &&
|
||||
(_implementedTokenFieldDelegateMethods & CPTokenFieldDelegate_tokenField_menuForRepresentedObject_))
|
||||
return [_tokenFieldDelegate tokenField:self hasMenuForRepresentedObject:aRepresentedObject];
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (CPMenu)_menuForRepresentedObject:(id)aRepresentedObject
|
||||
{
|
||||
var delegate = [self delegate];
|
||||
if ([delegate respondsToSelector:@selector(tokenField:hasMenuForRepresentedObject:)] &&
|
||||
[delegate respondsToSelector:@selector(tokenField:menuForRepresentedObject:)])
|
||||
if ((_implementedTokenFieldDelegateMethods & CPTokenFieldDelegate_tokenField_hasMenuForRepresentedObject_) &&
|
||||
(_implementedTokenFieldDelegateMethods & CPTokenFieldDelegate_tokenField_menuForRepresentedObject_))
|
||||
{
|
||||
var hasMenu = [delegate tokenField:self hasMenuForRepresentedObject:aRepresentedObject];
|
||||
var hasMenu = [_tokenFieldDelegate tokenField:self hasMenuForRepresentedObject:aRepresentedObject];
|
||||
|
||||
if (hasMenu)
|
||||
return [delegate tokenField:self menuForRepresentedObject:aRepresentedObject] || nil;
|
||||
return [_tokenFieldDelegate tokenField:self menuForRepresentedObject:aRepresentedObject] || nil;
|
||||
}
|
||||
|
||||
return nil;
|
||||
@@ -1389,12 +1481,12 @@ CPTokenFieldDeleteButtonType = 1;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (BOOL)setThemeState:(CPThemeState)aState
|
||||
- (BOOL)setThemeState:(ThemeState)aState
|
||||
{
|
||||
var r = [super setThemeState:aState];
|
||||
|
||||
// Share hover state with the disclosure and delete buttons.
|
||||
if (aState & CPThemeStateHovered)
|
||||
if (aState.hasThemeState(CPThemeStateHovered))
|
||||
{
|
||||
[_disclosureButton setThemeState:CPThemeStateHovered];
|
||||
[_deleteButton setThemeState:CPThemeStateHovered];
|
||||
@@ -1403,12 +1495,12 @@ CPTokenFieldDeleteButtonType = 1;
|
||||
return r;
|
||||
}
|
||||
|
||||
- (BOOL)unsetThemeState:(CPThemeState)aState
|
||||
- (BOOL)unsetThemeState:(ThemeState)aState
|
||||
{
|
||||
var r = [super unsetThemeState:aState];
|
||||
|
||||
// Share hover state with the disclosure and delete button.
|
||||
if (aState & CPThemeStateHovered)
|
||||
if (aState.hasThemeState(CPThemeStateHovered))
|
||||
{
|
||||
[_disclosureButton unsetThemeState:CPThemeStateHovered];
|
||||
[_deleteButton unsetThemeState:CPThemeStateHovered];
|
||||
|
||||
+147
-18
@@ -30,6 +30,15 @@
|
||||
|
||||
@global CPApp
|
||||
|
||||
var CPToolbarDelegate_toolbar_itemForItemIdentifier_willBeInsertedIntoToolbar_ = 1 << 0,
|
||||
CPToolbarDelegate_toolbarAllowedItemIdentifiers_ = 1 << 1,
|
||||
CPToolbarDelegate_toolbarDefaultItemIdentifiers_ = 1 << 2,
|
||||
CPToolbarDelegate_toolbarDidRemoveItem_ = 1 << 3,
|
||||
CPToolbarDelegate_toolbarSelectableItemIdentifiers_ = 1 << 4,
|
||||
CPToolbarDelegate_toolbarWillAddItem_ = 1 << 5;
|
||||
|
||||
|
||||
@typedef CPToolbarDisplayMode
|
||||
/*
|
||||
@global
|
||||
@group CPToolbarDisplayMode
|
||||
@@ -51,7 +60,7 @@ CPToolbarDisplayModeIconOnly = 2;
|
||||
*/
|
||||
CPToolbarDisplayModeLabelOnly = 3;
|
||||
|
||||
|
||||
@typedef CPToolbarSizeMode
|
||||
CPToolbarSizeModeDefault = 0;
|
||||
CPToolbarSizeModeRegular = 1;
|
||||
CPToolbarSizeModeSmall = 2;
|
||||
@@ -59,6 +68,20 @@ CPToolbarSizeModeSmall = 2;
|
||||
var CPToolbarsByIdentifier = nil,
|
||||
CPToolbarConfigurationsByIdentifier = nil;
|
||||
|
||||
|
||||
@protocol CPToolbarDelegate <CPObject>
|
||||
|
||||
@optional
|
||||
- (CPToolbarItem)toolbar:(CPToolbar)toolbar itemForItemIdentifier:(CPString)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag;
|
||||
- (CPArray)toolbarAllowedItemIdentifiers:(CPToolbar)toolbar;
|
||||
- (CPArray)toolbarDefaultItemIdentifiers:(CPToolbar)toolbar;
|
||||
- (void)toolbarDidRemoveItem:(CPNotification)notification;
|
||||
- (CPArray)toolbarSelectableItemIdentifiers:(CPToolbar)toolbar;
|
||||
- (void)toolbarWillAddItem:(CPNotification)notification;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPToolbar
|
||||
@@ -89,14 +112,15 @@ var CPToolbarsByIdentifier = nil,
|
||||
@implementation CPToolbar : CPObject
|
||||
{
|
||||
CPString _identifier;
|
||||
CPToolbarDisplayMode _displayMode @accessors(property=displayMode);
|
||||
CPToolbarDisplayMode _displayMode @accessors(property=displayMode);
|
||||
BOOL _showsBaselineSeparator;
|
||||
BOOL _allowsUserCustomization;
|
||||
BOOL _isVisible;
|
||||
CPToolbarSizeMode _sizeMode @accessors(property=sizeMode);
|
||||
CPToolbarSizeMode _sizeMode @accessors(property=sizeMode);
|
||||
int _desiredHeight;
|
||||
|
||||
id _delegate;
|
||||
id <CPToolbarDelegate> _delegate;
|
||||
unsigned _implementedDelegateMethods;
|
||||
|
||||
CPArray _itemIdentifiers;
|
||||
|
||||
@@ -129,7 +153,7 @@ var CPToolbarsByIdentifier = nil,
|
||||
|
||||
if (!toolbarsSharingIdentifier)
|
||||
{
|
||||
toolbarsSharingIdentifier = []
|
||||
toolbarsSharingIdentifier = [];
|
||||
[CPToolbarsByIdentifier setObject:toolbarsSharingIdentifier forKey:identifier];
|
||||
}
|
||||
|
||||
@@ -239,6 +263,25 @@ var CPToolbarsByIdentifier = nil,
|
||||
return;
|
||||
|
||||
_delegate = aDelegate;
|
||||
_implementedDelegateMethods = 0;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar:)])
|
||||
_implementedDelegateMethods |= CPToolbarDelegate_toolbar_itemForItemIdentifier_willBeInsertedIntoToolbar_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(toolbarAllowedItemIdentifiers:)])
|
||||
_implementedDelegateMethods |= CPToolbarDelegate_toolbarAllowedItemIdentifiers_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(toolbarDefaultItemIdentifiers:)])
|
||||
_implementedDelegateMethods |= CPToolbarDelegate_toolbarDefaultItemIdentifiers_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(toolbarDidRemoveItem:)])
|
||||
_implementedDelegateMethods |= CPToolbarDelegate_toolbarDidRemoveItem_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(toolbarSelectableItemIdentifiers:)])
|
||||
_implementedDelegateMethods |= CPToolbarDelegate_toolbarSelectableItemIdentifiers_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(toolbarWillAddItem:)])
|
||||
_implementedDelegateMethods |= CPToolbarDelegate_toolbarWillAddItem_;
|
||||
|
||||
[self _reloadToolbarItems];
|
||||
}
|
||||
@@ -289,9 +332,9 @@ var CPToolbarsByIdentifier = nil,
|
||||
// _defaultItems may have been loaded from Cib
|
||||
_itemIdentifiers = [_defaultItems valueForKey:@"itemIdentifier"] || [];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(toolbarDefaultItemIdentifiers:)])
|
||||
if ([self _delegateRespondsToToolbarDefaultItemIdentifiers])
|
||||
{
|
||||
var itemIdentifiersFromDelegate = [_delegate toolbarDefaultItemIdentifiers:self];
|
||||
var itemIdentifiersFromDelegate = [self _sendDelegateToolbarDefaultItemIdentifiers];
|
||||
|
||||
// If we get items both from the Cib and from the delegate method, put the delegate items before the
|
||||
// Cib ones.
|
||||
@@ -316,7 +359,7 @@ var CPToolbarsByIdentifier = nil,
|
||||
item = [_identifiedItems objectForKey:identifier];
|
||||
|
||||
if (!item && _delegate)
|
||||
item = [_delegate toolbar:self itemForItemIdentifier:identifier willBeInsertedIntoToolbar:YES];
|
||||
item = [self _sendDelegateItemForItemIdentifier:identifier willBeInsertedIntoToolbar:YES];
|
||||
|
||||
item = [item copy];
|
||||
|
||||
@@ -394,12 +437,14 @@ var CPToolbarsByIdentifier = nil,
|
||||
- (id)_itemForItemIdentifier:(CPString)identifier willBeInsertedIntoToolbar:(BOOL)toolbar
|
||||
{
|
||||
var item = [_identifiedItems objectForKey:identifier];
|
||||
|
||||
if (!item)
|
||||
{
|
||||
item = [CPToolbarItem _standardItemWithItemIdentifier:identifier];
|
||||
|
||||
if (_delegate && !item)
|
||||
{
|
||||
item = [[_delegate toolbar:self itemForItemIdentifier:identifier willBeInsertedIntoToolbar:toolbar] copy];
|
||||
item = [[self _sendDelegateItemForItemIdentifier:identifier willBeInsertedIntoToolbar:toolbar] copy];
|
||||
if (!item)
|
||||
[CPException raise:CPInvalidArgumentException
|
||||
reason:@"Toolbar delegate " + _delegate + " returned nil toolbar item for identifier " + identifier];
|
||||
@@ -414,21 +459,20 @@ var CPToolbarsByIdentifier = nil,
|
||||
/* @ignore */
|
||||
- (id)_itemsWithIdentifiers:(CPArray)identifiers
|
||||
{
|
||||
var items = [];
|
||||
for (var i = 0; i < identifiers.length; i++)
|
||||
[items addObject:[self _itemForItemIdentifier:identifiers[i] willBeInsertedIntoToolbar:NO]];
|
||||
|
||||
return items;
|
||||
return [identifiers arrayByApplyingBlock:function(identifier)
|
||||
{
|
||||
return [self _itemForItemIdentifier:identifier willBeInsertedIntoToolbar:NO];
|
||||
}];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (id)_defaultToolbarItems
|
||||
{
|
||||
if (!_defaultItems && [_delegate respondsToSelector:@selector(toolbarDefaultItemIdentifiers:)])
|
||||
if (!_defaultItems && [self _delegateRespondsToToolbarDefaultItemIdentifiers])
|
||||
{
|
||||
_defaultItems = [];
|
||||
|
||||
var identifiers = [_delegate toolbarDefaultItemIdentifiers:self],
|
||||
var identifiers = [self _sendDelegateToolbarDefaultItemIdentifiers],
|
||||
index = 0,
|
||||
count = [identifiers count];
|
||||
|
||||
@@ -544,7 +588,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 encodeInt:_sizeMode forKey:CPToolbarSizeModeKey];
|
||||
|
||||
[aCoder encodeObject:_identifiedItems forKey:CPToolbarIdentifiedItemsKey];
|
||||
[aCoder encodeObject:_defaultItems forKey:CPToolbarDefaultItemsKey];
|
||||
@@ -800,7 +844,6 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
var index = 0,
|
||||
count = _visibleItems.length,
|
||||
x = contentInset.left,
|
||||
contentInset = [self valueForThemeAttribute:@"content-inset"],
|
||||
y = contentInset.top;
|
||||
|
||||
for (; index < count; ++index)
|
||||
@@ -1240,3 +1283,89 @@ var LABEL_MARGIN = 2.0;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation CPToolbar (CPToolbarDelegate)
|
||||
|
||||
/*
|
||||
@ignore
|
||||
Return YES if the delegate implements toolbarDefaultItemIdentifiers:
|
||||
*/
|
||||
- (BOOL)_delegateRespondsToToolbarDefaultItemIdentifiers
|
||||
{
|
||||
return _implementedDelegateMethods & CPToolbarDelegate_toolbarDefaultItemIdentifiers_;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call the delegate toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar:
|
||||
*/
|
||||
- (CPToolbarItem)_sendDelegateItemForItemIdentifier:(CPString)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPToolbarDelegate_toolbar_itemForItemIdentifier_willBeInsertedIntoToolbar_))
|
||||
return nil;
|
||||
|
||||
return [_delegate toolbar:self itemForItemIdentifier:itemIdentifier willBeInsertedIntoToolbar:flag];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call the delegate toolbarAllowedItemIdentifiers:
|
||||
*/
|
||||
- (CPArray)_sendDelegateToolbarAllowedItemIdentifiers
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPToolbarDelegate_toolbarAllowedItemIdentifiers_))
|
||||
return [];
|
||||
|
||||
return [_delegate toolbarAllowedItemIdentifiers:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call the delegate toolbarDefaultItemIdentifiers:
|
||||
*/
|
||||
- (CPArray)_sendDelegateToolbarDefaultItemIdentifiers
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPToolbarDelegate_toolbarDefaultItemIdentifiers_))
|
||||
return [];
|
||||
|
||||
return [_delegate toolbarDefaultItemIdentifiers:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call the delegate toolbarDidRemoveItem:
|
||||
*/
|
||||
- (void)_sendDelegateToolbarDidRemoveItem:(CPNotification)notification
|
||||
{
|
||||
if (!(_delegate & CPToolbarDelegate_toolbarDidRemoveItem_))
|
||||
return;
|
||||
|
||||
[_delegate toolbarDidRemoveItem:notification];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call the delegate toolbarSelectableItemIdentifiers:
|
||||
*/
|
||||
- (CPArray)_sendDelegateToolbarSelectableItemIdentifiers
|
||||
{
|
||||
if (!(_implementedDelegateMethods & CPToolbarDelegate_toolbarSelectableItemIdentifiers_))
|
||||
return [];
|
||||
|
||||
return [_delegate toolbarSelectableItemIdentifiers:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
Call the delegate toolbarWillAddItem:
|
||||
*/
|
||||
- (void)_sendDelegateToolbarWillAddItem:(CPNotification)notification
|
||||
{
|
||||
if (!(_delegate & CPToolbarDelegate_toolbarWillAddItem_))
|
||||
return;
|
||||
|
||||
[_delegate toolbarWillAddItem:notification];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* CPTrackingArea.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Didier Korthoudt.
|
||||
* Copyright 2015, Cappuccino Project.
|
||||
*
|
||||
* 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/Foundation.j>
|
||||
|
||||
@class CPView
|
||||
|
||||
/* @group CPTrackingAreaOptions */
|
||||
@typedef CPTrackingAreaOptions
|
||||
CPTrackingMouseEnteredAndExited = 1 << 1;
|
||||
CPTrackingMouseMoved = 1 << 2;
|
||||
CPTrackingCursorUpdate = 1 << 3;
|
||||
CPTrackingActiveWhenFirstResponder = 1 << 4;
|
||||
CPTrackingActiveInKeyWindow = 1 << 5;
|
||||
CPTrackingActiveInActiveApp = 1 << 6;
|
||||
CPTrackingActiveAlways = 1 << 7;
|
||||
CPTrackingAssumeInside = 1 << 8;
|
||||
CPTrackingInVisibleRect = 1 << 9;
|
||||
CPTrackingEnabledDuringMouseDrag = 1 << 10;
|
||||
|
||||
var CPTrackingAreaViewRectKey = @"CPTrackinkAreaViewRectKey",
|
||||
CPTrackingAreaOptionsKey = @"CPTrackingAreaOptionsKey",
|
||||
CPTrackingAreaOwnerKey = @"CPTrackingAreaOwnerKey",
|
||||
CPTrackingAreaUserInfoKey = @"CPTrackingAreaUserInfoKey",
|
||||
CPTrackingAreaReferencingViewKey = @"CPTrackingAreaReferencingViewKey",
|
||||
CPTrackingAreaWindowRect = @"CPTrackingAreaWindowRect";
|
||||
|
||||
CPTrackingOwnerImplementsMouseEntered = 1 << 1;
|
||||
CPTrackingOwnerImplementsMouseExited = 1 << 2;
|
||||
CPTrackingOwnerImplementsMouseMoved = 1 << 3;
|
||||
CPTrackingOwnerImplementsCursorUpdate = 1 << 4;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
|
||||
A CPTrackingArea defines a region of view that generates mouse-tracking and
|
||||
cursor-update events when the mouse is over that region.
|
||||
*/
|
||||
@implementation CPTrackingArea : CPObject
|
||||
{
|
||||
CGRect _viewRect @accessors(getter=rect);
|
||||
CPTrackingAreaOptions _options @accessors(getter=options);
|
||||
id _owner @accessors(getter=owner);
|
||||
CPDictionary _userInfo @accessors(getter=userInfo);
|
||||
|
||||
CPView _referencingView @accessors(property=view);
|
||||
CGRect _windowRect @accessors(getter=windowRect);
|
||||
|
||||
unsigned _implementedOwnerMethods @accessors(getter=implementedOwnerMethods);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization
|
||||
|
||||
/*!
|
||||
Initializes and returns an object defining a region of a view to receive mouse-tracking events, mouse-moved events, cursor-update events, or possibly
|
||||
all these events.
|
||||
*/
|
||||
- (CPTrackingArea)initWithRect:(CGRect)aRect options:(CPTrackingAreaOptions)options owner:(id)owner userInfo:(CPDictionary)userInfo
|
||||
{
|
||||
if (owner === nil)
|
||||
[CPException raise:CPInternalInconsistencyException reason:"No owner specified"];
|
||||
|
||||
if (options === 0)
|
||||
[CPException raise:CPInternalInconsistencyException reason:"Invalid CPTrackingArea options"];
|
||||
|
||||
// Check options:
|
||||
// - at least one of CPTrackingMouseEnteredAndExited, CPTrackingMouseMoved, CPTrackingCursorUpdate
|
||||
// - exactly one of CPTrackingActiveWhenFirstResponder, CPTrackingActiveInKeyWindow, CPTrackingActiveInActiveApp, CPTrackingActiveAlways
|
||||
// - no check on CPTrackingAssumeInside, CPTrackingInVisibleRect, CPTrackingEnableDuringMouseDrag
|
||||
|
||||
if (!((options & CPTrackingMouseEnteredAndExited) || (options & CPTrackingMouseMoved) || (options & CPTrackingCursorUpdate)))
|
||||
[CPException raise:CPInternalInconsistencyException reason:"Invalid CPTrackingAreaOptions: must use at least one of [CPTrackingMouseEnteredAndExited | CPTrackingMouseMoved | CPTrackingCursorUpdate]"];
|
||||
|
||||
if ((((options & CPTrackingActiveWhenFirstResponder) > 0) + ((options & CPTrackingActiveInKeyWindow) > 0) + ((options & CPTrackingActiveInActiveApp) > 0) + ((options & CPTrackingActiveAlways) > 0)) !== 1)
|
||||
[CPException raise:CPInternalInconsistencyException reason:"Tracking area options may only specify one of [CPTrackingActiveWhenFirstResponder | CPTrackingActiveInKeyWindow | CPTrackingActiveInActiveApp | CPTrackingActiveAlways]."];
|
||||
|
||||
if (self = [super init])
|
||||
{
|
||||
_viewRect = aRect;
|
||||
_options = options;
|
||||
_owner = owner;
|
||||
_userInfo = userInfo;
|
||||
|
||||
// Cache owner implemented methods
|
||||
|
||||
if ([_owner respondsToSelector:@selector(mouseEntered:)])
|
||||
_implementedOwnerMethods |= CPTrackingOwnerImplementsMouseEntered;
|
||||
|
||||
if ([_owner respondsToSelector:@selector(mouseExited:)])
|
||||
_implementedOwnerMethods |= CPTrackingOwnerImplementsMouseExited;
|
||||
|
||||
if ([_owner respondsToSelector:@selector(mouseMoved:)])
|
||||
_implementedOwnerMethods |= CPTrackingOwnerImplementsMouseMoved;
|
||||
|
||||
if ([_owner respondsToSelector:@selector(cursorUpdate:)])
|
||||
_implementedOwnerMethods |= CPTrackingOwnerImplementsCursorUpdate;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Implementation
|
||||
|
||||
- (void)_updateWindowRect
|
||||
{
|
||||
_windowRect = [_referencingView convertRect:((_options & CPTrackingInVisibleRect) ? [_referencingView visibleRect] : _viewRect) toView:[[_referencingView window] _windowView]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark CPCoding
|
||||
|
||||
@implementation CPTrackingArea (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_viewRect = [aCoder decodeObjectForKey:CPTrackingAreaViewRectKey];
|
||||
_options = [aCoder decodeObjectForKey:CPTrackingAreaOptionsKey];
|
||||
_owner = [aCoder decodeObjectForKey:CPTrackingAreaOwnerKey];
|
||||
_userInfo = [aCoder decodeObjectForKey:CPTrackingAreaUserInfoKey];
|
||||
_referencingView = [aCoder decodeObjectForKey:CPTrackingAreaReferencingViewKey];
|
||||
_windowRect = [aCoder decodeObjectForKey:CPTrackingAreaWindowRect];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[aCoder encodeObject:_viewRect forKey:CPTrackingAreaViewRectKey];
|
||||
[aCoder encodeObject:_options forKey:CPTrackingAreaOptionsKey];
|
||||
[aCoder encodeObject:_owner forKey:CPTrackingAreaOwnerKey];
|
||||
[aCoder encodeObject:_userInfo forKey:CPTrackingAreaUserInfoKey];
|
||||
[aCoder encodeObject:_referencingView forKey:CPTrackingAreaReferencingViewKey];
|
||||
[aCoder encodeObject:_windowRect forKey:CPTrackingAreaWindowRect];
|
||||
}
|
||||
|
||||
@end
|
||||
+833
-397
File diff suppressed because it is too large
Load Diff
+175
-2
@@ -149,9 +149,10 @@ var CPViewControllerCachedCibs;
|
||||
|
||||
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.
|
||||
this method.
|
||||
|
||||
Note: The cib loading system is currently synchronous.
|
||||
@note When using this method, the cib loading system is synchronous.
|
||||
See the loadViewWithCompletionHandler: method for an asynchronous loading.
|
||||
*/
|
||||
- (void)loadView
|
||||
{
|
||||
@@ -176,6 +177,67 @@ var CPViewControllerCachedCibs;
|
||||
_view = [CPView new];
|
||||
}
|
||||
|
||||
/*!
|
||||
Asynchronously load the cib and create the view that the controller manages.
|
||||
|
||||
@param aHandler a function which will be passed the loaded view as the first
|
||||
argument and a network error or nil as the second argument: function(view, error).
|
||||
|
||||
@note If the view has already been loaded, the completion handler is run immediatly
|
||||
and the process is synchronous.
|
||||
*/
|
||||
- (void)loadViewWithCompletionHandler:(Function/*(view, error)*/)aHandler
|
||||
{
|
||||
if (_view)
|
||||
return;
|
||||
|
||||
if (_cibName)
|
||||
{
|
||||
// check if a cib is already cached for the current _cibName
|
||||
var cib = [CPViewControllerCachedCibs objectForKey:_cibName];
|
||||
|
||||
if (!cib)
|
||||
{
|
||||
var cibName = _cibName;
|
||||
|
||||
if (![cibName hasSuffix:@".cib"])
|
||||
cibName = [cibName stringByAppendingString:@".cib"];
|
||||
|
||||
// If aBundle is nil, use mainBundle, but ONLY for searching for the nib, not for resources later.
|
||||
var bundle = _cibBundle || [CPBundle mainBundle],
|
||||
url = [bundle _cibPathForResource:cibName];
|
||||
|
||||
// if the cib isn't cached yet : fetch it and cache it
|
||||
[CPURLConnection sendAsynchronousRequest:[CPURLRequest requestWithURL:url] queue:[CPOperationQueue mainQueue] completionHandler:function(aResponse, aData, anError)
|
||||
{
|
||||
if (anError == nil)
|
||||
{
|
||||
var data = [CPData dataWithRawString:aData],
|
||||
aCib = [[CPCib alloc] _initWithData:data bundle:_cibBundle cibName:_cibName];
|
||||
|
||||
[CPViewControllerCachedCibs setObject:aCib forKey:_cibName];
|
||||
[aCib instantiateCibWithExternalNameTable:_cibExternalNameTable];
|
||||
[self _viewDidLoadWithCompletionHandler:aHandler];
|
||||
}
|
||||
else
|
||||
{
|
||||
aHandler(nil, anError);
|
||||
}
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
[cib instantiateCibWithExternalNameTable:_cibExternalNameTable];
|
||||
[self _viewDidLoadWithCompletionHandler:aHandler];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_view = [CPView new];
|
||||
[self _viewDidLoadWithCompletionHandler:aHandler];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the view that the controller manages.
|
||||
|
||||
@@ -210,6 +272,7 @@ var CPViewControllerCachedCibs;
|
||||
[cibOwner viewControllerDidLoadCib:self];
|
||||
|
||||
_isLoading = NO;
|
||||
_isLazy = NO;
|
||||
[self _viewDidLoad];
|
||||
}
|
||||
else if (_isLazy)
|
||||
@@ -229,6 +292,16 @@ var CPViewControllerCachedCibs;
|
||||
[self didChangeValueForKey:"isViewLoaded"];
|
||||
}
|
||||
|
||||
- (void)_viewDidLoadWithCompletionHandler:(Function)aHandler
|
||||
{
|
||||
[self _registerOrUnregister:YES notificationsForView:_view];
|
||||
|
||||
[self willChangeValueForKey:"isViewLoaded"];
|
||||
aHandler(_view, nil);
|
||||
_isViewLoaded = YES;
|
||||
[self didChangeValueForKey:"isViewLoaded"];
|
||||
}
|
||||
|
||||
/*!
|
||||
This method is called after the view controller has loaded its associated views into memory.
|
||||
|
||||
@@ -242,6 +315,79 @@ var CPViewControllerCachedCibs;
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
Called after the view controller’s view has been loaded into memory is about to be added to the
|
||||
view hierarchy in the window.
|
||||
|
||||
@discussion You can override this method to perform tasks prior to a view controller’s view
|
||||
getting added to view hierarchy, such as setting the view’s highlight color. This method is called when:
|
||||
|
||||
• The view is about to be added to the view hierarchy of the view controller
|
||||
|
||||
If you override this method, call this method on super at some point in your implementation in case
|
||||
a superclass also overrides this method.
|
||||
|
||||
The default implementation of this method does nothing.
|
||||
*/
|
||||
- (void)viewWillAppear
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
Called when the view controller’s view is fully transitioned onto the screen.
|
||||
|
||||
@discussion This method is called after the completion of any drawing and animations
|
||||
involved in the initial appearance of the view. You can override this method to
|
||||
perform tasks appropriate for that time, such as work that should not interfere
|
||||
with the presentation animation, or starting an animation that you want to begin
|
||||
after the view appears.
|
||||
|
||||
If you override this method, call this method on super at some point in your
|
||||
implementation in case a superclass also overrides this method.
|
||||
|
||||
The default implementation of this method does nothing.
|
||||
*/
|
||||
- (void)viewDidAppear
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
Called when the view controller’s view is about to be removed from the view hierarchy in the window.
|
||||
|
||||
@discussion You can override this method to perform tasks that are to precede the disappearance
|
||||
of the view controller’s view, such as stopping a continuous animation that you
|
||||
started in response to the viewDidAppear method call. This method is called when:
|
||||
|
||||
• The view is about to be removed from the view hierarchy of the window
|
||||
|
||||
If you override this method, call this method on super at some point in your
|
||||
implementation in case a superclass also overrides this method.
|
||||
|
||||
The default implementation of this method does nothing.
|
||||
*/
|
||||
- (void)viewWillDisappear
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
Called after the view controller’s view is removed from the view hierarchy in a window.
|
||||
|
||||
@discussion You can override this method to perform tasks associated with removing the view
|
||||
controller’s view from the window’s view hierarchy, such as releasing resources
|
||||
not needed when the view is not visible or no longer part of the window.
|
||||
|
||||
If you override this method, call this method on super at some point in your
|
||||
implementation in case a superclass also overrides this method.
|
||||
|
||||
The default implementation of this method does nothing.
|
||||
*/
|
||||
- (void)viewDidDisappear
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
Manually sets the view that the controller manages.
|
||||
@@ -255,6 +401,9 @@ var CPViewControllerCachedCibs;
|
||||
{
|
||||
var willChangeIsViewLoaded = (_isViewLoaded == NO && aView != nil) || (_isViewLoaded == YES && aView == nil);
|
||||
|
||||
[self _registerOrUnregister:NO notificationsForView:_view];
|
||||
[self _registerOrUnregister:YES notificationsForView:aView];
|
||||
|
||||
if (willChangeIsViewLoaded)
|
||||
[self willChangeValueForKey:"isViewLoaded"];
|
||||
|
||||
@@ -270,6 +419,30 @@ var CPViewControllerCachedCibs;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)_registerOrUnregister:(BOOL)shouldRegister notificationsForView:(CPView)aView
|
||||
{
|
||||
if (aView === nil)
|
||||
return;
|
||||
|
||||
var center = [CPNotificationCenter defaultCenter],
|
||||
notifs_to_sel = @{_CPViewWillAppearNotification : @"viewWillAppear",
|
||||
_CPViewDidAppearNotification : @"viewDidAppear",
|
||||
_CPViewWillDisappearNotification : @"viewWillDisappear",
|
||||
_CPViewDidDisappearNotification : @"viewDidDisappear"};
|
||||
|
||||
[notifs_to_sel enumerateKeysAndObjectsUsingBlock:function(notif, selString, stop)
|
||||
{
|
||||
var selector = CPSelectorFromString(selString);
|
||||
if ([self implementsSelector:selector])
|
||||
{
|
||||
if (shouldRegister)
|
||||
[center addObserver:self selector:selector name:notif object:aView];
|
||||
else
|
||||
[center removeObserver:self name:notif object:aView];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* CPVisualEffectView.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Antoine Mercadal.
|
||||
* Copyright 2015, 280 Cappuccino Project.
|
||||
*
|
||||
* 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/Foundation.j>
|
||||
@import "CPAppearance.j"
|
||||
@import "CPView.j"
|
||||
|
||||
@typedef CPVisualEffectMaterial
|
||||
CPVisualEffectMaterialAppearanceBased = 0;
|
||||
CPVisualEffectMaterialLight = 1;
|
||||
CPVisualEffectMaterialDark = 2;
|
||||
CPVisualEffectMaterialTitlebar = 3;
|
||||
|
||||
@typedef CPVisualEffectBlendingMode
|
||||
CPVisualEffectBlendingModeBehindWindow = 0;
|
||||
CPVisualEffectBlendingModeWithinWindow = 1;
|
||||
|
||||
@typedef CPVisualEffectState
|
||||
CPVisualEffectStateFollowsWindowActiveState = 0;
|
||||
CPVisualEffectStateActive = 1;
|
||||
CPVisualEffectStateInactive = 2;
|
||||
|
||||
|
||||
/*! @ingroup appkit
|
||||
|
||||
Very naive implementation of CPVisualEffectView. This view allows
|
||||
to use vibrancy effect. This is only working with Safari 9+ and the
|
||||
support in Chrome/ium should come quite soon.
|
||||
Using this class with a browser that doesn't support backdrop-filter
|
||||
While still work, but you will not get the blurry effect.
|
||||
*/
|
||||
@implementation CPVisualEffectView : CPView
|
||||
{
|
||||
CPImage _maskImage @accessors(property=maskImage);
|
||||
CPVisualEffectBlendingMode _blendingMode @accessors(property=blendingMode);
|
||||
CPVisualEffectMaterial _material @accessors(property=material);
|
||||
CPVisualEffectState _state @accessors(property=state);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
_material = CPVisualEffectMaterialAppearanceBased;
|
||||
_blendingMode = CPVisualEffectBlendingModeWithinWindow;
|
||||
_state = CPVisualEffectStateFollowsWindowActiveState;
|
||||
_appearance = [CPAppearance appearanceNamed:CPAppearanceNameVibrantDark];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark CPVisualEffectView API
|
||||
|
||||
/*! Sets the appearance of the CPVisualEffectView.
|
||||
|
||||
Only CPAppearance named CPAppearanceNameVibrantDark or CPAppearanceNameVibrantLight are valid
|
||||
|
||||
@param anAppearance the CPAppearance.
|
||||
*/
|
||||
- (void)setAppearance:(CPAppearance)anAppearance
|
||||
{
|
||||
if (![self _validAppearance:anAppearance])
|
||||
[CPException raise:CPInvalidArgumentException reason:"Appearance can only be CPAppearanceNameVibrantDark or CPAppearanceNameVibrantLight in CPVisualEffectView, but is " + anAppearance];
|
||||
|
||||
[super setAppearance:anAppearance];
|
||||
|
||||
[self setNeedsLayout:YES];
|
||||
}
|
||||
|
||||
/*! Sets the received effect state.
|
||||
Possible values:
|
||||
<pre>
|
||||
CPVisualEffectStateFollowsWindowActiveState (default)
|
||||
CPVisualEffectStateActive
|
||||
CPVisualEffectStateInactive
|
||||
</pre>
|
||||
*/
|
||||
- (void)setState:(CPVisualEffectState)aState
|
||||
{
|
||||
if (_state == aState)
|
||||
return;
|
||||
|
||||
[self willChangeValueForKey:"state"];
|
||||
_state = aState;
|
||||
[self didChangeValueForKey:"state"];
|
||||
|
||||
[self setNeedsLayout:YES];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Utilities
|
||||
|
||||
- (void)_setEffectEnabled:(BOOL)shouldEnable
|
||||
{
|
||||
var dark = [[self appearance] isEqual:[CPAppearance appearanceNamed:CPAppearanceNameVibrantDark]],
|
||||
prop = CPBrowserStyleProperty("backdrop-filter"),
|
||||
color = (dark ? [CPColor colorWithHexString:@"1e1e1e"] : [CPColor whiteColor]),
|
||||
finalColor = shouldEnable ? [color colorWithAlphaComponent:0.6] : color;
|
||||
|
||||
[self setBackgroundColor:finalColor];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
self._DOMElement.style[prop] = shouldEnable ? "blur(30px)" : nil;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
switch (_state)
|
||||
{
|
||||
case CPVisualEffectStateFollowsWindowActiveState:
|
||||
[self _setEffectEnabled:[self hasThemeState:CPThemeStateKeyWindow]];
|
||||
break;
|
||||
|
||||
case CPVisualEffectStateActive:
|
||||
[self _setEffectEnabled:YES];
|
||||
break;
|
||||
|
||||
case CPVisualEffectStateInactive:
|
||||
[self _setEffectEnabled:NO];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)_validAppearance:(CPAppearance)anAppearance
|
||||
{
|
||||
return [anAppearance isEqual:[CPAppearance appearanceNamed:CPAppearanceNameVibrantDark]] || [anAppearance isEqual:[CPAppearance appearanceNamed:CPAppearanceNameVibrantLight]];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark CPCoding
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
{
|
||||
_blendingMode = [aCoder decodeIntForKey:@"_blendingMode"] || CPVisualEffectBlendingModeWithinWindow;
|
||||
_maskImage = [aCoder decodeObjectForKey:@"_maskImage"];
|
||||
_material = [aCoder decodeIntForKey:@"_material"] || CPVisualEffectMaterialAppearanceBased;
|
||||
_state = [aCoder decodeIntForKey:@"_state"] || CPVisualEffectStateFollowsWindowActiveState;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeObject:_maskImage forKey:@"_maskImage"];
|
||||
[aCoder encodeInt:_blendingMode forKey:@"_blendingMode"];
|
||||
[aCoder encodeInt:_material forKey:@"_material"];
|
||||
[aCoder encodeInt:_state forKey:@"_state"];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user