/*
This file is part of LilyPond, the GNU music typesetter.
- Copyright (C) 1997--2012 Han-Wen Nienhuys <hanwen@xs4all.nl>
+ Copyright (C) 1997--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
LilyPond is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "output-def.hh"
#include "paper-score.hh"
#include "staff-symbol-referencer.hh"
+#include "staff-symbol.hh"
#include "stencil.hh"
#include "grob.hh"
SCM
Rest::y_offset_callback (SCM smob)
{
- Grob *me = unsmob_grob (smob);
+ Grob *me = Grob::unsmob (smob);
int duration_log = scm_to_int (me->get_property ("duration-log"));
- int line_count = Staff_symbol_referencer::line_count (me);
Real ss = Staff_symbol_referencer::staff_space (me);
+ return scm_from_double (ss * 0.5 * Rest::staff_position_internal (me, duration_log, get_grob_direction (me)));
+}
+
+Real
+Rest::staff_position_internal (Grob *me, int duration_log, int dir)
+{
+ if (!me)
+ return 0;
+
bool position_override = scm_is_number (me->get_property ("staff-position"));
- Real amount;
+ Real pos;
if (position_override)
{
- amount =
- robust_scm2double (me->get_property ("staff-position"), 0) * 0.5 * ss;
+ pos
+ = robust_scm2double (me->get_property ("staff-position"), 0);
/*
- semibreve rests were always positioned one off
+ semibreve rests are positioned one staff line off
*/
if (duration_log == 0)
- amount += ss;
+ return pos + 2;
/*
trust the client on good positioning;
to be properly aligned to staff lines,
but custom rest shapes may not need that sort of care.
*/
+
+ return pos;
}
- else
- {
- int pos = 4 * get_grob_direction (me);
+ Real vpos = dir * robust_scm2int (me->get_property ("voiced-position"), 0);
+ pos = vpos;
+
+ if (duration_log > 1)
+ /* Only half notes or longer want alignment with staff lines */
+ return pos;
+
+ /*
+ We need a staff symbol for actually aligning anything
+ */
+ Grob *staff = Staff_symbol_referencer::get_staff_symbol (me);
+ if (!staff)
+ return pos;
+
+ std::vector<Real> linepos = Staff_symbol::line_positions (staff);
+
+ if (linepos.empty ())
+ return pos;
+
+ std::sort (linepos.begin (), linepos.end ());
+
+ if (duration_log == 0)
+ {
/*
- make a semibreve rest hang from the next line,
- except for a single line staff;
- assume the next line being integer steps away
+ lower voice semibreve rests generally hang a line lower
*/
- if (duration_log == 0 && line_count > 1)
- ++pos;
+
+ if (dir < 0)
+ pos -= 2;
/*
- make sure rest is aligned to a staff line
+ make a semibreve rest hang from the next available line,
+ except when there is none.
*/
- while (!Staff_symbol_referencer::on_line (me, pos))
- ++pos;
- amount = ss * 0.5 * pos;
+ std::vector<Real>::const_iterator it
+ = std::upper_bound (linepos.begin (), linepos.end (), pos);
+ if (it != linepos.end ())
+ pos = *it;
+ else
+ pos = linepos.back ();
+ }
+ else
+ {
+ std::vector<Real>::const_iterator it
+ = std::upper_bound (linepos.begin (), linepos.end (), pos);
+ if (it != linepos.begin ())
+ --it;
+ pos = *it;
}
- return scm_from_double (amount);
+ /* Finished for neutral position */
+ if (!dir)
+ return pos;
+
+ /* If we have a voiced position, make sure that it's on the
+ proper side of neutral before using it.
+ */
+
+ Real neutral = staff_position_internal (me, duration_log, 0);
+
+ if (dir * (pos - neutral) > 0)
+ return pos;
+ else
+ return neutral + vpos;
}
/* A rest might lie under a beam, in which case it should be cross-staff if
SCM
Rest::calc_cross_staff (SCM smob)
{
- Grob *me = unsmob_grob (smob);
- Grob *stem = unsmob_grob (me->get_object ("stem"));
+ Grob *me = Grob::unsmob (smob);
+ Grob *stem = Grob::unsmob (me->get_object ("stem"));
if (!stem)
return SCM_BOOL_F;
make this function easily usable in C++
*/
string
-Rest::glyph_name (Grob *me, int durlog, string style, bool try_ledgers)
+Rest::glyph_name (Grob *me, int durlog, const string &style, bool try_ledgers,
+ Real offset)
{
bool is_ledgered = false;
if (try_ledgers && (durlog == -1 || durlog == 0 || durlog == 1))
{
- int const pos = int (Staff_symbol_referencer::get_position (me));
-
+ int const pos = int (Staff_symbol_referencer::get_position (me)
+ + offset);
/*
- half rests need ledger if not lying on a staff line,
- whole rests need ledger if not hanging from a staff line,
- breve rests need ledger if neither lying on nor hanging from a staff line
+ half rests need ledger if not lying on a staff line,
+ whole rests need ledger if not hanging from a staff line,
+ breve rests need ledger if neither lying on nor hanging from a staff line
*/
if (-1 <= durlog && durlog <= 1)
is_ledgered = !Staff_symbol_referencer::on_staff_line (me, pos)
- && !(durlog == -1
- && Staff_symbol_referencer::on_staff_line (me, pos + 2));
+ && !(durlog == -1
+ && Staff_symbol_referencer::on_staff_line (me, pos + 2));
}
string actual_style (style.c_str ());
actual_style = "";
}
- return ("rests." + to_string (durlog) + (is_ledgered ? "o" : "")
+ return ("rests." + ::to_string (durlog) + (is_ledgered ? "o" : "")
+ actual_style);
}
string style = robust_symbol2string (me->get_property ("style"), "default");
Font_metric *fm = Font_interface::get_default_font (me);
- string font_char = glyph_name (me, durlog, style, ledgered);
+ string font_char = glyph_name (me, durlog, style, ledgered, 0.0);
Stencil out = fm->find_by_name (font_char);
if (out.is_empty ())
me->warning (_f ("rest `%s' not found", font_char.c_str ()));
SCM
Rest::print (SCM smob)
{
- return brew_internal_stencil (unsmob_grob (smob), true);
+ return brew_internal_stencil (Grob::unsmob (smob), true);
}
MAKE_SCHEME_CALLBACK (Rest, width, 1);
SCM
Rest::width (SCM smob)
{
- return generic_extent_callback (unsmob_grob (smob), X_AXIS);
+ return generic_extent_callback (Grob::unsmob (smob), X_AXIS);
}
MAKE_SCHEME_CALLBACK (Rest, height, 1);
SCM
Rest::height (SCM smob)
{
- return generic_extent_callback (unsmob_grob (smob), Y_AXIS);
+ return generic_extent_callback (Grob::unsmob (smob), Y_AXIS);
}
/*
with ledgered rests.
*/
SCM m = brew_internal_stencil (me, a != X_AXIS);
- return ly_interval2scm (unsmob_stencil (m)->extent (a));
+ return ly_interval2scm (Stencil::unsmob (m)->extent (a));
}
MAKE_SCHEME_CALLBACK (Rest, pure_height, 3);
SCM /* start */,
SCM /* end */)
{
- Grob *me = unsmob_grob (smob);
+ Grob *me = Grob::unsmob (smob);
SCM m = brew_internal_stencil (me, false);
- return ly_interval2scm (unsmob_stencil (m)->extent (Y_AXIS));
+ return ly_interval2scm (Stencil::unsmob (m)->extent (Y_AXIS));
}
ADD_INTERFACE (Rest,
"direction "
"minimum-distance "
"style "
+ "voiced-position "
);