2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2004--2014 Han-Wen Nienhuys <hanwen@xs4all.nl>
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
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 #include "self-alignment-interface.hh"
23 #include "note-column.hh"
24 #include "paper-column.hh"
25 #include "pointer-group-interface.hh"
28 MAKE_SCHEME_CALLBACK (Self_alignment_interface, y_aligned_on_self, 1);
30 Self_alignment_interface::y_aligned_on_self (SCM element)
32 return aligned_on_self (unsmob_grob (element), Y_AXIS, false, 0, 0);
35 MAKE_SCHEME_CALLBACK (Self_alignment_interface, x_aligned_on_self, 1);
37 Self_alignment_interface::x_aligned_on_self (SCM element)
39 return aligned_on_self (unsmob_grob (element), X_AXIS, false, 0, 0);
42 MAKE_SCHEME_CALLBACK (Self_alignment_interface, pure_y_aligned_on_self, 3);
44 Self_alignment_interface::pure_y_aligned_on_self (SCM smob, SCM start, SCM end)
46 return aligned_on_self (unsmob_grob (smob), Y_AXIS, true, robust_scm2int (start, 0), robust_scm2int (end, INT_MAX));
50 Self_alignment_interface::aligned_on_self (Grob *me, Axis a, bool pure, int start, int end)
52 SCM sym = (a == X_AXIS) ? ly_symbol2scm ("self-alignment-X")
53 : ly_symbol2scm ("self-alignment-Y");
55 SCM align (me->internal_get_property (sym));
56 if (scm_is_number (align))
58 Interval ext (me->maybe_pure_extent (me, a, pure, start, end));
59 // Empty extent doesn't mean an error - we simply don't align such grobs.
60 // However, empty extent and non-empty stencil would be suspicious.
62 return scm_from_double (- ext.linear_combination (scm_to_double (align)));
63 else if (me->get_stencil ())
64 warning (me->name () + " has empty extent and non-empty stencil.");
66 return scm_from_double (0.0);
70 Self_alignment_interface::centered_on_object (Grob *him, Axis a)
72 return scm_from_double (robust_relative_extent (him, him, a).center ());
75 MAKE_SCHEME_CALLBACK (Self_alignment_interface, centered_on_x_parent, 1);
77 Self_alignment_interface::centered_on_x_parent (SCM smob)
79 return centered_on_object (unsmob_grob (smob)->get_parent (X_AXIS), X_AXIS);
82 MAKE_SCHEME_CALLBACK (Self_alignment_interface, centered_on_note_columns, 1);
84 Self_alignment_interface::centered_on_note_columns (SCM smob)
86 Item *it = unsmob_item (smob)->get_column ();
88 return scm_from_double (0.0);
90 extract_grob_set (it, "elements", elts);
93 for (vsize i = 0; i < elts.size (); i++)
94 if (Note_column::has_interface (elts[i]))
95 centers.add_point (scm_to_double (centered_on_object (elts[i], X_AXIS)));
97 if (centers.is_empty ())
98 return scm_from_double (0.0);
100 return scm_from_double (centers.center ());
103 MAKE_SCHEME_CALLBACK (Self_alignment_interface, centered_on_y_parent, 1);
105 Self_alignment_interface::centered_on_y_parent (SCM smob)
107 return centered_on_object (unsmob_grob (smob)->get_parent (Y_AXIS), Y_AXIS);
110 MAKE_SCHEME_CALLBACK (Self_alignment_interface, aligned_on_x_parent, 1);
112 Self_alignment_interface::aligned_on_x_parent (SCM smob)
114 return aligned_on_parent (unsmob_grob (smob), X_AXIS);
117 MAKE_SCHEME_CALLBACK (Self_alignment_interface, aligned_on_y_parent, 1);
119 Self_alignment_interface::aligned_on_y_parent (SCM smob)
121 return aligned_on_parent (unsmob_grob (smob), Y_AXIS);
125 Self_alignment_interface::aligned_on_parent (Grob *me, Axis a)
127 Grob *him = me->get_parent (a);
129 if (Paper_column::has_interface (him))
131 PaperColumn extents aren't reliable (they depend on size and alignment
132 of PaperColumn's children), so we align on NoteColumn instead.
133 This happens e.g. for lyrics without associatedVoice.
135 he = Paper_column::get_interface_extent
136 (him, ly_symbol2scm ("note-column-interface"), a);
138 he = him->extent (him, a);
140 SCM sym = (a == X_AXIS) ? ly_symbol2scm ("self-alignment-X")
141 : ly_symbol2scm ("self-alignment-Y");
142 SCM align_prop (me->internal_get_property (sym));
144 if (!scm_is_number (align_prop))
145 return scm_from_int (0);
148 Real align = scm_to_double (align_prop);
150 Interval ext (me->extent (me, a));
152 // Empty extent doesn't mean an error - we simply don't align such grobs.
153 // However, empty extent and non-empty stencil would be suspicious.
154 if (!ext.is_empty ())
155 x -= ext.linear_combination (align);
156 else if (me->get_stencil ())
157 warning (me->name () + " has empty extent and non-empty stencil.");
159 // See comment above.
161 x += he.linear_combination (align);
162 else if (him->get_stencil ())
163 warning (him->name () + " has empty extent and non-empty stencil.");
165 return scm_from_double (x);
169 Self_alignment_interface::set_center_parent (Grob *me, Axis a)
171 add_offset_callback (me,
172 (a == X_AXIS) ? centered_on_x_parent_proc : centered_on_y_parent_proc,
177 Self_alignment_interface::set_align_self (Grob *me, Axis a)
179 add_offset_callback (me,
180 (a == X_AXIS) ? x_aligned_on_self_proc : y_aligned_on_self_proc,
184 ADD_INTERFACE (Self_alignment_interface,
185 "Position this object on itself and/or on its parent. To this"
186 " end, the following functions are provided:\n"
189 "@item Self_alignment_interface::[xy]_aligned_on_self\n"
190 "Align self on reference point, using"
191 " @code{self-alignment-X} and @code{self-alignment-Y}."
192 "@item Self_alignment_interface::aligned_on_[xy]_parent\n"
193 "@item Self_alignment_interface::centered_on_[xy]_parent\n"
194 "Shift the object so its own reference point is centered on"
195 " the extent of the parent\n"