]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/page-layout-problem.cc
Run grand-replace (issue 3765)
[lilypond.git] / lily / page-layout-problem.cc
index 39260b4173edc98845cee4d038bf0a8e1d2b51fc..52720d54490738c1579e09d218b0a6cf688f786b 100644 (file)
@@ -1,7 +1,7 @@
 /*
   This file is part of LilyPond, the GNU music typesetter.
 
-  Copyright (C) 2009--2012 Joe Neeman <joeneeman@gmail.com>
+  Copyright (C) 2009--2014 Joe Neeman <joeneeman@gmail.com>
 
   LilyPond is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -108,7 +108,7 @@ Page_layout_problem::get_footnotes_from_lines (SCM lines)
         programming_error ("Systems on a page must be a prob or grob.");
     }
 
-  return scm_reverse (out);
+  return scm_reverse_x (out, SCM_EOL);
 }
 
 /*
@@ -161,8 +161,10 @@ Page_layout_problem::add_footnotes_to_lines (SCM lines, int counter, Paper_book
     in duplicated work, either by making this process less complicated or (preferably)
     by passing its results downstream.
   */
-  vector<SCM> footnote_number_markups; // Holds the numbering markups.
-  vector<Stencil *> footnote_number_stencils; // Holds translated versions of the stencilized numbering markups.
+
+  // find the maximum X_AXIS length
+  Real max_length = -infinity_f;
+
   for (vsize i = 0; i < fn_count; i++)
     {
       if (fn_grobs[i])
@@ -172,40 +174,40 @@ Page_layout_problem::add_footnotes_to_lines (SCM lines, int counter, Paper_book
             (void) scm_call_1 (assertion_function, scm_from_int (counter));
         }
       SCM markup = scm_call_1 (numbering_function, scm_from_int (counter));
-      Stencil *s = unsmob_stencil (Text_interface::interpret_markup (layout, props, markup));
-      if (!s)
+      SCM stencil = Text_interface::interpret_markup (layout, props, markup);
+      Stencil *st = unsmob_stencil (stencil);
+      if (!st)
         {
           programming_error ("Your numbering function needs to return a stencil.");
           markup = SCM_EOL;
-          s = new Stencil (Box (Interval (0, 0), Interval (0, 0)), SCM_EOL);
+          stencil = Stencil (Box (Interval (0, 0), Interval (0, 0)), SCM_EOL).smobbed_copy ();
+          st = unsmob_stencil (stencil);
         }
-      footnote_number_markups.push_back (markup);
-      footnote_number_stencils.push_back (s);
+      in_text_numbers = scm_cons (markup, in_text_numbers);
+      numbers = scm_cons (stencil, numbers);
+
+      if (!st->extent (X_AXIS).is_empty ())
+        max_length = max (max_length, st->extent (X_AXIS)[RIGHT]);
+
       counter++;
     }
 
-  // find the maximum X_AXIS length
-  Real max_length = -infinity_f;
-  for (vsize i = 0; i < fn_count; i++)
-    max_length = max (max_length, footnote_number_stencils[i]->extent (X_AXIS).length ());
+  in_text_numbers = scm_reverse_x (in_text_numbers, SCM_EOL);
+  numbers = scm_reverse_x (numbers, SCM_EOL);
 
   /*
     translate each stencil such that it attains the correct maximum length and bundle the
     footnotes into a scheme object.
   */
-  SCM *tail = &numbers;
-  SCM *in_text_tail = &in_text_numbers;
 
-  for (vsize i = 0; i < fn_count; i++)
+  for (SCM p = numbers; scm_is_pair (p); p = scm_cdr (p))
     {
-      *in_text_tail = scm_cons (footnote_number_markups[i], SCM_EOL);
-      in_text_tail = SCM_CDRLOC (*in_text_tail);
-      footnote_number_stencils[i]->translate_axis ((max_length
-                                                    - footnote_number_stencils[i]->extent (X_AXIS).length ()),
-                                                   X_AXIS);
-      *tail = scm_cons (footnote_number_stencils[i]->smobbed_copy (), SCM_EOL);
-      tail = SCM_CDRLOC (*tail);
+      Stencil *st = unsmob_stencil (scm_car (p));
+      if (!st->extent (X_AXIS).is_empty ())
+        st->translate_axis ((max_length - st->extent (X_AXIS)[RIGHT]),
+                            X_AXIS);
     }
+
   // build the footnotes
 
   for (SCM s = lines; scm_is_pair (s); s = scm_cdr (s))
@@ -236,7 +238,7 @@ Page_layout_problem::add_footnotes_to_lines (SCM lines, int counter, Paper_book
               SCM footnote_stl = Text_interface::interpret_markup (paper->self_scm (),
                                                                    props, footnote_markup);
 
-              Stencil *footnote_stencil = unsmob_stencil (footnote_stl);
+              Stencil footnote_stencil = *unsmob_stencil (footnote_stl);
               bool do_numbering = to_boolean (footnote->get_property ("automatically-numbered"));
               if (Spanner *orig = dynamic_cast<Spanner *>(footnote))
                 {
@@ -257,21 +259,21 @@ Page_layout_problem::add_footnotes_to_lines (SCM lines, int counter, Paper_book
                           orig->broken_intos_[i]->set_property ("text", annotation_scm);
                     }
 
-                  Stencil *annotation = unsmob_stencil (scm_car (numbers));
-                  annotation->translate_axis ((footnote_stencil->extent (Y_AXIS)[UP]
-                                               + number_raise
-                                               - annotation->extent (Y_AXIS)[UP]),
-                                              Y_AXIS);
-                  footnote_stencil->add_at_edge (X_AXIS, LEFT, *annotation, 0.0);
+                  Stencil annotation = *unsmob_stencil (scm_car (numbers));
+                  annotation.translate_axis ((footnote_stencil.extent (Y_AXIS)[UP]
+                                              + number_raise
+                                              - annotation.extent (Y_AXIS)[UP]),
+                                             Y_AXIS);
+                  footnote_stencil.add_at_edge (X_AXIS, LEFT, annotation, 0.0);
                   numbers = scm_cdr (numbers);
                   in_text_numbers = scm_cdr (in_text_numbers);
                 }
-              if (!footnote_stencil->is_empty ())
+              if (!footnote_stencil.is_empty ())
                 {
                   if (to_boolean (footnote->get_property ("footnote")))
-                    mol.add_at_edge (Y_AXIS, DOWN, *footnote_stencil, padding);
+                    mol.add_at_edge (Y_AXIS, DOWN, footnote_stencil, padding);
                   else
-                    in_note_mol.add_at_edge (Y_AXIS, DOWN, *footnote_stencil, padding);
+                    in_note_mol.add_at_edge (Y_AXIS, DOWN, footnote_stencil, padding);
                 }
             }
           sys->set_property ("in-note-stencil", in_note_mol.smobbed_copy ());
@@ -285,25 +287,23 @@ Page_layout_problem::add_footnotes_to_lines (SCM lines, int counter, Paper_book
 
           for (SCM st = stencils; scm_is_pair (st); st = scm_cdr (st))
             {
-              Stencil footnote_stencil;
-              Stencil *footnote = unsmob_stencil (scm_caddar (st));
-              footnote_stencil.add_stencil (*footnote);
+              Stencil footnote_stencil = *unsmob_stencil (scm_caddar (st));
               bool do_numbering = to_boolean (scm_cadar (st));
               SCM in_text_stencil = Stencil ().smobbed_copy ();
               if (do_numbering)
                 {
-                  Stencil *annotation = unsmob_stencil (scm_car (numbers));
+                  Stencil annotation = *unsmob_stencil (scm_car (numbers));
                   SCM in_text_annotation = scm_car (in_text_numbers);
                   in_text_stencil = Text_interface::interpret_markup (layout,
                                                                       props,
                                                                       in_text_annotation);
                   if (!unsmob_stencil (in_text_stencil))
                     in_text_stencil = SCM_EOL;
-                  annotation->translate_axis ((footnote_stencil.extent (Y_AXIS)[UP]
-                                               + number_raise
-                                               - annotation->extent (Y_AXIS)[UP]),
-                                              Y_AXIS);
-                  footnote_stencil.add_at_edge (X_AXIS, LEFT, *annotation, 0.0);
+                  annotation.translate_axis ((footnote_stencil.extent (Y_AXIS)[UP]
+                                              + number_raise
+                                              - annotation.extent (Y_AXIS)[UP]),
+                                             Y_AXIS);
+                  footnote_stencil.add_at_edge (X_AXIS, LEFT, annotation, 0.0);
                   numbers = scm_cdr (numbers);
                   in_text_numbers = scm_cdr (in_text_numbers);
                 }
@@ -321,7 +321,7 @@ Page_layout_problem::add_footnotes_to_lines (SCM lines, int counter, Paper_book
   pb->top_paper ()->set_variable (ly_symbol2scm ("number-footnote-table"), number_footnote_table);
 }
 
-Stencil *
+Stencil
 Page_layout_problem::get_footnote_separator_stencil (Output_def *paper)
 {
   SCM props = scm_call_1 (ly_lily_module_constant ("layout-extract-page-properties"),
@@ -330,24 +330,20 @@ Page_layout_problem::get_footnote_separator_stencil (Output_def *paper)
   SCM markup = paper->c_variable ("footnote-separator-markup");
 
   if (!Text_interface::is_markup (markup))
-    return NULL;
+    return Stencil ();
 
   SCM footnote_stencil = Text_interface::interpret_markup (paper->self_scm (),
                                                            props, markup);
 
   Stencil *footnote_separator = unsmob_stencil (footnote_stencil);
 
-  return footnote_separator;
+  return footnote_separator ? *footnote_separator : Stencil ();
 }
 
-void
-Page_layout_problem::add_footnotes_to_footer (SCM footnotes, Stencil *foot, Paper_book *pb)
+Stencil
+Page_layout_problem::add_footnotes_to_footer (SCM footnotes, Stencil foot, Paper_book *pb)
 {
-  if (!foot && scm_is_pair (footnotes))
-    {
-      warning ("Must have a footer to add footnotes.");
-      return;
-    }
+
   bool footnotes_found = false;
   Real footnote_padding = robust_scm2double (pb->paper_->c_variable ("footnote-padding"), 0.0);
   Real footnote_footer_padding = robust_scm2double (pb->paper_->c_variable ("footnote-footer-padding"), 0.0);
@@ -363,23 +359,26 @@ Page_layout_problem::add_footnotes_to_footer (SCM footnotes, Stencil *foot, Pape
 
       if (!stencil->is_empty ())
         {
-          foot->add_at_edge (Y_AXIS, UP, *stencil, (!footnotes_found ? footnote_footer_padding : footnote_padding));
+          foot.add_at_edge (Y_AXIS, UP, *stencil, (!footnotes_found ? footnote_footer_padding : footnote_padding));
           footnotes_found = true;
         }
     }
 
   if (footnotes_found)
     {
-      Stencil *separator = get_footnote_separator_stencil (pb->paper_);
-      if (separator)
-        foot->add_at_edge (Y_AXIS, UP, *separator, footnote_padding);
+      Stencil separator = get_footnote_separator_stencil (pb->paper_);
+      if (!separator.is_empty ())
+        foot.add_at_edge (Y_AXIS, UP, separator, footnote_padding);
     }
+
+  return foot;
 }
 
 Page_layout_problem::Page_layout_problem (Paper_book *pb, SCM page_scm, SCM systems)
   : bottom_skyline_ (DOWN)
 {
   Prob *page = unsmob_prob (page_scm);
+  bottom_loose_baseline_ = 0;
   header_height_ = 0;
   footer_height_ = 0;
   header_padding_ = 0;
@@ -392,16 +391,18 @@ 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"));
 
+      Stencil foot_stencil = foot ? *foot : Stencil ();
+
       if (pb && pb->paper_)
         {
           SCM footnotes = get_footnotes_from_lines (systems);
-          add_footnotes_to_footer (footnotes, foot, pb);
+          foot_stencil = add_footnotes_to_footer (footnotes, foot_stencil, pb);
         }
       else
-        warning ("A page layout problem has been initiated that cannot accommodate footnotes.");
+        warning (_ ("A page layout problem has been initiated that cannot accommodate footnotes."));
 
       header_height_ = head ? head->extent (Y_AXIS).length () : 0;
-      footer_height_ = foot ? foot->extent (Y_AXIS).length () : 0;
+      footer_height_ = foot_stencil.extent (Y_AXIS).length ();
       page_height_ = robust_scm2double (page->get_property ("paper-height"), 100);
     }
 
@@ -537,7 +538,7 @@ Page_layout_problem::set_footer_height (Real height)
 void
 Page_layout_problem::append_system (System *sys, Spring const &spring, Real indent, Real padding)
 {
-  Grob *align = sys->get_vertical_alignment ();
+  Grob *align = unsmob_grob (sys->get_object ("vertical-alignment"));
   if (!align)
     return;
 
@@ -581,8 +582,19 @@ Page_layout_problem::append_system (System *sys, Spring const &spring, Real inde
   spring_copy.ensure_min_distance (minimum_distance);
   springs_.push_back (spring_copy);
 
+  if (elts.size () && !is_spaceable (elts[0]))
+    {
+      // store the minimum distance, considering relative indents,
+      // for a loose line
+      Skyline first_skyline (UP);
+      Skyline_pair *sky = Skyline_pair::unsmob (elts[0]->get_property ("vertical-skylines"));
+      if (sky)
+        first_skyline.merge ((*sky)[UP]);
+      first_skyline.shift (indent);
+      minimum_distance = first_skyline.distance (bottom_skyline_) - bottom_loose_baseline_;
+    }
   bottom_skyline_ = down_skyline;
-  elements_.push_back (Element (elts, minimum_offsets, padding));
+  elements_.push_back (Element (elts, minimum_offsets, minimum_distance, padding));
 
   // Add the springs for the VerticalAxisGroups in this system.
 
@@ -596,12 +608,17 @@ Page_layout_problem::append_system (System *sys, Spring const &spring, Real inde
     {
       if (is_spaceable (elts[i]))
         {
-          // We don't add a spring for the first staff, since
-          // we are only adding springs _between_ staves here.
           if (!found_spaceable_staff)
             {
+              // Ensure space for any loose lines above this system
+              if (i > 0)
+                springs_.back ().ensure_min_distance (bottom_loose_baseline_
+                                                      - minimum_offsets_with_min_dist[i]
+                                                      + padding);
               found_spaceable_staff = true;
               last_spaceable_staff = i;
+              // We don't add a spring for the first staff, since
+              // we are only adding springs _between_ staves here.
               continue;
             }
 
@@ -629,9 +646,12 @@ Page_layout_problem::append_system (System *sys, Spring const &spring, Real inde
         }
     }
 
+  bottom_loose_baseline_ = found_spaceable_staff
+                           ? ( minimum_offsets_with_min_dist[last_spaceable_staff]
+                               - minimum_offsets_with_min_dist.back ())
+                           : 0;
+
   // Corner case: there was only one staff, and it wasn't spaceable.
-  // Mark it spaceable, because we do not allow non-spaceable staves
-  // to be at the top or bottom of a system.
   if (!found_spaceable_staff && elts.size ())
     mark_as_spaceable (elts[0]);
 }
@@ -645,7 +665,8 @@ Page_layout_problem::append_prob (Prob *prob, Spring const &spring, Real padding
 
   if (sky)
     {
-      minimum_distance = (*sky)[UP].distance (bottom_skyline_);
+      minimum_distance = max ((*sky)[UP].distance (bottom_skyline_),
+                              bottom_loose_baseline_);
       bottom_skyline_ = (*sky)[DOWN];
     }
   else if (Stencil *sten = unsmob_stencil (prob->get_property ("stencil")))
@@ -656,6 +677,7 @@ Page_layout_problem::append_prob (Prob *prob, Spring const &spring, Real padding
       bottom_skyline_.clear ();
       bottom_skyline_.set_minimum_height (iv[DOWN]);
     }
+  bottom_loose_baseline_ = 0.0;
 
   Spring spring_copy = spring;
   if (tight_spacing)
@@ -706,12 +728,12 @@ Page_layout_problem::solve_rod_spring_problem (bool ragged, Real fixed_force)
       Real overflow = spacer.configuration_length (spacer.force ())
                       - page_height_;
       if (ragged && overflow < 1e-6)
-        warning (_ ("cannot fit music on page: ragged-spacing was requested, but page was compressed"));
+        warning (_ ("ragged-bottom was specified, but page must be compressed"));
       else
         {
-          warning (_f ("cannot fit music on page: overflow is %f",
+          warning (_f ("compressing over-full page by %.1f staff-spaces",
                        overflow));
-          warning (_ ("compressing music to fit"));
+          force_ = -infinity_f;
           vsize space_count = solution_.size ();
           Real spacing_increment = overflow / (space_count - 2);
           for (vsize i = 2; i < space_count; i++)
@@ -828,8 +850,11 @@ Page_layout_problem::find_system_offsets ()
                   found_spaceable_staff = true;
                   spring_idx++;
                 }
-              else
+              else // ! is_spaceable
                 {
+                  if (staff->extent (staff, Y_AXIS).is_empty ())
+                    continue;
+
                   if (loose_lines.empty ())
                     loose_lines.push_back (last_spaceable_line);
 
@@ -847,16 +872,14 @@ Page_layout_problem::find_system_offsets ()
                         {
                           // distance to the final line in the preceding system,
                           // including 'system-system-spacing 'padding
-                          min_dist = (Axis_group_interface::minimum_distance (loose_lines.back (),
-                                                                              staff, Y_AXIS)
-                                      + elements_[i].padding);
+                          min_dist = elements_[i].min_distance + elements_[i].padding;
                           // A null line to break any staff-affinity for the previous system
                           loose_line_min_distances.push_back (0.0);
                           loose_lines.push_back (0);
                         }
                       else if (!last_title_extent.is_empty ())
                         // distance to the preceding title,
-                        //  including 'markup-system-spacing 'padding
+                        //  including 'markup-system-wg 'padding
                         min_dist = (staff->extent (staff, Y_AXIS)[UP] - last_title_extent[DOWN]
                                     + elements_[i].padding);
                       else // distance to the top margin