<<
{
\once \override Stem #'transparent = ##t
+ \once \override Flag #'transparent = ##t
b8~ b\noBeam
}
\\
<<
{
\once \override Stem #'transparent = ##t
+ \once \override Flag #'transparent = ##t
\once \override Stem #'length = #8
b8~ b\noBeam
}
only the @code{mensural} style is supported.
@lilypond[quote,fragment,ragged-right,verbatim]
-\override Stem #'flag-style = #'mensural
+\override Flag #'style = #'mensural
\override Stem #'thickness = #1.0
\override NoteHead #'style = #'mensural
\autoBeamOff
\override Staff.StaffSymbol #'color = #red
\override Staff.LedgerLineSpanner #'color = #red
\override Voice.Stem #'transparent = ##t
+ \override Voice.Flag #'transparent = ##t
\override NoteHead #'style = #'vaticana.punctum
\clef "vaticana-do2"
c
\override Staff.StaffSymbol #'color = #red
\override Staff.LedgerLineSpanner #'color = #red
\override Voice.Stem #'transparent = ##t
+ \override Voice.Flag #'transparent = ##t
\override NoteHead #'style = #'vaticana.punctum
\clef "vaticana-fa2"
c
\override Staff.StaffSymbol #'color = #red
\override Staff.LedgerLineSpanner #'color = #red
\override Voice.Stem #'transparent = ##t
+ \override Voice.Flag #'transparent = ##t
\override NoteHead #'style = #'medicaea.punctum
\clef "medicaea-do2"
c
\override Staff.StaffSymbol #'color = #red
\override Staff.LedgerLineSpanner #'color = #red
\override Voice.Stem #'transparent = ##t
+ \override Voice.Flag #'transparent = ##t
\override NoteHead #'style = #'medicaea.punctum
\clef "medicaea-fa2"
c
\override Staff.StaffSymbol #'color = #red
\override Staff.LedgerLineSpanner #'color = #red
\override Voice.Stem #'transparent = ##t
+ \override Voice.Flag #'transparent = ##t
\override NoteHead #'style = #'hufnagel.punctum
\clef "hufnagel-do2"
c
\override Staff.StaffSymbol #'color = #red
\override Staff.LedgerLineSpanner #'color = #red
\override Voice.Stem #'transparent = ##t
+ \override Voice.Flag #'transparent = ##t
\override NoteHead #'style = #'hufnagel.punctum
\clef "hufnagel-fa2"
c
\override Staff.StaffSymbol #'color = #red
\override Staff.LedgerLineSpanner #'color = #red
\override Voice.Stem #'transparent = ##t
+ \override Voice.Flag #'transparent = ##t
\override NoteHead #'style = #'hufnagel.punctum
\clef "hufnagel-do-fa"
c
one can use either @code{\override Stem #'transparent = ##t} or
@code{\override Stem #'length = #0} instead, and restore the stem
when needed with the corresponding @code{\once \override Stem
-#'transparent = ##f} (see example below).
+#'transparent = ##f} (see example below). When using stems that
+carry flags, make sure to set @code{\override Flag #'transparent
+= ##t} as well.
@b{Timing.} For unmetered chant, there are several alternatives.
\remove "Time_signature_engraver"
\override BarLine #'X-extent = #'(-1 . 1)
\override Stem #'transparent = ##t
+ \override Flag #'transparent = ##t
\override Beam #'transparent = ##t
\override BarLine #'transparent = ##t
\override TupletNumber #'transparent = ##t
@example
\override NoteHead #'style = #'slash
\override Stem #'transparent = ##t
+\override Flag #'transparent = ##t
@end example
All these plug-ins have to cooperate, and this is achieved with a
squashedPosition = #0
\override NoteHead #'style = #'slash
\override Stem #'transparent = ##t
+ \override Flag #'transparent = ##t
\alias Voice
@}
@end example
% extend the stems to reach the other staff
\override Stem #'length = #12
% do not print extra flags
- \override Stem #'flag-style = #'no-flag
+ \override Flag #'style = #'no-flag
% prevent beaming as needed
a8 g4 f8 f bes\noBeam g4
}
\once \override NoteHead #'X-offset = #1.7
\once \override Stem #'rotation = #'(45 0 0)
\once \override Stem #'extra-offset = #'(-0.2 . -0.2)
- \once \override Stem #'flag-style = #'no-flag
+ \once \override Flag #'style = #'no-flag
\once \override Accidental #'extra-offset = #'(4 . 0)
}
\once \override TabNoteHead #'transparent = ##t
\once \override NoteHead #'transparent = ##t
\once \override Stem #'transparent = ##t
+ \once \override Flag #'transparent = ##t
\once \override NoteHead #'no-ledgers = ##t
\once \override Glissando #'(bound-details left padding) = #0.3
}
%% Flag [Note Head - Stem]
%%
-noflag = \once \override Stem #'flag-style = #'no-flag
+noflag = \once \override Flag #'style = #'no-flag
%%%
%%% Functions
s32 s32_\appassmolto s8. \voiceOne r8 <bes'' es bes'>-> s4
\override Stem #'cross-staff = ##t
\override Stem #'length = #28
- \override Stem #'flag-style = #'no-flag
+ \override Flag #'style = #'no-flag
s8 \voiceTwo g,8 aes4 s4
}
middleVoiceOne = \relative c' {
\override Stem #'cross-staff = ##t
\override Stem #'length = #32
- \override Stem #'flag-style = #'no-flag
+ \override Flag #'style = #'no-flag
d!8\noBeam s8 s8 s8_\crmolto s4 % 1
s4 <g bes\arpeggio>8[ <es' g>] \voiceOne e,8( dis16 e) | % 2
\revert Stem #'length
s2. | % 1
\override Stem #'cross-staff = ##t
\override Stem #'length = #24
- \override Stem #'flag-style = #'no-flag
+ \override Flag #'style = #'no-flag
s2 \voiceTwo e!4 | % 2
s4 \voiceTwo <bes c es f>8 <f' aes es'>16 d' <bes, f' aes c>8 <bes' fis'> | % 3
}
b
\override NoteHead #'color = #green
\override Stem #'color = #blue
+ \override Flag #'color = #magenta
e8 es d dis e4 r
}
\header {
texidoc = "Default flag styles: '(), 'mensural and 'no-flag.
- Compare all three methods to print them: (1) C++ default implementation,
- (2) Scheme implementation using the 'flag-style grob property and
+ Compare all three methods to print them: (1) C++ default implementation,
+ (2) Scheme implementation using the 'style grob property and
(3) setting the 'flag property explicitly to the desired Scheme function.
All three systems should be absolutely identical."
}
c''8 d''16 c''32 d''64 \acciaccatura {c''8} d''64
}
-% Old settings: flag-style set to default, 'mensural, 'no-flag; using the
+% Old settings: style set to default, 'mensural, 'no-flag; using the
% default C++ function ly:stem::calc-stem
{
\override Score.RehearsalMark #'self-alignment-X = #LEFT
\testnotes
\mark "Symbol: 'mensural (C++)"
- \override Stem #'flag-style = #'mensural
+ \override Flag #'style = #'mensural
\testnotes
\mark "Symbol: 'no-flag (C++)"
- \override Stem #'flag-style = #'no-flag
+ \override Flag #'style = #'no-flag
\testnotes
}
\override Score.RehearsalMark #'self-alignment-X = #LEFT
\time 2/4
- \override Stem #'flag = #default-flag
- \revert Stem #'flag-style
+ \override Flag #'stencil = #default-flag
+ \revert Flag #'style
\mark "Default flags (Scheme)"
\testnotes
\mark "Symbol: 'mensural (Scheme)"
- \override Stem #'flag-style = #'mensural
+ \override Flag #'style = #'mensural
\testnotes
\mark "Symbol: 'no-flag (Scheme)"
- \override Stem #'flag-style = #'no-flag
+ \override Flag #'style = #'no-flag
\testnotes
}
\time 2/4
\mark "Function: normal-flag"
- \override Stem #'flag = #normal-flag
+ \override Flag #'stencil = #normal-flag
\testnotes
\mark "Function: mensural-flag"
- \override Stem #'flag = #mensural-flag
+ \override Flag #'stencil = #mensural-flag
\testnotes
\mark "Function: no-flag"
- \override Stem #'flag = #no-flag
+ \override Flag #'stencil = #no-flag
\testnotes
}
\version "2.14.0"
\header {
- texidoc = "The 'flag property of the Stem grob can be set to a custom
+ texidoc = "The 'stencil property of the Flag grob can be set to a custom
scheme function to generate the glyph for the flag."
}
% test notes, which will be shown in different style:
testnotes = { \autoBeamOff c'8 d'16 c'32 d'64 \acciaccatura {c'8} d'64 c''8 d''16 c''32 d''64 \acciaccatura {c''8} d''64 }
-#(define-public (weight-flag stem-grob)
- (let* ((log (- (ly:grob-property stem-grob 'duration-log) 2))
+#(define-public (weight-flag grob)
+ (let* ((stem-grob (ly:grob-parent grob X))
+ (log (- (ly:grob-property stem-grob 'duration-log) 2))
(is-up (eqv? (ly:grob-property stem-grob 'direction) UP))
(yext (if is-up (cons (* log -0.8) 0) (cons 0 (* log 0.8))))
(flag-stencil (make-filled-box-stencil '(-0.4 . 0.4) yext))
- (stroke-style (ly:grob-property stem-grob 'stroke-style))
+ (stroke-style (ly:grob-property grob 'stroke-style))
(stroke-stencil (if (equal? stroke-style "grace") (make-line-stencil 0.2 -0.9 -0.4 0.9 -0.4) empty-stencil)))
(ly:stencil-add flag-stencil stroke-stencil)))
% Create a flag stencil by looking up the glyph from the font
-#(define (inverted-flag stem-grob)
- (let* ((dir (if (eqv? (ly:grob-property stem-grob 'direction) UP) "d" "u"))
- (flag (retrieve-glyph-flag "" dir "" stem-grob))
- (line-thickness (ly:staff-symbol-line-thickness stem-grob))
+#(define (inverted-flag grob)
+ (let* ((stem-grob (ly:grob-parent grob X))
+ (dir (if (eqv? (ly:grob-property stem-grob 'direction) UP) "d" "u"))
+ (flag (retrieve-glyph-flag "" dir "" grob))
+ (line-thickness (ly:staff-symbol-line-thickness grob))
(stem-thickness (ly:grob-property stem-grob 'thickness))
(stem-width (* line-thickness stem-thickness))
- (stroke-style (ly:grob-property stem-grob 'stroke-style))
+ (stroke-style (ly:grob-property grob 'stroke-style))
(stencil (if (null? stroke-style) flag
- (add-stroke-glyph flag stem-grob dir stroke-style "")))
+ (add-stroke-glyph flag grob dir stroke-style "")))
(rotated-flag (ly:stencil-rotate-absolute stencil 180 0 0)))
(ly:stencil-translate rotated-flag (cons (- (/ stem-width 2)) 0))))
\override Score.RehearsalMark #'self-alignment-X = #LEFT
\time 2/4
\mark "Function: weight-flag (custom)"
- \override Stem #'flag = #weight-flag
+ \override Flag #'stencil = #weight-flag
\testnotes
\mark "Function: inverted-flag (custom)"
- \override Stem #'flag = #inverted-flag
+ \override Flag #'stencil = #inverted-flag
\testnotes
}
{
\autoBeamOff
\time 3/8
- \override Stem #'flag = #modern-straight-flag
+ \override Flag #'stencil = #modern-straight-flag
\override Stem #'length-fraction = #'1.5
r8
\acciaccatura {
\override Score.RehearsalMark #'self-alignment-X = #LEFT
\time 2/4
\mark "modern straight"
- \override Stem #'flag = #modern-straight-flag
+ \override Flag #'stencil = #modern-straight-flag
\testnotes
\mark "old straight (large angles)"
- \override Stem #'flag = #old-straight-flag
+ \override Flag #'stencil = #old-straight-flag
\testnotes
%
% \mark "custom slant"
% % flag thickness and spacing
% % up-flag angle and length
% % down-flag angle and length
-% \override Stem #'flag = #(straight-flag 0.35 0.8 -5 0.5 60 2.0)
+% \override Flag #'stencil = #(straight-flag 0.35 0.8 -5 0.5 60 2.0)
% \testnotes
}
#(whitelist-grob 'NoteHead)
#(whitelist-grob 'Stem)
+#(whitelist-grob 'Flag)
#(whitelist-grob "NoteHead")
#(whitelist-grob "Stem")
+#(whitelist-grob "Flag")
#(map whitelist-symbol '(stencil style duration-log
stem-attachment end-position staff-position
\override NoteHead #'transparent = ##t
\override NoteHead #'no-ledgers = ##t
\override Stem #'transparent = ##t
+ \override Flag #'transparent = ##t
\override Beam #'transparent = ##t
<< \skips
>>
\grace {
- \override Stem #'stroke-style = #"grace"
+ \override Flag #'stroke-style = #"grace"
s8
s16 s s
\clef bass
<e,,, e,>32(\sustainOff\sustainOn
- \revert Stem #'stroke-style
+ \revert Flag #'stroke-style
}
<gis' e>2)
%
-longgrace = \override Stem #'stroke-style = #'()
-endlonggrace = \revert Stem #'stroke-style
+longgrace = \override Flag #'stroke-style = #'()
+endlonggrace = \revert Flag #'stroke-style
ritenuto = \markup { \italic "rit." }
\version "2.14.0"
}
mus = \relative c' {
- % Acciaccaturas contain a slur and \override Stem #'stroke-style
+ % Acciaccaturas contain a slur and \override Flag #'stroke-style
% Thus, we're checking \override here
c4 \acciaccatura d8 c4
% Checking \set and \unset
% Checking \once \override
\once \override Stem #'thickness = #8.0 d8
% Checking two overrides
- \override Stem #'thickness = #8.0 \override Stem #'stroke-style = "grace"
+ \override Stem #'thickness = #8.0 \override Flag #'stroke-style = "grace"
d8
% reverting one of them
\revert Stem #'thickness d8
% and the other
- \revert Stem #'stroke-style c8
+ \revert Flag #'stroke-style c8
% checking tweaks
c2-\tweak #'color #red ->
- beam->relative_coordinate (common[Y_AXIS], Y_AXIS);
Real factor = parameters.STEM_COLLISION_FACTOR;
- if (!unsmob_grob (s->get_object ("beam"))
- && !Stem::flag (s).is_empty ())
+ if (!unsmob_grob (s->get_object ("beam")))
factor = 1.0;
add_collision (x, y, factor);
}
i != stems.end (); i++)
{
Grob *stem = (*i);
- Stencil flag = Stem::flag (stem);
- if (!flag.is_empty ())
+ Grob *flag = Stem::flag (stem);
+ if (flag)
{
- Interval y = flag.extent (Y_AXIS)
- * (2 / ss)
- + Stem::stem_end_position (stem);
+ Grob *commony = stem->common_refpoint (flag, Y_AXIS);
+ Interval y = flag->extent (commony, Y_AXIS) * (2 / ss);
- Interval x = stem->relative_coordinate (commonx, X_AXIS)
- + flag.extent (X_AXIS);
+ Interval x = flag->extent (commonx, X_AXIS);
boxes.push_back (Box (x, y));
}
--- /dev/null
+/*
+ This file is part of LilyPond, the GNU music typesetter.
+
+ Copyright (C) 1996--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
+ Jan Nieuwenhuizen <janneke@gnu.org>
+
+ 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 "stem.hh"
+
+#include "directional-element-interface.hh"
+#include "font-interface.hh"
+#include "grob.hh"
+#include "international.hh"
+#include "output-def.hh"
+#include "staff-symbol-referencer.hh"
+#include "stencil.hh"
+#include "warn.hh"
+
+class Flag
+{
+public:
+ DECLARE_SCHEME_CALLBACK (print, (SCM));
+ DECLARE_SCHEME_CALLBACK (width, (SCM));
+ DECLARE_SCHEME_CALLBACK (calc_y_offset, (SCM));
+ DECLARE_SCHEME_CALLBACK (calc_x_offset, (SCM));
+ DECLARE_GROB_INTERFACE ();
+};
+
+
+
+MAKE_SCHEME_CALLBACK (Flag, width, 1);
+SCM
+Flag::width (SCM smob)
+{
+ Grob *me = unsmob_grob (smob);
+ Stencil *sten = unsmob_stencil (me->get_property ("stencil"));
+ if (!sten)
+ return ly_interval2scm (Interval (0.0, 0.0));
+
+ Grob *stem = me->get_parent (X_AXIS);
+
+ /*
+ TODO:
+ This reproduces a bad hard-coding that has been in the code for quite some time:
+ the bounding boxes for the flags are slightly off and need to be fixed.
+ */
+
+ return ly_interval2scm (sten->extent (X_AXIS) - stem->extent (stem, X_AXIS)[RIGHT]);
+}
+MAKE_SCHEME_CALLBACK (Flag, print, 1);
+SCM
+Flag::print (SCM smob)
+{
+ Grob *me = unsmob_grob (smob);
+ Grob *stem = me->get_parent (X_AXIS);
+
+ int log = Stem::duration_log (stem);
+ string flag_style;
+
+ SCM flag_style_scm = me->get_property ("style");
+ if (scm_is_symbol (flag_style_scm))
+ flag_style = ly_symbol2string (flag_style_scm);
+
+ if (flag_style == "no-flag")
+ return Stencil ().smobbed_copy ();
+
+ bool adjust = true;
+
+ string staffline_offs;
+ if (flag_style == "mensural")
+ /* Mensural notation: For notes on staff lines, use different
+ flags than for notes between staff lines. The idea is that
+ flags are always vertically aligned with the staff lines,
+ regardless if the note head is on a staff line or between two
+ staff lines. In other words, the inner end of a flag always
+ touches a staff line.
+ */
+ {
+ if (adjust)
+ {
+ int p = (int) (rint (Stem::stem_end_position (stem)));
+ staffline_offs
+ = Staff_symbol_referencer::on_line (stem, p) ? "0" : "1";
+ }
+ else
+ staffline_offs = "2";
+ }
+ else
+ staffline_offs = "";
+
+ char dir = (get_grob_direction (stem) == UP) ? 'u' : 'd';
+ string font_char = flag_style
+ + to_string (dir) + staffline_offs + to_string (log);
+ Font_metric *fm = Font_interface::get_default_font (me);
+ Stencil flag = fm->find_by_name ("flags." + font_char);
+ if (flag.is_empty ())
+ me->warning (_f ("flag `%s' not found", font_char));
+
+ /*
+ TODO: maybe property stroke-style should take different values,
+ e.g. "" (i.e. no stroke), "single" and "double" (currently, it's
+ '() or "grace"). */
+ SCM stroke_style_scm = me->get_property ("stroke-style");
+ if (scm_is_string (stroke_style_scm))
+ {
+ string stroke_style = ly_scm2string (stroke_style_scm);
+ if (!stroke_style.empty ())
+ {
+ string font_char = flag_style + to_string (dir) + stroke_style;
+ Stencil stroke = fm->find_by_name ("flags." + font_char);
+ if (stroke.is_empty ())
+ {
+ font_char = to_string (dir) + stroke_style;
+ stroke = fm->find_by_name ("flags." + font_char);
+ }
+ if (stroke.is_empty ())
+ me->warning (_f ("flag stroke `%s' not found", font_char));
+ else
+ flag.add_stencil (stroke);
+ }
+ }
+
+ return flag.smobbed_copy ();
+}
+
+MAKE_SCHEME_CALLBACK (Flag, calc_y_offset, 1);
+SCM
+Flag::calc_y_offset (SCM smob)
+{
+ Grob *me = unsmob_grob (smob);
+ Grob *stem = me->get_parent (X_AXIS);
+ Direction d = get_grob_direction (stem);
+
+ Real blot
+ = me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter"));
+ Real half_space = Staff_symbol_referencer::staff_space (me) * 0.5;
+ Real y2 = robust_scm2double (stem->get_property ("stem-end-position"), 0.0);
+
+ return scm_from_double (y2 * half_space - d * blot / 2);
+}
+
+MAKE_SCHEME_CALLBACK (Flag, calc_x_offset, 1);
+SCM
+Flag::calc_x_offset (SCM smob)
+{
+ Grob *me = unsmob_grob (smob);
+ Grob *stem = me->get_parent (X_AXIS);
+ return scm_from_double (stem->extent (stem, X_AXIS)[RIGHT]);
+}
+
+ADD_INTERFACE (Flag,
+ "A flag that gets attached to a stem."
+ "The style property is symbol determining"
+ " what style of flag glyph is typeset on a"
+ " @code{Stem}. Valid options include @code{'()}"
+ " for standard flags, @code{'mensural} and"
+ " @code{'no-flag}, which switches off the flag.",
+
+ /* properties */
+ "style "
+ "stroke-style "
+ );
\ No newline at end of file
static bool is_cross_staff (Grob *);
static Interval head_positions (Grob *);
static Real stem_end_position (Grob *);
- static Stencil flag (Grob *);
- static Stencil get_translated_flag (Grob *);
DECLARE_GROB_INTERFACE ();
static void set_spacing_hints (Grob *);
+ static Grob *flag (Grob *);
DECLARE_SCHEME_CALLBACK (print, (SCM));
DECLARE_SCHEME_CALLBACK (calc_default_direction, (SCM));
DECLARE_SCHEME_CALLBACK (pure_height, (SCM, SCM, SCM));
DECLARE_SCHEME_CALLBACK (height, (SCM));
DECLARE_SCHEME_CALLBACK (calc_cross_staff, (SCM));
- DECLARE_SCHEME_CALLBACK (calc_flag, (SCM));
};
#endif
{
vector<Grob *> rheads_;
Grob *stem_;
+ Grob *flag_;
Grob *note_column_;
Grob *arpeggio_;
protected:
DECLARE_ACKNOWLEDGER (stem);
+ DECLARE_ACKNOWLEDGER (flag);
DECLARE_ACKNOWLEDGER (rhythmic_head);
DECLARE_ACKNOWLEDGER (arpeggio);
void process_acknowledged ();
{
stem_ = 0;
+ flag_ = 0;
note_column_ = 0;
arpeggio_ = 0;
}
Pointer_group_interface::add_grob (note_column_, ly_symbol2scm ("elements"), arpeggio_);
note_column_->set_object ("arpeggio", arpeggio_->self_scm ());
}
+ if (flag_)
+ Pointer_group_interface::add_grob (note_column_, ly_symbol2scm ("elements"), flag_);
}
}
stem_ = i.grob ();
}
+void
+Rhythmic_column_engraver::acknowledge_flag (Grob_info i)
+{
+ flag_ = i.grob ();
+}
+
void
Rhythmic_column_engraver::acknowledge_rhythmic_head (Grob_info i)
{
note_column_ = 0;
stem_ = 0;
arpeggio_ = 0;
+ flag_ = 0;
}
ADD_ACKNOWLEDGER (Rhythmic_column_engraver, stem);
+ADD_ACKNOWLEDGER (Rhythmic_column_engraver, flag);
ADD_ACKNOWLEDGER (Rhythmic_column_engraver, rhythmic_head);
ADD_ACKNOWLEDGER (Rhythmic_column_engraver, arpeggio);
{
Grob *stem_;
Grob *tremolo_;
+ vector <Grob *> maybe_flags_;
Stream_event *rhythmic_ev_;
Stream_event *tremolo_ev_;
DECLARE_TRANSLATOR_LISTENER (tremolo);
DECLARE_ACKNOWLEDGER (rhythmic_head);
void stop_translation_timestep ();
+ void finalize ();
+ void kill_unused_flags ();
};
Stem_engraver::Stem_engraver ()
/* Announce the cause of the head as cause of the stem. The
stem needs a rhythmic structure to fit it into a beam. */
stem_ = make_item ("Stem", gi.grob ()->self_scm ());
-
if (tremolo_ev_)
{
/* Stem tremolo is never applied to a note by default,
}
Stem::add_head (stem_, gi.grob ());
+
+ if (Stem::is_normal_stem (stem_)
+ && Stem::duration_log (stem_) > 2)
+ {
+ Item *flag = make_item ("Flag", stem_->self_scm ());
+ flag->set_parent (stem_, X_AXIS);
+ stem_->set_object ("flag", flag->self_scm ());
+ maybe_flags_.push_back (flag);
+ }
+}
+
+void
+Stem_engraver::kill_unused_flags ()
+{
+ for (vsize i = 0; i < maybe_flags_.size (); i++)
+ if (unsmob_grob (maybe_flags_[i]->get_parent (X_AXIS)->get_object ("beam")))
+ maybe_flags_[i]->suicide ();
+}
+
+void
+Stem_engraver::finalize ()
+{
+ kill_unused_flags ();
}
void
Stem_engraver::stop_translation_timestep ()
{
+ if (scm_is_string (get_property ("whichBar")))
+ kill_unused_flags ();
+
tremolo_ = 0;
if (stem_)
{
/* read */
"tremoloFlags "
"stemLeftBeamCount "
- "stemRightBeamCount ",
+ "stemRightBeamCount "
+ "whichBar ",
/* write */
""
return robust_scm2double (me->get_property ("stem-end-position"), 0);
}
-MAKE_SCHEME_CALLBACK (Stem, calc_flag, 1);
-SCM
-Stem::calc_flag (SCM smob)
-{
- Grob *me = unsmob_grob (smob);
-
- int log = duration_log (me);
- /*
- TODO: maybe property stroke-style should take different values,
- e.g. "" (i.e. no stroke), "single" and "double" (currently, it's
- '() or "grace"). */
- string flag_style;
-
- SCM flag_style_scm = me->get_property ("flag-style");
- if (scm_is_symbol (flag_style_scm))
- flag_style = ly_symbol2string (flag_style_scm);
-
- if (flag_style == "no-flag")
- return Stencil ().smobbed_copy ();
-
- bool adjust = true;
-
- string staffline_offs;
- if (flag_style == "mensural")
- /* Mensural notation: For notes on staff lines, use different
- flags than for notes between staff lines. The idea is that
- flags are always vertically aligned with the staff lines,
- regardless if the note head is on a staff line or between two
- staff lines. In other words, the inner end of a flag always
- touches a staff line.
- */
- {
- if (adjust)
- {
- int p = (int) (rint (stem_end_position (me)));
- staffline_offs
- = Staff_symbol_referencer::on_line (me, p) ? "0" : "1";
- }
- else
- staffline_offs = "2";
- }
- else
- staffline_offs = "";
-
- char dir = (get_grob_direction (me) == UP) ? 'u' : 'd';
- string font_char = flag_style
- + to_string (dir) + staffline_offs + to_string (log);
- Font_metric *fm = Font_interface::get_default_font (me);
- Stencil flag = fm->find_by_name ("flags." + font_char);
- if (flag.is_empty ())
- me->warning (_f ("flag `%s' not found", font_char));
-
- SCM stroke_style_scm = me->get_property ("stroke-style");
- if (scm_is_string (stroke_style_scm))
- {
- string stroke_style = ly_scm2string (stroke_style_scm);
- if (!stroke_style.empty ())
- {
- string font_char = flag_style + to_string (dir) + stroke_style;
- Stencil stroke = fm->find_by_name ("flags." + font_char);
- if (stroke.is_empty ())
- {
- font_char = to_string (dir) + stroke_style;
- stroke = fm->find_by_name ("flags." + font_char);
- }
- if (stroke.is_empty ())
- me->warning (_f ("flag stroke `%s' not found", font_char));
- else
- flag.add_stencil (stroke);
- }
- }
-
- return flag.smobbed_copy ();
-}
-
-Stencil
-Stem::flag (Grob *me)
-{
- int log = duration_log (me);
- if (log < 3
- || unsmob_grob (me->get_object ("beam")))
- return Stencil ();
-
- if (!is_normal_stem (me))
- return Stencil ();
-
- // This get_property call already evaluates the scheme function with
- // the grob passed as argument! Thus, we only have to check if a valid
- // stencil is returned.
- SCM flag_style_scm = me->get_property ("flag");
- if (Stencil *flag = unsmob_stencil (flag_style_scm))
- {
- return *flag;
- }
- else
- {
- return Stencil ();
- }
-}
-
MAKE_SCHEME_CALLBACK (Stem, width, 1);
SCM
Stem::width (SCM e)
if (is_invisible (me))
r.set_empty ();
- else if (unsmob_grob (me->get_object ("beam"))
- || abs (duration_log (me)) <= 2)
+ else
{
r = Interval (-1, 1);
r *= thickness (me) / 2;
}
- else
- {
- r = Interval (-1, 1) * thickness (me) * 0.5;
- r.unite (flag (me).extent (X_AXIS));
- }
+
return ly_interval2scm (r);
}
Stencil ss = Lookup::round_filled_box (b, blot);
mol.add_stencil (ss);
- mol.add_stencil (get_translated_flag (me));
-
return mol.smobbed_copy ();
}
-Stencil
-Stem::get_translated_flag (Grob *me)
-{
- Stencil fl = flag (me);
- if (!fl.is_empty ())
- {
- Direction d = get_grob_direction (me);
- Real blot
- = me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter"));
- Real stem_width = thickness (me);
- Real half_space = Staff_symbol_referencer::staff_space (me) * 0.5;
- Real y2 = robust_scm2double (me->get_property ("stem-end-position"), 0.0);
- fl.translate_axis (y2 * half_space - d * blot / 2, Y_AXIS);
- fl.translate_axis (stem_width / 2, X_AXIS);
- }
- return fl;
-}
-
/*
move the stem to right of the notehead if it is up.
*/
return scm_from_bool (is_cross_staff (unsmob_grob (smob)));
}
+Grob*
+Stem::flag (Grob *me)
+{
+ return unsmob_grob (me->get_object ("flag"));
+}
+
/* FIXME: Too many properties */
ADD_INTERFACE (Stem,
"The stem represents the graphical stem. In addition, it"
"direction "
"duration-log "
"flag "
- "flag-style "
"french-beaming "
"length "
"length-fraction "
"stem-end-position "
"stem-info "
"stemlet-length "
- "stroke-style "
"thickness "
"tremolo-flag "
);
if (dir == LEFT)
{
- Box flag_box = Stem::get_translated_flag (stem).extent_box ();
- flag_box.translate ( Offset (x[RIGHT], X_AXIS));
- boxes.push_back (flag_box);
+ Grob *flag = Stem::flag (stem);
+ if (flag)
+ {
+ Grob* commony = stem->common_refpoint (flag, Y_AXIS);
+ boxes.push_back (Box (flag->extent (x_refpoint_, X_AXIS),
+ flag->extent (commony, Y_AXIS)));
+ }
}
}
else
graceSettings = #`(
(Voice Stem direction ,UP)
(Voice Stem font-size -3)
+ (Voice Flag font-size -3)
(Voice NoteHead font-size -3)
(Voice TabNoteHead font-size -4)
(Voice Dots font-size -3)
%% on the slur::calc-control-points routine
\override Stem #'length = #0
\override Stem #'no-stem-extend = ##t
- \override Stem #'flag-style = #'no-flag
+ \override Flag #'style = #'no-flag
\override Stem #'details = #'((lengths 0 0 0 0 0 0)
(beamed-lengths 0 0 0)
(beamed-minimum-free-lengths 0 0 0)
startAcciaccaturaMusic = {
s1*0\startGraceSlur
- \override Stem #'stroke-style = #"grace"
+ \override Flag #'stroke-style = #"grace"
}
stopAcciaccaturaMusic = {
- \revert Stem #'stroke-style
+ \revert Flag #'stroke-style
s1*0\stopGraceSlur
}
startSlashedGraceMusic = {
- \override Stem #'stroke-style = #"grace"
+ \override Flag #'stroke-style = #"grace"
}
stopSlashedGraceMusic = {
- \revert Stem #'stroke-style
+ \revert Flag #'stroke-style
}
\consists Vaticana_ligature_engraver
\override NoteHead #'style = #'vaticana.punctum
\override Stem #'transparent = ##t
+ \override Flag #'transparent = ##t
}
}
\override NoteHead #'transparent = ##t
\override NoteHead #'no-ledgers = ##t
\override Stem #'transparent = ##t
+ \override Flag #'transparent = ##t
\override Beam #'transparent = ##t
\override Accidental #'transparent = ##t
}
\revert Accidental #'transparent
\revert Beam #'transparent
\revert Stem #'transparent
+ \revert Flag #'transparent
\revert NoteHead #'transparent
\revert NoteHead #'no-ledgers
\revert Dots #'transparent
% stems (the half note gets a double stem)
\revert TabVoice.Stem #'length
\revert TabVoice.Stem #'no-stem-extend
- \revert TabVoice.Stem #'flag-style
+ \revert TabVoice.Flag #'style
\revert TabVoice.Stem #'details
\revert TabVoice.Stem #'transparent
\override TabVoice.Stem #'stencil = #tabvoice::draw-double-stem-for-half-notes
\override NoteHead #'style = #'diamond
\override NoteHead #'color = #red
\override Stem #'color = #red
+ \override Flag #'color = #red
\override Beam #'color = #red
}
voiceTwoStyle = {
\override NoteHead #'style = #'triangle
\override NoteHead #'color = #blue
\override Stem #'color = #blue
+ \override Flag #'color = #blue
\override Beam #'color = #blue
}
voiceThreeStyle = {
\override NoteHead #'style = #'xcircle
\override NoteHead #'color = #green
\override Stem #'color = #green
+ \override Flag #'color = #green
\override Beam #'color = #green
}
voiceFourStyle = {
\override NoteHead #'style = #'cross
\override NoteHead #'color = #magenta
\override Stem #'color = #magenta
+ \override Flag #'color = #magenta
\override Beam #'color = #magenta
}
voiceNeutralStyle = {
\revert NoteHead #'style
\revert NoteHead #'color
\revert Stem #'color
+ \revert Flag #'color
\revert Beam #'color
}
;;
;; f
;;
- (flag ,ly:stencil? "A function returning the full flag stencil
-for the @code{Stem}, which is passed to the function as the only
-argument. The default ly:stem::calc-stencil function uses the
-@code{flag-style} property to determine the correct glyph for the
-flag. By providing your own function, you can create arbitrary
-flags.")
(flag-count ,number? "The number of tremolo beams.")
- (flag-style ,symbol? "A symbol determining what style of flag
-glyph is typeset on a @code{Stem}. Valid options include @code{'()}
-for standard flags, @code{'mensural} and @code{'no-flag}, which
-switches off the flag.")
(font-encoding ,symbol? "The font encoding is the broadest
category for selecting a font. Currently, only lilypond's system
fonts (Emmentaler) are using this property. Available
in addition to notes and stems.")
(figures ,ly:grob-array? "Figured bass objects for continuation line.")
+ (flag ,ly:grob? "A pointer to a @code{Flag} object.")
(glissando-index ,integer? "The index of a glissando in its note
column.")
(clip-edges . #t)
(collision-interfaces . (beam-interface
clef-interface
+ flag-interface
inline-accidental-interface
key-signature-interface
note-head-interface
text-interface
text-script-interface))))))
+ (Flag
+ . (
+ (stencil . ,ly:flag::print)
+ (X-extent . ,ly:flag::width)
+ (X-offset . ,ly:flag::calc-x-offset)
+ (Y-offset . ,ly:flag::calc-y-offset)
+ (meta . ((class . Item)
+ (interfaces . (flag-interface
+ font-interface))))))
+
(FootnoteItem
. (
(annotation-balloon . #f)
(direction . ,ly:stem::calc-direction)
(duration-log . ,stem::calc-duration-log)
- (flag . ,ly:stem::calc-flag)
(length . ,ly:stem::calc-length)
(neutral-direction . ,DOWN)
(positioning-done . ,ly:stem::calc-positioning-done)
(Y-extent . ,ly:stem::height)
(Y-offset . ,ly:staff-symbol-referencer::callback)
(meta . ((class . Item)
- (interfaces . (font-interface
- stem-interface))))))
+ (interfaces . (stem-interface))))))
(StemTremolo
. (
ly:note-head::print
ly:dots::print
ly:clef::print
+ ly:flag::print
+ default-flag
+ normal-flag
+ mensural-flag
+ no-flag
+ modern-straight-flag
+ old-straight-flag
ly:key-signature-interface::print
ly:percent-repeat-item-interface::beat-slash
ly:text-interface::print
(list
parenthesize-elements
laissez-vibrer::print
+ ly:flag::calc-y-offset
ly:rest::y-offset-callback
ly:staff-symbol-referencer::callback
ly:staff-symbol::height))
;;;; notably the old-straight-flag and the modern-straight-flag styles.
-(define-public (no-flag stem-grob)
+(define-public (no-flag grob)
"No flag: Simply return empty stencil."
empty-stencil)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(define-public (add-stroke-straight stencil stem-grob dir log stroke-style
+(define-public (add-stroke-straight stencil grob dir log stroke-style
offset length thickness stroke-thickness)
"Add the stroke for acciaccatura to the given flag stencil.
The stroke starts for up-flags at `upper-end-of-flag + (0,length/2)'
the angle! Other combinations don't look as good.
For down-stems the y-coordinates are simply mirrored."
- (let* ((start (offset-add offset (cons 0 (* (/ length 2) dir))))
+ (let* ((stem-grob (ly:grob-parent grob X))
+ (start (offset-add offset (cons 0 (* (/ length 2) dir))))
(end (offset-add (cons 0 (cdr offset))
(cons (- (/ (car offset) 2)) (* (- (+ thickness (car offset))) dir))))
(stroke (make-line-stencil stroke-thickness (car start) (cdr start) (car end) (cdr end))))
All lengths are scaled according to the font size of the note."
- (lambda (stem-grob)
- (let* ((log (ly:grob-property stem-grob 'duration-log))
+ (lambda (grob)
+ (let* ((stem-grob (ly:grob-parent grob X))
+ (log (ly:grob-property stem-grob 'duration-log))
(dir (ly:grob-property stem-grob 'direction))
(stem-up (eqv? dir UP))
- (layout (ly:grob-layout stem-grob))
+ (layout (ly:grob-layout grob))
; scale with the note size (e.g. for grace notes)
- (factor (magstep (ly:grob-property stem-grob 'font-size 0)))
+ (factor (magstep (ly:grob-property grob 'font-size 0)))
(grob-stem-thickness (ly:grob-property stem-grob 'thickness))
(line-thickness (ly:output-def-lookup layout 'line-thickness))
(half-stem-thickness (/ (* grob-stem-thickness line-thickness) 2))
(stencil (ly:round-filled-polygon points half-stem-thickness))
; Log for 1/8 is 3, so we need to subtract 3
(flag-stencil (buildflag stencil (- log 3) stencil spacing))
- (stroke-style (ly:grob-property stem-grob 'stroke-style)))
+ (stroke-style (ly:grob-property grob 'stroke-style)))
(if (equal? stroke-style "grace")
- (add-stroke-straight flag-stencil stem-grob
+ (add-stroke-straight flag-stencil grob
dir log
stroke-style
flag-end flag-length
(* half-stem-thickness 2))
flag-stencil))))
-(define-public (modern-straight-flag stem-grob)
+(define-public (modern-straight-flag grob)
"Modern straight flag style (for composers like Stockhausen, Boulez, etc.).
The angles are 18 and 22 degrees and thus smaller than for the ancient style
of Bach, etc."
- ((straight-flag 0.55 1 -18 1.1 22 1.2) stem-grob))
+ ((straight-flag 0.55 1 -18 1.1 22 1.2) grob))
-(define-public (old-straight-flag stem-grob)
+(define-public (old-straight-flag grob)
"Old straight flag style (for composers like Bach). The angles of the
flags are both 45 degrees."
- ((straight-flag 0.55 1 -45 1.2 45 1.4) stem-grob))
+ ((straight-flag 0.55 1 -45 1.2 45 1.4) grob))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; NOTE: By default, lilypond uses the C++ method Stem::calc-flag
-; (ly:stem::calc-flag is the corresponding Scheme interface) to generate the
+; NOTE: By default, lilypond uses the C++ method Flag::stencil
+; (ly:flag::stencil is the corresponding Scheme interface) to generate the
; flag stencil. The following functions are simply a reimplementation in
; Scheme, so that one has that functionality available in Scheme, if one
; wants to write a flag style, which modifies one of the standard flags
; by some stencil operations.
-(define-public (add-stroke-glyph stencil stem-grob dir stroke-style flag-style)
+(define-public (add-stroke-glyph stencil grob dir stroke-style flag-style)
"Load and add a stroke (represented by a glyph in the font) to the given
flag stencil."
(if (not (string? stroke-style))
stencil
; Otherwise: look up the stroke glyph and combine it with the flag
- (let* ((font-char (string-append "flags." flag-style dir stroke-style))
+ (let* ((stem-grob (ly:grob-parent grob X))
+ (font-char (string-append "flags." flag-style dir stroke-style))
(alt-font-char (string-append "flags." dir stroke-style))
- (font (ly:grob-default-font stem-grob))
+ (font (ly:grob-default-font grob))
(tmpstencil (ly:font-get-glyph font font-char))
(stroke-stencil (if (ly:stencil-empty? tmpstencil)
(ly:font-get-glyph font alt-font-char)
(ly:stencil-add stencil stroke-stencil)))))
-(define-public (retrieve-glyph-flag flag-style dir dir-modifier stem-grob)
+(define-public (retrieve-glyph-flag flag-style dir dir-modifier grob)
"Load the correct flag glyph from the font."
- (let* ((log (ly:grob-property stem-grob 'duration-log))
- (font (ly:grob-default-font stem-grob))
+ (let* ((stem-grob (ly:grob-parent grob X))
+ (log (ly:grob-property stem-grob 'duration-log))
+ (font (ly:grob-default-font grob))
(font-char (string-append "flags." flag-style dir dir-modifier (number->string log)))
(flag (ly:font-get-glyph font font-char)))
(if (ly:stencil-empty? flag)
flag))
-(define-public (create-glyph-flag flag-style dir-modifier stem-grob)
+(define-public (create-glyph-flag flag-style dir-modifier grob)
"Create a flag stencil by looking up the glyph from the font."
- (let* ((dir (if (eqv? (ly:grob-property stem-grob 'direction) UP) "u" "d"))
- (flag (retrieve-glyph-flag flag-style dir dir-modifier stem-grob))
- (stroke-style (ly:grob-property stem-grob 'stroke-style)))
+ (let* ((stem-grob (ly:grob-parent grob X))
+ (dir (if (eqv? (ly:grob-property stem-grob 'direction) UP) "u" "d"))
+ (flag (retrieve-glyph-flag flag-style dir dir-modifier grob))
+ (stroke-style (ly:grob-property grob 'stroke-style)))
(if (null? stroke-style)
flag
- (add-stroke-glyph flag stem-grob dir stroke-style flag-style))))
+ (add-stroke-glyph flag grob dir stroke-style flag-style))))
-(define-public (mensural-flag stem-grob)
+(define-public (mensural-flag grob)
"Mensural flags: Create the flag stencil by loading the glyph from the font.
Flags are always aligned with staff lines, so we need to check the end point
of the stem: For stems ending on staff lines, use different flags than for
staff line or between two staff lines. In other words, the inner end of
a flag always touches a staff line."
- (let* ((adjust #t)
+ (let* ((stem-grob (ly:grob-parent grob X))
+ (adjust #t)
(stem-end (inexact->exact (round (ly:grob-property stem-grob 'stem-end-position))))
; For some reason the stem-end is a real instead of an integer...
(dir-modifier (if (ly:position-on-line? stem-grob stem-end) "1" "0"))
(modifier (if adjust dir-modifier "2")))
- (create-glyph-flag "mensural" modifier stem-grob)))
+ (create-glyph-flag "mensural" modifier grob)))
-(define-public ((glyph-flag flag-style) stem-grob)
+(define-public ((glyph-flag flag-style) grob)
"Simulatesthe default way of generating flags: Look up glyphs
@code{flags.style[ud][1234]} from the feta font and use it for the flag
stencil."
- (create-glyph-flag flag-style "" stem-grob))
+ (create-glyph-flag flag-style "" grob))
-(define-public (normal-flag stem-grob)
+(define-public (normal-flag grob)
"Create a default flag."
- (create-glyph-flag "" "" stem-grob))
+ (create-glyph-flag "" "" grob))
-(define-public (default-flag stem-grob)
+(define-public (default-flag grob)
"Create a flag stencil for the stem. Its style will be derived from the
-@code{'flag-style} Stem property. By default, @code{lilypond} uses a
+@code{'style} Flag property. By default, @code{lilypond} uses a
C++ Function (which is slightly faster) to do exactly the same as this
function. However, if one wants to modify the default flags, this function
can be used to obtain the default flag stencil, which can then be modified
at will. The correct way to do this is:
@example
-\\override Stem #'flag = #default-flag
-\\override Stem #'flag-style = #'mensural
+\\override Flag #'stencil = #default-flag
+\\override Flag #'style = #'mensural
@end example
"
- (let* ((flag-style-symbol (ly:grob-property stem-grob 'flag-style))
+ (let* ((stem-grob (ly:grob-parent grob X))
+ (flag-style-symbol (ly:grob-property grob 'style))
(flag-style (if (symbol? flag-style-symbol)
(symbol->string flag-style-symbol)
"")))
(cond
- ((equal? flag-style "") (normal-flag stem-grob))
- ((equal? flag-style "mensural") (mensural-flag stem-grob))
- ((equal? flag-style "no-flag") (no-flag stem-grob))
- (else ((glyph-flag flag-style) stem-grob)))))
+ ((equal? flag-style "") (normal-flag grob))
+ ((equal? flag-style "mensural") (mensural-flag grob))
+ ((equal? flag-style "no-flag") (no-flag grob))
+ (else ((glyph-flag flag-style) grob)))))
(make-property-set 'graceSettings
;; TODO: take this from voicedGraceSettings or similar.
'((Voice Stem font-size -3)
+ (Voice Flag font-size -3)
(Voice NoteHead font-size -3)
(Voice TabNoteHead font-size -4)
(Voice Dots font-size -3)