From: Mike Solomon Date: Sun, 27 Feb 2011 13:34:38 +0000 (-0500) Subject: bad X-Git-Tag: release/2.13.52-1~23 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=82a9add4f1d4790bddb79459d5f63b01b3e7cc97;p=lilypond.git bad --- diff --git a/lily/balloon.cc b/lily/balloon.cc index f4efd4c489..672fb95a4d 100644 --- a/lily/balloon.cc +++ b/lily/balloon.cc @@ -19,17 +19,21 @@ #include "text-interface.hh" #include "grob.hh" +#include "item.hh" #include "line-interface.hh" #include "lookup.hh" #include "font-interface.hh" #include "lily-guile.hh" #include "output-def.hh" #include "misc.hh" +#include "spanner.hh" +#include "international.hh" class Balloon_interface { public: DECLARE_SCHEME_CALLBACK (print, (SCM)); + DECLARE_SCHEME_CALLBACK (print_spanner, (SCM)); DECLARE_GROB_INTERFACE (); }; @@ -51,7 +55,9 @@ Balloon_interface::print (SCM smob) b.widen (padding, padding); // FIXME - Stencil fr = Lookup::frame (b, 0.1, 0.05); + Stencil fr; + if (to_boolean (me->get_property ("annotation-balloon"))) + fr = Lookup::frame (b, 0.1, 0.05); SCM bt = me->get_property ("text"); SCM chain = Font_interface::text_font_alist_chain (me); @@ -71,7 +77,77 @@ Balloon_interface::print (SCM smob) Offset z2 = z1 + off; - fr.add_stencil (Line_interface::line (me, z1, z2)); + if (to_boolean (me->get_property ("annotation-line"))) + fr.add_stencil (Line_interface::line (me, z1, z2)); + + text_stil->translate (z2); + fr.add_stencil (*text_stil); + + fr.translate (-off); + return fr.smobbed_copy (); +} + +// ugh...code dup...hopefully can be consolidated w/ above one day +MAKE_SCHEME_CALLBACK (Balloon_interface, print_spanner, 1); +SCM +Balloon_interface::print_spanner (SCM smob) +{ + Spanner *me = unsmob_spanner (smob); + Spanner *parent = unsmob_spanner (me->get_property ("parent-spanner")); + Spanner *p; + message (_f ("foo %d", robust_scm2int (me->get_property ("spanner-to-annotate"), 0))); + message (_f ("bar %d", robust_scm2int (me->broken_intos_[0]->get_property ("spanner-to-annotate"), 0))); + if (parent->broken_intos_.size () == 0) + p = parent; + else + p = parent->broken_intos_[robust_scm2int (me->get_property ("spanner-to-annotate"), 0) % parent->broken_intos_.size ()]; + + + Drul_array bounds; + Direction d = LEFT; + + do + { + bounds[d] = me->get_bound (d); + } + while (flip (&d) != LEFT); + + Grob *commonx = bounds[LEFT]->common_refpoint (bounds[RIGHT], X_AXIS); + + Offset off (me->relative_coordinate (commonx, X_AXIS), + me->relative_coordinate (p, Y_AXIS)); + + Box b (p->extent (p, X_AXIS), + p->extent (p, Y_AXIS)); + + Real padding = robust_scm2double (me->get_property ("padding"), .1); + b.widen (padding, padding); + + // FIXME + Stencil fr; + if (to_boolean (me->get_property ("annotation-balloon"))) + fr = Lookup::frame (b, 0.1, 0.05); + + SCM bt = me->get_property ("text"); + SCM chain = Font_interface::text_font_alist_chain (me); + + SCM stencil = Text_interface::interpret_markup (me->layout ()->self_scm (), + chain, bt); + + Stencil *text_stil = unsmob_stencil (stencil); + + Offset z1; + for (int i = X_AXIS; i < NO_AXES; i++) + { + Axis a ((Axis)i); + z1[a] = b[a].linear_combination (sign (off[a])); + text_stil->align_to (a, -sign (off[a])); + } + + Offset z2 = z1 + off; + + if (to_boolean (me->get_property ("annotation-line"))) + fr.add_stencil (Line_interface::line (me, z1, z2)); text_stil->translate (z2); fr.add_stencil (*text_stil); @@ -85,7 +161,10 @@ ADD_INTERFACE (Balloon_interface, " object.", /* properties */ + "annotation-balloon " + "annotation-line " "padding " + "spanner-to-annotate " "text " ); diff --git a/lily/constrained-breaking.cc b/lily/constrained-breaking.cc index fdcd645866..f6f84b8090 100644 --- a/lily/constrained-breaking.cc +++ b/lily/constrained-breaking.cc @@ -519,6 +519,8 @@ Constrained_breaking::fill_line_details (Line_details *const out, vsize start, v out->title_space_ = system_markup_space_; out->inverse_hooke_ = out->full_height () + system_system_space_; + out->footnotes_ = sys->get_footnotes_in_range (start_rank, end_rank); + out->refpoint_extent_ = sys->pure_refpoint_extent (start_rank, end_rank); if (out->refpoint_extent_.is_empty ()) out->refpoint_extent_ = Interval (0, 0); @@ -550,6 +552,11 @@ Line_details::Line_details (Prob *pb, Output_def *paper) Page_layout_problem::read_spacing_spec (spec, &min_distance_, ly_symbol2scm ("minimum-distance")); Page_layout_problem::read_spacing_spec (title_spec, &title_min_distance_, ly_symbol2scm ("minimum-distance")); + SCM footnotes = pb->get_property ("footnotes"); + if (scm_is_pair (footnotes)) + for (SCM s = footnotes; scm_is_pair (s); s = scm_cdr (s)) + footnotes_.push_back (unsmob_stencil (scm_car (s))); + last_column_ = 0; force_ = 0; Interval stencil_extent = unsmob_stencil (pb->get_property ("stencil"))->extent (Y_AXIS); diff --git a/lily/dynamic-align-engraver.cc b/lily/dynamic-align-engraver.cc index 43498089d0..e34554e654 100644 --- a/lily/dynamic-align-engraver.cc +++ b/lily/dynamic-align-engraver.cc @@ -37,6 +37,7 @@ class Dynamic_align_engraver : public Engraver DECLARE_TRANSLATOR_LISTENER (break_span); DECLARE_ACKNOWLEDGER (note_column); DECLARE_ACKNOWLEDGER (dynamic); + DECLARE_ACKNOWLEDGER (footnote_spanner); DECLARE_END_ACKNOWLEDGER (dynamic); protected: @@ -63,6 +64,7 @@ Dynamic_align_engraver::Dynamic_align_engraver () ADD_ACKNOWLEDGER (Dynamic_align_engraver, dynamic); ADD_ACKNOWLEDGER (Dynamic_align_engraver, note_column); +ADD_ACKNOWLEDGER (Dynamic_align_engraver, footnote_spanner); ADD_END_ACKNOWLEDGER (Dynamic_align_engraver, dynamic); void @@ -80,6 +82,17 @@ Dynamic_align_engraver::acknowledge_end_dynamic (Grob_info info) ended_.push_back (info.spanner ()); } +void +Dynamic_align_engraver::acknowledge_footnote_spanner (Grob_info info) +{ + Grob *parent = unsmob_grob (info.grob ()->get_property ("parent-spanner")); + if (line_ && parent + && parent->internal_has_interface (ly_symbol2scm ("dynamic-interface")) + && (scm_to_int (line_->get_property ("direction")) + * robust_scm2double (info.grob ()->get_property ("Y-offset"), 0.0) > 0.0)) { + Axis_group_interface::add_element (line_, info.grob ());message ("ADD"); } +} + void Dynamic_align_engraver::acknowledge_note_column (Grob_info info) { diff --git a/lily/include/constrained-breaking.hh b/lily/include/constrained-breaking.hh index fc1b44e41f..52d99b6ba2 100644 --- a/lily/include/constrained-breaking.hh +++ b/lily/include/constrained-breaking.hh @@ -44,6 +44,7 @@ struct Line_details { Grob *last_column_; Real force_; Line_shape shape_; + vector footnotes_; Interval refpoint_extent_; /* The refpoints of the first and last spaceable staff in this line. min-distance should be measured from the bottom diff --git a/lily/include/page-breaking.hh b/lily/include/page-breaking.hh index b34b6c4c84..fa68c61752 100644 --- a/lily/include/page-breaking.hh +++ b/lily/include/page-breaking.hh @@ -124,6 +124,8 @@ public: Real page_height (int page_number, bool last) const; Real paper_height () const; vsize system_count () const; + Real footnote_separator_stencil_height () const; + Real footnote_padding () const; Real line_count_penalty (int line_count) const; int line_count_status (int line_count) const; bool too_many_lines (int line_count) const; @@ -145,6 +147,7 @@ protected: void break_into_pieces (vsize start, vsize end, Line_division const &div); SCM systems (); + SCM footnotes (); void set_current_breakpoints (vsize start, vsize end, @@ -184,6 +187,8 @@ private: int max_systems_per_page_; int min_systems_per_page_; vsize system_count_; + Real footnote_separator_stencil_height_; + Real footnote_padding_; int orphan_penalty_; vector current_configurations_; diff --git a/lily/include/page-layout-problem.hh b/lily/include/page-layout-problem.hh index 941ccef2a7..fb1c7c373d 100644 --- a/lily/include/page-layout-problem.hh +++ b/lily/include/page-layout-problem.hh @@ -34,8 +34,11 @@ public: static bool read_spacing_spec (SCM spec, Real* dest, SCM sym); static bool is_spaceable (Grob *g); static SCM get_details (Grob *g); + static SCM get_footnotes_from_lines (SCM lines, Real padding); + static Stencil* get_footnote_separator_stencil (Output_def *paper); static SCM get_spacing_spec (Grob *before, Grob *after, bool pure, int start, int end); static Real get_fixed_spacing (Grob *before, Grob *after, int spaceable_index, bool pure, int start, int end); + static void add_footnotes_to_footer (SCM footnotes, Stencil *foot, Paper_book *pb); protected: void append_system (System*, Spring const&, Real indent, Real padding); diff --git a/lily/include/page-spacing.hh b/lily/include/page-spacing.hh index be261735aa..206bcbf426 100644 --- a/lily/include/page-spacing.hh +++ b/lily/include/page-spacing.hh @@ -102,6 +102,7 @@ struct Page_spacing Real rod_height_; Real spring_len_; Real inverse_spring_k_; + bool has_footnotes_; Line_details last_line_; Line_details first_line_; @@ -111,11 +112,13 @@ struct Page_spacing { page_height_ = page_height; breaker_ = breaker; + has_footnotes_ = false; clear (); } void calc_force (); void resize (Real new_height); + Real account_for_footnotes (Line_details const &line); void append_system (const Line_details &line); void prepend_system (const Line_details &line); void clear (); diff --git a/lily/include/paper-system.hh b/lily/include/paper-system.hh index 96053d8d03..1aaa530b8a 100644 --- a/lily/include/paper-system.hh +++ b/lily/include/paper-system.hh @@ -30,5 +30,6 @@ */ Prob *make_paper_system (SCM immutable_init); void paper_system_set_stencil (Prob *prob, Stencil s); +SCM get_footnotes (SCM expr); #endif /* PAPER_SYSTEM_HH */ diff --git a/lily/include/system.hh b/lily/include/system.hh index 882f209f96..f4053da5e6 100644 --- a/lily/include/system.hh +++ b/lily/include/system.hh @@ -36,19 +36,25 @@ class System : public Spanner void init_elements (); friend class Paper_score; // ugh. Paper_score *pscore_; // ugh. - + vector footnote_grobs_; + public: Paper_score *paper_score () const; + vector footnotes_; Grob *get_vertical_alignment (); Grob *get_extremal_staff (Direction dir, Interval const&); Grob *get_pure_bound (Direction dir, int start, int end); Grob *get_maybe_pure_bound (Direction dir, bool pure, int start, int end); int get_rank () const; + vector get_footnotes_in_range (vsize st, vsize end); + Stencil make_footnote_stencil (Real padding); void do_break_substitution_and_fixup_refpoints (); void post_processing (); + void populate_footnote_grob_vector (); SCM get_paper_system (); SCM get_paper_systems (); SCM get_broken_system_grobs (); + SCM get_broken_footnote_stencils (); DECLARE_SCHEME_CALLBACK (calc_pure_relevant_grobs, (SCM)); DECLARE_SCHEME_CALLBACK (height, (SCM)); diff --git a/lily/page-breaking.cc b/lily/page-breaking.cc index 4e386b8183..25044078df 100644 --- a/lily/page-breaking.cc +++ b/lily/page-breaking.cc @@ -131,12 +131,14 @@ #include "international.hh" #include "item.hh" +#include "line-interface.hh" #include "output-def.hh" #include "page-layout-problem.hh" #include "page-spacing.hh" #include "paper-book.hh" #include "paper-score.hh" #include "paper-system.hh" +#include "text-interface.hh" #include "system.hh" #include "warn.hh" @@ -178,7 +180,12 @@ compress_lines (const vector &orig) // compressed.title_ is true if and only if the first of its // compressed lines was a title. - compressed.title_ = old.title_; + compressed.title_ = old.title_; + + // take care of footnotes + compressed.footnotes_.insert (compressed.footnotes_.begin (), + old.footnotes_.begin (), old.footnotes_.end ()); + ret.back () = compressed; } else @@ -243,6 +250,20 @@ Page_breaking::Page_breaking (Paper_book *pb, Break_predicate is_break, Prob_bre min_systems_per_page_ = max (0, robust_scm2int (pb->paper_->c_variable ("min-systems-per-page"), 0)); orphan_penalty_ = robust_scm2int (pb->paper_->c_variable ("orphan-penalty"), 100000); + Stencil *footnote_separator = Page_layout_problem::get_footnote_separator_stencil (pb->paper_); + + if (footnote_separator) + { + Interval separator_extent = footnote_separator->extent (Y_AXIS); + Real separator_span = max (separator_extent[UP] - separator_extent[DOWN], 0.0); + + footnote_separator_stencil_height_ = separator_span; + } + else + footnote_separator_stencil_height_ = 0.0; + + footnote_padding_ = robust_scm2double (pb->paper_->c_variable ("footnote-padding"), 0.0); + if (systems_per_page_ && (max_systems_per_page_ || min_systems_per_page_)) { warning (_f ("ignoring min-systems-per-page and max-systems-per-page because systems-per-page was set")); @@ -302,6 +323,18 @@ Page_breaking::system_count () const return system_count_; } +Real +Page_breaking::footnote_separator_stencil_height () const +{ + return footnote_separator_stencil_height_; +} + +Real +Page_breaking::footnote_padding () const +{ + return footnote_padding_; +} + bool Page_breaking::too_many_lines (int line_count) const { @@ -514,6 +547,12 @@ Page_breaking::draw_page (SCM systems, SCM configuration, int page_num, bool las Prob *p = unsmob_prob (page); p->set_property ("lines", paper_systems); p->set_property ("configuration", configuration); + + Stencil *foot = unsmob_stencil (p->get_property ("foot-stencil")); + SCM footnotes = Page_layout_problem::get_footnotes_from_lines (systems, footnote_padding ()); + Page_layout_problem::add_footnotes_to_footer (footnotes, foot, unsmob_paper_book (p->get_property ("paper-book"))); + + p->set_property ("foot-stencil", foot->smobbed_copy ()); scm_apply_1 (page_stencil, page, SCM_EOL); return page; @@ -559,6 +598,7 @@ Page_breaking::make_pages (vector lines_per_page, SCM systems) { SCM lines = scm_caar (s); SCM config = scm_cdar (s); + bool bookpart_last_page = (s == systems_and_configs); SCM page = draw_page (lines, config, page_num, bookpart_last_page); diff --git a/lily/page-layout-problem.cc b/lily/page-layout-problem.cc index c0af4dae1e..fa0689bf8f 100644 --- a/lily/page-layout-problem.cc +++ b/lily/page-layout-problem.cc @@ -32,6 +32,89 @@ #include "prob.hh" #include "skyline-pair.hh" #include "system.hh" +#include "text-interface.hh" + +SCM +Page_layout_problem::get_footnotes_from_lines (SCM lines, Real padding) +{ + SCM footnotes = SCM_EOL; + // ugh...code dup + for (SCM s = lines; scm_is_pair (s); s = scm_cdr (s)) + { + if (Grob *g = unsmob_grob (scm_car (s))) + { + System *sys = dynamic_cast (g); + if (!sys) + { + programming_error ("got a grob for footnotes that wasn't a System"); + continue; + } + footnotes = scm_cons (sys->make_footnote_stencil (padding).smobbed_copy (), footnotes); + } + else if (Prob *p = unsmob_prob (scm_car (s))) + { + SCM stencils = p->get_property ("footnotes"); + if (stencils == SCM_EOL) + continue; + Stencil footnote_stencil; + + for (SCM st = stencils; scm_is_pair (st); st = scm_cdr (st)) + footnote_stencil.add_at_edge (Y_AXIS, DOWN, *unsmob_stencil (scm_car (st)), padding); + footnotes = scm_cons (footnote_stencil.smobbed_copy (), footnotes); + } + } + + if (!scm_is_pair (footnotes)) + return SCM_EOL; + + return scm_reverse (footnotes); +} + +Stencil* +Page_layout_problem::get_footnote_separator_stencil (Output_def *paper) +{ + SCM props = scm_call_1 (ly_lily_module_constant ("layout-extract-page-properties"), + paper->self_scm ()); + + SCM markup = paper->c_variable ("footnote-separator-markup"); + + if (!Text_interface::is_markup (markup)) + return NULL; + + SCM footnote_stencil = Text_interface::interpret_markup (paper->self_scm (), + props, markup); + + Stencil *footnote_separator = unsmob_stencil (footnote_stencil); + + return footnote_separator; +} + +void +Page_layout_problem::add_footnotes_to_footer (SCM footnotes, Stencil *foot, Paper_book *pb) +{ + bool are_footnotes = false; + Real footnote_padding = robust_scm2double (pb->paper_->c_variable ("footnote-padding"), 0.0); + + footnotes = scm_reverse (footnotes); + for (SCM s = footnotes; scm_is_pair (s); s = scm_cdr (s)) + { + if (scm_car (s) == SCM_EOL) + continue; + Stencil *stencil = unsmob_stencil (scm_car (s)); + if (stencil->extent (Y_AXIS).length() > 0.0) + { + foot->add_at_edge (Y_AXIS, UP, *stencil, footnote_padding); + are_footnotes = true; + } + } + + if (are_footnotes) + { + Stencil *separator = get_footnote_separator_stencil (pb->paper_); + if (separator) + foot->add_at_edge (Y_AXIS, UP, *separator, footnote_padding); + } +} Page_layout_problem::Page_layout_problem (Paper_book *pb, SCM page_scm, SCM systems) : bottom_skyline_ (DOWN) @@ -47,7 +130,13 @@ Page_layout_problem::Page_layout_problem (Paper_book *pb, SCM page_scm, SCM syst { Stencil *head = unsmob_stencil (page->get_property ("head-stencil")); Stencil *foot = unsmob_stencil (page->get_property ("foot-stencil")); - + + Real footnote_padding = 0.0; + if (pb && pb->paper_) + footnote_padding = robust_scm2double (pb->paper_->c_variable ("footnote-padding"), 0.0); + SCM footnotes = get_footnotes_from_lines (systems, footnote_padding); + add_footnotes_to_footer (footnotes, foot, pb); + header_height_ = head ? head->extent (Y_AXIS).length () : 0; footer_height_ = foot ? foot->extent (Y_AXIS).length () : 0; page_height_ = robust_scm2double (page->get_property ("paper-height"), 100); diff --git a/lily/page-spacing.cc b/lily/page-spacing.cc index 17ba73d923..13c6a0c02a 100644 --- a/lily/page-spacing.cc +++ b/lily/page-spacing.cc @@ -19,6 +19,7 @@ #include "page-spacing.hh" +#include "international.hh" #include "matrix.hh" #include "page-breaking.hh" #include "warn.hh" @@ -59,6 +60,7 @@ Page_spacing::append_system (const Line_details &line) first_line_ = line; } + rod_height_ += account_for_footnotes (line); inverse_spring_k_ += line.inverse_hooke_; last_line_ = line; @@ -66,6 +68,25 @@ Page_spacing::append_system (const Line_details &line) calc_force (); } +Real +Page_spacing::account_for_footnotes (Line_details const &line) +{ + Real footnote_height = 0.0; + for (vsize i = 0; i < line.footnotes_.size (); i++) + { + footnote_height += (has_footnotes_ + ? 0.0 + : (breaker_->footnote_separator_stencil_height () + + breaker_->footnote_padding ())); + + has_footnotes_ = true; + Interval extent = line.footnotes_[i]->extent (Y_AXIS); + footnote_height += extent[UP] - extent[DOWN]; + footnote_height += breaker_->footnote_padding (); + } + return footnote_height; +} + void Page_spacing::prepend_system (const Line_details &line) { @@ -77,7 +98,7 @@ Page_spacing::prepend_system (const Line_details &line) rod_height_ -= first_line_.full_height (); rod_height_ += first_line_.tallness_; rod_height_ += line.full_height(); - + rod_height_ += account_for_footnotes (line); inverse_spring_k_ += line.inverse_hooke_; first_line_ = line; @@ -90,6 +111,7 @@ Page_spacing::clear () { force_ = rod_height_ = spring_len_ = 0; inverse_spring_k_ = 0; + has_footnotes_ = false; } diff --git a/lily/paper-book.cc b/lily/paper-book.cc index 4678ee3895..0de38c54fa 100644 --- a/lily/paper-book.cc +++ b/lily/paper-book.cc @@ -532,6 +532,9 @@ Paper_book::get_system_specs () list == texts? SCM_BOOL_T : SCM_BOOL_F); paper_system_set_stencil (ps, *unsmob_stencil (t)); + + SCM footnotes = get_footnotes (unsmob_stencil (t)->expr ()); + ps->set_property ("footnotes", scm_reverse (footnotes)); ps->set_property ("is-title", SCM_BOOL_T); if (list != texts) /* For each markup other than the first, place it as closely as diff --git a/lily/paper-system.cc b/lily/paper-system.cc index aef20f10c0..352334a0a7 100644 --- a/lily/paper-system.cc +++ b/lily/paper-system.cc @@ -27,6 +27,46 @@ make_paper_system (SCM immutable_init) return prob; } +SCM +get_footnotes (SCM expr) +{ + if (!scm_is_pair (expr)) + return SCM_EOL; + + SCM head = scm_car (expr); + + if (head == ly_symbol2scm ("delay-stencil-evaluation")) + { + // we likely need to do something here...just don't know what... + return SCM_EOL; + } + + if (head == ly_symbol2scm ("combine-stencil")) + { + SCM out = SCM_EOL; + for (SCM x = scm_cdr (expr); scm_is_pair (x); x = scm_cdr (x)) + { + SCM footnote = get_footnotes (scm_car (x)); + if (scm_is_pair (footnote)) + { + for (SCM y = scm_reverse (footnote); scm_is_pair (y); y = scm_cdr (y)) + out = scm_cons (scm_car (y), out); + } + else if (SCM_EOL != footnote) + out = scm_cons (footnote, out); + } + return out; + } + if (head == ly_symbol2scm ("translate-stencil")) + return get_footnotes (scm_caddr (expr)); + + if (head == ly_symbol2scm ("footnote")) + return scm_cadr (expr); + + return SCM_EOL; +} + + void paper_system_set_stencil (Prob *prob, Stencil s) { diff --git a/lily/stencil-interpret.cc b/lily/stencil-interpret.cc index 19c241ea84..4f8c6bbc8b 100644 --- a/lily/stencil-interpret.cc +++ b/lily/stencil-interpret.cc @@ -37,6 +37,8 @@ interpret_stencil_expression (SCM expr, interpret_stencil_expression (scm_force (scm_cadr (expr)), func, func_arg, o); return; } + if (head == ly_symbol2scm ("footnote")) + return; if (head == ly_symbol2scm ("translate-stencil")) { o += ly_scm2offset (scm_cadr (expr)); diff --git a/lily/system.cc b/lily/system.cc index 19279d7cd0..82c368e784 100644 --- a/lily/system.cc +++ b/lily/system.cc @@ -35,6 +35,7 @@ #include "pointer-group-interface.hh" #include "skyline-pair.hh" #include "staff-symbol-referencer.hh" +#include "text-interface.hh" #include "warn.hh" System::System (System const &src) @@ -162,7 +163,7 @@ System::do_break_substitution_and_fixup_refpoints () Grob *g = all_elts[j]; g->fixup_refpoint (); } - + count += all_elts.size (); } @@ -226,6 +227,61 @@ System::get_paper_systems () return lines; } +void +System::populate_footnote_grob_vector () +{ + extract_grob_set (this, "all-elements", all_elts); + for (vsize i = 0; i < all_elts.size (); i++) + { + if ((all_elts[i]->name () == "Footnote") || (all_elts[i]->name () == "FootnoteSpanner")) + footnote_grobs_.push_back (all_elts[i]); + } + sort (footnote_grobs_.begin (), footnote_grobs_.end (), Grob::less); + +} + +vector +System::get_footnotes_in_range (vsize st, vsize end) +{ + vector out; + if (footnote_grobs_.size () == 0) + populate_footnote_grob_vector (); + + for (vsize j = 0; j < footnote_grobs_.size (); j++) + { + if (footnote_grobs_[j]->spanned_rank_interval ()[LEFT] < (int)st) + continue; + if (footnote_grobs_[j]->spanned_rank_interval ()[LEFT] >= (int)end) + break; + SCM footnote_markup = footnote_grobs_[j]->get_property ("footnote-text"); + + if (!Text_interface::is_markup (footnote_markup)) + continue; + + SCM props = scm_call_1 (ly_lily_module_constant ("layout-extract-page-properties"), + pscore_->layout ()->self_scm ()); + + SCM footnote_stl = Text_interface::interpret_markup (pscore_->layout ()->self_scm (), + props, footnote_markup); + + Stencil *footnote_stencil = unsmob_stencil (footnote_stl); + out.push_back (footnote_stencil); + } + + return out; +} + +Stencil +System::make_footnote_stencil (Real padding) +{ + Stencil mol; + + for (vsize i = 0; i < footnotes_.size (); i++) + mol.add_at_edge (Y_AXIS, DOWN, *footnotes_[i], padding); + + return mol; +} + void System::break_into_pieces (vector const &breaking) { @@ -242,6 +298,8 @@ System::break_into_pieces (vector const &breaking) Interval iv (pure_height (this, st, end)); system->set_property ("pure-Y-extent", ly_interval2scm (iv)); + system->footnotes_ = get_footnotes_in_range (st, end); + system->set_bound (LEFT, c[0]); system->set_bound (RIGHT, c.back ()); SCM system_labels = SCM_EOL; diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly index 28c7c9706f..e8d39ab560 100644 --- a/ly/engraver-init.ly +++ b/ly/engraver-init.ly @@ -534,6 +534,7 @@ automatically when an output definition (a @code{\score} or \consists "Stanza_number_align_engraver" \consists "Bar_number_engraver" \consists "Parenthesis_engraver" + \consists "Footnote_engraver" \defaultchild "Staff" diff --git a/ly/music-functions-init.ly b/ly/music-functions-init.ly index ac62bffa9a..2ebbd8f1bc 100644 --- a/ly/music-functions-init.ly +++ b/ly/music-functions-init.ly @@ -342,7 +342,28 @@ featherDurations= argument)) - +footnoteGrob = +#(define-music-function (parser location grob-name offset text footnote) + (symbol? number-pair? markup? markup?) + (_i "Attach @var{text} to @var{grob-name} at offset @var{offset}, + with @var{text} referring to @var{footnote} (use like @code{\\once})") + (make-music 'FootnoteEvent + 'symbol grob-name + 'X-offset (car offset) + 'Y-offset (cdr offset) + 'text text + 'footnote-text footnote)) + +footnote = +#(define-music-function (parser location offset text footnote) + (number-pair? markup? markup?) + (_i "Attach @var{text} at @var{offset} with @var{text} referring + to @var{footnote} (use like @code{\\tweak})") + (make-music 'FootnoteEvent + 'X-offset (car offset) + 'Y-offset (cdr offset) + 'text text + 'footnote-text footnote)) grace = #(def-grace-function startGraceMusic stopGraceMusic diff --git a/ly/paper-defaults-init.ly b/ly/paper-defaults-init.ly index 69fecc16b6..9f88def048 100644 --- a/ly/paper-defaults-init.ly +++ b/ly/paper-defaults-init.ly @@ -56,7 +56,6 @@ ragged-bottom = ##f ragged-last-bottom = ##t % best for shorter scores - %% %% Flexible vertical spacing %% @@ -104,6 +103,13 @@ page-breaking = #ly:optimal-breaking + %% + %% Footnotes + %% + footnote-separator-markup = \markup { \draw-hline } + footnote-padding = 0.5\mm + + %% %% Page numbering %% @@ -111,7 +117,6 @@ print-first-page-number = ##f print-page-number = ##t - %% %% Headers, footers, and titles %% diff --git a/scm/define-event-classes.scm b/scm/define-event-classes.scm index 022ae640e1..c632e430a9 100644 --- a/scm/define-event-classes.scm +++ b/scm/define-event-classes.scm @@ -25,7 +25,7 @@ (RemoveContext ChangeParent Override Revert UnsetProperty SetProperty music-event OldMusicEvent CreateContext Prepare OneTimeStep Finish)) - (music-event . (annotate-output-event + (music-event . (annotate-output-event footnote-event arpeggio-event breathing-event extender-event span-event rhythmic-event dynamic-event break-event label-event percent-event key-change-event string-number-event stroke-finger-event tie-event diff --git a/scm/define-grob-interfaces.scm b/scm/define-grob-interfaces.scm index 23e5f4a0a9..237f8d1805 100644 --- a/scm/define-grob-interfaces.scm +++ b/scm/define-grob-interfaces.scm @@ -81,6 +81,16 @@ note)." "A fingering instruction." '()) +(ly:add-interface + 'footnote-interface + "Make a footnote." + '(footnote-text)) + +(ly:add-interface + 'footnote-spanner-interface + "Make a footnote spanner." + '(footnote-text)) + (ly:add-interface 'fret-diagram-interface "A fret diagram" diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm index 168a4f43d8..434d02c419 100644 --- a/scm/define-grob-properties.scm +++ b/scm/define-grob-properties.scm @@ -48,6 +48,8 @@ be created below this bar line.") (alteration-alist ,list? "List of @code{(@var{pitch} . @var{accidental})} pairs for key signature.") (annotation ,string? "Annotate a grob for debug purposes.") + (annotation-balloon ,boolean? "Draw a balloon around an annotation.") + (annotation-line ,boolean? "Draw a line from an annotation.") (arpeggio-direction ,ly:dir? "If set, put an arrow on the arpeggio squiggly line.") (arrow-length ,number? "Arrow length.") @@ -293,6 +295,7 @@ include @code{upright}, @code{italic}, @code{caps}.") @code{-1} is smaller, @code{+1} is bigger. Each step of@tie{}1 is approximately 12% larger; 6@tie{}steps are exactly a factor@tie{}2 larger. Fractional values are allowed.") + (footnote-text ,markup? "A footnote for the grob.") (force-hshift ,number? "This specifies a manual shift for notes in collisions. The unit is the note head width of the first voice note. This is used by @rinternals{note-collision-interface}.") @@ -731,6 +734,10 @@ slashes in percent repeat glyphs. Larger values bring the two elements closer together.") (slope ,number? "The slope of this object.") (slur-padding ,number? "Extra distance between slur and script.") + (spanner-to-annotate ,integer? "The number of a spanner in a +spanner's broken spanner list to annotate. Values less than 0 or +greater than the number of broken spanners will be wrapped modulo the +number of spanners.") (space-alist ,list? "A table that specifies distances between prefatory items, like clef and time-signature. The format is an alist of spacing tuples: @code{(@var{break-align-symbol} @var{type} diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index 286490e81b..7369e95e42 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -177,6 +177,8 @@ (BalloonTextItem . ( + (annotation-balloon . #t) + (annotation-line . #t) (stencil . ,ly:balloon-interface::print) (text . ,(grob::calc-property-by-copy 'text)) (X-offset . ,(grob::calc-property-by-copy 'X-offset)) @@ -863,6 +865,35 @@ text-interface text-script-interface)))))) + (Footnote + . ( + (annotation-balloon . #f) + (annotation-line . #t) + (stencil . ,ly:balloon-interface::print) + (text . ,(grob::calc-property-by-copy 'text)) + (X-offset . ,(grob::calc-property-by-copy 'X-offset)) + (Y-offset . ,(grob::calc-property-by-copy 'Y-offset)) + (meta . ((class . Item) + (interfaces . (balloon-interface + footnote-interface + font-interface + text-interface)))))) + + (FootnoteSpanner + . ( + (annotation-balloon . #f) + (annotation-line . #t) + (footnote-text . #f) + (stencil . ,ly:balloon-interface::print-spanner) + (text . ,(grob::calc-property-by-copy 'text)) + (X-offset . ,(grob::calc-property-by-copy 'X-offset)) + (Y-offset . ,(grob::calc-property-by-copy 'Y-offset)) + (meta . ((class . Spanner) + (interfaces . (balloon-interface + footnote-spanner-interface + font-interface + text-interface)))))) + (FretBoard . ( (after-line-breaking . ,ly:chord-name::after-line-breaking) diff --git a/scm/define-markup-commands.scm b/scm/define-markup-commands.scm index 5dbc5d2f52..716c37f284 100644 --- a/scm/define-markup-commands.scm +++ b/scm/define-markup-commands.scm @@ -139,6 +139,25 @@ A simple line. (y (cdr dest))) (make-line-stencil th 0 0 x y))) +(define-markup-command (draw-hline layout props) + () + #:category graphic + #:properties ((thickness 1)) + " +@cindex drawing a line across a page + +Draws a line across a page. +@lilypond[verbatim,quote] +\\markup { + \\draw-hline +} +@end lilypond" + (let ((th (* (ly:output-def-lookup layout 'line-thickness) + thickness)) + (x (ly:output-def-lookup layout 'line-width)) + (y 0.0)) + (make-line-stencil th 0 0 x y))) + (define-markup-command (draw-circle layout props radius thickness filled) (number? number? boolean?) #:category graphic @@ -1812,6 +1831,20 @@ returns an empty markup. (list markup?)) (interpret-markup layout props (list anonymous-with-signature arg)))) +(define-markup-command (footnote layout props arg1 arg2) + (markup? markup?) + #:category other + "Apply the footnote @var{arg2} to @var{arg1}." + (ly:stencil-combine-at-edge + (interpret-markup layout props arg1) + X + RIGHT + (ly:make-stencil + `(footnote ,(interpret-markup layout props arg2)) + '(0 . 0) + '(0 . 0)) + 0.0)) + (define-markup-command (override layout props new-prop arg) (pair? markup?) #:category other diff --git a/scm/define-music-types.scm b/scm/define-music-types.scm index cdf5c0a6a1..d57cba8118 100644 --- a/scm/define-music-types.scm +++ b/scm/define-music-types.scm @@ -209,6 +209,11 @@ An alternative syntax is @var{note}@code{\\decr} @dots{} (types . (general-music fingering-event event)) )) + (FootnoteEvent + . ((description . "Footnote a grob.") + (types . (general-music event footnote-event)) + )) + (GlissandoEvent . ((description . "Start a glissando on this note.") (types . (general-music glissando-event event)) diff --git a/scm/define-stencil-commands.scm b/scm/define-stencil-commands.scm index eb7f85ddc1..50787c2bef 100644 --- a/scm/define-stencil-commands.scm +++ b/scm/define-stencil-commands.scm @@ -34,6 +34,7 @@ defined in the output modules (@file{output-*.scm})." ellipse embedded-ps embedded-svg + footnote glyph-string grob-cause named-glyph