along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "bar-line.hh"
#include "beaming-pattern.hh"
#include "beam.hh"
#include "context.hh"
along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "bar-line.hh"
#include "context.hh"
#include "score-engraver.hh"
#include "warn.hh"
*/
#include "bar-line.hh"
-
-#include "all-font-metrics.hh"
-#include "font-interface.hh"
-#include "line-interface.hh"
-#include "lookup.hh"
-#include "output-def.hh"
#include "paper-column.hh"
-#include "staff-symbol-referencer.hh"
-
-MAKE_SCHEME_CALLBACK (Bar_line, calc_bar_extent, 1)
-SCM
-Bar_line::calc_bar_extent (SCM smob)
-{
- Interval result;
- Grob *me = unsmob_grob (smob);
- if (Grob *staff = Staff_symbol_referencer::get_staff_symbol (me))
- {
- result = staff->extent (staff, Y_AXIS);
-
- /* Due to rounding problems, bar lines extending to the outermost edges
- of the staff lines appear wrongly in on-screen display
- (and, to a lesser extent, in print) - they stick out a pixel.
- The solution is to extend bar lines only to the middle
- of the staff line - unless they have different colors,
- when it would be undesirable.
- */
- SCM bar_line_color = me->get_property ("color");
- SCM staff_color = staff->get_property ("color");
- Real radius = Staff_symbol_referencer::staff_radius (me);
- if (bar_line_color == staff_color && radius)
- result *= (1 - 0.5 * (Staff_symbol_referencer::line_thickness (me) / radius));
- }
- return ly_interval2scm (result);
-}
-
-Interval
-Bar_line::bar_y_extent (Grob *me, Grob *refpoint)
-{
- Interval iv = robust_scm2interval (me->get_property ("bar-extent"), Interval ());
-
- iv.translate (me->relative_coordinate (refpoint, Y_AXIS));
- return iv;
-}
bool
Bar_line::non_empty_barline (Grob *me)
{
- return has_interface (me) && !me->extent (me, X_AXIS).is_empty ();
-}
-
-MAKE_SCHEME_CALLBACK (Bar_line, print, 1);
-SCM
-Bar_line::print (SCM smob)
-{
- Grob *me = unsmob_grob (smob);
-
- SCM s = me->get_property ("glyph-name");
- SCM extent = me->get_property ("bar-extent");
-
- if (scm_is_string (s) && is_number_pair (extent))
- {
- string str = ly_scm2string (s);
- Interval ex = ly_scm2interval (extent);
- if (ex.length () > 0)
- {
- Stencil result = compound_barline (me, str, ex, false);
-
- return result.smobbed_copy ();
- }
- }
- return SCM_EOL;
+ return me->internal_has_interface (ly_symbol2scm ("bar-line-interface"))
+ && !me->extent (me, X_AXIS).is_empty ();
}
-
-Stencil
-Bar_line::compound_barline (Grob *me, string str, Interval const &extent,
- bool rounded)
-{
- Real kern = robust_scm2double (me->get_property ("kern"), 1);
- Real thinkern = robust_scm2double (me->get_property ("thin-kern"), 1);
- Real hair = robust_scm2double (me->get_property ("hair-thickness"), 1);
- Real fatline = robust_scm2double (me->get_property ("thick-thickness"), 1);
-
- Real staffline = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
- Real staff_space = Staff_symbol_referencer::staff_space (me);
-
- kern *= staffline;
- thinkern *= staffline;
- hair *= staffline;
- fatline *= staffline;
-
- Stencil thin = simple_barline (me, hair, extent, rounded);
- Stencil thick = simple_barline (me, fatline, extent, rounded);
- Stencil dot = Font_interface::get_default_font (me)->find_by_name ("dots.dot");
-
- int lines = Staff_symbol_referencer::line_count (me);
- Real dist
- = ((lines & 1 || lines == 0)
- ? 1
- : (staff_space < 2 ? 2 : .5)) * staff_space;
- Stencil colon (dot);
- colon.translate_axis (dist, Y_AXIS);
- colon.add_stencil (dot);
- colon.translate_axis (-dist / 2, Y_AXIS);
-
- Real const h = extent.length ();
- Stencil m;
-
- if (str == "||:")
- str = "|:";
-
- if (str == "|S" || str == "S|")
- str = "S";
-
- if (str == "")
- {
- Stencil empty = Lookup::blank (Box (Interval (0, 0), extent));
- return empty;
- }
- else if (str == "|")
- return thin;
- else if (str == ".")
- return thick;
- else if (str == "|." || (h == 0 && str == ":|"))
- {
- m.add_at_edge (X_AXIS, LEFT, thick, 0);
- m.add_at_edge (X_AXIS, LEFT, thin, kern);
- }
- else if (str == ".|" || (h == 0 && str == "|:"))
- {
- m.add_at_edge (X_AXIS, RIGHT, thick, 0);
- m.add_at_edge (X_AXIS, RIGHT, thin, kern);
- }
- else if (str == ":|")
- {
- m.add_at_edge (X_AXIS, LEFT, thick, 0);
- m.add_at_edge (X_AXIS, LEFT, thin, kern);
- m.add_at_edge (X_AXIS, LEFT, colon, kern);
- }
- else if (str == "|:")
- {
- m.add_at_edge (X_AXIS, RIGHT, thick, 0);
- m.add_at_edge (X_AXIS, RIGHT, thin, kern);
- m.add_at_edge (X_AXIS, RIGHT, colon, kern);
- }
- else if (str == ":|:")
- {
- m.add_at_edge (X_AXIS, LEFT, thick, thinkern);
- m.add_at_edge (X_AXIS, LEFT, colon, kern);
- m.add_at_edge (X_AXIS, RIGHT, thick, kern);
- m.add_at_edge (X_AXIS, RIGHT, colon, kern);
- }
- else if (str == ":|.|:")
- {
- m.add_at_edge (X_AXIS, LEFT, thick, 0);
- m.add_at_edge (X_AXIS, LEFT, thin, kern);
- m.add_at_edge (X_AXIS, LEFT, colon, kern);
- m.add_at_edge (X_AXIS, RIGHT, thin, kern);
- m.add_at_edge (X_AXIS, RIGHT, colon, kern);
- }
- else if (str == ":|.:")
- {
- m.add_at_edge (X_AXIS, LEFT, thick, 0);
- m.add_at_edge (X_AXIS, LEFT, thin, kern);
- m.add_at_edge (X_AXIS, LEFT, colon, kern);
- m.add_at_edge (X_AXIS, RIGHT, colon, kern);
- }
- else if (str == ".|.")
- {
- m.add_at_edge (X_AXIS, LEFT, thick, thinkern);
- m.add_at_edge (X_AXIS, RIGHT, thick, kern);
- }
- else if (str == "|.|")
- {
- m.add_at_edge (X_AXIS, LEFT, thick, 0);
- m.add_at_edge (X_AXIS, LEFT, thin, kern);
- m.add_at_edge (X_AXIS, RIGHT, thin, kern);
- }
- else if (str == "||")
- {
- /*
- should align to other side? this never appears
- on the system-start?
- m.add_at_edge (X_AXIS, RIGHT, thin, 0);
- m.add_at_edge (X_AXIS, RIGHT, thin, thinkern);
- */
- m.add_at_edge (X_AXIS, LEFT, thin, thinkern);
- m.add_at_edge (X_AXIS, RIGHT, thin, thinkern);
- }
- else if (str.find ("S") != NPOS || str == "|._.|")
- {
- // Handle all varsegno stuff
- Stencil segno;
- segno.add_at_edge (X_AXIS, LEFT, thin, thinkern);
- segno.add_at_edge (X_AXIS, RIGHT, thin, thinkern);
- segno.add_stencil (Font_interface::get_default_font (me)->find_by_name ("scripts.varsegno"));
-
- if (str == "S")
- m.add_stencil (segno);
- else if (str == "S|:" || str == ".S|:")
- {
- m.add_at_edge (X_AXIS, RIGHT, thick, 0);
- m.add_at_edge (X_AXIS, RIGHT, thin, kern);
- m.add_at_edge (X_AXIS, RIGHT, colon, kern);
- m.add_at_edge (X_AXIS, LEFT, segno, thinkern);
- }
- else if (str == ":|S" || str == ":|S.")
- {
- m.add_at_edge (X_AXIS, LEFT, thick, 0);
- m.add_at_edge (X_AXIS, LEFT, thin, kern);
- m.add_at_edge (X_AXIS, LEFT, colon, kern);
- m.add_at_edge (X_AXIS, RIGHT, segno, thinkern);
- }
- else if (str == ":|S|:" || str == ":|S.|:")
- {
- m.add_at_edge (X_AXIS, LEFT, thick, 0);
- m.add_at_edge (X_AXIS, LEFT, thin, kern);
- m.add_at_edge (X_AXIS, LEFT, colon, kern);
- m.add_at_edge (X_AXIS, RIGHT, segno, thinkern);
- m.add_at_edge (X_AXIS, RIGHT, thick, thinkern);
- m.add_at_edge (X_AXIS, RIGHT, thin, kern);
- m.add_at_edge (X_AXIS, RIGHT, colon, kern);
- }
- else if (str == "|._.|") // :|S|: or :|S.|: without segno and colon
- {
- // get the width of the segno sign
- Real segno_width = segno.extent (X_AXIS).length ();
- m.add_at_edge (X_AXIS, LEFT, thick, 0);
- m.add_at_edge (X_AXIS, LEFT, thin, kern);
- m.add_at_edge (X_AXIS, RIGHT, thick, segno_width + 2 * thinkern);
- m.add_at_edge (X_AXIS, RIGHT, thin, kern);
- }
- // end varsegno block
- }
- else if (str == ":")
- {
- if (Grob *staff = Staff_symbol_referencer::get_staff_symbol (me))
- {
- Interval staff_extent = staff->extent (staff, Y_AXIS);
-
- /*
- assume staff lines are disposed equally at unit space;
- put a dot into each space within extent (may extend staff_extent).
-
- staff_extent is an interval of two integers or two half-integers;
- in the former case dots are to be placed at half-integers,
- in the latter at integers.
-
- these integers are not exact due to staff line thickness.
- */
- int const pos = int (rint (staff_extent.at (UP) * 2));
- Real const correction = pos & 1 ? 0.0 : 0.5;
-
- for (int i = int (rint (extent.at (DOWN) + (0.5 - correction))),
- e = int (rint (extent.at (UP) + (0.5 - correction)));
- i < e;
- ++i)
- {
- Stencil d (dot);
-
- d.translate_axis (i + correction, Y_AXIS);
- m.add_stencil (d);
- }
- }
- }
- else if (str == "dashed")
- m = dashed_bar_line (me, extent, hair);
- else if (str == "'")
- m = tick_bar_line (me, extent.at (UP), rounded);
- else if (str == "kievan")
- {
- me->set_property ("layer", scm_from_int (1));
- m.add_stencil (Font_interface::get_default_font (me)->find_by_name ("scripts.barline.kievan"));
- m = *unsmob_stencil (scm_call_1 (ly_lily_module_constant ("stencil-whiteout"), m.smobbed_copy ()));
- }
- return m;
-}
-
-Stencil
-Bar_line::simple_barline (Grob *me,
- Real w,
- Interval const &extent,
- bool rounded)
-{
- Real blot
- = rounded
- ? me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter"))
- : 0.0;
-
- return Lookup::round_filled_box (Box (Interval (0, w), extent), blot);
-}
-
-Stencil
-Bar_line::tick_bar_line (Grob *me, Real h, bool rounded)
-{
- Real th = Staff_symbol_referencer::staff_space (me) / 2;
- Real line_thick = Staff_symbol_referencer::line_thickness (me);
-
- Real blot
- = rounded
- ? me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter"))
- : 0.0;
-
- return Lookup::round_filled_box (Box (Interval (0, line_thick),
- Interval (h - th, h + th)), blot);
-}
-
-Stencil
-Bar_line::dashed_bar_line (Grob *me, Interval const &extent, Real thick)
-{
- Real dash_size
- = 1.0 - robust_scm2double (me->get_property ("gap"), 0.3);
- /*
- this is a tad complex for what we want to achieve, but with a
- simple line, the round blotting interferes with staff line
- connections.
- */
- Real ss = Staff_symbol_referencer::staff_space (me);
- Real const h = extent.length ();
- int dashes = int (rint (h / ss));
-
- /*
- there are two concerns:
- 1. one dash plus one space should be one staff space
- 2. the line should begin and end with half a dash
-
- both can be satisfied, if the extent is (roughly) an integer
- multiple of staff space.
- */
- if (fabs (h / ss - dashes) < 0.1)
- {
- Real blot
- = me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter"));
-
- Real const half_dash = dash_size / 2;
- Stencil bar;
-
- for (int i = 0; i <= dashes; ++i)
- {
- Real top_y = extent.at (DOWN)
- + (i == dashes ? h : (i + half_dash) * ss);
- Real bot_y = extent.at (DOWN) + (i ? (i - half_dash) * ss : 0.0);
-
- bar.add_stencil (Lookup::round_filled_box (Box (Interval (0, thick),
- Interval (bot_y, top_y)),
- blot));
- }
- return bar;
- }
- else
- {
- /*
- We have to scale the dashing so it starts and ends with half a
- dash exactly.
- */
- Real total_dash_size = h / dashes;
- Real factor = (dash_size - thick) / ss;
-
- SCM at = scm_list_n (ly_symbol2scm ("dashed-line"),
- scm_from_double (thick),
- scm_from_double (factor * total_dash_size),
- scm_from_double ((1 - factor) * total_dash_size),
- scm_from_double (0),
- scm_from_double (h),
- scm_from_double (factor * total_dash_size * 0.5),
- SCM_UNDEFINED);
-
- Box box;
- box.add_point (Offset (0, 0));
- box.add_point (Offset (0, h));
-
- Stencil s (box, at);
- s.translate (Offset (thick / 2, extent.at (DOWN)));
- return s;
- }
- return Stencil ();
-}
-
-MAKE_SCHEME_CALLBACK (Bar_line, calc_anchor, 1)
-SCM
-Bar_line::calc_anchor (SCM smob)
-{
- Grob *me = unsmob_grob (smob);
- Real kern = robust_scm2double (me->get_property ("kern"), 1);
- Real staffline = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
- string str = robust_scm2string (me->get_property ("glyph-name"), "");
-
- /* we put the anchor in the center of the barline, unless we are
- a repeat bar, in which case we put the anchor in the center of
- the barline without the dots. */
- Interval ext = me->extent (me, X_AXIS);
- if (ext.is_empty ())
- return scm_from_double (0);
-
- Real anchor = ext.center ();
-
- Stencil dot = Font_interface::get_default_font (me)->find_by_name ("dots.dot");
- Real dot_width = dot.extent (X_AXIS).length () + kern * staffline;
- if (str == "|:")
- anchor -= dot_width / 2;
- else if (str == ":|")
- anchor += dot_width / 2;
-
- return scm_from_double (anchor);
-}
-
-ADD_INTERFACE (Bar_line,
- "Bar line.\n"
- "\n"
- "Print a special bar symbol. It replaces the regular bar"
- " symbol with a special symbol. The argument @var{bartype}"
- " is a string which specifies the kind of bar line to print."
- " Options are @code{|}, @code{:|}, @code{|:}, @code{:|:}, @code{:|.|:},"
- " @code{:|.:}, @code{.}, @code{||}, @code{|.}, @code{.|}, @code{.|.},"
- " @code{|.|}, @code{:}, @code{dashed}, @code{'} and @code{S}.\n"
- "\n"
- "These produce, respectively, a normal bar line, a right repeat, a left repeat,"
- " a thick double repeat, a thin-thick-thin double repeat,"
- " a thin-thick double repeat, a thick bar, a double bar, a start bar,"
- " an end bar, a thick double bar, a thin-thick-thin bar,"
- " a dotted bar, a dashed bar, a tick as bar line and a segno bar.\n"
- "\n"
- "In addition, there is an option"
- " @code{||:} which is equivalent to @code{|:} except at line"
- " breaks, where it produces a double bar (@code{||}) at the"
- " end of the line and a repeat sign (@code{|:}) at the"
- " beginning of the new line.\n"
- "\n"
- "For segno, @code{S} produces a segno sign except at line breaks,"
- " where it produces a double bar (@code{||}) at the"
- " end of the line and a segno sign at the beginning of the new line."
- " @code{|S} is equivalent to @code{S} but produces a simple bar line"
- " (@code{|}) instead of a double bar line (@code{||}) at line breaks."
- " @code{S|} produces the segno sign at line breaks and starts the following"
- " line without special bar lines.\n"
- "\n"
- "@code{S|:} and @code{:|S} are used for repeat/segno combinations that are"
- " separated at line breaks. Alternatively, @code{.S|:} and @code{:|S.}"
- " may be used which combine repeat signs and segno at the same line in"
- " case of a line break. @code{:|S|:} is a combination of a left repeat"
- " (@code{:|}), a segno (@code{S}) and a right repeat @code{|:} which"
- " splits before the segno at line breaks; @code{:|S.|:} splits after"
- " the segno sign.\n"
- "\n"
- "If @var{bartype} is set to @code{empty} then nothing is"
- " printed, but a line break is allowed at that spot.\n"
- "\n"
- "@code{gap} is used for the gaps in dashed bar lines.",
-
- /* properties */
- "allow-span-bar "
- "gap "
- "kern "
- "thin-kern "
- "hair-thickness "
- "has-span-bar "
- "thick-thickness "
- "glyph "
- "glyph-name "
- "bar-extent "
- );
#include "item.hh"
#include "context.hh"
-#include "bar-line.hh"
#include "staff-symbol-referencer.hh"
#include "engraver.hh"
#include "direction.hh"
#include "item.hh"
#include "context.hh"
-#include "bar-line.hh"
#include "staff-symbol-referencer.hh"
#include "engraver.hh"
#include "direction.hh"
*/
#include "engraver.hh"
-#include "bar-line.hh"
#include "item.hh"
#include "note-head.hh"
#include "pitch.hh"
chain_callback (gr, proc, sym);
return SCM_UNSPECIFIED;
}
+
+LY_DEFINE (ly_grob_vertical_less_p, "ly:grob-vertical<?",
+ 2, 0, 0, (SCM a, SCM b),
+ "Does @var{a} lie above @var{b} on the page?")
+{
+ LY_ASSERT_SMOB (Grob, a, 1);
+ LY_ASSERT_SMOB (Grob, b, 2);
+
+ Grob *ga = unsmob_grob (a);
+ Grob *gb = unsmob_grob (b);
+
+ return ly_bool2scm (Grob::vertical_less (ga, gb));
+}
#include "hairpin.hh"
#include "axis-group-interface.hh"
-#include "bar-line.hh"
#include "dimensions.hh"
#include "directional-element-interface.hh"
#include "international.hh"
{
extract_grob_set (vertical_axis_groups[d], "elements", elts);
for (vsize i = elts.size (); i--;)
- if (Bar_line::has_interface (elts[i])
+ if (elts[i]->internal_has_interface (ly_symbol2scm ("bar-line-interface"))
&& dynamic_cast<Item *> (elts[i])->break_status_dir () == -1)
{
SCM hsb = elts[i]->get_property ("has-span-bar");
span_bars[d] = unsmob_grob ((d == UP ? scm_car : scm_cdr) (hsb));
break;
}
+
if (!span_bars[d])
return scm_from_double (0.0);
}
public:
DECLARE_GROB_INTERFACE ();
- static Stencil dashed_bar_line (Grob *me, Interval const &extent, Real thick);
- static Stencil tick_bar_line (Grob *me, Real h, bool rounded);
- static Stencil compound_barline (Grob *, string, Interval const &extent,
- bool rounded);
- static Stencil simple_barline (Grob *, Real wid, Interval const &extent,
- bool rounded);
- static Interval bar_y_extent (Grob *, Grob *);
static bool non_empty_barline (Grob *me);
-
- DECLARE_SCHEME_CALLBACK (calc_bar_extent, (SCM));
- DECLARE_SCHEME_CALLBACK (print, (SCM));
- DECLARE_SCHEME_CALLBACK (calc_anchor, (SCM));
};
#endif // BAR_LINE_HH
+++ /dev/null
-/*
- This file is part of LilyPond, the GNU music typesetter.
-
- Copyright (C) 1997--2012 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
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- LilyPond 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef SPAN_BAR_HH
-#define SPAN_BAR_HH
-
-#include "lily-proto.hh"
-#include "grob-interface.hh"
-
-/**
- This is a barline that is spanned across other bar lines. This is
- the implementation of the long barlines that occur in orchestral
- score and other multi-staff music.
-*/
-class Span_bar
-{
-public:
-
- DECLARE_GROB_INTERFACE ();
- static Interval get_spanned_interval (Grob *);
- static void add_bar (Grob *, Grob *);
- static void evaluate_glyph (Grob *);
- static void notify_grobs_of_my_existence (Grob *);
- DECLARE_SCHEME_CALLBACK (width, (SCM smob));
- DECLARE_SCHEME_CALLBACK (print, (SCM));
- DECLARE_SCHEME_CALLBACK (calc_glyph_name, (SCM));
- DECLARE_SCHEME_CALLBACK (before_line_breaking, (SCM));
- DECLARE_SCHEME_CALLBACK (center_on_spanned_callback, (SCM element));
-};
-
-#endif // SPAN_BAR_HH
along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "bar-line.hh"
#include "clef.hh"
#include "context.hh"
#include "engraver.hh"
#include "engraver.hh"
#include "axis-group-interface.hh"
-#include "bar-line.hh"
#include "context.hh"
#include "grob-array.hh"
#include "international.hh"
along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "bar-line.hh"
#include "item.hh"
-#include "span-bar.hh"
#include "engraver.hh"
+#include "pointer-group-interface.hh"
/**
Span_bar_engraver::acknowledge_bar_line (Grob_info i)
{
int depth = i.origin_contexts (this).size ();
- if (depth && !Span_bar::has_interface (i.grob ()))
+ if (depth && !i.grob ()->internal_has_interface (ly_symbol2scm ("span-bar-interface")))
{
Item *it = dynamic_cast<Item *> (i.grob ());
bars_.push_back (it);
spanbar_->set_parent (bars_[0], X_AXIS);
for (vsize i = 0; i < bars_.size (); i++)
- Span_bar::add_bar (spanbar_, bars_[i]);
+ Pointer_group_interface::add_grob (spanbar_, ly_symbol2scm ("elements"), bars_[i]);
make_spanbar_ = false;
}
}
SCM vis = bars_[0]->internal_get_property (vissym);
if (ly_is_equal (spanbar_->internal_get_property (vissym), vis))
spanbar_->set_property (vissym, vis);
- Span_bar::notify_grobs_of_my_existence (spanbar_);
+ scm_call_1 (ly_lily_module_constant ("span-bar::notify-grobs-of-my-existence"), spanbar_->self_scm ());
spanbar_ = 0;
}
bars_.resize (0);
#include <algorithm>
#include "align-interface.hh"
-#include "bar-line.hh"
#include "context.hh"
#include "grob.hh"
#include "item.hh"
#include "pointer-group-interface.hh"
-#include "span-bar.hh"
#include "engraver.hh"
/*
+++ /dev/null
-/*
- This file is part of LilyPond, the GNU music typesetter.
-
- Copyright (C) 1997--2012 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
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- LilyPond 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "span-bar.hh"
-
-#include "font-interface.hh"
-#include "dimensions.hh"
-#include "output-def.hh"
-#include "stencil.hh"
-#include "warn.hh"
-#include "axis-group-interface.hh"
-#include "bar-line.hh"
-#include "grob.hh"
-#include "pointer-group-interface.hh"
-#include "staff-symbol-referencer.hh"
-
-void
-Span_bar::add_bar (Grob *me, Grob *b)
-{
- Pointer_group_interface::add_grob (me, ly_symbol2scm ("elements"), b);
-}
-
-MAKE_SCHEME_CALLBACK (Span_bar, print, 1);
-
-/* Limitations/Bugs:
-
-(1) Elements from 'me->get_object ("elements")' must be
-ordered according to their y coordinates relative to their common
-axis group parent. Otherwise, the computation goes mad.
-
-(2) This method depends on bar_engraver not being removed from
-staff context. If bar_engraver is removed, the size of the staff
-lines is evaluated as 0, which results in a solid span bar line
-with faulty y coordinate. */
-
-/* This routine was originally by Juergen Reuter, but it was a on the
- bulky side. Rewritten by Han-Wen. */
-SCM
-Span_bar::print (SCM smobbed_me)
-{
- Grob *me = unsmob_grob (smobbed_me);
- extract_grob_set (me, "elements", elements);
- Grob *refp = common_refpoint_of_array (elements, me, Y_AXIS);
-
- SCM glyph = me->get_property ("glyph-name");
-
- /* glyph may not be a string, when ME is killed by Hara Kiri in
- between. */
- if (!scm_is_string (glyph))
- return SCM_EOL;
-
- string glyph_string = ly_scm2string (glyph);
-
- /* compose span_bar_mol */
- vector<Interval> extents;
- vector<bool> make_span_bar;
- Grob *model_bar = 0;
- for (vsize i = elements.size (); i--;)
- {
- Grob *bar = elements[i];
- Interval ext = Bar_line::bar_y_extent (bar, refp);
- if (Grob *staff = Staff_symbol_referencer::get_staff_symbol (bar))
- ext.unite (staff->extent (refp, Y_AXIS));
- if (ext.is_empty ())
- continue;
-
- extents.push_back (ext);
- make_span_bar.push_back (to_boolean (bar->get_property ("allow-span-bar")));
- model_bar = bar;
- }
-
- if (!model_bar)
- model_bar = me;
-
- // Fixes problem with disappearing span bars when alignAboveContext is active
- vector_sort (extents, Interval::left_less);
-
- Stencil span_bar;
- for (vsize i = 1; i < extents.size (); i++)
- {
- Interval prev_extent = extents[i - 1];
- Interval ext = extents[i];
- if (!prev_extent.is_empty ())
- {
- Interval l (prev_extent [UP],
- ext[DOWN]);
-
- if (l.is_empty () || !make_span_bar[i])
- {
- /* There is overlap between the bar lines. Do nothing. */
- }
- else
- {
- Stencil interbar = Bar_line::compound_barline (model_bar,
- glyph_string,
- l,
- false);
- span_bar.add_stencil (interbar);
- }
- }
- prev_extent = ext;
- }
-
- span_bar.translate_axis (- me->relative_coordinate (refp, Y_AXIS),
- Y_AXIS);
-
- return span_bar.smobbed_copy ();
-}
-
-MAKE_SCHEME_CALLBACK (Span_bar, width, 1);
-SCM
-Span_bar::width (SCM smob)
-{
- Grob *me = unsmob_grob (smob);
- SCM gn = me->get_property ("glyph-name");
- if (!me->is_live ())
- return ly_interval2scm (Interval ());
-
- string gl = ly_scm2string (gn);
-
- /*
- urg.
- */
- Stencil m
- = Bar_line::compound_barline (me, gl, Interval (-20 PT, 20 PT), false);
-
- return ly_interval2scm (m.extent (X_AXIS));
-}
-
-MAKE_SCHEME_CALLBACK (Span_bar, before_line_breaking, 1);
-SCM
-Span_bar::before_line_breaking (SCM smob)
-{
- Grob *me = unsmob_grob (smob);
- extract_grob_set (me, "elements", elements);
- if (elements.empty ())
- me->suicide ();
-
- return SCM_UNSPECIFIED;
-}
-
-MAKE_SCHEME_CALLBACK (Span_bar, center_on_spanned_callback, 1);
-
-SCM
-Span_bar::center_on_spanned_callback (SCM smob)
-{
- Grob *me = unsmob_grob (smob);
- Interval i (get_spanned_interval (me));
-
- /* Bar_line::print delivers a barline of y-extent (-h/2, h/2), so
- we have to translate ourselves to be in the center of the
- interval that we span. */
- if (i.is_empty ())
- {
- me->suicide ();
- return scm_from_double (0.0);
- }
-
- return scm_from_double (i.center ());
-}
-
-MAKE_SCHEME_CALLBACK (Span_bar, calc_glyph_name, 1);
-SCM
-Span_bar::calc_glyph_name (SCM smob)
-{
- Grob *me = unsmob_grob (smob);
- extract_grob_set (me, "elements", elements);
- SCM gl = SCM_EOL;
- for (vsize i = elements.size ();
- i-- && !scm_is_string (gl);)
- gl = elements[i]->get_property ("glyph-name");
-
- if (!scm_is_string (gl))
- {
- me->suicide ();
- return SCM_UNSPECIFIED;
- }
-
- string type = ly_scm2string (gl);
- if (type == "|:" || type == "||:")
- type = ".|";
- else if (type == ":|")
- type = "|.";
- else if (type == ":|:")
- type = ".|.";
- else if (type == ":|.|:")
- type = "|.|";
- else if (type == ":|.:")
- type = "|.";
- else if (type == "S" || type == "S|" || type == "|S")
- type = "||";
- else if (type == "S|:" || type == ".S|:")
- type = ".|";
- else if (type == ":|S" || type == ":|S.")
- type = "|.";
- else if (type == ":|S|:" || type == ":|S.|:")
- type = "|._.|";
- else if (type == "'")
- type = "";
-
- return ly_string2scm (type);
-}
-
-void
-Span_bar::notify_grobs_of_my_existence (Grob *me)
-{
- extract_grob_set (me, "elements", elts);
- vector<Grob *> sortable (elts.begin (), elts.end ());
- vector_sort (sortable, Grob::vertical_less);
- for (vsize i = 0; i < sortable.size (); i++)
- sortable[i]->set_property ("has-span-bar",
- scm_cons (i != sortable.size () - 1 ? me->self_scm () : scm_from_bool (false),
- i != 0 ? me->self_scm () : scm_from_bool (false)));
-}
-
-Interval
-Span_bar::get_spanned_interval (Grob *me)
-{
- return ly_scm2interval (Axis_group_interface::generic_group_extent (me, Y_AXIS));
-}
-
-ADD_INTERFACE (Span_bar,
- "A bar line that is spanned between other barlines. This"
- " interface is used for bar lines that connect different"
- " staves.",
-
- /* properties */
- "glyph-name "
- "elements "
- "pure-Y-common "
- "pure-relevant-grobs "
- "pure-relevant-items "
- "pure-relevant-spanners "
- );
-
#include "paper-column.hh"
#include "separation-item.hh"
#include "warn.hh"
-#include "bar-line.hh"
#include "staff-symbol-referencer.hh"
#include "note-column.hh"
#include "stem.hh"
{
Interval bar_size;
bar_size.set_empty ();
- if (Bar_line::has_interface (bar_grob))
+
+ if (bar_grob->internal_has_interface (ly_symbol2scm ("bar-line-interface")))
{
SCM glyph = bar_grob->get_property ("glyph-name");
Grob *staff_sym = Staff_symbol_referencer::get_staff_symbol (bar_grob);
#include "context.hh"
#include "paper-column.hh"
#include "align-interface.hh"
-#include "span-bar.hh"
#include "axis-group-interface.hh"
#include "engraver.hh"
#include "spanner.hh"
#include "engraver.hh"
#include "axis-group-interface.hh"
-#include "bar-line.hh"
#include "context.hh"
#include "grob-array.hh"
#include "international.hh"
--- /dev/null
+;;;; This file is part of LilyPond, the GNU music typesetter.
+;;;;
+;;;; Copyright (C) 2009--2012 Marc Hohl <marc@hohlart.de>
+;;;;
+;;;; LilyPond is free software: you can redistribute it and/or modify
+;;;; it under the terms of the GNU General Public License as published by
+;;;; the Free Software Foundation, either version 3 of the License, or
+;;;; (at your option) any later version.
+;;;;
+;;;; LilyPond 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 General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU General Public License
+;;;; along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
+
+;; helper functions
+
+(define (get-staff-symbol grob)
+ (if (grob::has-interface grob 'staff-symbol-interface)
+ grob
+ (ly:grob-object grob 'staff-symbol)))
+
+(define (layout-blot-diameter grob)
+ (let* ((layout (ly:grob-layout grob))
+ (blot (ly:output-def-lookup layout 'blot-diameter)))
+
+ blot))
+
+(define (layout-line-thickness grob)
+ (let* ((layout (ly:grob-layout grob))
+ (line-thickness (ly:output-def-lookup layout 'line-thickness)))
+
+ line-thickness))
+
+(define (staff-symbol-line-count grob)
+ (let ((line-count 0))
+
+ (if (ly:grob? grob)
+ (let ((line-pos (ly:grob-property grob 'line-positions '())))
+
+ (set! line-count (if (pair? line-pos)
+ (length line-pos)
+ (ly:grob-property grob 'line-count 0)))))
+
+ line-count))
+
+(define (staff-symbol-line-span grob)
+ (let ((line-pos (ly:grob-property grob 'line-positions '()))
+ (iv (cons 0.0 0.0)))
+
+ (if (pair? line-pos)
+ (map (lambda (x)
+ (set! iv (cons (min (car iv) x)
+ (max (cdr iv) x))))
+ line-pos)
+ (let ((line-count (ly:grob-property grob 'line-count 0)))
+
+ (set! iv (cons (- 1 line-count)
+ (- line-count 1)))))
+ iv))
+
+(define (staff-symbol-line-positions grob)
+ (let ((line-pos (ly:grob-property grob 'line-positions '())))
+
+ (if (not (pair? line-pos))
+ (let* ((line-count (ly:grob-property grob 'line-count 0))
+ (height (- line-count 1.0)))
+
+ (set! line-pos (map (lambda (x)
+ (- height (* x 2)))
+ (iota line-count)))))
+ line-pos))
+
+;; functions used by external routines
+
+(define-public (span-bar::notify-grobs-of-my-existence grob)
+ (let* ((elts (ly:grob-array->list (ly:grob-object grob 'elements)))
+ (sorted-elts (sort elts ly:grob-vertical<?))
+ (last-pos (1- (length sorted-elts)))
+ (idx 0))
+
+ (map (lambda (g)
+ (ly:grob-set-property!
+ g
+ 'has-span-bar
+ (cons (if (eq? idx last-pos)
+ #f
+ grob)
+ (if (zero? idx)
+ #f
+ grob)))
+ (set! idx (1+ idx)))
+ sorted-elts)))
+
+;; How should a bar line behave at a break?
+;; the following alist has the form
+;; ( unbroken-bar-glyph . ( bar-glyph-at-end-of-line . bar-glyph-at-begin-of-line ))
+
+(define bar-glyph-alist
+ '((":|:" . (":|" . "|:"))
+ (":|.|:" . (":|" . "|:"))
+ (":|.:" . (":|" . "|:"))
+ ("||:" . ("||" . "|:"))
+ ("dashed" . ("dashed" . '()))
+ ("|" . ("|" . ()))
+ ("|s" . (() . "|"))
+ ("|:" . ("|" . "|:"))
+ ("|." . ("|." . ()))
+
+ ;; hmm... should we end with a bar line here?
+ (".|" . ("|" . ".|"))
+ (":|" . (":|" . ()))
+ ("||" . ("||" . ()))
+ (".|." . (".|." . ()))
+ ("|.|" . ("|.|" . ()))
+ ("" . ("" . ""))
+ (":" . (":" . ""))
+ ("." . ("." . ()))
+ ("'" . ("'" . ()))
+ ("empty" . (() . ()))
+ ("brace" . (() . "brace"))
+ ("bracket" . (() . "bracket"))
+
+ ;; segno bar lines
+ ("S" . ("||" . "S"))
+ ("|S" . ("|" . "S"))
+ ("S|" . ("S" . ()))
+ (":|S" . (":|" . "S"))
+ (":|S." . (":|S" . ()))
+ ("S|:" . ("S" . "|:"))
+ (".S|:" . ("|" . "S|:"))
+ (":|S|:" . (":|" . "S|:"))
+ (":|S.|:" . (":|S" . "|:"))
+
+ ;; ancient bar lines
+ ("kievan" . ("kievan" . ""))))
+
+;; drawing functions for various bar line types
+
+(define (make-empty-bar-line grob extent)
+ (ly:make-stencil "" (cons 0 0) extent))
+
+(define (make-simple-bar-line grob width extent rounded)
+ (let ((blot (if rounded
+ (layout-blot-diameter grob)
+ 0)))
+
+ (ly:round-filled-box (cons 0 width)
+ extent
+ blot)))
+
+(define (make-tick-bar-line grob height rounded)
+ (let ((half-staff (* 1/2 (ly:staff-symbol-staff-space grob)))
+ (staff-line-thickness (ly:staff-symbol-line-thickness grob))
+ (blot (if rounded
+ (layout-blot-diameter grob)
+ 0)))
+
+ (ly:round-filled-box (cons 0 staff-line-thickness)
+ (cons (- height half-staff) (+ height half-staff))
+ blot)))
+
+(define (make-colon-bar-line grob)
+ (let* ((staff-space (ly:staff-symbol-staff-space grob))
+ (dot (ly:font-get-glyph (ly:grob-default-font grob) "dots.dot"))
+ (staff-symbol (get-staff-symbol grob))
+ (lines (staff-symbol-line-count staff-symbol))
+ (stencil empty-stencil)
+ (dist (* (if (or (odd? lines)
+ (zero? lines))
+ 1
+ (if (< staff-space 2)
+ 2
+ 0.5))
+ staff-space)))
+
+ (if (zero? staff-space)
+ (set! staff-space 1.0))
+
+ (let* ((stencil (ly:stencil-add stencil dot))
+ (stencil (ly:stencil-translate-axis
+ stencil dist Y))
+ (stencil (ly:stencil-add stencil dot))
+ (stencil (ly:stencil-translate-axis
+ stencil (/ dist -2) Y)))
+ stencil)))
+
+(define (make-dotted-bar-line grob extent)
+ (let* ((position (round (* (interval-end extent) 2)))
+ (correction (if (even? position) 0.5 0.0))
+ (dot (ly:font-get-glyph (ly:grob-default-font grob) "dots.dot"))
+ (i (round (+ (interval-start extent)
+ (- 0.5 correction))))
+ (e (round (+ (interval-end extent)
+ (- 0.5 correction))))
+ (counting (interval-length (cons i e)))
+ (stil-list (map
+ (lambda (x)
+ (ly:stencil-translate-axis
+ dot (+ x correction) Y))
+ (iota counting i 1))))
+
+ (define (add-stencils! stil l)
+ (if (null? l)
+ stil
+ (if (null? (cdr l))
+ (ly:stencil-add stil (car l))
+ (add-stencils! (ly:stencil-add stil (car l)) (cdr l)))))
+
+ (add-stencils! empty-stencil stil-list)))
+
+(define (make-dashed-bar-line grob extent thickness)
+ (let* ((height (interval-length extent))
+ (staff-symbol (get-staff-symbol grob))
+ (staff-space (ly:staff-symbol-staff-space grob))
+ (line-thickness (layout-line-thickness grob))
+ (dash-size (- 1.0 (ly:grob-property grob 'gap 0.3)))
+ (line-count (staff-symbol-line-count staff-symbol)))
+
+ (if (< (abs (+ line-thickness
+ (* (1- line-count) staff-space)
+ (- height)))
+ 0.1)
+ (let ((blot (layout-blot-diameter grob))
+ (half-space (/ staff-space 2.0))
+ (half-thick (/ line-thickness 2.0))
+ (stencil empty-stencil))
+
+ (map (lambda (i)
+ (let ((top-y (min (* (+ i dash-size) half-space)
+ (+ (* (1- line-count) half-space)
+ half-thick)))
+ (bot-y (max (* (- i dash-size) half-space)
+ (- 0 (* (1- line-count) half-space)
+ half-thick))))
+
+ (set! stencil
+ (ly:stencil-add
+ stencil
+ (ly:round-filled-box (cons 0 thickness)
+ (cons bot-y top-y)
+ blot)))))
+ (iota line-count (1- line-count) (- 2)))
+ stencil)
+ (let* ((dashes (/ height staff-space))
+ (total-dash-size (/ height dashes))
+ (factor (/ (- dash-size thickness) staff-space)))
+
+ (ly:stencil-translate-axis
+ (ly:make-stencil (list 'dashed-line
+ thickness
+ (* factor total-dash-size)
+ (* (- 1 factor) total-dash-size)
+ 0
+ height
+ (* factor total-dash-size 0.5))
+ (cons 0 thickness)
+ (cons 0 height))
+ (interval-start extent)
+ Y)))))
+
+(define (make-segno-bar-line grob glyph extent rounded)
+ (let* ((line-thickness (layout-line-thickness grob))
+ (kern (* (ly:grob-property grob 'kern 1) line-thickness))
+ (thinkern (* (ly:grob-property grob 'thin-kern 1) line-thickness))
+ (hair (* (ly:grob-property grob 'hair-thickness 1) line-thickness))
+ (fatline (* (ly:grob-property grob 'thick-thickness 1) line-thickness))
+ (thin-stil (make-simple-bar-line grob hair extent rounded))
+ (thick-stil (make-simple-bar-line grob fatline extent rounded))
+ (colon-stil (make-colon-bar-line grob))
+ (segno-stil (ly:stencil-add
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ '() X LEFT thin-stil thinkern)
+ X RIGHT thin-stil thinkern)
+ (ly:font-get-glyph (ly:grob-default-font grob) "scripts.varsegno")))
+ (glyph (cond
+ ((string=? glyph "|S") "S")
+ ((string=? glyph "S|") "S")
+ (else glyph)))
+ (stencil (cond
+ ((or (string=? glyph "S|:")
+ (string=? glyph ".S|:"))
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ thick-stil X RIGHT thin-stil kern)
+ X RIGHT colon-stil kern)
+ X LEFT segno-stil thinkern))
+ ((or (string=? glyph ":|S")
+ (string=? glyph ":|S."))
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ thick-stil X LEFT thin-stil kern)
+ X LEFT colon-stil kern)
+ X RIGHT segno-stil thinkern))
+ ((or (string=? glyph ":|S|:")
+ (string=? glyph ":|S.|:"))
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ thick-stil X LEFT thin-stil kern)
+ X LEFT colon-stil kern)
+ X RIGHT segno-stil thinkern)
+ X RIGHT thick-stil thinkern)
+ X RIGHT thin-stil kern)
+ X RIGHT colon-stil kern))
+ ((string=? glyph "|._.|")
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ thick-stil X LEFT thin-stil kern)
+ X RIGHT thick-stil (+ (interval-length
+ (ly:stencil-extent segno-stil X))
+ (* 2 thinkern)))
+ X RIGHT thin-stil kern))
+ (else segno-stil))))
+
+ stencil))
+
+(define (make-kievan-bar-line grob)
+ (let* ((font (ly:grob-default-font grob))
+ (stencil (stencil-whiteout
+ (ly:font-get-glyph font "scripts.barline.kievan"))))
+
+ ;; the kievan bar line has mo staff lines underneath,
+ ;; so we whiteout them and move ithe grob to a higher layer
+ (ly:grob-set-property! grob 'layer 1)
+ stencil))
+
+;; bar line callbacks
+
+(define-public (ly:bar-line::calc-bar-extent grob)
+ (let ((staff-symbol (get-staff-symbol grob))
+ (staff-extent (cons 0 0)))
+
+ (if (ly:grob? staff-symbol)
+ (let* ((bar-line-color (ly:grob-property grob 'color))
+ (staff-color (ly:grob-property staff-symbol 'color))
+ (radius (ly:staff-symbol-staff-radius grob))
+ (staff-line-thickness (ly:staff-symbol-line-thickness grob)))
+
+ ;; Due to rounding problems, bar lines extending to the outermost edges
+ ;; of the staff lines appear wrongly in on-screen display
+ ;; (and, to a lesser extent, in print) - they stick out a pixel.
+ ;; The solution is to extend bar lines only to the middle
+ ;; of the staff line - unless they have different colors,
+ ;;when it would be undesirable.
+ (set! staff-extent (ly:staff-symbol::height staff-symbol))
+ (if (and (eq? bar-line-color staff-color)
+ radius)
+ (set! staff-extent
+ (interval-scale staff-extent
+ (- 1 (* 1/2 (/ staff-line-thickness radius))))))))
+ staff-extent))
+
+(define (bar-line::bar-y-extent grob refpoint)
+ (let* ((extent (ly:grob-property grob 'bar-extent '(0 . 0)))
+ (rel-y (ly:grob-relative-coordinate grob refpoint Y))
+ (y-extent (coord-translate extent rel-y)))
+
+ y-extent))
+
+(define-public (ly:bar-line::print grob)
+ (let ((glyph (ly:grob-property grob 'glyph-name))
+ (extent (ly:grob-property grob 'bar-extent '(0 . 0))))
+
+ (if (and (not (eq? glyph '()))
+ (> (interval-length extent) 0))
+ (bar-line::compound-bar-line grob glyph extent #f)
+ #f)))
+
+(define-public (bar-line::compound-bar-line grob glyph extent rounded)
+ (let* ((line-thickness (layout-line-thickness grob))
+ (height (interval-length extent))
+ (kern (* (ly:grob-property grob 'kern 1) line-thickness))
+ (thinkern (* (ly:grob-property grob 'thin-kern 1) line-thickness))
+ (hair (* (ly:grob-property grob 'hair-thickness 1) line-thickness))
+ (fatline (* (ly:grob-property grob 'thick-thickness 1) line-thickness))
+ (thin-stil (make-simple-bar-line grob hair extent rounded))
+ (thick-stil (make-simple-bar-line grob fatline extent rounded))
+ (colon-stil (make-colon-bar-line grob))
+ (glyph (cond
+ ((not glyph) "")
+ ((string=? glyph "||:") "|:")
+ ;; bar-line::compound-bar-line is called only if
+ ;; height > 0, but just in case ...
+ ((and (string=? glyph ":|")
+ (zero? height)) "|.")
+ ((and (string=? glyph "|:")
+ (zero? height)) ".|")
+ (else glyph)))
+ (stencil (cond
+ ((string=? glyph "|") thin-stil)
+ ((string=? glyph ".") thick-stil)
+ ((string=? glyph "||")
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ '() X LEFT thin-stil thinkern)
+ X RIGHT thin-stil thinkern))
+ ((string=? glyph "|.")
+ (ly:stencil-combine-at-edge
+ thick-stil X LEFT thin-stil kern))
+ ((string=? glyph ".|")
+ (ly:stencil-combine-at-edge
+ thick-stil X RIGHT thin-stil kern))
+ ((string=? glyph "|:")
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ thick-stil X RIGHT thin-stil kern)
+ X RIGHT colon-stil kern))
+ ((string=? glyph ":|")
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ thick-stil X LEFT thin-stil kern)
+ X LEFT colon-stil kern))
+ ((string=? glyph ":|:")
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ '() X LEFT thick-stil thinkern)
+ X LEFT colon-stil kern)
+ X RIGHT thick-stil kern)
+ X RIGHT colon-stil kern))
+ ((string=? glyph ":|.|:")
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ thick-stil X LEFT thin-stil kern)
+ X LEFT colon-stil kern)
+ X RIGHT thin-stil kern)
+ X RIGHT colon-stil kern))
+ ((string=? glyph ":|.:")
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ thick-stil X LEFT thin-stil kern)
+ X LEFT colon-stil kern)
+ X RIGHT colon-stil kern))
+ ((string=? glyph ".|.")
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ '() X LEFT thick-stil thinkern)
+ X RIGHT thick-stil kern))
+ ((string=? glyph "|.|")
+ (ly:stencil-combine-at-edge
+ (ly:stencil-combine-at-edge
+ thick-stil X LEFT thin-stil kern)
+ X RIGHT thin-stil kern))
+ ((string=? glyph ":")
+ (make-dotted-bar-line grob extent))
+ ((or (string=? glyph "|._.|")
+ (string-contains glyph "S"))
+ (make-segno-bar-line grob glyph extent rounded))
+ ((string=? glyph "'")
+ (make-tick-bar-line grob (interval-end extent) rounded))
+ ((string=? glyph "dashed")
+ (make-dashed-bar-line grob extent hair))
+ ((string=? glyph "kievan")
+ (make-kievan-bar-line grob))
+ (else (make-empty-bar-line grob extent)))))
+ stencil))
+
+(define-public (ly:bar-line::calc-anchor grob)
+ (let* ((line-thickness (layout-line-thickness grob))
+ (kern (* (ly:grob-property grob 'kern 1) line-thickness))
+ (glyph (ly:grob-property grob 'glyph-name ""))
+ (x-extent (ly:grob-extent grob grob X))
+ (dot-width (+ (interval-length
+ (ly:stencil-extent
+ (ly:font-get-glyph
+ (ly:grob-default-font grob)
+ "dots.dot")
+ X))
+ kern))
+ (anchor 0.0))
+
+ (if (> (interval-length x-extent) 0)
+ (begin
+ (set! anchor (interval-center x-extent))
+ (cond ((string=? glyph "|:")
+ (set! anchor (+ anchor (/ dot-width -2.0))))
+ ((string=? glyph ":|")
+ (set! anchor (+ anchor (/ dot-width 2.0)))))))
+ anchor))
+
+(define-public (bar-line::calc-glyph-name grob)
+ (let* ((glyph (ly:grob-property grob 'glyph))
+ (dir (ly:item-break-dir grob))
+ (result (assoc-get glyph bar-glyph-alist))
+ (glyph-name (if (= dir CENTER)
+ glyph
+ (if (and result
+ (string? (index-cell result dir)))
+ (index-cell result dir)
+ #f))))
+ glyph-name))
+
+(define-public (bar-line::calc-break-visibility grob)
+ (let* ((glyph (ly:grob-property grob 'glyph))
+ (result (assoc-get glyph bar-glyph-alist)))
+
+ (if result
+ (vector (string? (car result)) #t (string? (cdr result)))
+ all-invisible)))
+
+;; which span bar belongs to a bar line?
+
+(define-public span-bar-glyph-alist
+ '(("|:" . ".|")
+ ("||:" . ".|")
+ (":|" . "|.")
+ (":|.:" . "|.")
+ (":|:" . ".|.")
+ (":|.|:" . "|.|")
+ (":|.|" . "|.")
+ ("S" . "||" )
+ ("S|" . "||")
+ ("|S" . "||")
+ ("S|:" . ".|")
+ (".S|:" . ".|")
+ (":|S" . "|.")
+ (":|S." . "|.")
+ (":|S|:" . "|._.|")
+ (":|S.|:" . "|._.|")
+ ("kievan" . "")
+ ("'" . "")))
+
+;; span bar callbacks
+
+(define-public (ly:span-bar::calc-glyph-name grob)
+ (let* ((elts (ly:grob-object grob 'elements))
+ (pos (1- (ly:grob-array-length elts)))
+ (glyph '()))
+
+ (while (and (eq? glyph '())
+ (> pos -1))
+ (begin (set! glyph (ly:grob-property (ly:grob-array-ref elts pos)
+ 'glyph-name))
+ (set! pos (1- pos))))
+ (if (eq? glyph '())
+ (begin (ly:grob-suicide! grob)
+ (set! glyph "")))
+ (assoc-get glyph span-bar-glyph-alist glyph)))
+
+(define-public (ly:span-bar::width grob)
+ (let ((width (cons 0 0)))
+
+ (if (grob::is-live? grob)
+ (let* ((glyph (ly:grob-property grob 'glyph-name))
+ (stencil (bar-line::compound-bar-line grob glyph (cons -1 1) #f)))
+
+ (set! width (ly:stencil-extent stencil X))))
+ width))
+
+(define-public (ly:span-bar::before-line-breaking grob)
+ (let ((elts (ly:grob-object grob 'elements)))
+
+ (if (zero? (ly:grob-array-length elts))
+ (ly:grob-suicide! grob))))
+
+;; The method used in the following routine depends on bar_engraver
+;; not being removed from staff context. If bar_engraver is removed,
+;; the size of the staff lines is evaluated as 0, which results in a
+;; solid span bar line with faulty y coordinate.
+;;
+;; This routine was originally by Juergen Reuter, but it was a on the
+;; bulky side. Rewritten by Han-Wen. Ported from c++ to Scheme by Marc Hohl.
+(define-public (ly:span-bar::print grob)
+ (let* ((elts-array (ly:grob-object grob 'elements))
+ (refp (ly:grob-common-refpoint-of-array grob elts-array Y))
+ (elts (reverse (sort (ly:grob-array->list elts-array)
+ ly:grob-vertical<?)))
+ ;; Elements must be ordered according to their y coordinates
+ ;; relative to their common axis group parent.
+ ;; Otherwise, the computation goes mad.
+ (glyph (ly:grob-property grob 'glyph-name))
+ (span-bar empty-stencil))
+
+ (if (string? glyph)
+ (let* ((extents '())
+ (make-span-bars '())
+ (model-bar #f))
+
+ ;; we compute the extents of each system and store them
+ ;; in a list; dito for the 'allow-span-bar property.
+ ;; model-bar takes the bar grob, if given.
+ (map (lambda (bar)
+ (let* ((ext (bar-line::bar-y-extent bar refp))
+ (staff-symbol (ly:grob-object bar 'staff-symbol)))
+
+ (if (ly:grob? staff-symbol)
+ (let ((refp-extent (ly:grob-extent staff-symbol refp Y)))
+
+ (set! ext (interval-union ext refp-extent))
+
+ (if (> (interval-length ext) 0)
+ (begin
+ (set! extents (append extents (list ext)))
+ (set! model-bar bar)
+ (set! make-span-bars
+ (append make-span-bars
+ (list (ly:grob-property bar 'allow-span-bar #t))))))))))
+ elts)
+ ;; if there is no bar grob, we use the callback argument
+ (if (not model-bar)
+ (set! model-bar grob))
+ ;; we discard the first entry in make-span-bars, because its corresponding
+ ;; bar line is the uppermost and therefore not connected to another bar line
+ (if (pair? make-span-bars)
+ (set! make-span-bars (cdr make-span-bars)))
+ ;; the span bar reaches from the lower end of the upper staff
+ ;; to the upper end of the lower staff - when allow-span-bar is #t
+ (reduce (lambda (curr prev)
+ (let ((l (cons 0 0))
+ (allow-span-bar (car make-span-bars)))
+
+ (set! make-span-bars (cdr make-span-bars))
+ (if (> (interval-length prev) 0)
+ (begin
+ (set! l (cons (cdr prev) (car curr)))
+ (if (or (zero? (interval-length l))
+ (not allow-span-bar))
+ (begin
+ ;; there is overlap between the bar lines
+ ;; or 'allow-span-bar = #f.
+ ;; Do nothing.
+ )
+ (set! span-bar
+ (ly:stencil-add span-bar
+ (bar-line::compound-bar-line
+ model-bar
+ glyph
+ l
+ #f))))))
+ curr))
+ "" extents)
+ (set! span-bar (ly:stencil-translate-axis
+ span-bar
+ (- (ly:grob-relative-coordinate grob refp Y))
+ Y))))
+ span-bar))
"The line between note heads for a pitch range."
'(gap note-heads thickness))
+(ly:add-interface
+ 'bar-line-interface
+ "Print a special bar symbol. It replaces the regular bar
+symbol with a special symbol. The argument @var{bartype}
+is a string which specifies the kind of bar line to print.
+Options are @code{|}, @code{:|}, @code{|:}, @code{:|:}, @code{:|.|:},
+@code{:|.:}, @code{.}, @code{||}, @code{|.}, @code{.|}, @code{.|.},
+@code{|.|}, @code{:}, @code{dashed}, @code{'} and @code{S}.
+
+These produce, respectively, a normal bar line, a right repeat, a left repeat,
+a thick double repeat, a thin-thick-thin double repeat,
+a thin-thick double repeat, a thick bar, a double bar, a start bar,
+an end bar, a thick double bar, a thin-thick-thin bar,
+a dotted bar, a dashed bar, a tick as bar line and a segno bar.
+
+In addition, there is an option
+@code{||:} which is equivalent to @code{|:} except at line
+breaks, where it produces a double bar (@code{||}) at the
+end of the line and a repeat sign (@code{|:}) at the
+beginning of the new line.
+
+For segno, @code{S} produces a segno sign except at line breaks,
+where it produces a double bar (@code{||}) at the
+end of the line and a segno sign at the beginning of the new line.
+@code{|S} is equivalent to @code{S} but produces a simple bar line
+(@code{|}) instead of a double bar line (@code{||}) at line breaks.
+@code{S|} produces the segno sign at line breaks and starts the following
+line without special bar lines.
+
+@code{S|:} and @code{:|S} are used for repeat/segno combinations that are
+separated at line breaks. Alternatively, @code{.S|:} and @code{:|S.}
+may be used which combine repeat signs and segno at the same line in
+case of a line break. @code{:|S|:} is a combination of a left repeat
+(@code{:|}), a segno (@code{S}) and a right repeat @code{|:} which
+splits before the segno at line breaks; @code{:|S.|:} splits after
+the segno sign.
+
+If @var{bartype} is set to @code{empty} then nothing is
+printed, but a line break is allowed at that spot.
+
+@code{gap} is used for the gaps in dashed bar lines."
+ '(allow-span-bar bar-extent gap glyph glyph-name has-span-bar
+ hair-thickness kern thin-kern thick-thickness))
+
(ly:add-interface
'bass-figure-interface
"A bass figure text."
"Supports setting of spacing variables."
'(spacing-increment shortest-duration-space))
+(ly:add-interface
+ 'span-bar-interface
+ "A bar line that is spanned between other barlines.
+ This interface is used for bar lines that connect different
+ staves."
+ '(glyph-name elements pure-Y-common pure-relevant-grobs
+ pure-relevant-items pure-relevant-spanners))
+
(ly:add-interface
'stanza-number-interface
"A stanza number, to be put in from of a lyrics line."
(define (other-axis a)
(remainder (+ a 1) 2))
+(define-public (interval-scale iv factor)
+ (cons (* (car iv) factor)
+ (* (cdr iv) factor)))
+
(define-public (interval-widen iv amount)
(cons (- (car iv) amount)
(+ (cdr iv) amount)))
"font.scm"
"encoding.scm"
+ "bar-line.scm"
"flag-styles.scm"
"fret-diagrams.scm"
"tablature.scm"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Bar lines.
+;; neighbor-interface routines
-;;
-;; How should a bar line behave at a break?
-(define bar-glyph-alist
- '((":|:" . (":|" . "|:"))
- (":|.|:" . (":|" . "|:"))
- (":|.:" . (":|" . "|:"))
- ("||:" . ("||" . "|:"))
- ("dashed" . ("dashed" . '()))
- ("|" . ("|" . ()))
- ("|s" . (() . "|"))
- ("|:" . ("|" . "|:"))
- ("|." . ("|." . ()))
-
- ;; hmm... should we end with a bar line here?
- (".|" . ("|" . ".|"))
- (":|" . (":|" . ()))
- ("||" . ("||" . ()))
- (".|." . (".|." . ()))
- ("|.|" . ("|.|" . ()))
- ("" . ("" . ""))
- (":" . (":" . ""))
- ("." . ("." . ()))
- ("'" . ("'" . ()))
- ("empty" . (() . ()))
- ("brace" . (() . "brace"))
- ("bracket" . (() . "bracket"))
-
- ;; segno bar lines
- ("S" . ("||" . "S"))
- ("|S" . ("|" . "S"))
- ("S|" . ("S" . ()))
- (":|S" . (":|" . "S"))
- (":|S." . (":|S" . ()))
- ("S|:" . ("S" . "|:"))
- (".S|:" . ("|" . "S|:"))
- (":|S|:" . (":|" . "S|:"))
- (":|S.|:" . (":|S" . "|:"))
-
- ;; ancient bar lines
- ("kievan" . ("kievan" . ""))))
-
-(define-public (bar-line::calc-glyph-name grob)
- (let* ((glyph (ly:grob-property grob 'glyph))
- (dir (ly:item-break-dir grob))
- (result (assoc-get glyph bar-glyph-alist))
- (glyph-name (if (= dir CENTER)
- glyph
- (if (and result
- (string? (index-cell result dir)))
- (index-cell result dir)
- #f))))
- glyph-name))
-
-(define-public (bar-line::calc-break-visibility grob)
- (let* ((glyph (ly:grob-property grob 'glyph))
- (result (assoc-get glyph bar-glyph-alist)))
-
- (if result
- (vector (string? (car result)) #t (string? (cdr result)))
- all-invisible)))
(define-public (shift-right-at-line-begin g)
"Shift an item to the right, but only at the start of the line."