Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 /* | 1 /* |
2 This file is part of LilyPond, the GNU music typesetter. | 2 This file is part of LilyPond, the GNU music typesetter. |
3 | 3 |
4 Copyright (C) 2004--2012 Han-Wen Nienhuys <hanwen@xs4all.nl> | 4 Copyright (C) 2004--2012 Han-Wen Nienhuys <hanwen@xs4all.nl> |
5 | 5 |
6 LilyPond is free software: you can redistribute it and/or modify | 6 LilyPond is free software: you can redistribute it and/or modify |
7 it under the terms of the GNU General Public License as published by | 7 it under the terms of the GNU General Public License as published by |
8 the Free Software Foundation, either version 3 of the License, or | 8 the Free Software Foundation, either version 3 of the License, or |
9 (at your option) any later version. | 9 (at your option) any later version. |
10 | 10 |
(...skipping 15 matching lines...) Expand all Loading... | |
26 #include "note-column.hh" | 26 #include "note-column.hh" |
27 #include "paper-column.hh" | 27 #include "paper-column.hh" |
28 #include "pointer-group-interface.hh" | 28 #include "pointer-group-interface.hh" |
29 #include "warn.hh" | 29 #include "warn.hh" |
30 | 30 |
31 MAKE_SCHEME_CALLBACK (Self_alignment_interface, y_aligned_on_self, 1); | 31 MAKE_SCHEME_CALLBACK (Self_alignment_interface, y_aligned_on_self, 1); |
32 SCM | 32 SCM |
33 Self_alignment_interface::y_aligned_on_self (SCM element) | 33 Self_alignment_interface::y_aligned_on_self (SCM element) |
34 { | 34 { |
35 Grob *me = unsmob_grob (element); | 35 Grob *me = unsmob_grob (element); |
36 return align_grob (me, NULL, get_alignment (me, Y_AXIS), Y_AXIS, false, 0, 0); | 36 return align_grob (me, NULL, Y_AXIS, false, 0, 0); |
37 } | 37 } |
38 | 38 |
39 MAKE_SCHEME_CALLBACK (Self_alignment_interface, x_aligned_on_self, 1); | 39 MAKE_SCHEME_CALLBACK (Self_alignment_interface, x_aligned_on_self, 1); |
40 SCM | 40 SCM |
41 Self_alignment_interface::x_aligned_on_self (SCM element) | 41 Self_alignment_interface::x_aligned_on_self (SCM element) |
42 { | 42 { |
43 Grob *me = unsmob_grob (element); | 43 Grob *me = unsmob_grob (element); |
44 return align_grob (me, NULL, get_alignment (me, X_AXIS), X_AXIS, false, 0, 0); | 44 return align_grob (me, NULL, X_AXIS, false, 0, 0); |
45 } | 45 } |
46 | 46 |
47 MAKE_SCHEME_CALLBACK (Self_alignment_interface, pure_y_aligned_on_self, 3); | 47 MAKE_SCHEME_CALLBACK (Self_alignment_interface, pure_y_aligned_on_self, 3); |
48 SCM | 48 SCM |
49 Self_alignment_interface::pure_y_aligned_on_self (SCM smob, SCM start, SCM end) | 49 Self_alignment_interface::pure_y_aligned_on_self (SCM smob, SCM start, SCM end) |
50 { | 50 { |
51 Grob *me = unsmob_grob (smob); | 51 Grob *me = unsmob_grob (smob); |
52 return align_grob (me, NULL, get_alignment (me, Y_AXIS), Y_AXIS, true, robust_ scm2int (start, 0), robust_scm2int (end, INT_MAX)); | 52 return align_grob (me, NULL, Y_AXIS, true, robust_scm2int (start, 0), robust_s cm2int (end, INT_MAX)); |
53 } | |
54 | |
55 SCM | |
56 Self_alignment_interface::centered_on_object (Grob *him, Axis a) | |
57 { | |
58 return scm_from_double (robust_relative_extent (him, him, a).center ()); | |
53 } | 59 } |
54 | 60 |
55 MAKE_SCHEME_CALLBACK (Self_alignment_interface, centered_on_x_parent, 1); | 61 MAKE_SCHEME_CALLBACK (Self_alignment_interface, centered_on_x_parent, 1); |
56 SCM | 62 SCM |
57 Self_alignment_interface::centered_on_x_parent (SCM smob) | 63 Self_alignment_interface::centered_on_x_parent (SCM smob) |
58 { | 64 { |
59 Grob *me = unsmob_grob (smob); | 65 return centered_on_object (unsmob_grob (smob)->get_parent (X_AXIS), X_AXIS); |
60 return align_grob (NULL, me->get_parent (X_AXIS), scm_from_double (0), X_AXIS, false, 0, 0); | |
61 } | |
62 | |
63 MAKE_SCHEME_CALLBACK (Self_alignment_interface, centered_on_note_columns, 1); | |
64 SCM | |
65 Self_alignment_interface::centered_on_note_columns (SCM smob) | |
66 { | |
67 Item *it = unsmob_item (smob)->get_column (); | |
68 if (!it) | |
69 return scm_from_double (0.0); | |
70 | |
71 extract_grob_set (it, "elements", elts); | |
72 vector<Grob *> ncs; | |
73 Interval centers; | |
74 for (vsize i = 0; i < elts.size (); i++) | |
75 if (Note_column::has_interface (elts[i])) | |
76 centers.add_point (robust_relative_extent (elts[i], elts[i], X_AXIS).cente r ()); | |
77 | |
78 if (centers.is_empty ()) | |
79 return scm_from_double (0.0); | |
80 | |
81 return scm_from_double (centers.center ()); | |
82 } | 66 } |
83 | 67 |
84 MAKE_SCHEME_CALLBACK (Self_alignment_interface, centered_on_y_parent, 1); | 68 MAKE_SCHEME_CALLBACK (Self_alignment_interface, centered_on_y_parent, 1); |
85 SCM | 69 SCM |
86 Self_alignment_interface::centered_on_y_parent (SCM smob) | 70 Self_alignment_interface::centered_on_y_parent (SCM smob) |
87 { | 71 { |
88 Grob *me = unsmob_grob (smob); | 72 return centered_on_object (unsmob_grob (smob)->get_parent (Y_AXIS), Y_AXIS); |
89 return align_grob (NULL, me->get_parent (Y_AXIS), scm_from_double (0), Y_AXIS, false, 0, 0); | |
90 } | 73 } |
91 | 74 |
92 MAKE_SCHEME_CALLBACK (Self_alignment_interface, x_centered_on_y_parent, 1); | 75 MAKE_SCHEME_CALLBACK (Self_alignment_interface, x_centered_on_y_parent, 1); |
93 SCM | 76 SCM |
94 Self_alignment_interface::x_centered_on_y_parent (SCM smob) | 77 Self_alignment_interface::x_centered_on_y_parent (SCM smob) |
95 { | 78 { |
96 Grob *me = unsmob_grob (smob); | 79 return centered_on_object (unsmob_grob (smob)->get_parent (Y_AXIS), X_AXIS); |
97 return align_grob (NULL, me->get_parent (Y_AXIS), scm_from_double (0), X_AXIS, false, 0, 0); | |
98 } | 80 } |
99 | 81 |
100 MAKE_SCHEME_CALLBACK (Self_alignment_interface, aligned_on_x_parent, 1); | 82 MAKE_SCHEME_CALLBACK (Self_alignment_interface, x_align_grob, 1); |
101 SCM | 83 SCM |
102 Self_alignment_interface::aligned_on_x_parent (SCM smob) | 84 Self_alignment_interface::x_align_grob (SCM smob) |
103 { | 85 { |
104 Grob *me = unsmob_grob (smob); | 86 Grob *me = unsmob_grob (smob); |
105 return align_grob (me, me->get_parent (X_AXIS), get_alignment (me, X_AXIS), X_ AXIS, false, 0, 0); | 87 return align_grob (me, me->get_parent (X_AXIS), X_AXIS, false, 0, 0); |
106 } | 88 } |
107 | 89 |
108 MAKE_SCHEME_CALLBACK (Self_alignment_interface, aligned_on_y_parent, 1); | 90 MAKE_SCHEME_CALLBACK (Self_alignment_interface, y_align_grob, 1); |
109 SCM | 91 SCM |
110 Self_alignment_interface::aligned_on_y_parent (SCM smob) | 92 Self_alignment_interface::y_align_grob (SCM smob) |
111 { | 93 { |
112 Grob *me = unsmob_grob (smob); | 94 Grob *me = unsmob_grob (smob); |
113 return align_grob (me, me->get_parent (Y_AXIS), get_alignment (me, Y_AXIS), Y_ AXIS, false, 0, 0); | 95 return align_grob (me, me->get_parent (Y_AXIS), Y_AXIS, false, 0, 0); |
114 } | 96 } |
115 | 97 |
116 // This is not a part of align_grob because 'me' from align_grob | 98 /* |
117 // sometimes is a null pointer. | 99 Positioning of grobs is done relative to their parents in respective axes. |
118 SCM | 100 Grob properties [XY]-offset measure the displacement between grob's reference |
119 Self_alignment_interface::get_alignment (Grob *me, Axis a) | 101 point and the reference point of grob's parent in [XY]_AXIS (in staffspaces). |
120 { | |
121 return (a == X_AXIS) | |
122 ? me->internal_get_property (ly_symbol2scm ("self-alignment-X")) | |
123 : me->internal_get_property (ly_symbol2scm ("self-alignment-Y")); | |
124 } | |
125 | 102 |
126 // TODO: should this method have a different name, for example calc_offset? | 103 To align a particular point of the grob with a particular point of its parent |
127 | 104 one has to calculate what this offset should be, based on dimensions (extents) |
128 /* LilyPond positions every grob relative to its parent in respective axis. | 105 of both objects. |
MikeSol
2013/03/19 15:28:45
In general, try to avoid using the word LilyPond i
janek
2013/03/19 21:04:16
Done.
| |
129 Grob properties [XY]-offset measure the displacement between grob's reference | 106 */ |
130 point and the reference point of grob's parent in [XY]_AXIS. For example, | |
131 LyricText's X-offset = 2 means that the reference point of LyricText will be | |
132 placed 2 staffspaces to the right of LyricText's parent reference point. | |
133 | |
MikeSol
2013/03/19 15:28:45
I don't see staff space being looked up anywhere i
janek
2013/03/19 21:04:16
Well, staffspace is the unit in which XY-offsets a
| |
134 To align a particular point of the grob to a particular point of its parent | |
135 one has to calculate what this offset should be, based on dimensions (extents ) | |
136 of both objects. For example, LyricText's reference point in horizontal axis | |
137 is on the left edge of its stencil; to align LyricText's right edge to the | |
138 reference point of its parent we have to move LyricText to the left, and the | |
139 offset should be equal to LyricText's width. | |
140 | |
141 Alignment is passed as a scheme value because we need a way of telling LilyPo nd | |
142 to ignore it (and thus use reference point as alignment point). | |
143 */ | |
144 | |
MikeSol
2013/03/19 15:28:45
With respect to my last review, this function shou
MikeSol
2013/03/19 15:28:45
I don't have the energy to trigger another comment
janek
2013/03/19 21:04:16
I've trimmed the comments and tried to make them l
| |
145 SCM | 107 SCM |
146 Self_alignment_interface::align_grob (Grob *me, | 108 Self_alignment_interface::align_grob (Grob *me, |
147 Grob *him, | 109 Grob *him, |
148 SCM alignment, | |
149 Axis a, | 110 Axis a, |
150 bool pure, | 111 bool pure, |
151 int start, | 112 int start, |
152 int end) | 113 int end) |
153 { | 114 { |
154 Real offset = 0.0; | 115 Real offset = 0.0; |
155 | 116 |
156 // me is NULL = don't care about grob's dimensions (use grob's refpoint for al igning) | 117 SCM alignment = (a == X_AXIS) |
157 if (me && scm_is_number (alignment)) | 118 ? me->internal_get_property (ly_symbol2scm ("self-alignment-X" )) |
119 : me->internal_get_property (ly_symbol2scm ("self-alignment-Y" )); | |
120 | |
121 SCM my_alignment, his_alignment; | |
122 if (scm_is_pair (alignment)) | |
158 { | 123 { |
159 Interval my_ext (me->maybe_pure_extent (me, a, pure, start, end)); | 124 my_alignment = scm_car (alignment); |
160 if (my_ext.is_empty ()) | 125 his_alignment = scm_cdr (alignment); |
161 programming_error ("cannot align on self: empty element"); | 126 } |
162 else | 127 else |
163 offset -= my_ext.linear_combination (scm_to_double (alignment)); | 128 { |
129 my_alignment = alignment; | |
130 his_alignment = alignment; | |
164 } | 131 } |
165 | 132 |
166 // him is NULL = don't care about parent dimensions, align grob only on itself | 133 // calculate offset related to grob's own dimensions |
167 if (him && scm_is_number (alignment)) | 134 if (scm_is_number (my_alignment)) |
168 { | 135 { |
136 Interval my_ext = me->maybe_pure_extent (me, a, pure, start, end); | |
137 | |
138 // Empty extent doesn't mean an error - we simply don't align such grobs. | |
139 // However, empty extent and non-empty stencil would be suspicious. | |
140 if (!my_ext.is_empty ()) | |
141 offset -= my_ext.linear_combination (scm_to_double (my_alignment)); | |
142 else if (me->get_stencil ()) | |
143 warning (me->name () + " has empty extent and non-empty stencil."); | |
144 } | |
145 | |
146 // calculate offset related to grob's parent dimensions | |
147 if (him && scm_is_number (his_alignment)) | |
148 { | |
149 Interval his_ext; | |
169 if (Paper_column::has_interface (him)) | 150 if (Paper_column::has_interface (him)) |
170 return scm_from_double (0.0); | 151 /* |
152 PaperColumn extents aren't reliable (they depend on size and alignment | |
153 of PaperColumn's children), so we cannot use them. Instead, we extract | |
154 the extent of a respective NoteColumn and align on it. | |
155 This situation (i.e. having PaperColumn as parent) happens for example | |
156 for unassociated lyrics (i.e. lyrics without associatedVoice set), | |
157 or dynamics attached to spacers. | |
158 */ | |
159 his_ext = Paper_column::get_generic_interface_extent | |
160 (him, ly_symbol2scm ("note-column-interface"), a); | |
161 else | |
162 his_ext = him->maybe_pure_extent (him, a, pure, start, end); | |
171 | 163 |
172 Interval his_ext = him->maybe_pure_extent (him, a, pure, start, end); | 164 // Empty extent doesn't mean an error - we simply don't align such grobs. |
165 // However, empty extent and non-empty stencil would be suspicious. | |
173 if (!his_ext.is_empty ()) | 166 if (!his_ext.is_empty ()) |
174 offset += his_ext.linear_combination (scm_to_double (alignment)); | 167 offset += his_ext.linear_combination (scm_to_double (his_alignment)); |
168 else if (him->get_stencil ()) | |
169 warning (him->name () + " has empty extent and non-empty stencil."); | |
175 } | 170 } |
176 | 171 |
177 return scm_from_double (offset); | 172 return scm_from_double (offset); |
178 } | 173 } |
179 | 174 |
180 void | |
181 Self_alignment_interface::set_center_parent (Grob *me, Axis a) | |
182 { | |
183 add_offset_callback (me, | |
184 (a == X_AXIS) ? centered_on_x_parent_proc : centered_on_y _parent_proc, | |
185 a); | |
186 } | |
187 | |
188 void | |
189 Self_alignment_interface::set_align_self (Grob *me, Axis a) | |
190 { | |
191 add_offset_callback (me, | |
192 (a == X_AXIS) ? x_aligned_on_self_proc : y_aligned_on_sel f_proc, | |
193 a); | |
194 } | |
195 | |
196 ADD_INTERFACE (Self_alignment_interface, | 175 ADD_INTERFACE (Self_alignment_interface, |
197 "Position this object on itself and/or on its parent. To this" | 176 "Align a particular point of this object on" |
198 " end, the following functions are provided:\n" | 177 " a particular point of its parent, for example" |
199 "\n" | 178 " object's reference point on its parent's center." |
200 "@table @code\n" | 179 " Alignment is read from properties @code{self-alignment-X}" |
201 "@item Self_alignment_interface::[xy]_aligned_on_self\n" | 180 " and @code{self-alignment-Y}.", |
202 "Align self on reference point, using" | |
203 " @code{self-alignment-X} and @code{self-alignment-Y}." | |
204 "@item Self_alignment_interface::aligned_on_[xy]_parent\n" | |
205 "@item Self_alignment_interface::centered_on_[xy]_parent\n" | |
206 "Shift the object so its own reference point is centered on" | |
207 " the extent of the parent\n" | |
208 "@end table\n", | |
209 | 181 |
210 /* properties */ | 182 /* properties */ |
211 "collision-bias " | 183 "collision-bias " |
212 "collision-padding " | 184 "collision-padding " |
213 "potential-X-colliding-grobs " | 185 "potential-X-colliding-grobs " |
214 "self-alignment-X " | 186 "self-alignment-X " |
215 "self-alignment-Y " | 187 "self-alignment-Y " |
216 "X-colliding-grobs " | 188 "X-colliding-grobs " |
217 "Y-colliding-grobs " | 189 "Y-colliding-grobs " |
218 ); | 190 ); |
LEFT | RIGHT |