]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/page-layout-problem.cc
Build: Typos in make/lilypond-book-{rules,vars}.make.
[lilypond.git] / lily / page-layout-problem.cc
index 319ba396f14a5d087e6e64938f53623a2136cfd4..6320827c767a74b07078d328eb7041d7649f6179 100644 (file)
@@ -1,7 +1,7 @@
 /*
   This file is part of LilyPond, the GNU music typesetter.
 
-  Copyright (C) 2009--2011 Joe Neeman <joeneeman@gmail.com>
+  Copyright (C) 2009--2012 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
  Returns the number of footntoes associated with a given line.
 */
 
-vsize
-Page_layout_problem::get_footnote_count (SCM lines)
+vector<Grob *>
+Page_layout_problem::get_footnote_grobs (SCM lines)
 {
-  vsize fn_count = 0;
+  vector<Grob *> footnotes;
   for (SCM s = lines; scm_is_pair (s); s = scm_cdr (s))
     {
       if (Grob *g = unsmob_grob (scm_car (s)))
@@ -52,7 +52,8 @@ Page_layout_problem::get_footnote_count (SCM lines)
               programming_error ("got a grob for footnotes that wasn't a System");
               continue;
             }
-          fn_count += sys->num_footnotes ();
+          extract_grob_set (sys, "footnotes-after-line-breaking", footnote_grobs);
+          footnotes.insert (footnotes.end (), footnote_grobs.begin (), footnote_grobs.end ());
         }
       else if (Prob *p = unsmob_prob (scm_car (s)))
         {
@@ -60,11 +61,18 @@ Page_layout_problem::get_footnote_count (SCM lines)
           if (stencils == SCM_EOL)
             continue;
           for (SCM st = stencils; scm_is_pair (st); st = scm_cdr (st))
-            fn_count++;
+            footnotes.push_back (0);
         }
     }
 
-  return fn_count;
+  return footnotes;
+}
+
+vsize
+Page_layout_problem::get_footnote_count (SCM lines)
+{
+  vector<Grob *> notes = get_footnote_grobs (lines);
+  return notes.size ();
 }
 
 SCM
@@ -137,7 +145,8 @@ Page_layout_problem::add_footnotes_to_lines (SCM lines, int counter, Paper_book
   Real padding = robust_scm2double (paper->c_variable ("footnote-padding"), 0.0);
   Real number_raise = robust_scm2double (paper->c_variable ("footnote-number-raise"), 0.0);
 
-  vsize fn_count = get_footnote_count (lines);
+  vector<Grob *> fn_grobs = get_footnote_grobs (lines);
+  vsize fn_count = fn_grobs.size ();
 
   // now, make the footnote stencils with the numbering function
   SCM numbers = SCM_EOL;
@@ -156,6 +165,12 @@ Page_layout_problem::add_footnotes_to_lines (SCM lines, int counter, Paper_book
   vector<Stencil *> footnote_number_stencils; // Holds translated versions of the stencilized numbering markups.
   for (vsize i = 0; i < fn_count; i++)
     {
+      if (fn_grobs[i])
+        {
+          SCM assertion_function = fn_grobs[i]->get_property ("numbering-assertion-function");
+          if (ly_is_procedure (assertion_function))
+            (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)
@@ -228,7 +243,7 @@ Page_layout_problem::add_footnotes_to_lines (SCM lines, int counter, Paper_book
                   if (orig->is_broken ())
                     for (vsize i = 0; i < orig->broken_intos_.size (); i++)
                       do_numbering = do_numbering
-                                    || to_boolean (orig->broken_intos_[i]->get_property ("automatically-numbered"));
+                                     || to_boolean (orig->broken_intos_[i]->get_property ("automatically-numbered"));
                 }
               if (do_numbering)
                 {
@@ -365,11 +380,13 @@ Page_layout_problem::Page_layout_problem (Paper_book *pb, SCM page_scm, SCM syst
   : bottom_skyline_ (DOWN)
 {
   Prob *page = unsmob_prob (page_scm);
+  bottom_loose_baseline_ = 0;
   header_height_ = 0;
   footer_height_ = 0;
   header_padding_ = 0;
   footer_padding_ = 0;
   page_height_ = 100;
+  force_ = 0;
 
   if (page)
     {
@@ -546,8 +563,8 @@ Page_layout_problem::append_system (System *sys, Spring const &spring, Real inde
       Skyline *sky = in_note_direction_ == UP ? &up_skyline : &down_skyline;
       sky->set_minimum_height (sky->max_height ()
                                + in_note_direction_
-                                 * (in_note_padding_
-                                    + in_note_stencil->extent (Y_AXIS).length ()));
+                               * (in_note_padding_
+                                  + in_note_stencil->extent (Y_AXIS).length ()));
     }
 
   /*
@@ -558,7 +575,7 @@ Page_layout_problem::append_system (System *sys, Spring const &spring, Real inde
   */
   Real minimum_distance = up_skyline.distance (bottom_skyline_,
                                                robust_scm2double (sys->get_property ("skyline-horizontal-padding"),
-                                                                  0))
+                                                   0))
                           + padding;
 
   Spring spring_copy = spring;
@@ -580,12 +597,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;
             }
 
@@ -613,6 +635,11 @@ 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.
@@ -655,16 +682,35 @@ Page_layout_problem::append_prob (Prob *prob, Spring const &spring, Real padding
   elements_.push_back (Element (prob, padding));
 }
 
+/**
+   For ragged-last pages, we usually want to stretch the page so that it
+   is not much more compressed than the previous page.  Here, if ragged is
+   true and you pass a value of fixed_force that !isinf, then I will try
+   to space this page using the given force.  If it does not fit, I will
+   resort to just filling the page (non-raggedly).
+*/
 void
-Page_layout_problem::solve_rod_spring_problem (bool ragged)
+Page_layout_problem::solve_rod_spring_problem (bool ragged, Real fixed_force)
 {
   Simple_spacer spacer;
 
   for (vsize i = 0; i < springs_.size (); ++i)
     spacer.add_spring (springs_[i]);
 
-  spacer.solve (page_height_, ragged);
+  if (ragged && !isinf (fixed_force))
+    {
+      // We need to tell the spacer it isn't ragged.  Otherwise, it will
+      // refuse to stretch.
+      spacer.solve (page_height_, false);
+
+      if (spacer.configuration_length (fixed_force) <= page_height_)
+        spacer.set_force (fixed_force);
+    }
+  else
+    spacer.solve (page_height_, ragged);
+
   solution_ = spacer.spring_positions ();
+  force_ = spacer.force ();
 
   if (!spacer.fits ())
     {
@@ -685,6 +731,12 @@ Page_layout_problem::solve_rod_spring_problem (bool ragged)
     }
 }
 
+Real
+Page_layout_problem::force () const
+{
+  return force_;
+}
+
 // The solution_ vector stores the position of every live VerticalAxisGroup
 // and every title. From that information,
 // 1) within each system, stretch the staves so they land at the right position
@@ -769,7 +821,12 @@ Page_layout_problem::find_system_offsets ()
                       if (staff_idx)
                         loose_line_min_distances.push_back (min_offsets[staff_idx - 1] - min_offsets[staff_idx]);
                       else
-                        loose_line_min_distances.push_back (elements_[i].padding - min_offsets[staff_idx]);
+                        {
+                          // A null line to break any staff-affinity from the previous system
+                          loose_line_min_distances.push_back (0.0);
+                          loose_lines.push_back (0);
+                          loose_line_min_distances.push_back (elements_[i].padding - min_offsets[0]);
+                        }
                       loose_lines.push_back (staff);
 
                       distribute_loose_lines (loose_lines, loose_line_min_distances,
@@ -798,12 +855,16 @@ Page_layout_problem::find_system_offsets ()
                       // this is the first line in a system
                       Real min_dist = 0;
                       if (loose_lines.back ())
-                        // 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);
+                        {
+                          // 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);
+                          // 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
@@ -869,16 +930,24 @@ Page_layout_problem::distribute_loose_lines (vector<Grob *> const &loose_lines,
 
   vector<Real> solution = spacer.spring_positions ();
   for (vsize i = 1; i + 1 < solution.size (); ++i)
-    {
-      Real system_offset = scm_to_double (loose_lines[i]->get_property ("system-Y-offset"));
-      loose_lines[i]->translate_axis (first_translation - solution[i] - system_offset, Y_AXIS);
-    }
+    if (loose_lines[i])
+      {
+        Real system_offset = scm_to_double (loose_lines[i]->get_property ("system-Y-offset"));
+        loose_lines[i]->translate_axis (first_translation - solution[i] - system_offset, Y_AXIS);
+      }
+}
+
+SCM
+Page_layout_problem::fixed_force_solution (Real force)
+{
+  solve_rod_spring_problem (true, force);
+  return find_system_offsets ();
 }
 
 SCM
 Page_layout_problem::solution (bool ragged)
 {
-  solve_rod_spring_problem (ragged);
+  solve_rod_spring_problem (ragged, -infinity_f);
   return find_system_offsets ();
 }