]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/paper-column-engraver.cc
* scm/page.scm (make-page): make it friendlier to call (esp. from C++)
[lilypond.git] / lily / paper-column-engraver.cc
index cef0f9e5c055659010f63a2d3afaba9953f4d770..32bb0b2fdd733669ae06e59b9733521ca26df45d 100644 (file)
@@ -8,14 +8,15 @@
 
 #include "paper-column-engraver.hh"
 #include "system.hh"
+#include "international.hh"
+#include "axis-group-interface.hh"
+#include "context.hh"
 #include "item.hh"
-#include "paper-column.hh"
-#include "staff-spacing.hh"
 #include "note-spacing.hh"
+#include "paper-column.hh"
 #include "pointer-group-interface.hh"
-#include "context.hh"
-#include "score-context.hh"
-#include "axis-group-interface.hh"
+#include "staff-spacing.hh"
+#include "system.hh"
 #include "warn.hh"
 
 #include "translator.icc"
@@ -27,9 +28,9 @@ Paper_column_engraver::Paper_column_engraver ()
   musical_column_ = 0;
   breaks_ = 0;
   system_ = 0;
-  first_ = true;
+  last_special_barline_column_ = 0;
   last_breakable_column_ = 0;
-  last_breakable_moment_ = Moment (-1);
+  first_ = true;
 }
 
 void
@@ -85,6 +86,7 @@ Paper_column_engraver::acknowledge_staff_spacing (Grob_info gi)
                                     ly_symbol2scm ("spacing-wishes"),
                                     gi.grob ());
 }
+
 void
 Paper_column_engraver::acknowledge_note_spacing (Grob_info gi)
 {
@@ -109,12 +111,11 @@ Paper_column_engraver::set_columns (Paper_column *new_command,
   system_->add_column (musical_column_);
 }
 
-bool
-Paper_column_engraver::try_music (Music *m)
+IMPLEMENT_TRANSLATOR_LISTENER (Paper_column_engraver, break);
+void
+Paper_column_engraver::listen_break (Stream_event *ev)
 {
-  break_events_.push_back (m);
-
-  return true;
+  break_events_.push_back (ev);
 }
 
 void
@@ -123,18 +124,17 @@ Paper_column_engraver::process_music ()
   for (vsize i = 0; i < break_events_.size (); i++)
     {
       string prefix;
-      SCM name = break_events_[i]->get_property ("name");
-      if (name == ly_symbol2scm ("LineBreakEvent"))
-       prefix = "line-break";
-      else if (name == ly_symbol2scm ("PageBreakEvent"))
-       prefix = "page-break";
-      else if (name == ly_symbol2scm ("PageTurnEvent"))
-       prefix = "page-turn";
+      SCM name_sym = break_events_[i]->get_property ("class");
+      string name = ly_scm2string (scm_symbol_to_string (name_sym));
+      size_t end = name.rfind ("-event");
+      if (end)
+       prefix = name.substr (0, end);
       else
        {
          programming_error ("Paper_column_engraver doesn't know about this break-event");
          return;
        }
+
       string perm_str = prefix + "-permission";
       string pen_str = prefix + "-penalty";
 
@@ -170,6 +170,56 @@ Paper_column_engraver::process_music ()
     }
 }
 
+/* return either
+   - the last column with a special (ie. not "|" or "") barline
+   - the last column
+   after the given moment
+*/
+Paper_column*
+Paper_column_engraver::find_turnable_column (Moment after_this)
+{
+  if (last_special_barline_column_)
+    {
+      Moment m = *unsmob_moment (last_special_barline_column_->get_property ("when"));
+      if (m >= after_this)
+       return last_special_barline_column_;
+    }
+  if (last_breakable_column_)
+    {
+      Moment m = *unsmob_moment (last_breakable_column_->get_property ("when"));
+      if (m >= after_this)
+       return last_breakable_column_;
+    }
+  return 0;
+}
+
+void
+Paper_column_engraver::revoke_page_turns (Moment after_this, Real new_penalty)
+{
+  if (!page_turnable_columns_.size ())
+    return;
+
+  for (vsize i = page_turnable_columns_.size () - 1; i--;)
+    {
+      Paper_column *col = page_turnable_columns_[i];
+      Moment mom = *unsmob_moment (col->get_property ("when"));
+      if (mom >= after_this)
+       {
+         if (isinf (new_penalty))
+           {
+             col->del_property ( ly_symbol2scm ("page-turn-permission"));
+             page_turnable_columns_.erase (page_turnable_columns_.begin () + i);
+           }
+         else
+           {
+             Real prev_pen = robust_scm2double (col->get_property ("page-turn-penalty"), 0);
+             if (new_penalty > prev_pen)
+               col->set_property ("page-turn-penalty", scm_from_double (new_penalty));
+           }
+       }
+    }
+}
+
 void
 Paper_column_engraver::stop_translation_timestep ()
 {
@@ -195,25 +245,50 @@ Paper_column_engraver::stop_translation_timestep ()
     {
       breaks_++;
       last_breakable_column_ = command_column_;
-      last_breakable_moment_ = now_mom ();
+
+      SCM which_bar = get_property ("whichBar");
+      if (scm_is_string (which_bar))
+       {
+         string bar = ly_scm2string (which_bar);
+         if (bar != "" && bar != "|")
+           last_special_barline_column_ = command_column_;
+       }
+
       if (! (breaks_%8))
        progress_indication ("[" + to_string (breaks_) + "]");
     }
 
   SCM page_br = get_property ("allowPageTurn");
-  if (scm_is_pair (page_br) && last_breakable_moment_ >= Rational (0))
+  if (scm_is_pair (page_br) && last_breakable_column_)
     {
       SCM pen = scm_cdr (page_br);
       Moment *m = unsmob_moment (scm_car (page_br));
-      if (m && scm_is_number (pen) && *m <= last_breakable_moment_)
+      if (m)
        {
-         last_breakable_column_->set_property ("page-turn-permission", ly_symbol2scm ("allow"));
-         last_breakable_column_->set_property ("page-turn-penalty", pen);
+         Paper_column *turn = find_turnable_column (*m);
+         if (turn)
+           {
+             turn->set_property ("page-turn-permission", ly_symbol2scm ("allow"));
+             turn->set_property ("page-turn-penalty", pen);
+             page_turnable_columns_.push_back (turn);
+           }
        }
     }
 
+  /* The page-turn-engraver is allowed to change its mind and revoke previously-allowed
+     page turns (for example if there is a volta repeat where a turn is inconvenient) */
+  SCM revokes = get_property ("revokePageTurns");
+  if (scm_is_pair (revokes))
+    {
+      Moment *start = unsmob_moment (scm_car (revokes));
+      Real pen = robust_scm2double (scm_cdr (revokes), infinity_f);
+      if (start)
+       revoke_page_turns (*start, pen);
+    }
+
   context ()->get_score_context ()->unset_property (ly_symbol2scm ("forbidBreak"));
   context ()->get_score_context ()->unset_property (ly_symbol2scm ("allowPageTurn"));
+  context ()->get_score_context ()->unset_property (ly_symbol2scm ("revokePageTurns"));
 
   first_ = false;
   break_events_.clear ();
@@ -250,9 +325,13 @@ ADD_TRANSLATOR (Paper_column_engraver,
                /* accept */ "break-event",
                /* read */
                 "forbidBreak "
-                "allowPageTurn",
+                "allowPageTurn "
+               "revokePageTurns "
+               ,
                /* write */
                 "forbidBreak "
                 "allowPageTurn "
+               "revokePageTurns "
                "currentCommandColumn "
-               "currentMusicalColumn");
+               "currentMusicalColumn "
+               );