From 3128487939b2bfd363a4fd48c289727fe6dbc61b Mon Sep 17 00:00:00 2001
From: Joe Neeman <joeneeman@gmail.com>
Date: Sun, 11 Oct 2009 19:49:33 -0700
Subject: [PATCH] Add padding between Lyrics and the following staff.

---
 .../page-spacing-loose-lines-non-affinity.ly  | 13 +++++
 lily/axis-group-interface.cc                  |  1 +
 lily/page-layout-problem.cc                   | 51 ++++++++++++-------
 ly/engraver-init.ly                           |  1 +
 scm/define-grob-properties.scm                |  5 ++
 scm/define-grobs.scm                          |  1 +
 6 files changed, 53 insertions(+), 19 deletions(-)
 create mode 100644 input/regression/page-spacing-loose-lines-non-affinity.ly

diff --git a/input/regression/page-spacing-loose-lines-non-affinity.ly b/input/regression/page-spacing-loose-lines-non-affinity.ly
new file mode 100644
index 0000000000..095080d6c0
--- /dev/null
+++ b/input/regression/page-spacing-loose-lines-non-affinity.ly
@@ -0,0 +1,13 @@
+\version "2.13.4"
+
+\header {
+  texidoc = "Loose lines can specify their padding or min-distance to the
+staff for which they don't have affinity."
+}
+
+<<
+  \new Staff { c'1 }
+  \new Lyrics \with { \override VerticalAxisGroup #'non-affinity-spacing #'padding = #'20 }
+    \lyricmode { foo }
+  \new Staff { c'1 }
+>>
\ No newline at end of file
diff --git a/lily/axis-group-interface.cc b/lily/axis-group-interface.cc
index 396a95857c..0e9ca9264c 100644
--- a/lily/axis-group-interface.cc
+++ b/lily/axis-group-interface.cc
@@ -729,6 +729,7 @@ ADD_INTERFACE (Axis_group_interface,
 	       "inter-staff-spacing "
 	       "keep-fixed-while-stretching "
 	       "max-stretch "
+	       "non-affinity-spacing "
 	       "next-staff-spacing "
 	       "no-alignment "
 	       "pure-Y-common "
diff --git a/lily/page-layout-problem.cc b/lily/page-layout-problem.cc
index 1aa83d3c0b..35443dfc84 100644
--- a/lily/page-layout-problem.cc
+++ b/lily/page-layout-problem.cc
@@ -446,19 +446,6 @@ Page_layout_problem::distribute_loose_lines (vector<Grob*> const &loose_lines,
       Spring spring (1.0, 0.0);
       alter_spring_from_spacing_spec (spec, &spring);
       spring.ensure_min_distance (min_distances[i]);
-
-      if ((spec == SCM_BOOL_F && loose_lines[0] && loose_lines.back ())
-	  || !loose_lines[i]
-	  || !loose_lines[i+1])
-	{
-	  // Insert a very flexible spring, so it doesn't have much effect.
-	  // TODO: set a default distance and a compress strength so that a
-	  // lyrics line, for example, will stay closer to the top staff
-	  // even in a compressed configuration.
-	  spring.set_inverse_stretch_strength (100000);
-	  spring.set_inverse_compress_strength (100000);
-	}
-
       spacer.add_spring (spring);
     }
 
@@ -608,14 +595,33 @@ Page_layout_problem::read_spacing_spec (SCM spec, Real* dest, SCM sym)
   return false;
 }
 
-// Returns the spacing spec connecting BEFORE to AFTER.  A return
-// value of SCM_BOOL_F means that there should be no spring (in
-// practice, this means that we use a very flexible spring).
+static SCM
+add_stretchability (SCM alist, Real stretch)
+{
+  if (!scm_is_pair (scm_sloppy_assq (ly_symbol2scm ("stretchability"), alist)))
+    return scm_acons (ly_symbol2scm ("stretchability"), scm_from_double (stretch), alist);
+
+  return alist;
+}
+
+// We want to put a large stretch between a non-spaceable line and its
+// non-affinity staff. We want to put an even larger stretch between
+// a non-spaceable line and the top/bottom of the page. That way,
+// a spacing-affinity UP line at the bottom of the page will still be
+// placed close to its staff.
+const double LARGE_STRETCH = 10e5;
+const double HUGE_STRETCH = 10e7;
+
+// Returns the spacing spec connecting BEFORE to AFTER.
 SCM
 Page_layout_problem::get_spacing_spec (Grob *before, Grob *after)
 {
+  // If there are no spacing wishes, return a very flexible spring.
+  // This will occur, for example, if there are lyrics at the bottom of
+  // the page, in which case we don't want the spring from the lyrics to
+  // the bottom of the page to have much effect.
   if (!before || !after)
-    return SCM_BOOL_F;
+    return add_stretchability (SCM_EOL, HUGE_STRETCH);
 
   if (is_spaceable (before))
     {
@@ -624,7 +630,9 @@ Page_layout_problem::get_spacing_spec (Grob *before, Grob *after)
       else
 	{
 	  Direction affinity = to_dir (after->get_property ("staff-affinity"));
-	  return (affinity == DOWN) ? SCM_BOOL_F : after->get_property ("inter-staff-spacing");
+	  return (affinity == DOWN)
+	    ? add_stretchability (after->get_property ("non-affinity-spacing"), LARGE_STRETCH)
+	    : after->get_property ("inter-staff-spacing");
 	}
     }
   else
@@ -632,7 +640,9 @@ Page_layout_problem::get_spacing_spec (Grob *before, Grob *after)
       if (is_spaceable (after))
 	{
 	  Direction affinity = to_dir (before->get_property ("staff-affinity"));
-	  return (affinity == UP) ? SCM_BOOL_F : before->get_property ("inter-staff-spacing");
+	  return (affinity == UP)
+	    ? add_stretchability (before->get_property ("non-affinity-spacing"), LARGE_STRETCH)
+	    : before->get_property ("inter-staff-spacing");
 	}
       else
 	{
@@ -647,8 +657,11 @@ Page_layout_problem::get_spacing_spec (Grob *before, Grob *after)
 	    return before->get_property ("inter-loose-line-spacing");
 	  else if (after_affinity != DOWN)
 	    return before->get_property ("inter-loose-line-spacing");
+	  return add_stretchability (before->get_property ("non-affinity-spacing"), LARGE_STRETCH);
 	}
     }
+
+  assert (0);
   return SCM_BOOL_F;
 }
 
diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly
index 0832f8bca9..722250d6f4 100644
--- a/ly/engraver-init.ly
+++ b/ly/engraver-init.ly
@@ -393,6 +393,7 @@ printing of a single line of lyrics."
   \override VerticalAxisGroup #'staff-affinity = #UP
   \override VerticalAxisGroup #'inter-staff-spacing = #'((space . 5.5) (stretchability . 1) (padding . 0.5))
   \override VerticalAxisGroup #'inter-loose-line-spacing = #'((space . 0) (stretchability . 0) (padding . 0.2))
+  \override VerticalAxisGroup #'non-affinity-spacing #'padding = #1.0
   \override SeparationItem #'padding = #0.2
   \override InstrumentName #'self-alignment-Y = ##f
 
diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm
index b9cf4ed3a2..33c12020db 100644
--- a/scm/define-grob-properties.scm
+++ b/scm/define-grob-properties.scm
@@ -600,6 +600,11 @@ staff is crucial for @var{padding}).
 object.")
      (no-stem-extend ,boolean? "If set, notes with ledger lines do not
 get stems extending to the middle staff line.")
+     (non-affinity-spacing ,list? "An alist of spacing variables
+that controls the spacing from a loose line (see @var{staff-affinity})
+to the staff for which the loose line does not have affinity.
+See @var{next-staff-spacing} for a description of the elements of
+this alist.")
      (non-default ,boolean? "Set for manually specified clefs.")
      (non-musical ,boolean? "True if the grob belongs to a
 @code{NonMusicalPaperColumn}.")
diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm
index a5e8b29160..3bad280e12 100644
--- a/scm/define-grobs.scm
+++ b/scm/define-grobs.scm
@@ -2186,6 +2186,7 @@
 	(axes . (,Y))
 	(default-next-staff-spacing . ((space . 9) (minimum-distance . 8)))
 	(next-staff-spacing . ,ly:axis-group-interface::calc-next-staff-spacing)
+	(non-affinity-spacing . ((padding . 0.5)))
 	(stencil . ,ly:axis-group-interface::print)
 	(vertical-skylines . ,ly:hara-kiri-group-spanner::calc-skylines)
 	(X-extent . ,ly:axis-group-interface::width)
-- 
2.39.5