2 staff-spacing.cc -- implement Staff_spacing
4 source file of the GNU LilyPond music typesetter
6 (c) 2001--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
9 #include "staff-spacing.hh"
14 #include "paper-column.hh"
15 #include "separation-item.hh"
17 #include "bar-line.hh"
18 #include "staff-symbol-referencer.hh"
19 #include "note-column.hh"
21 #include "accidental-placement.hh"
22 #include "pointer-group-interface.hh"
23 #include "directional-element-interface.hh"
26 Insert some more space for the next note, in case it has a stem in
30 Staff_spacing::next_note_correction (Grob
*me
,
38 if (!g
|| !Note_column::has_interface (g
))
41 Item
*col
= dynamic_cast<Item
*> (g
)->get_column ();
42 Real max_corr
= max (0., (- g
->extent (col
, X_AXIS
)[LEFT
]));
45 Duh. If this gets out of hand, we should invent something more generic.
47 if (Grob
*a
= Note_column::accidentals (g
))
50 if (Accidental_placement::has_interface (a
))
51 v
= Accidental_placement::get_relevant_accidental_extent (a
, col
, me
);
53 v
= a
->extent (col
, X_AXIS
);
55 max_corr
= max (max_corr
, (- v
[LEFT
]));
57 if (Grob
*a
= unsmob_grob (g
->get_object ("arpeggio")))
58 max_corr
= max (max_corr
, - a
->extent (col
, X_AXIS
)[LEFT
]);
61 Let's decrease the space a little if the problem is not located
64 if (bar_size
.is_empty ())
67 if (!bar_size
.is_empty ())
68 if (Grob
*stem
= Note_column::get_stem (g
))
70 Direction d
= get_grob_direction (stem
);
73 Real stem_start
= Stem::head_positions (stem
) [DOWN
];
74 Real stem_end
= Stem::stem_end_position (stem
);
75 Interval
stem_posns (min (stem_start
, stem_end
),
76 max (stem_end
, stem_start
));
78 stem_posns
.intersect (bar_size
);
80 Real corr
= min (abs (stem_posns
.length () / 7.0), 1.0);
81 corr
*= robust_scm2double (me
->get_property ("stem-spacing-correction"), 1);
85 max_corr
= max (max_corr
, corr
);
93 Y-positions that are covered by BAR_GROB, in the case that it is a
96 Staff_spacing::bar_y_positions (Grob
*bar_grob
)
99 bar_size
.set_empty ();
100 if (Bar_line::has_interface (bar_grob
))
102 SCM glyph
= bar_grob
->get_property ("glyph-name");
103 Grob
*staff_sym
= Staff_symbol_referencer::get_staff_symbol (bar_grob
);
105 string glyph_string
= scm_is_string (glyph
) ? ly_scm2string (glyph
) : "";
106 if (glyph_string
.substr (0, 1) == "|"
107 || glyph_string
.substr (0, 1) == ".")
109 Grob
*common
= bar_grob
->common_refpoint (staff_sym
, Y_AXIS
);
110 Interval bar_size
= bar_grob
->extent (common
, Y_AXIS
);
111 bar_size
*= 1.0 / Staff_symbol_referencer::staff_space (bar_grob
);
118 Do corrections for the following notes.
120 This is slightly convoluted, since the staffspacing grob gets
121 pointers to the separation-items, not the note-columns or
125 Staff_spacing::next_notes_correction (Grob
*me
, Grob
*last_grob
,
126 Real
*compound_space
, Real
*compound_fixed
129 Interval bar_size
= bar_y_positions (last_grob
);
131 extract_grob_set (me
, "right-items", right_items
);
133 *compound_fixed
= 0.0;
134 *compound_space
= 0.0;
137 for (vsize i
= right_items
.size (); i
--;)
139 Grob
*g
= right_items
[i
];
144 next_note_correction (me
, g
, bar_size
, &space
, &fixed
);
146 *compound_space
+= space
;
147 *compound_fixed
+= fixed
;
150 extract_grob_set (g
, "elements", elts
);
151 for (vsize j
= elts
.size (); j
--;)
155 next_note_correction (me
, elts
[j
], bar_size
, &space
, &fixed
);
156 *compound_fixed
+= fixed
;
157 *compound_space
+= space
;
164 *compound_space
/= wish_count
;
165 *compound_fixed
/= wish_count
;
170 Staff_spacing::get_spacing_params (Grob
*me
, Real
*space
, Real
*fixed
)
175 Grob
*separation_item
= 0;
176 Item
*me_item
= dynamic_cast<Item
*> (me
);
178 extract_grob_set (me
, "left-items", items
);
179 for (vsize i
= items
.size (); i
--;)
181 Grob
*cand
= items
[i
];
182 if (cand
&& Separation_item::has_interface (cand
))
183 separation_item
= cand
;
186 // printf ("doing col %d\n" , Paper_column::get_rank (left_col));
187 if (!separation_item
)
189 programming_error ("no sep item");
194 Grob
*last_grob
= Separation_item::extremal_break_aligned_grob (separation_item
, RIGHT
,
201 Should insert a adjustable space here? For excercises, you might want to
202 use a staff without a clef in the beginning.
206 we used to have a warning here, but it generates a lot of
207 spurious error messages.
212 *fixed
= last_ext
[RIGHT
];
213 *space
= *fixed
+ 1.0;
215 SCM alist
= last_grob
->get_property ("space-alist");
216 if (!scm_list_p (alist
))
219 SCM space_def
= scm_sloppy_assq (ly_symbol2scm ("first-note"), alist
);
220 if (me_item
->break_status_dir () == CENTER
)
222 SCM nndef
= scm_sloppy_assq (ly_symbol2scm ("next-note"), alist
);
223 if (scm_is_pair (nndef
))
227 if (!scm_is_pair (space_def
))
229 programming_error ("unknown prefatory spacing");
233 space_def
= scm_cdr (space_def
);
234 Real distance
= scm_to_double (scm_cdr (space_def
));
235 SCM type
= scm_car (space_def
);
237 *fixed
= last_ext
[RIGHT
];
238 if (type
== ly_symbol2scm ("fixed-space"))
243 else if (type
== ly_symbol2scm ("extra-space"))
244 *space
= *fixed
+ distance
;
245 else if (type
== ly_symbol2scm ("semi-fixed-space"))
247 *fixed
+= distance
/ 2;
248 *space
= *fixed
+ distance
/ 2;
250 else if (type
== ly_symbol2scm ("minimum-space"))
251 *space
= last_ext
[LEFT
] + max (last_ext
.length (), distance
);
252 else if (type
== ly_symbol2scm ("minimum-fixed-space"))
254 *space
= last_ext
[LEFT
] + max (last_ext
.length (), distance
);
258 Real correction_fixed
, correction_space
;
259 next_notes_correction (me
, last_grob
, &correction_space
, &correction_fixed
);
260 *space
+= correction_space
;
261 *fixed
+= correction_fixed
;
264 ADD_INTERFACE (Staff_spacing
, "staff-spacing-interface",
265 "This object calculates spacing details from a "
266 " breakable symbol (left) to another object. For example, it takes care "
267 " of optical spacing from a bar lines to a note.",
270 "stem-spacing-correction "