]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/spacing-spanner.cc
* Documentation/user/refman.itely,
[lilypond.git] / lily / spacing-spanner.cc
index 2d5c5fd2c3b5293afd69e654698788f1d0009839..5a889c74b480154d3e452a64e75c7ddc9f278d77 100644 (file)
@@ -3,14 +3,16 @@
   
   source file of the GNU LilyPond music typesetter
   
-  (c) 1999--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+  (c) 1999--2003 Han-Wen Nienhuys <hanwen@cs.uu.nl>
   
  */
 
 #include <math.h>
 #include <stdio.h>
 
+#include "main.hh"
 #include "system.hh"
+#include "warn.hh"
 #include "paper-def.hh"
 #include "paper-score.hh"
 #include "paper-column.hh"
 #include "paper-column.hh"
 #include "spaceable-grob.hh"
 #include "break-align-interface.hh"
+#include "spacing-interface.hh"
 
-
-
-
-/*
-  paper-column:
- */
 class Spacing_spanner
 {
 public:
@@ -44,7 +41,7 @@ public:
   static Rational find_shortest (Grob *, Link_array<Grob> const &);  
   static void breakable_column_spacing (Grob*, Item* l, Item *r, Moment);
   static void find_loose_columns () {}
-  static void prune_loose_colunms (Grob*,Link_array<Grob> *cols, Rational);
+  static void prune_loose_columns (Grob*,Link_array<Grob> *cols, Rational);
   static void find_loose_columns (Link_array<Grob> cols);
   static void set_explicit_neighbor_columns (Link_array<Grob> cols);
   static void set_implicit_neighbor_columns (Link_array<Grob> cols);
@@ -101,7 +98,7 @@ loose_column (Grob *l, Grob *c, Grob *r)
   if (!l_neighbor || !r_neighbor)
     return false;
 
-  l_neighbor = l_neighbor->column_l();
+  l_neighbor = l_neighbor->get_column ();
   r_neighbor = dynamic_cast<Item*> (Note_spacing::right_column  (r_neighbor));
 
   if (l == l_neighbor && r == r_neighbor)
@@ -157,7 +154,7 @@ loose_column (Grob *l, Grob *c, Grob *r)
   between.
 */
 void
-Spacing_spanner::prune_loose_colunms (Grob*me,Link_array<Grob> *cols, Rational shortest)
+Spacing_spanner::prune_loose_columns (Grob*me,Link_array<Grob> *cols, Rational shortest)
 {
   Link_array<Grob> newcols;
   Real increment = gh_scm2double (me->get_grob_property ("spacing-increment"));
@@ -241,7 +238,7 @@ Spacing_spanner::prune_loose_colunms (Grob*me,Link_array<Grob> *cols, Rational s
          while (flip (&d) != LEFT);
 
          Rod r;
-         r.distance_f_ = dists[LEFT] + dists[RIGHT];
+         r.distance_ = dists[LEFT] + dists[RIGHT];
          r.item_l_drul_[LEFT] = dynamic_cast<Item*> (cols->elem(i-1));
          r.item_l_drul_[RIGHT] = dynamic_cast<Item*> (cols->elem (i+1));
 
@@ -273,7 +270,7 @@ Spacing_spanner::set_explicit_neighbor_columns (Link_array<Grob> cols)
        {
          Item * wish = dynamic_cast<Item*> (unsmob_grob (gh_car (s)));
 
-         Item * lc = wish->column_l ();
+         Item * lc = wish->get_column ();
          Grob * right = Note_spacing::right_column (wish);
 
          if (!right)
@@ -281,8 +278,8 @@ Spacing_spanner::set_explicit_neighbor_columns (Link_array<Grob> cols)
 
          Item * rc = dynamic_cast<Item*> (right);
 
-         int right_rank = Paper_column::rank_i (rc);
-         int left_rank = Paper_column::rank_i (lc);      
+         int right_rank = Paper_column::get_rank (rc);
+         int left_rank = Paper_column::get_rank (lc);    
 
          /*
            update the left column.
@@ -305,7 +302,7 @@ Spacing_spanner::set_explicit_neighbor_columns (Link_array<Grob> cols)
              && unsmob_grob (gh_car (left_neighs)))
            {
              Item * it = dynamic_cast<Item*> (unsmob_grob (gh_car (left_neighs)));
-             maxrank = Paper_column::rank_i (it->column_l());
+             maxrank = Paper_column::get_rank (it->get_column ());
            }
 
          if (left_rank >= maxrank)
@@ -364,12 +361,25 @@ Spacing_spanner::set_springs (SCM smob)
 {
   Grob *me = unsmob_grob (smob);
 
-  Link_array<Grob> all (me->pscore_l_->line_l_->column_l_arr ()) ;
+  Link_array<Grob> all (me->pscore_->system_->columns ()) ;
 
   set_explicit_neighbor_columns (all);
 
-  Rational global_shortest = find_shortest (me, all);
-  prune_loose_colunms (me, &all, global_shortest);
+  SCM preset_shortest = me->get_grob_property ("common-shortest-duration");
+  Rational global_shortest;
+  if (unsmob_moment (preset_shortest))
+    {
+      global_shortest = unsmob_moment (preset_shortest)->main_part_;
+    }
+  else
+    {
+      global_shortest = find_shortest (me, all);
+      if (verbose_global_b)
+       {
+         progress_indication (_f("Global shortest duration is %s\n", global_shortest.to_string ())); 
+       }
+    }
+  prune_loose_columns (me, &all, global_shortest);
   set_implicit_neighbor_columns (all);
 
   
@@ -559,7 +569,7 @@ Spacing_spanner::musical_column_spacing (Grob *me, Item * lc, Item *rc, Real inc
 
       Item *wish_rcol = Note_spacing::right_column (wish);
       if (Note_spacing::left_column (wish) != lc
-         || (wish_rcol != rc && wish_rcol != rc->original_l_))
+         || (wish_rcol != rc && wish_rcol != rc->original_))
        continue;
 
       /*
@@ -576,14 +586,21 @@ Spacing_spanner::musical_column_spacing (Grob *me, Item * lc, Item *rc, Real inc
        }
     }
 
+  if (Paper_column::when_mom (rc).grace_part_ &&
+      !Paper_column::when_mom (lc).grace_part_)
+    {
+      /*
+       Ugh. 0.8 is arbitrary.
+       */
+      max_note_space *= 0.8; 
+    }
+  
   if (max_note_space < 0)
     {
       max_note_space = base_note_space;
       max_fixed_note_space =  increment;
     }
 
-  bool ragged = to_boolean (me->paper_l ()->get_scmvar ("raggedright"));
-
   /*
     Whatever we do, the fixed space is smaller than the real
     space.
@@ -591,12 +608,36 @@ Spacing_spanner::musical_column_spacing (Grob *me, Item * lc, Item *rc, Real inc
     TODO: this criterion is discontinuous in the derivative.
     Maybe it should be continuous?
   */
-  max_fixed_note_space = max_fixed_note_space <?  max_note_space;
-  
-  Real strength = (ragged) ? 1.0 : 1 / (max_note_space - max_fixed_note_space);
-  Real distance = (ragged) ? max_fixed_note_space : max_note_space;
+  max_fixed_note_space = max_fixed_note_space <? max_note_space;
+
+  bool packed = to_boolean (me->get_paper ()->get_scmvar ("packed"));
+  Real strength, distance;
+
+  /*
+    TODO: make sure that the space doesn't exceed the right margin.
+   */
+  if (packed)
+    {
+      /*
+       In packed mode, pack notes as tight as possible.  This makes
+       sense mostly in combination with raggedright mode: the notes
+       are then printed at minimum distance.  This is mostly useful
+       for ancient notation, but may also be useful for some flavours
+       of contemporary music.  If not in raggedright mode, lily will
+       pack as much bars of music as possible into a line, but the
+       line will then be stretched to fill the whole linewidth.
+      */
+      strength = 1.0;
+      distance = max_fixed_note_space;
+    }
+  else
+    {
+      strength = 1 / (max_note_space - max_fixed_note_space);
+      distance = max_note_space;
+    }
+
   //  Spaceable_grob::add_spring (lc, rc, distance, strength, expand_only);
-  
+
   Spaceable_grob::add_spring (lc, rc, distance, strength, false);  
 }
 
@@ -610,8 +651,25 @@ Spacing_spanner::standard_breakable_column_spacing (Grob * me, Item*l, Item*r,
                                   Real * fixed, Real * space,
                                   Moment shortest)
 {
-  *fixed = l->extent (l, X_AXIS)[RIGHT] - r->extent (r, X_AXIS)[LEFT];
-      
+  *fixed = 0.0;
+  Direction d = LEFT;
+  Drul_array<Item*> cols(l,r);
+  
+  do
+    {
+      if (!Paper_column::musical_b (cols[d]))
+       {
+         /*
+           Tied accidentals over barlines cause problems, so lets see
+           what happens if we do this for non musical columns only.
+          */
+         Interval lext = cols[d]->extent (cols [d], X_AXIS);
+         *fixed += -d * lext[-d];
+       }
+    }
+  while (flip (&d) != LEFT);
+
   if (l->breakable_b (l) && r->breakable_b(r))
     {
       Moment *dt = unsmob_moment (l->get_grob_property ("measure-length"));
@@ -630,8 +688,6 @@ Spacing_spanner::standard_breakable_column_spacing (Grob * me, Item*l, Item*r,
 
       *space = *fixed + get_duration_space (me, dt, shortest.main_part_, &dummy);
     }
-  
-  
 }
 
 
@@ -663,10 +719,20 @@ Spacing_spanner::breakable_column_spacing (Grob*me, Item* l, Item *r,Moment shor
        pointer munging.
 
       */
-      assert (spacing_grob-> column_l () == l);
+      assert (spacing_grob-> get_column () == l);
 
       Staff_spacing::get_spacing_params (spacing_grob,
-                                        &space, &fixed_space);  
+                                        &space, &fixed_space);
+
+      if (Paper_column::when_mom (r).grace_part_)
+       {
+         /*
+           Correct for grace notes.
+
+           Ugh. The 0.8 is arbitrary.
+          */
+         space *= 0.8;
+       }
       if (space > max_space)
        {
          max_space = space;
@@ -690,7 +756,7 @@ Spacing_spanner::breakable_column_spacing (Grob*me, Item* l, Item *r,Moment shor
 
       (here no StaffSpacing from Y to X is found.)
     */      
-      programming_error ("No StaffSpacing wishes found");
+      warning ("No spacing wishes found. Does your score have a staff?");
       max_space = 2.0;
       max_fixed = 1.0;
     }
@@ -707,10 +773,16 @@ Spacing_spanner::breakable_column_spacing (Grob*me, Item* l, Item *r,Moment shor
     Hmm.  we do 1/0 in the next thing. Perhaps we should check if this
     works on all architectures.
    */
-  
-  bool ragged = to_boolean (me->paper_l ()->get_scmvar ("raggedright"));
-  Real strength = (ragged) ? 1.0 : 1 / (max_space - max_fixed);
-  Real distance = (ragged) ? max_fixed : max_space;
+
+  /*
+    There used to be code that changed spacing depending on
+    raggedright setting.  Ugh.
+
+    Do it more cleanly, or rename the property. 
+    
+   */
+  Real strength = 1 / (max_space - max_fixed);
+  Real distance =  max_space;
   Spaceable_grob::add_spring (l, r, distance, strength, false);
 }
 
@@ -743,8 +815,10 @@ Spacing_spanner::get_duration_space (Grob*me, Moment d, Rational shortest, bool
 
        */
       Rational ratio = d.main_part_ / shortest;
-      
+
+#if 0
       *expand_only = true;
+#endif
       return ((k-1) + double (ratio)) * incr;
     }
   else
@@ -775,7 +849,7 @@ Spacing_spanner::note_spacing (Grob*me, Grob *lc, Grob *rc,
   
   if (! shortest_playing_len.to_bool ())
     {
-      programming_error ("can't find a ruling note at " + Paper_column::when_mom (lc).str ());
+      programming_error ("can't find a ruling note at " + Paper_column::when_mom (lc).to_string ());
       shortest_playing_len = 1;
     }
 
@@ -820,17 +894,21 @@ Spacing_spanner::note_spacing (Grob*me, Grob *lc, Grob *rc,
 
 
 ADD_INTERFACE (Spacing_spanner,"spacing-spanner-interface",
-  "
-The space taken by a note is dependent on its duration. Doubling a
-duration adds spacing-increment to the space. The most common shortest
-note gets shortest-duration-space. Notes that are even shorter are
-spaced proportonial to their duration.
-
-Typically, the increment is the width of a black note head.  In a
-piece with lots of 8th notes, and some 16th notes, the eighth note
-gets 2 note heads width (i.e. the space following a note is 1 note
-head width) A 16th note is followed by 0.5 note head width. The
-quarter note is followed by  3 NHW, the half by 4 NHW, etc.
-",
-  "grace-space-factor spacing-increment base-shortest-duration shortest-duration-space");
+"The space taken by a note is dependent on its duration. Doubling a\n"
+"duration adds spacing-increment to the space. The most common shortest\n"
+"note gets shortest-duration-space. Notes that are even shorter are\n"
+"spaced proportonial to their duration.\n"
+"\n"
+"Typically, the increment is the width of a black note head.  In a\n"
+"piece with lots of 8th notes, and some 16th notes, the eighth note\n"
+"gets 2 note heads width (i.e. the space following a note is 1 note\n"
+"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 shortest-duration-space common-shortest-duration");
+
+
+
+ADD_INTERFACE (Spacing_interface,"spacing-interface",
+  "Something to do with line breaking and spacing. Kill this one after determining line breaks.",
+  "");