]> git.donarmstrong.com Git - lilypond.git/commitdiff
* lily/spacing-determine-loose-columns.cc: new file.
authorHan-Wen Nienhuys <hanwen@xs4all.nl>
Fri, 5 Aug 2005 10:42:22 +0000 (10:42 +0000)
committerHan-Wen Nienhuys <hanwen@xs4all.nl>
Fri, 5 Aug 2005 10:42:22 +0000 (10:42 +0000)
* input/regression/spacing-strict-notespacing.ly: new file.

* lily/spacing-spanner.cc (generate_springs): rename from
do_measure.
(generate_pair_spacing): new function.
(init, generate_pair_spacing): set between-cols for floating
nonmusical columns.

* lily/spaceable-grob.cc (get_spring): new function.

* lily/tuplet-bracket.cc (print): on the left, the overshoot is
relative to the right edge of the prefatory matter.

* lily/beam.cc (print): read break-overshoot to determine where to
stop/start broken beams.

18 files changed:
.cvsignore
ChangeLog
Documentation/topdocs/NEWS.tely
input/regression/spacing-strict-notespacing.ly [new file with mode: 0644]
lily/beam.cc
lily/dynamic-engraver.cc
lily/include/spaceable-grob.hh
lily/include/spacing-spanner.hh
lily/include/system.hh
lily/simple-spacer.cc
lily/spaceable-grob.cc
lily/spacing-determine-loose-columns.cc [new file with mode: 0644]
lily/spacing-engraver.cc
lily/spacing-loose-columns.cc
lily/spacing-spanner.cc
lily/tuplet-bracket.cc
scm/define-grob-properties.scm
scm/define-grobs.scm

index 91b42ae1336317a4ec9529bc818e166e7abe0ec7..99e904cc8bfd5a977cee59ab26493c6b4ed88caf 100644 (file)
 *~
 .dstreamrc
 .gdbinit
+.htaccess
+1000.scsm
 GNUmakefile
+Lily_piano.socket
+System
 TAGS
+a.pfa
+ab
 aclocal.m4
+add
 afm
+arial.pfa
 autom4te.cache
+aybabtu.afm
+b
+bench.sh
+bigcheese20.cff
+bla
+calls
+cf1.zip
+cf2.zip
+cffpats
+chinese-otfs.zip
+clip-demo.epsi
+config-g16.hh
+config-g16.make
+config-g16nothread.hh
+config-g16nothread.make
+config-g16opt.hh
+config-g16opt.make
+config-opt.hh
+config-opt.make
+config-prof.hh
+config-prof.make
+config-speed.hh
+config-speed.make
 config.cache
 config.h
 config.hh
@@ -31,16 +62,117 @@ config.log
 config.make
 config.status
 configure
+cont
+core.4183
+cp.out
+crashes
+custom.py
+e.py
+example-1.socket
+example-1.texstr
+exp.scm
+f.lytex
+f.socket
+f.texstr
+fcc.c
+fi.py
+fingpats
+firefox.icns
+fondu3FB3-2
+fontconfig
+fontconfig.c
 fonts
+foo.c
+foo.cc
+foo.cff
+foo.pfa
+foobar
+grob-array-pats
+gsbug-inv
+gstest
+hello
+hello.utf
+hir.otf
+hira.cff
+hk.cff
+hk2.afm
+hk2.cff
+hk3.cid.afm
+hk3.cid.cff
+htpasswd
+invstrength
+les-nereides.dsc
+les-nereides.texstr
+les-nereides.textmetrics
 lib
+lilymydear.zip
+lilypond-2.6.0-2.7.0.diff
+lilypond-internals.texi
+lilypond-testpage-systems.texi
+lilypond-tools.zip
+lilypond.dir
 log
 ls-R
-lilypond.dir
+makefile.pango
+makelily.py
+ml-systems.texi
+morgenlied.lpm
+morgenlied.texstr
+mozart-hrn-3.socket
+msgothic.ttc
+msmincho.ttc
+munix
+ok
+otftest.c
 out
+out
+out-g16
+out-g16nothread
+out-g16opt
+out-opt
+out-prof
+out-speed
 out-www
+out.ai
+out.pfa
+out.sk
+out.spsc
+p
+p.cc
+pango
+pango.c
+parmesan16list-systems.texi
+patent
+pats
+polyprof
+profile
+profile2
+profile3
+profile6
+q.cc
 scons.cache
+setup.ini
 share
+simple-song.twy
+simsun.ttc
+socket-output
+stat
+system-separator-systems.texi
+t2.c
+talk.py
+test.scm
+test.socket
+test.socket.socket
 tfm
 tfm.[0-9]
-out
-custom.py
+timtekst
+ud
+uninstalldirs
+us
+usr
+ver
+wrap.scm
+wtk-prof
+wtk-prof2
+wtk1-fugue2.scm
+wtk1-fugue2.socket
index 94202d9f48988829a03c5b51ea1d3ef9d57ba3f9..76d0d19912d9689c1b0d492518a1aa98f8a2c3b7 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2005-08-05  Han-Wen Nienhuys  <hanwen@xs4all.nl>
+
+       * lily/spacing-determine-loose-columns.cc: new file.
+
+       * input/regression/spacing-strict-notespacing.ly: new file.
+
+       * lily/spacing-spanner.cc (generate_springs): rename from
+       do_measure. 
+       (generate_pair_spacing): new function.
+       (init, generate_pair_spacing): set between-cols for floating
+       nonmusical columns.
+
+       * lily/spaceable-grob.cc (get_spring): new function. 
+
+       * lily/tuplet-bracket.cc (print): on the left, the overshoot is
+       relative to the right edge of the prefatory matter.
+
+       * lily/beam.cc (print): read break-overshoot to determine where to
+       stop/start broken beams.
+
+       * input/regression/spanner-break-overshoot.ly: new file.
+
 2005-08-04  Graham Percival  <gperlist@shaw.ca>
 
        * ly/bagpipe.ly: updated.
@@ -6,6 +28,9 @@
 
 2005-08-04  Han-Wen Nienhuys  <hanwen@xs4all.nl>
 
+       * lily/dynamic-engraver.cc (acknowledge_slur): add slur to
+       support: now (de)crescs avoid slurs as well.
+
        * Documentation/user/instrument-notation.itely (Bagpipe example):
        comment out non-functioning bagpipe example.
        (Bagpipe definitions): idem.
index a0ff53528a7693ccc6b81228ae8baba0d076dd5e..99622e13bf4be9cea865bba87a96df9ba211769a 100644 (file)
@@ -33,6 +33,29 @@ See user manual, \NAME\
 
 @itemize @bullet
 
+@item
+When @code{strict-note-spacing} is set, note are spaced without regard
+for clefs and bar lines. For example,
+
+@lilypond[fragment,verbatim,relative=2]
+\override Score.SpacingSpanner #'strict-note-spacing = ##t 
+\new Staff { c8[ c \clef alto c c c c]  c32 c32 }
+@end lilypond
+
+
+This feature was sponsored by Trevor Baca. 
+
+@item
+Beams support the @code{break-overshoot} property, for example
+
+@lilypond[relative=2,fragment,verbatim]
+\set allowBeamBreak = ##t
+\override Beam #'break-overshoot = #'(1.0 . 2.0)
+c2.. c8[ \break c]
+@end lilypond
+This feature was sponsored by Trevor Baca. 
+
 @item
 Proportional notation is supported.  Notes can be spaced proportional
 to their time-difference, by assigning a duration.  to
diff --git a/input/regression/spacing-strict-notespacing.ly b/input/regression/spacing-strict-notespacing.ly
new file mode 100644 (file)
index 0000000..797a3a2
--- /dev/null
@@ -0,0 +1,31 @@
+\header {
+
+
+  texidoc = "If @code{strict-note-spacing} is set, then spacing of
+notes is not influenced by bars and clefs half-way on the system.
+Rather, they are put just before the note that occurs at the same
+time.  This may cause collisions.  "
+
+}
+
+
+\version "2.7.4"
+
+\paper {
+  raggedright = ##t
+  indent = 0
+}
+\layout {
+  \context {
+    \Score
+  }
+}
+
+\relative c''
+<<
+  \override Score.SpacingSpanner #'strict-note-spacing = ##t 
+  \set Score.proportionalNotationDuration = #(ly:make-moment 1 16)
+  \new Staff { c8[ c \clef alto c c c c]  c4 c2 r2 }
+  \new Staff { c2  \times 2/3 { c8 \clef bass cis,, c } c4 c1 }
+>>
+  
index 38120cd681156f9038f67e53cf069cadfd4795d0..681efd206a70e4990ef0aa874652c6d4e1800fba 100644 (file)
@@ -284,7 +284,8 @@ Beam::connect_beams (Grob *me)
 }
 
 /*
-  TODO: should not make beams per stem, but per Y-level.
+  TODO: should not make beams per stem, but per Y-level; probably when
+  someone wants to sponsor feathered beaming.
 */
 MAKE_SCHEME_CALLBACK (Beam, print, 1);
 SCM
@@ -341,19 +342,19 @@ Beam::print (SCM grob)
 
   for (int i = 0; i <= stems.size (); i++)
     {
-      Grob *st = (i < stems.size ()) ? stems[i] : 0;
-
-      SCM this_beaming = st ? st->get_property ("beaming") : SCM_EOL;
-      Real xposn = st ? st->relative_coordinate (xcommon, X_AXIS) : 0.0;
-      Real stem_width = st ? robust_scm2double (st->get_property ("thickness"), 1.0) * lt : 0;
-      Direction stem_dir = st ? to_dir (st->get_property ("direction")) : CENTER;
+      Grob *stem = (i < stems.size ()) ? stems[i] : 0;
+      
+      SCM this_beaming = stem ? stem->get_property ("beaming") : SCM_EOL;
+      Real xposn = stem ? stem->relative_coordinate (xcommon, X_AXIS) : 0.0;
+      Real stem_width = stem ? robust_scm2double (stem->get_property ("thickness"), 1.0) * lt : 0;
+      Direction stem_dir = stem ? to_dir (stem->get_property ("direction")) : CENTER;
       /*
        We do the space left of ST, with lfliebertjes pointing to the
        right from the left stem, and rfliebertjes pointing left from
        right stem.
       */
       SCM left = (i > 0) ? scm_cdr (last_beaming) : SCM_EOL;
-      SCM right = st ? scm_car (this_beaming) : SCM_EOL;
+      SCM right = stem ? scm_car (this_beaming) : SCM_EOL;
 
       Array<int> full_beams;
       Array<int> lfliebertjes;
@@ -382,11 +383,14 @@ Beam::print (SCM grob)
            }
        }
 
-      /*
-       how much to stick out for beams across linebreaks
-      */
-      Real break_overshoot = 3.0;
-      Real w = (i > 0 && st) ? (xposn - last_xposn) : break_overshoot;
+      Drul_array<Real> break_overshoot
+       = robust_scm2drul (me->get_property ("break-overshoot"),
+                          Drul_array<Real> (-0.5, 0.0));
+
+      
+      Real w = (i > 0 && stem)
+       ? (xposn - last_xposn)
+       : break_overshoot[(i==0) ? LEFT: RIGHT];
 
       Real stem_offset = 0.0;
       if (i > 0)
@@ -395,7 +399,7 @@ Beam::print (SCM grob)
          stem_offset = -last_stem_width / 2;
        }
 
-      if (st)
+      if (stem)
        w += stem_width / 2;
 
       Real blot = me->get_layout ()->get_dimension (ly_symbol2scm ("blotdiameter"));
@@ -433,16 +437,16 @@ Beam::print (SCM grob)
        {
          Real nw_f;
 
-         if (st)
+         if (stem)
            {
-             int t = Stem::duration_log (st);
+             int t = Stem::duration_log (stem);
 
              SCM proc = me->get_property ("flag-width-function");
              SCM result = scm_call_1 (proc, scm_from_int (t));
              nw_f = scm_to_double (result);
            }
          else
-           nw_f = break_overshoot / 2;
+           nw_f = break_overshoot[RIGHT] / 2;
 
          /* Half beam should be one note-width,
             but let's make sure two half-beams never touch */
@@ -451,17 +455,15 @@ Beam::print (SCM grob)
          if (i > 0)
            rw = min (nw_f, ((xposn - last_xposn) / 2));
          else
-           /*
-             TODO: 0.5 is a guess.
-           */
            rw = xposn - me->get_bound (LEFT)->extent (xcommon, X_AXIS)[RIGHT]
-             - 0.5;
+             + break_overshoot[LEFT];
 
-         if (st)
+         if (stem)
            lw = min (nw_f, ((xposn - last_xposn) / 2));
          else
            lw = me->get_bound (RIGHT)->relative_coordinate (xcommon, X_AXIS)
-             - last_xposn;
+             - last_xposn
+             + break_overshoot[RIGHT];
 
          Stencil rhalf = Lookup::beam (slope, rw, thick, blot);
          Stencil lhalf = Lookup::beam (slope, lw, thick, blot);
@@ -476,7 +478,8 @@ Beam::print (SCM grob)
            {
              Stencil b (rhalf);
              b.translate_axis (xposn - x0 - rw, X_AXIS);
-             b.translate_axis (slope * (xposn - x0 -rw) + bdy * rfliebertjes[j], Y_AXIS);
+             b.translate_axis (slope * (xposn - x0 - rw)
+                               + bdy * rfliebertjes[j], Y_AXIS);
              the_beam.add_stencil (b);
            }
        }
@@ -1181,18 +1184,18 @@ Beam::set_beaming (Grob *me, Beaming_info_list *beaming)
              || (d == RIGHT && i == stems.size () -1))
            continue;
 
-         Grob *st = stems[i];
-         SCM beaming_prop = st->get_property ("beaming");
+         Grob *stem = stems[i];
+         SCM beaming_prop = stem->get_property ("beaming");
          if (beaming_prop == SCM_EOL
              || index_get_cell (beaming_prop, d) == SCM_EOL)
            {
              int b = beaming->infos_.elem (i).beams_i_drul_[d];
              if (i > 0
                  && i < stems.size () -1
-                 && Stem::is_invisible (st))
+                 && Stem::is_invisible (stem))
                b = min (b, beaming->infos_.elem (i).beams_i_drul_[-d]);
 
-             Stem::set_beaming (st, b, d);
+             Stem::set_beaming (stem, b, d);
            }
        }
       while (flip (&d) != LEFT);
@@ -1399,6 +1402,7 @@ ADD_INTERFACE (Beam, "beam-interface",
               "knee positioning-done position-callbacks "
               "concaveness dir-function quant-score auto-knee-gap gap "
               "gap-count chord-tremolo beamed-stem-shorten shorten least-squares-dy "
-              "details damping inspect-quants flag-width-function neutral-direction positions space-function "
+              "details damping inspect-quants flag-width-function "
+              "neutral-direction positions space-function break-overshoot "
               "thickness");
 
index 6575d8962c8a23fa50c8d2c9ca8575705c0123a2..dde923ea1d7e27b2a47b0d00a446b935db6892bb 100644 (file)
@@ -62,6 +62,7 @@ class Dynamic_engraver : public Engraver
   TRANSLATOR_DECLARATIONS (Dynamic_engraver);
   DECLARE_ACKNOWLEDGER (script);
   DECLARE_ACKNOWLEDGER (note_column);
+  DECLARE_ACKNOWLEDGER (slur);
 
 
 protected:
@@ -369,6 +370,15 @@ Dynamic_engraver::typeset_all ()
     }
 }
 
+void
+Dynamic_engraver::acknowledge_slur (Grob_info info)
+{
+  if (line_spanner_)
+    {
+      Side_position_interface::add_support (line_spanner_, info.grob ());
+    }
+}
+
 void
 Dynamic_engraver::acknowledge_note_column (Grob_info info)
 {
@@ -433,6 +443,7 @@ Dynamic_engraver::acknowledge_script (Grob_info info)
 
 ADD_ACKNOWLEDGER (Dynamic_engraver,script);
 ADD_ACKNOWLEDGER (Dynamic_engraver,note_column);
+ADD_ACKNOWLEDGER (Dynamic_engraver,slur);
 
 ADD_TRANSLATOR (Dynamic_engraver,
                /* descr */
index 0fa6356cd0e7faa4100f71d44f98bb3a53a874a2..995b5fd2bc7dc9eebdd7e7f5bdd9cb9f96a0fed4 100644 (file)
@@ -17,6 +17,8 @@ struct Spaceable_grob
   /// set a minimum distance
   static void add_rod (Grob *me, Grob *to, Real distance);
   static void add_spring (Grob *me, Grob *to, Real dist, Real strength);
+  static void get_spring (Grob *me, Grob *other, Real *dist, Real *inv_strength);
+
   static bool has_interface (Grob *);
   static void remove_interface (Grob *);
   static SCM get_minimum_distances (Grob *);
index effb83920f164ba47c8cb9940b9759bc5da100ef..73fffccadd4b180b5531881f300056ac0af0531a 100644 (file)
 struct Spacing_options
 {
   bool packed_;
-  bool uniform_;
+  bool stretch_uniformly_;
+  bool float_nonmusical_columns_;
+  
   Rational global_shortest_;
+  Real increment_;
   
   void init (Grob *me);
 };
 
+/*
+  TODO: prune to public interface.
+ */
 class Spacing_spanner
 {
 public:
+  static void generate_pair_spacing (Grob *me,
+                                    Paper_column *l, Paper_column *r,
+                                    Paper_column *nextr,
+                                    Spacing_options const *options);  
   static void standard_breakable_column_spacing (Grob *me, Item *l, Item *r,
-                                                Real *fixed, Real *space, Spacing_options const*);
-
+                                                Real *fixed, Real *space,
+                                                Spacing_options const*);
   static Real default_bar_spacing (Grob *, Grob *, Grob *, Moment);
   static Real note_spacing (Grob *, Grob *, Grob *, Spacing_options const*, bool *);
   static Real get_duration_space (Grob *, Moment dur, Rational shortest, bool *);
@@ -38,8 +48,8 @@ public:
   static void prune_loose_columns (Grob *, Link_array<Grob> *cols, Spacing_options const*);
   static void set_explicit_neighbor_columns (Link_array<Grob> const &cols);
   static void set_implicit_neighbor_columns (Link_array<Grob> const &cols);
-  static void do_measure (Grob *me, Link_array<Grob> *cols, Spacing_options const*);
-  static void musical_column_spacing (Grob *, Item *, Item *, Real, Spacing_options const*);
+  static void generate_springs (Grob *me, Link_array<Grob> const &cols, Spacing_options const*);
+  static void musical_column_spacing (Grob *, Item *, Item *, Spacing_options const*);
   DECLARE_SCHEME_CALLBACK (set_springs, (SCM));
   static bool has_interface (Grob *);
 };
index 82d942d396dd7574faa5f73af6d4eef003406c06..e79f96cbe53398f34381a52b7596540f74ba62b3 100644 (file)
@@ -50,5 +50,6 @@ protected:
 };
 
 void set_loose_columns (System *which, Column_x_positions const *posns);
+
 #endif /* SYSTEM_HH */
 
index 6464651a27dc7bb060e4b670c324b841be966e58..9138e4544a7d0e5a3bdc2783f6572887a09afeb4 100644 (file)
@@ -383,14 +383,18 @@ void
 Simple_spacer_wrapper::add_columns (Link_array<Grob> const &icols)
 {
   Link_array<Grob> cols (icols);
-
-  for (int i = cols.size (); i--;)
-    if (scm_is_pair (cols[i]->get_object ("between-cols")))
+  cols.clear();
+  
+  for (int i = 0;  i < icols.size (); i++)
+    if (scm_is_pair (icols[i]->get_object ("between-cols")))
       {
-       loose_cols_.push (cols[i]);
-       cols.del (i);
+       loose_cols_.push (icols[i]);
       }
-
+    else
+      {
+       cols.push (icols[i]);
+      }
+  
   spaced_cols_ = cols;
   for (int i = 0; i < cols.size () - 1; i++)
     {
index a36fe3c175adfb905d657a3dc8df984ac5c7341c..79b4173efd91036eadc6b9c479d3caa3990b6dfb 100644 (file)
@@ -99,6 +99,22 @@ Spaceable_grob::add_spring (Grob *me, Grob *p, Real d, Real inverse_strength)
   me->set_object ("ideal-distances", ideal);
 }
 
+void
+Spaceable_grob::get_spring (Grob *me, Grob *other, Real *dist, Real *inv_strength)
+{
+  for (SCM s = me->get_object ("ideal-distances");
+       scm_is_pair (s); s = scm_cdr (s))
+    {
+      Spring_smob *spring = unsmob_spring (scm_car (s));
+      if (spring && spring->other_ == other)
+       {
+         *dist = spring->distance_;
+         *inv_strength = spring->inverse_strength_;
+       }
+    }
+}
+
+
 void
 Spaceable_grob::remove_interface (Grob *me)
 {
diff --git a/lily/spacing-determine-loose-columns.cc b/lily/spacing-determine-loose-columns.cc
new file mode 100644 (file)
index 0000000..610b96b
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+  spacing-determine-loose-columns.cc -- implement Spacing_spanner
+  methods that decide which columns to turn loose.
+
+  source file of the GNU LilyPond music typesetter
+
+  (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+*/
+
+
+
+#include "system.hh"
+#include "paper-column.hh"
+#include "column-x-positions.hh"
+#include "staff-spacing.hh"
+#include "pointer-group-interface.hh"
+#include "spacing-spanner.hh"
+#include "note-spacing.hh"
+
+#include "break-align-interface.hh"
+
+/*
+  Return whether COL is fixed to its neighbors by some kind of spacing
+  constraint.
+
+
+  If in doubt, then we're not loose; the spacing engine should space
+  for it, risking suboptimal spacing.
+
+  (Otherwise, we might risk core dumps, and other weird stuff.)
+*/
+static bool
+is_loose_column (Grob *l, Grob *c, Grob *r)
+{
+  extract_grob_set (c, "right-neighbors", rns);
+  extract_grob_set (c, "left-neighbors", lns);
+  
+  /*
+    If this column doesn't have a proper neighbor, we should really
+    make it loose, but spacing it correctly is more than we can
+    currently can handle.
+
+    (this happens in the following situation:
+
+    |
+    |    clef G
+    *
+
+    |               |      ||
+    |               |      ||
+    O               O       ||
+
+
+    the column containing the clef is really loose, and should be
+    attached right to the first column, but that is a lot of work for
+    such a borderline case.)
+
+  */
+  if (lns.is_empty () || rns.is_empty ())
+    return false;
+
+  Item *l_neighbor = dynamic_cast<Item *> (lns[0]);
+  Item *r_neighbor = dynamic_cast<Item *> (rns[0]);
+
+  if (!l_neighbor || !r_neighbor)
+    return false;
+
+  l_neighbor = l_neighbor->get_column ();
+  r_neighbor = dynamic_cast<Item *> (Note_spacing::right_column (r_neighbor));
+
+  if (l == l_neighbor && r == r_neighbor)
+    return false;
+
+  if (!l_neighbor || !r_neighbor)
+    return false;
+
+  /*
+    Only declare loose if the bounds make a little sense.  This means
+    some cases (two isolated, consecutive clef changes) won't be
+    nicely folded, but hey, then don't do that.
+  */
+  if (! ((Paper_column::is_musical (l_neighbor) || Item::is_breakable (l_neighbor))
+        && (Paper_column::is_musical (r_neighbor) || Item::is_breakable (r_neighbor))))
+    {
+      return false;
+    }
+
+  /*
+    A rather hairy check, but we really only want to move around
+    clefs. (anything else?)
+
+    in any case, we don't want to move bar lines.
+  */
+  extract_grob_set (c, "elements", elts);
+  for (int i = elts.size (); i--; )
+    {
+      Grob *g = elts[i];
+      if (g && Break_align_interface::has_interface (g))
+       {
+         extract_grob_set (g, "elements", gelts);
+         for (int j = gelts.size (); j--; )
+           {
+             Grob *h = gelts[j];
+
+             /*
+               ugh. -- fix staff-bar name?
+             */
+             if (h && h->get_property ("break-align-symbol") == ly_symbol2scm ("staff-bar"))
+               return false;
+           }
+       }
+    }
+
+  return true;
+}
+
+/*
+  Remove columns that are not tightly fitting from COLS. In the
+  removed columns, set 'between-cols to the columns where it is in
+  between.
+*/
+void
+Spacing_spanner::prune_loose_columns (Grob *me, Link_array<Grob> *cols,
+                                     Spacing_options const *options)
+{
+  Link_array<Grob> newcols;
+  Real increment = robust_scm2double (me->get_property ("spacing-increment"), 1.2);
+  for (int i = 0; i < cols->size (); i++)
+    {
+      if (Item::is_breakable (cols->elem (i))
+         || Paper_column::is_musical (cols->elem (i)))
+       {
+         newcols.push (cols->elem (i));
+         continue;
+       }
+
+      Grob *c = cols->elem (i);
+      if (is_loose_column (cols->elem (i - 1), c, cols->elem (i + 1)))
+       {
+         extract_grob_set (c, "right-neighbors", rns_arr);
+         extract_grob_set (c, "left-neighbors", lns_arr);
+         
+         SCM lns = lns_arr.size () ? lns_arr.top()->self_scm () : SCM_BOOL_F;
+         SCM rns = rns_arr.size () ? rns_arr.top()->self_scm () : SCM_BOOL_F;
+         
+         /*
+           Either object can be non existent, if the score ends
+           prematurely.
+         */
+
+         extract_grob_set (unsmob_grob (rns), "right-items", right_items);
+         c->set_object ("between-cols", scm_cons (lns,
+                                                  right_items[0]->self_scm ()));
+
+         /*
+           Set distance constraints for loose columns
+         */
+         Drul_array<Grob *> next_door;
+         next_door[LEFT] = cols->elem (i - 1);
+         next_door[RIGHT] = cols->elem (i + 1);
+         Direction d = LEFT;
+         Drul_array<Real> dists (0, 0);
+
+         do
+           {
+             dists[d] = 0.0;
+             Item *lc = dynamic_cast<Item *> ((d == LEFT) ? next_door[LEFT] : c);
+             Item *rc = dynamic_cast<Item *> (d == LEFT ? c : next_door[RIGHT]);
+
+
+             extract_grob_set (lc, "spacing-wishes", wishes);
+             for (int k = wishes.size(); k--;)
+               {
+                 Grob *sp = wishes[k];
+                 if (Note_spacing::left_column (sp) != lc
+                     || Note_spacing::right_column (sp) != rc)
+                   continue;
+
+                 Real space, fixed;
+                 fixed = 0.0;
+                 bool dummy;
+
+                 if (d == LEFT)
+                   {
+                     /*
+                       The note spacing should be taken from the musical
+                       columns.
+
+                     */
+                     Real base = note_spacing (me, lc, rc, options, &dummy);
+                     Note_spacing::get_spacing (sp, rc, base, increment, &space, &fixed);
+
+                     space -= increment;
+
+                     dists[d] = max (dists[d], space);
+                   }
+                 else
+                   {
+                     Real space, fixed_space;
+                     Staff_spacing::get_spacing_params (sp,
+                                                        &space, &fixed_space);
+
+                     dists[d] = max (dists[d], fixed_space);
+                   }
+               }
+           }
+         while (flip (&d) != LEFT);
+
+         Rod r;
+         r.distance_ = dists[LEFT] + dists[RIGHT];
+         r.item_drul_[LEFT] = dynamic_cast<Item *> (cols->elem (i - 1));
+         r.item_drul_[RIGHT] = dynamic_cast<Item *> (cols->elem (i + 1));
+
+         r.add_to_cols ();
+       }
+      else
+       {
+         newcols.push (c);
+       }
+    }
+
+  *cols = newcols;
+}
+
+/*
+  Set neighboring columns determined by the spacing-wishes grob property.
+*/
+void
+Spacing_spanner::set_explicit_neighbor_columns (Link_array<Grob> const &cols)
+{
+  for (int i = 0; i < cols.size (); i++)
+    {
+      SCM right_neighbors = Grob_array::make_array ();
+      Grob_array *rn_arr = unsmob_grob_array (right_neighbors);
+      int min_rank = 100000;   // inf.
+
+      extract_grob_set (cols[i], "spacing-wishes", wishes);
+      for (int k = wishes.size(); k--;)
+       {
+         Item *wish = dynamic_cast<Item *> ( wishes[k]);
+
+         Item *lc = wish->get_column ();
+         Grob *right = Note_spacing::right_column (wish);
+
+         if (!right)
+           continue;
+
+         Item *rc = dynamic_cast<Item *> (right);
+
+         int right_rank = Paper_column::get_rank (rc);
+         int left_rank = Paper_column::get_rank (lc);
+
+         /*
+           update the left column.
+         */
+         if (right_rank <= min_rank)
+           {
+             if (right_rank < min_rank)
+               rn_arr->clear ();
+
+             min_rank = right_rank;
+             rn_arr->add (wish);
+           }
+
+         /*
+           update the right column of the wish.
+         */
+         int maxrank = 0;
+
+         extract_grob_set (rc, "left-neighbors", lns_arr);
+         if (lns_arr.size ())
+           {
+             Item *it = dynamic_cast<Item *> (lns_arr.top());
+             maxrank = Paper_column::get_rank (it->get_column ());
+           }
+
+         if (left_rank >= maxrank)
+           {
+             
+             if (left_rank > maxrank)
+               {
+                 Grob_array *ga = unsmob_grob_array (rc->get_object ("left-neighbors"));
+                 if (ga)
+                   ga->clear ();
+               }
+
+             Pointer_group_interface::add_grob (rc, ly_symbol2scm ("left-neighbors"), wish);
+           }
+       }
+
+      if (rn_arr->size ())
+       {
+         cols[i]->set_object ("right-neighbors", right_neighbors);
+       }
+    }
+}
+
+/*
+  Set neighboring columns that have no left/right-neighbor set
+  yet. Only do breakable non-musical columns, and musical columns.
+*/
+void
+Spacing_spanner::set_implicit_neighbor_columns (Link_array<Grob> const &cols)
+{
+  for (int i = 0; i < cols.size (); i++)
+    {
+      Item *it = dynamic_cast<Item *> (cols[i]);
+      if (!Item::is_breakable (it) && !Paper_column::is_musical (it))
+       continue;
+
+      // it->breakable || it->musical
+
+      /*
+       sloppy with typing left/right-neighbors should take list, but paper-column found instead.
+      */
+      extract_grob_set (cols[i], "left-neighbors", lns);
+      if (lns.is_empty () && i )
+       {
+         SCM ga_scm = Grob_array::make_array();
+         Grob_array *ga = unsmob_grob_array (ga_scm);
+         ga->add (cols[i-1]);
+         cols[i]->set_object ("left-neighbors", ga_scm);
+       }
+      extract_grob_set (cols[i], "right-neighbors", rns);
+      if (rns.is_empty () && i < cols.size () - 1)
+       {
+         SCM ga_scm = Grob_array::make_array();
+         Grob_array *ga = unsmob_grob_array (ga_scm);
+         ga->add (cols[i+1]);
+         cols[i]->set_object ("right-neighbors", ga_scm);
+       }
+    }
+}
index cc4b3f39c8e462b1ccc27d7c8f13bdb727151f43..1f8b5ecebe39ea3f5c97f13c2ac2e4e850704ea0 100644 (file)
@@ -14,6 +14,8 @@
 #include "pointer-group-interface.hh"
 #include "spanner.hh"
 
+#include "translator.icc"
+
 struct Rhythmic_tuple
 {
   Grob_info info_;
@@ -30,11 +32,13 @@ struct Rhythmic_tuple
   static int time_compare (Rhythmic_tuple const &, Rhythmic_tuple const &);
 };
 
-/**
+
+/*
+  TODO: allow starting & stopping of spacing regions.
+ */
+/*
    Acknowledge rhythmic elements, for initializing spacing fields in
    the columns.
-
-   should be the  last one of the toplevel context
 */
 class Spacing_engraver : public Engraver
 {
@@ -137,13 +141,13 @@ Spacing_engraver::stop_translation_timestep ()
   Paper_column *musical_column
     = dynamic_cast<Paper_column *> (unsmob_grob (get_property ("currentMusicalColumn")));
   
- SCM proportional = get_property ("proportionalNotationDuration");
- if (unsmob_moment (proportional))
-   {
-     musical_column->set_property ("shortest-playing-duration", proportional);
-     musical_column->set_property ("shortest-starter-duration", proportional);
-     return; 
-   }
 SCM proportional = get_property ("proportionalNotationDuration");
 if (unsmob_moment (proportional))
+    {
+      musical_column->set_property ("shortest-playing-duration", proportional);
+      musical_column->set_property ("shortest-starter-duration", proportional);
+      return; 
+    }
   
   Moment shortest_playing;
   shortest_playing.set_infinite (1);
@@ -192,14 +196,14 @@ Spacing_engraver::start_translation_timestep ()
     stopped_durations_.push (playing_durations_.get ());
 }
 
-#include "translator.icc"
-
 ADD_ACKNOWLEDGER (Spacing_engraver, staff_spacing);
 ADD_ACKNOWLEDGER (Spacing_engraver, note_spacing);
 ADD_ACKNOWLEDGER (Spacing_engraver, rhythmic_head);
   
 ADD_TRANSLATOR (Spacing_engraver,
-               /* descr */ "make a SpacingSpanner and do bookkeeping of shortest starting and playing notes  ",
+               "make a SpacingSpanner and do "
+               "bookkeeping of shortest starting and playing notes  ",
+
                /* creats*/ "SpacingSpanner",
                /* accepts */ "",
                /* reads */ "currentMusicalColumn currentCommandColumn proportionalNotationDuration",
index c50ee887d9df2bf0bd9b37e10514dec15fa00daf..a2f87ba6bf91a2682525026effe15284b1cb31e4 100644 (file)
 #include "system.hh"
 #include "paper-column.hh"
 #include "column-x-positions.hh"
-#include "staff-spacing.hh"
 #include "pointer-group-interface.hh"
-#include "spacing-spanner.hh"
-#include "note-spacing.hh"
-
-#include "break-align-interface.hh"
+#include "staff-spacing.hh"
 
 /* Find the loose columns in POSNS, and drape them around the columns
    specified in BETWEEN-COLS.  */
@@ -23,6 +19,10 @@ void
 set_loose_columns (System *which, Column_x_positions const *posns)
 {
   int loose_col_count = posns->loose_cols_.size ();
+  if (!loose_col_count)
+    return; 
+
+  Real default_padding = 1.0;
   for (int i = 0; i < loose_col_count; i++)
     {
       int divide_over = 1;
@@ -95,7 +95,7 @@ set_loose_columns (System *which, Column_x_positions const *posns)
       else
        {
          Interval my_extent = col->extent (col, X_AXIS);
-         distance_to_next = my_extent[RIGHT] + 1.0;
+         distance_to_next = my_extent[RIGHT] + default_padding;
          right_point = right->extent (common, X_AXIS)[LEFT];
        }
 
@@ -107,316 +107,3 @@ set_loose_columns (System *which, Column_x_positions const *posns)
 }
 
 
-
-/*
-  Return whether COL is fixed to its neighbors by some kind of spacing
-  constraint.
-
-
-  If in doubt, then we're not loose; the spacing engine should space
-  for it, risking suboptimal spacing.
-
-  (Otherwise, we might risk core dumps, and other weird stuff.)
-*/
-static bool
-loose_column (Grob *l, Grob *c, Grob *r)
-{
-  extract_grob_set (c, "right-neighbors", rns);
-  extract_grob_set (c, "left-neighbors", lns);
-  
-  /*
-    If this column doesn't have a proper neighbor, we should really
-    make it loose, but spacing it correctly is more than we can
-    currently can handle.
-
-    (this happens in the following situation:
-
-    |
-    |    clef G
-    *
-
-    |               |      ||
-    |               |      ||
-    O               O       ||
-
-
-    the column containing the clef is really loose, and should be
-    attached right to the first column, but that is a lot of work for
-    such a borderline case.)
-
-  */
-  if (lns.is_empty () || rns.is_empty ())
-    return false;
-
-  Item *l_neighbor = dynamic_cast<Item *> (lns[0]);
-  Item *r_neighbor = dynamic_cast<Item *> (rns[0]);
-
-  if (!l_neighbor || !r_neighbor)
-    return false;
-
-  l_neighbor = l_neighbor->get_column ();
-  r_neighbor = dynamic_cast<Item *> (Note_spacing::right_column (r_neighbor));
-
-  if (l == l_neighbor && r == r_neighbor)
-    return false;
-
-  if (!l_neighbor || !r_neighbor)
-    return false;
-
-  /*
-    Only declare loose if the bounds make a little sense.  This means
-    some cases (two isolated, consecutive clef changes) won't be
-    nicely folded, but hey, then don't do that.
-  */
-  if (! ((Paper_column::is_musical (l_neighbor) || Item::is_breakable (l_neighbor))
-        && (Paper_column::is_musical (r_neighbor) || Item::is_breakable (r_neighbor))))
-    {
-      return false;
-    }
-
-  /*
-    A rather hairy check, but we really only want to move around
-    clefs. (anything else?)
-
-    in any case, we don't want to move bar lines.
-  */
-  extract_grob_set (c, "elements", elts);
-  for (int i = elts.size (); i--; )
-    {
-      Grob *g = elts[i];
-      if (g && Break_align_interface::has_interface (g))
-       {
-         extract_grob_set (g, "elements", gelts);
-         for (int j = gelts.size (); j--; )
-           {
-             Grob *h = gelts[j];
-
-             /*
-               ugh. -- fix staff-bar name?
-             */
-             if (h && h->get_property ("break-align-symbol") == ly_symbol2scm ("staff-bar"))
-               return false;
-           }
-       }
-    }
-
-  return true;
-}
-
-/*
-  Remove columns that are not tightly fitting from COLS. In the
-  removed columns, set 'between-cols to the columns where it is in
-  between.
-*/
-void
-Spacing_spanner::prune_loose_columns (Grob *me, Link_array<Grob> *cols,
-                                     Spacing_options const *options)
-{
-  Link_array<Grob> newcols;
-  Real increment = robust_scm2double (me->get_property ("spacing-increment"), 1.2);
-  for (int i = 0; i < cols->size (); i++)
-    {
-      if (Item::is_breakable (cols->elem (i))
-         || Paper_column::is_musical (cols->elem (i)))
-       {
-         newcols.push (cols->elem (i));
-         continue;
-       }
-
-      Grob *c = cols->elem (i);
-      if (loose_column (cols->elem (i - 1), c, cols->elem (i + 1)))
-       {
-         extract_grob_set (c, "right-neighbors", rns_arr);
-         extract_grob_set (c, "left-neighbors", lns_arr);
-         
-         SCM lns = lns_arr.size () ? lns_arr.top()->self_scm () : SCM_BOOL_F;
-         SCM rns = rns_arr.size () ? rns_arr.top()->self_scm () : SCM_BOOL_F;
-         
-         /*
-           Either object can be non existent, if the score ends
-           prematurely.
-         */
-
-         extract_grob_set (unsmob_grob (rns), "right-items", right_items);
-         c->set_object ("between-cols", scm_cons (lns,
-                                                  right_items[0]->self_scm ()));
-
-         /*
-           Set distance constraints for loose columns
-         */
-         Drul_array<Grob *> next_door;
-         next_door[LEFT] = cols->elem (i - 1);
-         next_door[RIGHT] = cols->elem (i + 1);
-         Direction d = LEFT;
-         Drul_array<Real> dists (0, 0);
-
-         do
-           {
-             dists[d] = 0.0;
-             Item *lc = dynamic_cast<Item *> ((d == LEFT) ? next_door[LEFT] : c);
-             Item *rc = dynamic_cast<Item *> (d == LEFT ? c : next_door[RIGHT]);
-
-
-             extract_grob_set (lc, "spacing-wishes", wishes);
-             for (int k = wishes.size(); k--;)
-               {
-                 Grob *sp = wishes[k];
-                 if (Note_spacing::left_column (sp) != lc
-                     || Note_spacing::right_column (sp) != rc)
-                   continue;
-
-                 Real space, fixed;
-                 fixed = 0.0;
-                 bool dummy;
-
-                 if (d == LEFT)
-                   {
-                     /*
-                       The note spacing should be taken from the musical
-                       columns.
-
-                     */
-                     Real base = note_spacing (me, lc, rc, options, &dummy);
-                     Note_spacing::get_spacing (sp, rc, base, increment, &space, &fixed);
-
-                     space -= increment;
-
-                     dists[d] = max (dists[d], space);
-                   }
-                 else
-                   {
-                     Real space, fixed_space;
-                     Staff_spacing::get_spacing_params (sp,
-                                                        &space, &fixed_space);
-
-                     dists[d] = max (dists[d], fixed_space);
-                   }
-               }
-           }
-         while (flip (&d) != LEFT);
-
-         Rod r;
-         r.distance_ = dists[LEFT] + dists[RIGHT];
-         r.item_drul_[LEFT] = dynamic_cast<Item *> (cols->elem (i - 1));
-         r.item_drul_[RIGHT] = dynamic_cast<Item *> (cols->elem (i + 1));
-
-         r.add_to_cols ();
-       }
-      else
-       {
-         newcols.push (c);
-       }
-    }
-
-  *cols = newcols;
-}
-
-/*
-  Set neighboring columns determined by the spacing-wishes grob property.
-*/
-void
-Spacing_spanner::set_explicit_neighbor_columns (Link_array<Grob> const &cols)
-{
-  for (int i = 0; i < cols.size (); i++)
-    {
-      SCM right_neighbors = Grob_array::make_array ();
-      Grob_array *rn_arr = unsmob_grob_array (right_neighbors);
-      int min_rank = 100000;   // inf.
-
-      extract_grob_set (cols[i], "spacing-wishes", wishes);
-      for (int k = wishes.size(); k--;)
-       {
-         Item *wish = dynamic_cast<Item *> ( wishes[k]);
-
-         Item *lc = wish->get_column ();
-         Grob *right = Note_spacing::right_column (wish);
-
-         if (!right)
-           continue;
-
-         Item *rc = dynamic_cast<Item *> (right);
-
-         int right_rank = Paper_column::get_rank (rc);
-         int left_rank = Paper_column::get_rank (lc);
-
-         /*
-           update the left column.
-         */
-         if (right_rank <= min_rank)
-           {
-             if (right_rank < min_rank)
-               rn_arr->clear ();
-
-             min_rank = right_rank;
-             rn_arr->add (wish);
-           }
-
-         /*
-           update the right column of the wish.
-         */
-         int maxrank = 0;
-
-         extract_grob_set (rc, "left-neighbors", lns_arr);
-         if (lns_arr.size ())
-           {
-             Item *it = dynamic_cast<Item *> (lns_arr.top());
-             maxrank = Paper_column::get_rank (it->get_column ());
-           }
-
-         if (left_rank >= maxrank)
-           {
-             
-             if (left_rank > maxrank)
-               {
-                 Grob_array *ga = unsmob_grob_array (rc->get_object ("left-neighbors"));
-                 if (ga)
-                   ga->clear ();
-               }
-
-             Pointer_group_interface::add_grob (rc, ly_symbol2scm ("left-neighbors"), wish);
-           }
-       }
-
-      if (rn_arr->size ())
-       {
-         cols[i]->set_object ("right-neighbors", right_neighbors);
-       }
-    }
-}
-
-/*
-  Set neighboring columns that have no left/right-neighbor set
-  yet. Only do breakable non-musical columns, and musical columns.
-*/
-void
-Spacing_spanner::set_implicit_neighbor_columns (Link_array<Grob> const &cols)
-{
-  for (int i = 0; i < cols.size (); i++)
-    {
-      Item *it = dynamic_cast<Item *> (cols[i]);
-      if (!Item::is_breakable (it) && !Paper_column::is_musical (it))
-       continue;
-
-      // it->breakable || it->musical
-
-      /*
-       sloppy with typing left/right-neighbors should take list, but paper-column found instead.
-      */
-      extract_grob_set (cols[i], "left-neighbors", lns);
-      if (lns.is_empty () && i )
-       {
-         SCM ga_scm = Grob_array::make_array();
-         Grob_array *ga = unsmob_grob_array (ga_scm);
-         ga->add (cols[i-1]);
-         cols[i]->set_object ("left-neighbors", ga_scm);
-       }
-      extract_grob_set (cols[i], "right-neighbors", rns);
-      if (rns.is_empty () && i < cols.size () - 1)
-       {
-         SCM ga_scm = Grob_array::make_array();
-         Grob_array *ga = unsmob_grob_array (ga_scm);
-         ga->add (cols[i+1]);
-         cols[i]->set_object ("right-neighbors", ga_scm);
-       }
-    }
-}
index 108454d63e5d77666264b17b1b04861c33445667..703337bd0bd46dbd6030783e0758089490e6db04 100644 (file)
 
 
 void
-Spacing_options::init (Grob*me)
+Spacing_options::init (Grob *me)
 {
+  increment_ = robust_scm2double (me->get_property ("spacing-increment"), 1);
   packed_ = to_boolean (me->get_layout ()->c_variable ("packed"));
-  uniform_ = to_boolean (me->get_property ("uniform-stretching")); 
+  stretch_uniformly_ = to_boolean (me->get_property ("uniform-stretching"));
+  float_nonmusical_columns_
+    = to_boolean (me->get_property ("strict-note-spacing"));
 }
 
 
@@ -72,18 +75,7 @@ Spacing_spanner::set_springs (SCM smob)
   
   prune_loose_columns (me, &all, &options);
   set_implicit_neighbor_columns (all);
-
-  int j = 0;
-  for (int i = 1; i < all.size (); i++)
-    {
-      Grob *sc = all[i];
-      if (Item::is_breakable (sc))
-       {
-         Link_array<Grob> measure (all.slice (j, i + 1));
-         do_measure (me, &measure, &options);
-         j = i;
-       }
-    }
+  generate_springs (me, all, &options);
 
   return SCM_UNSPECIFIED;
 }
@@ -165,7 +157,8 @@ Spacing_spanner::find_shortest (Grob *me, Link_array<Grob> const &cols)
          max_count = counts[i];
        }
 
-      //      printf ("duration %d/%d, count %d\n", durations[i].num (), durations[i].den (), counts[i]);
+      // printf ("duration %d/%d, count %d\n",
+      // durations[i].num (), durations[i].den (), counts[i]);
     }
 
   SCM bsd = me->get_property ("base-shortest-duration");
@@ -179,77 +172,99 @@ Spacing_spanner::find_shortest (Grob *me, Link_array<Grob> const &cols)
   return d;
 }
 
-/*
-  Generate spacing for a single measure. We used to have code that did
-  per-measure spacing. Now we have piecewise spacing. We should fix
-  this to support "spacing-regions": some regions have different notes
-  (different time sigs) than others, and should be spaced differently.
-*/
 void
-Spacing_spanner::do_measure (Grob *me,
-                            Link_array<Grob> *cols,
-                            Spacing_options const *options
-                            )
+Spacing_spanner::generate_pair_spacing (Grob *me,
+                                       Paper_column *left_col, Paper_column *right_col,
+                                       Paper_column *after_right_col,
+                                       Spacing_options const *options)
 {
-  Real headwid = robust_scm2double (me->get_property ("spacing-increment"), 1);
-  for (int i = 0; i < cols->size () - 1; i++)
+  if (Paper_column::is_musical (left_col))
     {
-      Item *l = dynamic_cast<Item *> (cols->elem (i));
-      Item *r = dynamic_cast<Item *> (cols->elem (i + 1));
-
-      Paper_column *lc = dynamic_cast<Paper_column *> (l);
-      Paper_column *rc = dynamic_cast<Paper_column *> (r);
-
-      if (Paper_column::is_musical (l))
+      bool skip_unbroken_right = false;
+      
+      if (!Paper_column::is_musical (right_col)
+         && options->float_nonmusical_columns_
+         && after_right_col
+         && Paper_column::is_musical (after_right_col))
        {
-         musical_column_spacing (me, lc, rc, headwid, options);
-         if (Item *rb = r->find_prebroken_piece (LEFT))
-           musical_column_spacing (me, lc, rb, headwid, options);
+         skip_unbroken_right = true;
        }
-      else
+
+      if (skip_unbroken_right)
        {
          /*
-           The case that the right part is broken as well is rather
-           rare, but it is possible, eg. with a single empty measure,
-           or if one staff finishes a tad earlier than the rest.
+           TODO: should generate rods to prevent collisions.
          */
-         Item *lb = l->find_prebroken_piece (RIGHT);
-         Item *rb = r->find_prebroken_piece (LEFT);
+         musical_column_spacing (me, left_col, after_right_col, options);
+         right_col->set_object ("between-cols", scm_cons (left_col->self_scm (),
+                                                          after_right_col->self_scm ()));
+       }
+      else
+       musical_column_spacing (me, left_col, right_col, options);
+      
 
-         if (i == 0 && Paper_column::get_rank (l) == 0)
-           l = 0;
+      if (Item *rb = right_col->find_prebroken_piece (LEFT))
+       musical_column_spacing (me, left_col, rb, options);
+    }
+  else
+    {
+      /*
+       The case that the right part is broken as well is rather
+       rare, but it is possible, eg. with a single empty measure,
+       or if one staff finishes a tad earlier than the rest.
+      */
+      Item *lb = left_col->find_prebroken_piece (RIGHT);
+      Item *rb = right_col->find_prebroken_piece (LEFT);
 
-         if (l && r)
-           breakable_column_spacing (me, l, r, options);
+      if (left_col && right_col)
+       breakable_column_spacing (me, left_col, right_col, options);
          
-         if (lb && r)
-           breakable_column_spacing (me, lb, r, options);
+      if (lb && right_col)
+       breakable_column_spacing (me, lb, right_col, options);
 
-         if (l && rb)
-           breakable_column_spacing (me, l, rb, options);
+      if (left_col && rb)
+       breakable_column_spacing (me, left_col, rb, options);
 
-         if (lb && rb)
-           breakable_column_spacing (me, lb, rb, options);
-       }
+      if (lb && rb)
+       breakable_column_spacing (me, lb, rb, options);
+    }
+}
+
+void
+Spacing_spanner::generate_springs (Grob *me,
+                                  Link_array<Grob> const &cols,
+                                  Spacing_options const *options)
+{
+  Paper_column *next = 0;
+  Paper_column *next_next = 0;
+  for (int i = cols.size (); i--;)
+    {
+      Paper_column *col = dynamic_cast<Paper_column *> (cols[i]);
+      if (next)
+       generate_pair_spacing (me, col, next, next_next, options);
+
+      next_next = next;
+      next = col;
     }
 }
 
 /*
-  Generate the space between two musical columns LC and RC, given
+  Generate the space between two musical columns LEFT_COL and RIGHT_COL, given
   spacing parameters INCR and SHORTEST.
 */
 void
-Spacing_spanner::musical_column_spacing (Grob *me, Item *lc, Item *rc,
-                                        Real increment,
+Spacing_spanner::musical_column_spacing (Grob *me,
+                                        Item *left_col,
+                                        Item *right_col,
                                         Spacing_options const *options)
 {
   bool expand_only = false;
-  Real base_note_space = note_spacing (me, lc, rc, options, &expand_only);
+  Real base_note_space = note_spacing (me, left_col, right_col, options, &expand_only);
   
   Real compound_note_space = 0.0;
   Real compound_fixed_note_space = 0.0;
 
-  if (options->uniform_)
+  if (options->stretch_uniformly_)
     {
       compound_note_space = base_note_space;
     }
@@ -257,7 +272,7 @@ Spacing_spanner::musical_column_spacing (Grob *me, Item *lc, Item *rc,
     {
       int wish_count = 0;
 
-      extract_grob_set (lc, "right-neighbors", neighbors);
+      extract_grob_set (left_col, "right-neighbors", neighbors);
 
       /*
        We adjust the space following a note only if the next note
@@ -269,8 +284,8 @@ Spacing_spanner::musical_column_spacing (Grob *me, Item *lc, Item *rc,
          Grob *wish = neighbors[i];
 
          Item *wish_rcol = Note_spacing::right_column (wish);
-         if (Note_spacing::left_column (wish) != lc
-             || (wish_rcol != rc && wish_rcol != rc->original_))
+         if (Note_spacing::left_column (wish) != left_col
+             || (wish_rcol != right_col && wish_rcol != right_col->original_))
            continue;
 
          /*
@@ -281,7 +296,7 @@ Spacing_spanner::musical_column_spacing (Grob *me, Item *lc, Item *rc,
              Real space = 0.0;
              Real fixed = 0.0;
 
-             Note_spacing::get_spacing (wish, rc, base_note_space, increment, &space, &fixed);
+             Note_spacing::get_spacing (wish, right_col, base_note_space, options->increment_, &space, &fixed);
 
              compound_note_space = compound_note_space + space;
              compound_fixed_note_space = compound_fixed_note_space + fixed;
@@ -289,8 +304,8 @@ Spacing_spanner::musical_column_spacing (Grob *me, Item *lc, Item *rc,
            }
        }
 
-      if (Paper_column::when_mom (rc).grace_part_
-         && !Paper_column::when_mom (lc).grace_part_)
+      if (Paper_column::when_mom (right_col).grace_part_
+         && !Paper_column::when_mom (left_col).grace_part_)
        {
          /*
            Ugh. 0.8 is arbitrary.
@@ -301,7 +316,7 @@ Spacing_spanner::musical_column_spacing (Grob *me, Item *lc, Item *rc,
       if (compound_note_space < 0 || wish_count == 0)
        {
          compound_note_space = base_note_space;
-         compound_fixed_note_space = increment;
+         compound_fixed_note_space = options->increment_;
        }
       else
        {
@@ -346,7 +361,7 @@ Spacing_spanner::musical_column_spacing (Grob *me, Item *lc, Item *rc,
       distance = compound_note_space;
     }
 
-  Spaceable_grob::add_spring (lc, rc, distance, inverse_strength);
+  Spaceable_grob::add_spring (left_col, right_col, distance, inverse_strength);
 }
 
 /*
@@ -414,7 +429,7 @@ Spacing_spanner::breakable_column_spacing (Grob *me, Item *l, Item *r,
       compound_fixed /= wish_count;
     }
 
-  if (options->uniform_ && l->break_status_dir () != RIGHT)
+  if (options->stretch_uniformly_ && l->break_status_dir () != RIGHT)
     {
       compound_fixed = 0.0;
     }
@@ -446,7 +461,7 @@ ADD_INTERFACE (Spacing_spanner, "spacing-spanner-interface",
               "head width) A 16th note is followed by 0.5 note head width. The\n"
               "quarter note is followed by  3 NHW, the half by 4 NHW, etc.\n",
               
-              "grace-space-factor spacing-increment base-shortest-duration "
+              "grace-space-factor spacing-increment base-shortest-duration strict-note-spacing "
               "shortest-duration-space common-shortest-duration uniform-stretching"
 
               );
index bc91d17aea1f9ce1f110b7d9d350d8434da38a23..3f435d637694d55c7661f8e95b06c4abf28e3bd9 100644 (file)
@@ -181,9 +181,13 @@ Tuplet_bracket::print (SCM smob)
       if (bounds[d]->break_status_dir())
        {
          Interval overshoot (robust_scm2drul (me->get_property ("break-overshoot"),
-                                              Interval (0,0)));
+                                              Interval (-0.5, 1.0)));
 
-         x_span[d] += d * overshoot[d];
+         if (d == RIGHT)
+           x_span[d] += d * overshoot[d];
+         else
+           x_span[d] = robust_relative_extent(bounds[d], commonx, X_AXIS)[RIGHT]
+             - overshoot[LEFT];
        }
     }
   while (flip (&d) != LEFT);
index bb10de870ac40a695a2d58025b45a83e7b6da338..2ca7f0007a1cc443e17ab3e187ba469b974547f4 100644 (file)
@@ -211,6 +211,9 @@ typeset on a Stem. Valid options include @code{()} and
 flag.")
      
      (flag-width-function ,procedure? "Procedure that computes the width of a half-beam (a non-connecting beam.).")
+     (strict-note-spacing ,boolean? "If set, unbroken columns
+with non-musical material (clefs, barlines, etc.) are not spaced
+separately, but put before musical columns.")
      (font-family ,symbol? "The font family is the broadest category for selecting text fonts. Options include: @code{sans}, @code{roman} ")
      (font-encoding ,symbol? "The font encoding is the broadest
 category for selecting a font. Options include: @code{fetaMusic},
index 978ccdd9d47d27786945051aa85e440dd9f6fc99..8ab7c2c0f223f8b0663752afeb716663948e8447 100644 (file)
        (padding . 1.1)
        (thickness . 1.6)
        (edge-height . (0.7 . 0.7))
-       (break-overshoot . (1.0 . 1.0)) 
        (shorten-pair . (-0.2 . -0.2))
        (edge-text . ,(cons (markup #:arrow-head 0 -1 #f)
                            (markup #:arrow-head 0 1 #f)))