+2005-10-05 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+ * lily/horizontal-bracket.cc (make_bracket): new function.
+
+ * scm/define-grobs.scm (all-grob-descriptions): new grobs
+ NewBassFigure, BassFigureBracket, BassFigureContinuation,
+ BassFigureLine, BassFigureAlignment
+
+ * lily/new-figured-bass-engraver.cc (process_music): new file.
+
+ * lily/figured-bass-continuation.cc: new file.
+
+ * lily/include/horizontal-bracket.hh (struct Horizontal_bracket):
+ new file.
+
2005-10-04 Mats Bengtsson <mabe@drongo.s3.kth.se>
* scripts/lilypond-book.py: Bug fix, put the quote around the
if (a == Y_AXIS
&& me_spanner)
{
+#if 0
+ /*
+ TODO: messes up for figured bass alignments.
+ */
if (me_spanner->get_bound (LEFT)->break_status_dir () == CENTER)
me->warning (_ ("vertical alignment called before line-breaking. "
"Only do cross-staff spanners with PianoStaff."));
+#endif
SCM details = me_spanner->get_bound (LEFT)->get_property ("line-break-system-details");
SCM extra_space_handle = scm_assoc (ly_symbol2scm ("alignment-extra-space"), details);
--- /dev/null
+/*
+ figured-bass-continuation.cc -- implement Figured_bass_continuation
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+*/
+
+#include "line-interface.hh"
+#include "lily-guile.hh"
+#include "spanner.hh"
+#include "output-def.hh"
+#include "item.hh"
+#include "stencil.hh"
+#include "pointer-group-interface.hh"
+#include "axis-group-interface.hh"
+
+
+#include "horizontal-bracket.hh"
+
+struct Figured_bass_bracket
+{
+ static bool has_interface (Grob*);
+
+public:
+ DECLARE_SCHEME_CALLBACK(print, (SCM));
+};
+
+
+ADD_INTERFACE(Figured_bass_bracket,
+ "figured-bass-bracket-interface",
+ "Brackets alongside bass figures.",
+
+ /* props */
+
+ /* ugh: should make bracket interface. */
+ "bracket-flare "
+ "shorten-pair "
+ "edge-height "
+ "padding "
+ "thickness "
+ "elements "
+ );
+
+MAKE_SCHEME_CALLBACK (Figured_bass_bracket, print, 1);
+SCM
+Figured_bass_bracket::print (SCM grob)
+{
+ Grob *me = unsmob_grob (grob);
+ extract_grob_set (me, "elements", elements);
+ if (elements.is_empty ())
+ {
+ me->suicide ();
+ return SCM_EOL;
+ }
+
+ Grob *common_x = common_refpoint_of_array (elements, me, X_AXIS);
+ Interval xext = Axis_group_interface::relative_group_extent (elements, common_x, X_AXIS);
+
+ Stencil left_br = Horizontal_bracket::make_bracket (me, me, elements,
+ Y_AXIS, LEFT);
+ Stencil right_br = Horizontal_bracket::make_bracket (me, me, elements,
+ Y_AXIS, RIGHT);
+
+ xext.widen (robust_scm2double (me->get_property ("padding"), 0.25));
+ left_br.translate_axis (xext[LEFT], X_AXIS);
+ right_br.translate_axis (xext[RIGHT], X_AXIS);
+
+ left_br.add_stencil (right_br);
+ left_br.translate_axis (-me->relative_coordinate (common_x, X_AXIS), X_AXIS);
+ return left_br.smobbed_copy ();
+}
+
+
+struct Figured_bass_continuation
+{
+ static bool has_interface (Grob*);
+
+public:
+ DECLARE_SCHEME_CALLBACK(print, (SCM));
+ DECLARE_SCHEME_CALLBACK(center_on_figures, (SCM, SCM));
+};
+
+MAKE_SCHEME_CALLBACK (Figured_bass_continuation, center_on_figures, 2);
+SCM
+Figured_bass_continuation::center_on_figures (SCM grob, SCM axis)
+{
+ Spanner *me = dynamic_cast<Spanner*> (unsmob_grob (grob));
+ (void) axis;
+
+ extract_grob_set (me, "figures", figures);
+ Grob *common = common_refpoint_of_array (figures, me, Y_AXIS);
+
+ Interval ext = Axis_group_interface::relative_group_extent (figures, common, Y_AXIS);
+
+ return scm_from_double (ext.center () - me->relative_coordinate (common, Y_AXIS));
+}
+
+MAKE_SCHEME_CALLBACK (Figured_bass_continuation, print, 1);
+SCM
+Figured_bass_continuation::print (SCM grob)
+{
+ Spanner *me = dynamic_cast<Spanner*> (unsmob_grob (grob));
+
+ Real thick =
+ me->get_layout ()->get_dimension (ly_symbol2scm ("linethickness"))
+ * robust_scm2double (me->get_property ("thickness"), 1);
+
+ Interval spanned;
+ Direction d = LEFT;
+ Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT),
+ X_AXIS);
+ do
+ {
+ spanned[d]
+ = robust_relative_extent (me->get_bound (d), common, X_AXIS)[RIGHT]
+ - me->relative_coordinate (common, X_AXIS);
+ }
+ while (flip (&d) != LEFT);
+
+ Stencil extender
+ = Line_interface::make_line (thick,
+ Offset (spanned[LEFT], 0),
+ Offset (spanned[RIGHT], 0));
+
+ return extender.smobbed_copy ();
+}
+
+ADD_INTERFACE(Figured_bass_continuation,
+ "figured-bass-continuation-interface",
+ "Simple extender line between bounds.",
+
+ /* props */
+ "thickness "
+ "figures "
+ );
+
#include "item.hh"
#include "context.hh"
+#include "translator.icc"
+
class Figured_bass_engraver : public Engraver
{
TRANSLATOR_DECLARATIONS (Figured_bass_engraver);
}
}
-#include "translator.icc"
-
ADD_TRANSLATOR (Figured_bass_engraver,
/* doc */ "Make figured bass numbers.",
/* create */ "BassFigure",
#include "output-def.hh"
#include "staff-symbol-referencer.hh"
#include "tuplet-bracket.hh" // ugh.
-
-struct Horizontal_bracket
-{
- DECLARE_SCHEME_CALLBACK (print, (SCM));
- static bool has_interface (Grob *);
-};
+#include "horizontal-bracket.hh" // ugh.
/*
TODO:
Support texts on the brackets?
*/
-MAKE_SCHEME_CALLBACK (Horizontal_bracket, print, 1);
-SCM
-Horizontal_bracket::print (SCM smob)
+Stencil
+Horizontal_bracket::make_bracket (Grob *me, Grob *common,
+ Link_array<Grob> grobs, Axis a, Direction dir)
{
- Grob *me = unsmob_grob (smob);
- Spanner *sp = dynamic_cast<Spanner *> (me);
+ Axis other = other_axis (a);
+
+ Grob *cx = common_refpoint_of_array (grobs, common, a);
- extract_grob_set (me, "columns", gs);
- if (!gs.size ())
- {
- me->suicide ();
- return SCM_EOL;
- }
- Grob *cx = common_refpoint_of_array (gs, me, X_AXIS);
- cx = cx->common_refpoint (sp->get_bound (LEFT), X_AXIS);
- cx = cx->common_refpoint (sp->get_bound (RIGHT), X_AXIS);
-
- Interval ext = gs.top ()->extent (cx, X_AXIS);
- ext.unite (gs[0]->extent (cx, X_AXIS));
+ Interval ext = grobs.top ()->extent (cx, a);
+ ext.unite (grobs[0]->extent (cx, a));
Drul_array<Real> edge_height = robust_scm2interval (me->get_property ("edge-height"),
Interval (1.0, 1.0));
-
Drul_array<Real> flare = robust_scm2interval (me->get_property ("bracket-flare"),
Interval (0, 0));
-
Drul_array<Real> shorten = robust_scm2interval (me->get_property ("shorten-pair"),
Interval (0, 0));
// Make sure that it points in the correct direction:
- Real dir = get_grob_direction (me);
- scale_drul (&edge_height, -dir);
+ scale_drul (&edge_height, Real (-dir));
Interval empty;
+ Offset start;
+ start[a] = ext.length ();
Stencil b
- = Tuplet_bracket::make_bracket (me, Y_AXIS, Offset (ext.length (), 0),
+ = Tuplet_bracket::make_bracket (me, other, start,
edge_height, empty, flare, shorten);
- b.translate_axis (ext[LEFT] - sp->get_bound (LEFT)->relative_coordinate (cx, X_AXIS), X_AXIS);
+ b.translate_axis (ext[LEFT], a);
+
+ return b;
+}
+
+MAKE_SCHEME_CALLBACK (Horizontal_bracket, print, 1);
+SCM
+Horizontal_bracket::print (SCM smob)
+{
+ Grob *me = unsmob_grob (smob);
+ Spanner *sp = dynamic_cast<Spanner *> (me);
+
+ extract_grob_set (me, "columns", gs);
+ if (!gs.size ())
+ {
+ me->suicide ();
+ return SCM_EOL;
+ }
+
+ Grob *cx = me->common_refpoint (sp->get_bound (LEFT), X_AXIS);
+ cx = cx->common_refpoint (sp->get_bound (RIGHT), X_AXIS);
+
+ Stencil b = make_bracket (me, cx, gs, X_AXIS, get_grob_direction (me));
+
+ b.translate_axis (- sp->get_bound (LEFT)->relative_coordinate (cx, X_AXIS), X_AXIS);
return b.smobbed_copy ();
}
ADD_INTERFACE (Horizontal_bracket, "horizontal-bracket-interface",
"A horizontal bracket encompassing notes.",
- "columns bracket-flare shorten-pair edge-height");
+
+ /* props */
+ "columns "
+ "bracket-flare "
+ "shorten-pair "
+ "edge-height");
--- /dev/null
+/*
+ horizontal-bracket.hh -- declare Horizontal_bracket
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
+*/
+
+#ifndef HORIZONTAL_BRACKET_HH
+#define HORIZONTAL_BRACKET_HH
+
+struct Horizontal_bracket
+{
+ DECLARE_SCHEME_CALLBACK (print, (SCM));
+ static Stencil make_bracket (Grob *, Grob *, Link_array<Grob>, Axis, Direction);
+ static bool has_interface (Grob *);
+};
+
+#endif /* HORIZONTAL_BRACKET_HH */
--- /dev/null
+/*
+ new-figured-bass-engraver.cc -- implement New_figured_bass_engraver
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+*/
+
+#include "engraver.hh"
+
+#include "context.hh"
+#include "music.hh"
+#include "item.hh"
+#include "spanner.hh"
+#include "axis-group-interface.hh"
+#include "align-interface.hh"
+#include "pointer-group-interface.hh"
+#include "text-interface.hh"
+
+#include "translator.icc"
+
+struct Figure_group
+{
+ Spanner *group_;
+ Spanner *continuation_line_;
+
+ SCM number_;
+ SCM alteration_;
+
+ bool is_continuation_;
+ Item *figure_item_;
+ Music *current_music_;
+
+ Figure_group ()
+ {
+ is_continuation_ = false;
+ continuation_line_ = 0;
+ number_ = SCM_EOL;
+ alteration_ = SCM_EOL;
+ group_ = 0;
+ current_music_ = 0;
+ }
+};
+
+struct New_figured_bass_engraver : public Engraver
+{
+ TRANSLATOR_DECLARATIONS(New_figured_bass_engraver);
+ void finalize_spanners();
+ void add_brackets ();
+protected:
+ Array<Figure_group> groups_;
+ Spanner *alignment_;
+ Link_array<Music> new_musics_;
+ bool continuation_;
+ Moment stop_moment_;
+ Music *rest_event_;
+
+ virtual bool try_music (Music *);
+ virtual void finalize ();
+ virtual void derived_mark () const;
+
+ void start_translation_timestep ();
+ void stop_translation_timestep ();
+ void process_music ();
+};
+
+void
+New_figured_bass_engraver::derived_mark () const
+{
+ for (int i = 0; i < groups_.size (); i++)
+ {
+ scm_gc_mark (groups_[i].number_);
+ scm_gc_mark (groups_[i].alteration_);
+ }
+}
+
+void
+New_figured_bass_engraver::stop_translation_timestep ()
+{
+ if (groups_.is_empty ()
+ || now_mom ().main_part_ < stop_moment_.main_part_)
+ return ;
+
+ bool found = false;
+ for (int i = 0; !found && i < groups_.size (); i++)
+ found = found || groups_[i].current_music_;
+
+ if (!found)
+ finalize_spanners ();
+}
+
+New_figured_bass_engraver::New_figured_bass_engraver ()
+{
+ alignment_ = 0;
+ continuation_ = false;
+ rest_event_ = 0;
+}
+
+void
+New_figured_bass_engraver::start_translation_timestep ()
+{
+ if (now_mom ().main_part_ < stop_moment_.main_part_)
+ return ;
+
+ rest_event_ = 0;
+ new_musics_.clear ();
+ for (int i = 0; i < groups_.size (); i++)
+ {
+ groups_[i].current_music_ = 0;
+ groups_[i].is_continuation_ = false;
+ }
+ continuation_ = false;
+}
+
+bool
+New_figured_bass_engraver::try_music (Music *m)
+{
+ if (m->is_mus_type ("rest-event"))
+ {
+ rest_event_ = m;
+ return true;
+ }
+ else
+ {
+ SCM fig = m->get_property ("figure");
+ for (int i = 0; i < groups_.size (); i++)
+ {
+ if (ly_is_equal (groups_[i].number_, fig))
+ {
+ groups_[i].current_music_ = m;
+ groups_[i].is_continuation_ =
+ ly_is_equal (groups_[i].alteration_,
+ m->get_property ("alteration"));
+
+ continuation_ = true;
+ return true;
+ }
+ }
+
+ new_musics_.push (m);
+
+ stop_moment_ = now_mom () + m->get_length ();
+
+ return true;
+ }
+}
+void
+New_figured_bass_engraver::finalize_spanners ()
+{
+ if (!alignment_)
+ return;
+
+ alignment_ = 0;
+ groups_.clear ();
+}
+
+void
+New_figured_bass_engraver::add_brackets ()
+{
+ Link_array<Grob> encompass;
+ bool inside = false;
+ for (int i = 0; i < groups_.size (); i ++)
+ {
+ if (!groups_[i].current_music_)
+ continue;
+
+ if (to_boolean (groups_[i].current_music_->get_property ("bracket-start")))
+ {
+ inside = true;
+ }
+
+ if (inside && groups_[i].figure_item_)
+ encompass.push (groups_[i].figure_item_);
+
+ if (to_boolean (groups_[i].current_music_->get_property ("bracket-stop")))
+ {
+ inside = false;
+
+ Item * brack = make_item ("BassFigureBracket", groups_[i].current_music_->self_scm ());
+ for (int j = 0; j < encompass.size (); j++)
+ {
+ Pointer_group_interface::add_grob (brack,
+ ly_symbol2scm ("elements"),
+ encompass[j]);
+ }
+ encompass.clear ();
+ }
+ }
+}
+
+void
+New_figured_bass_engraver::process_music ()
+{
+ if (rest_event_)
+ {
+ finalize_spanners ();
+ return;
+ }
+
+ if (!continuation_
+ && new_musics_.is_empty ())
+ {
+ finalize_spanners ();
+ return;
+ }
+
+ Grob *muscol = dynamic_cast<Item*> (unsmob_grob (get_property ("currentMusicalColumn")));
+ if (!continuation_)
+ {
+ finalize_spanners ();
+ alignment_ = make_spanner ("BassFigureAlignment", SCM_EOL);
+ alignment_->set_bound (LEFT, muscol);
+ }
+
+ int k = 0;
+ for (int i = 0; i < new_musics_.size (); i++)
+ {
+ while (k < groups_.size() &&
+ groups_[k].current_music_)
+ k++;
+
+ if (k >= groups_.size ())
+ {
+ Figure_group group;
+ groups_.push (group);
+ }
+
+
+ groups_[k].current_music_ = new_musics_[i];
+ groups_[k].figure_item_ = 0;
+ k++;
+ }
+
+ SCM proc = get_property ("newFiguredBassFormatter");
+
+ alignment_->set_bound (RIGHT, muscol);
+ if (to_boolean (get_property ("useBassFigureExtenders")))
+ for (int i = 0; i < groups_.size(); i++)
+ {
+ if (groups_[i].is_continuation_)
+ {
+ if (!groups_[i].continuation_line_)
+ {
+ Spanner * line = make_spanner ("BassFigureContinuation", SCM_EOL);
+ Item * item = groups_[i].figure_item_;
+ groups_[i].continuation_line_ = line;
+ line->set_bound (LEFT, item);
+
+ /*
+ Don't add as child. This will cache the wrong
+ (pre-break) stencil when callbacks are triggered.
+ */
+ line->set_parent (groups_[i].group_, Y_AXIS);
+ Pointer_group_interface::add_grob (line, ly_symbol2scm ("figures"), item);
+
+ groups_[i].figure_item_ = 0;
+ }
+ }
+ else
+ groups_[i].continuation_line_ = 0;
+ }
+
+ for (int i = 0; i < groups_.size(); i++)
+ {
+ Figure_group &group = groups_[i];
+
+ if (group.continuation_line_)
+ {
+ group.continuation_line_->set_bound (RIGHT, muscol);
+ }
+ else if (group.current_music_)
+ {
+ Item *item
+ = make_item ("NewBassFigure",
+ group.current_music_->self_scm ());
+ SCM fig = group.current_music_->get_property ("figure");
+ if (!group.group_)
+ {
+ group.group_ = make_spanner ("BassFigureLine", SCM_EOL);
+ group.group_->set_bound (LEFT, muscol);
+ Align_interface::add_element (alignment_,
+ group.group_,
+ Align_interface::alignment_callback_proc);
+ }
+
+
+ group.number_ = fig;
+ group.alteration_ = group.current_music_->get_property ("alteration");
+
+ SCM text = group.current_music_->get_property ("text");
+ if (!Text_interface::is_markup (text)
+ && ly_is_procedure (proc))
+ {
+ text = scm_call_3 (proc, fig, group.current_music_->self_scm (),
+ context ()->self_scm ());
+ }
+
+ item->set_property ("text", text);
+
+ Axis_group_interface::add_element (group.group_, item);
+ group.figure_item_ = item;
+ }
+
+ groups_[i].group_->set_bound (RIGHT, muscol);
+ }
+
+ add_brackets ();
+}
+
+void
+New_figured_bass_engraver::finalize ()
+{
+ finalize_spanners ();
+}
+
+
+ADD_TRANSLATOR (New_figured_bass_engraver,
+ /* doc */
+
+ "Make figured bass numbers.",
+ /* create */
+ "BassFigure BassFigureLine BassFigureAlignment BassFigureBracket",
+
+ /* accept */
+ "bass-figure-event rest-event",
+
+ /* read */
+ "useBassFigureExtenders",
+
+ /* write */
+ "");
deleting them. Let's hope that a stack overflow doesnt trigger a move
of the parse stack onto the heap. */
+%left PREC_TOP
%left ADDLYRICS
+%left PREC_BOT
%union {
Book *book;
%type <scm> assignment_id
%type <scm> bare_number
%type <scm> bass_figure
-%type <scm> bass_number
%type <scm> br_bass_figure
+%type <scm> bass_number
%type <scm> chord_body_elements
%type <scm> chord_item
%type <scm> chord_items
bass_number:
DIGIT {
- $$ = scm_number_to_string (scm_from_int ($1), scm_from_int (10));
- $$ = scm_list_2 (ly_lily_module_constant ("number-markup"),
- $$);
+ $$ = scm_from_int ($1);
}
| UNSIGNED {
- $$ = scm_number_to_string (scm_from_int ($1), scm_from_int (10));
- $$ = scm_list_2 (ly_lily_module_constant ("number-markup"),
- $$);
+ $$ = scm_from_int ($1);
}
| STRING { $$ = $1; }
| full_markup { $$ = $1; }
Music *bfr = MY_MAKE_MUSIC ("BassFigureEvent");
$$ = bfr->self_scm ();
- bfr->set_property ("figure", $1);
+ if (scm_is_number ($1))
+ bfr->set_property ("figure", $1);
+ else if (Text_interface::is_markup ($1))
+ bfr->set_property ("text", $1);
+
bfr->unprotect ();
}
+ | bass_figure ']' {
+ $$ = $1;
+ unsmob_music ($1)->set_property ("bracket-stop", SCM_BOOL_T);
+ }
| bass_figure bass_mod {
Music *m = unsmob_music ($1);
if ($2) {
}
;
+
br_bass_figure:
- '[' bass_figure {
- $$ = $2;
- unsmob_music ($$)->set_property ("bracket-start", SCM_BOOL_T);
- }
- | bass_figure {
+ bass_figure {
$$ = $1;
}
- | br_bass_figure ']' {
- $$ = $1;
- unsmob_music ($1)->set_property ("bracket-stop", SCM_BOOL_T);
+ | '[' bass_figure {
+ $$ = $2;
+ unsmob_music ($$)->set_property ("bracket-start", SCM_BOOL_T);
}
;
%%
bassFigureFormatFunction = #format-bass-figure
+ newFiguredBassFormatter = #format-new-bass-figure
metronomeMarkFormatter = #format-metronome-markup
graceSettings = #`(
(Voice Stem direction 1)
\name FiguredBass
\consists "Figured_bass_engraver"
- \consists "Rest_swallow_translator"
\consists "Note_swallow_translator"
\consists "Skip_event_swallow_translator"
\consists "Separating_line_group_engraver"
"A bass figure, including bracket"
'())
+
+(define-public (format-new-bass-figure figure event context)
+ (let* ((fig (ly:music-property event 'figure))
+ (fig-markup (markup #:number (number->string figure 10)))
+
+ (alt (ly:music-property event 'alteration))
+ (alt-markup
+ (if (number? alt)
+ (alteration->text-accidental-markup alt)
+ #f))
+ (alt-dir (ly:context-property context 'figuredBassAlterationDirection))
+
+ )
+
+ (if alt-markup
+ (set! fig-markup
+ (markup #:put-adjacent fig-markup X
+ (if (number? alt-dir)
+ alt-dir
+ LEFT)
+ #:raise .33
+ #:pad-around 0.5 #:smaller alt-markup )))
+
+ fig-markup))
+
(define-public (format-bass-figure figures context grob)
;; TODO: support slashed numerals here.
(define (fig-to-markup fig-music)
(lambda (x)
(apply translator-property-description x))
`(
+
+ ;; TODO FIXME
+ (useBassFigureExtenders ,boolean? "")
+ (figuredBassAlterationDirection ,ly:dir? "")
+
(aDueText ,string? "Text to print at a unisono passage.")
(alignBelowContext ,string? "Where to insert newly created context in vertiical alignment.")
(alignAboveContext ,string? "Where to insert newly created context in vertiical alignment.")
bass-figure-interface
self-alignment-interface
font-interface))))))
+
+ (NewBassFigure
+ . (
+ (print-function . ,Text_interface::print)
+ (meta . ((class . Item)
+ (interfaces . (text-interface
+ rhythmic-grob-interface
+ bass-figure-interface
+ font-interface))))))
+
+ (BassFigureBracket
+ . ((print-function . ,Figured_bass_bracket::print)
+ (edge-height . (0.2 . 0.2))
+ (meta . ((class . Item)
+ (interfaces . (figured-bass-bracket-interface)) ))
+ ))
+ (BassFigureContinuation
+ . (
+ (print-function . ,Figured_bass_continuation::print)
+ (Y-offset-callbacks . (,Figured_bass_continuation::center_on_figures))
+ (meta . ((class . Spanner)
+ (interfaces . (figured-bass-continuation-interface))
+ ))))
+ (BassFigureLine
+ . (
+ (axes . (,Y))
+ (Y-extent-callback . ,Axis_group_interface::group_extent_callback)
+ (meta . ((class . Spanner)
+ (interfaces . (axis-group-interface
+ ))))))
+
+ (BassFigureAlignment
+ . (
+ (axes . (,Y))
+ (threshold . (2.4 . 1000))
+ (Y-extent-callback . ,Axis_group_interface::group_extent_callback)
+ (stacking-dir . -1)
+ (meta . ((class . Spanner)
+ (interfaces . (align-interface
+ axis-group-interface))))))
+
(Beam
. (
;; todo: clean this up a bit: the list is getting
(ly:stencil-aligned-to m X dir)))
+(def-markup-command (pad-around layout props amount arg) (number? markup?)
+
+ "Add padding @var{amount} all around @var{arg}. "
+
+ (let*
+ ((m (interpret-markup layout props arg))
+ (x (ly:stencil-extent m X))
+ (y (ly:stencil-extent m Y)))
+
+
+ (ly:make-stencil (ly:stencil-expr m)
+ (interval-widen x amount)
+ (interval-widen y amount))
+ ))
+(def-markup-command (put-adjacent layout props arg1 axis dir arg2) (markup? integer? ly:dir? markup?)
+
+ "Put @var{arg2} next to @var{arg1}, without moving @var{arg1}. "
+
+ (let* ((m1 (interpret-markup layout props arg1))
+ (m2 (interpret-markup layout props arg2)))
+
+ (ly:stencil-combine-at-edge m1 axis dir m2 0.0 0.0)
+ ))
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; property
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;