]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/stem.cc
Merge branch 'master' of git+ssh://jneem@git.sv.gnu.org/srv/git/lilypond
[lilypond.git] / lily / stem.cc
index d95ff4be3951c8ac7b6403a76fa0e09e09f2225e..09786b750b5d205d4b7f834b6c6fa69fe507453b 100644 (file)
@@ -3,7 +3,7 @@
 
   source file of the GNU LilyPond music typesetter
 
-  (c) 1996--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
+  (c) 1996--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
   Jan Nieuwenhuizen <janneke@gnu.org>
 
   TODO: This is way too hairy
@@ -14,6 +14,7 @@
 */
 
 #include "stem.hh"
+#include "spanner.hh"
 
 #include <cmath>               // rint
 using namespace std;
@@ -153,7 +154,7 @@ Stem::last_head (Grob *me)
 Drul_array<Grob *>
 Stem::extremal_heads (Grob *me)
 {
-  const int inf = 1000000;
+  const int inf = INT_MAX;
   Drul_array<int> extpos;
   extpos[DOWN] = inf;
   extpos[UP] = -inf;
@@ -180,12 +181,6 @@ Stem::extremal_heads (Grob *me)
   return exthead;
 }
 
-static int
-integer_compare (int const &a, int const &b)
-{
-  return a - b;
-}
-
 /* The positions, in ascending order.  */
 vector<int>
 Stem::note_head_positions (Grob *me)
@@ -201,7 +196,7 @@ Stem::note_head_positions (Grob *me)
       ps.push_back (p);
     }
 
-  vector_sort (ps, integer_compare);
+  vector_sort (ps, less<int> ());
   return ps;
 }
 
@@ -219,28 +214,40 @@ Stem::add_head (Grob *me, Grob *n)
 bool
 Stem::is_invisible (Grob *me)
 {
-  Real stemlet_length = robust_scm2double (me->get_property ("stemlet-length"),
-                                          0.0);
+  return !is_normal_stem (me)
+    && (robust_scm2double (me->get_property ("stemlet-length"),
+                          0.0) == 0.0);
+}
+
 
-  return !((head_count (me)
-           || stemlet_length > 0.0)
-          && scm_to_int (me->get_property ("duration-log")) >= 1);
+bool
+Stem::is_normal_stem (Grob *me)
+{
+  return head_count (me) && scm_to_int (me->get_property ("duration-log")) >= 1;
 }
 
+
 MAKE_SCHEME_CALLBACK (Stem, pure_height, 3)
 SCM
 Stem::pure_height (SCM smob, SCM start, SCM end)
 {
   (void) start;
   (void) end;
-  
-  
+
   Grob *me = unsmob_grob (smob);
+  Interval iv;
+
+  if (!is_normal_stem (me))
+    return ly_interval2scm (iv);
+
+  /* if we are part of a cross-staff beam, return empty */
+  if (get_beam (me) && Beam::is_cross_staff (get_beam (me)))
+    return ly_interval2scm (iv);
+  
   Real ss = Staff_symbol_referencer::staff_space (me);
   Real len = scm_to_double (calc_length (smob)) * ss / 2;
   Direction dir = get_grob_direction (me);
 
-  Interval iv;
   Interval hp = head_positions (me);
   if (dir == UP)
     iv = Interval (0, len);
@@ -322,7 +329,7 @@ Stem::calc_stem_end_position (SCM smob)
   return scm_from_double (stem_end);
 }
 
-
+/* Length is in half-spaces (or: positions) here. */
 MAKE_SCHEME_CALLBACK (Stem, calc_length, 1)
 SCM
 Stem::calc_length (SCM smob)
@@ -369,8 +376,7 @@ Stem::calc_length (SCM smob)
       (Stem_tremolo::raw_stencil () looks at the beam.) --hwn  */
 
       Real minlen = 1.0
-       + 2 * t_flag->extent (t_flag, Y_AXIS).length ()
-       / ss;
+       + 2 * Stem_tremolo::vertical_length (t_flag) / ss;
 
       /* We don't want to add the whole extent of the flag because the trem
          and the flag can overlap partly. beam_translation gives a good
@@ -408,9 +414,11 @@ Stem::calc_positioning_done (SCM smob)
   if (!head_count (me))
     return SCM_BOOL_T;
 
+  me->set_property ("positioning-done", SCM_BOOL_T);
+  
   extract_grob_set (me, "note-heads", ro_heads);
   vector<Grob*> heads (ro_heads);
-  vector_sort (heads, compare_position);
+  vector_sort (heads, position_less);
   Direction dir = get_grob_direction (me);
 
   if (dir < 0)
@@ -425,12 +433,25 @@ Stem::calc_positioning_done (SCM smob)
       dir = UP;
       set_grob_direction (me, dir);
     }
-  
+
+  bool is_harmonic_centered = false;
+  for (vsize i = 0; i < heads.size (); i++)
+    is_harmonic_centered = is_harmonic_centered 
+      || heads[i]->get_property ("style") == ly_symbol2scm ("harmonic");
+  is_harmonic_centered = is_harmonic_centered && is_invisible (me);
+
   Real w = hed->extent (hed, X_AXIS)[dir];
   for (vsize i = 0; i < heads.size (); i++)
-    heads[i]->translate_axis (w - heads[i]->extent (heads[i], X_AXIS)[dir],
-                             X_AXIS);
+    {
+      Real amount = w - heads[i]->extent (heads[i], X_AXIS)[dir];
 
+      if (is_harmonic_centered)
+       amount =
+         hed->extent (hed, X_AXIS).linear_combination (CENTER)
+         - heads[i]->extent (heads[i], X_AXIS).linear_combination (CENTER);
+      
+      heads[i]->translate_axis (amount, X_AXIS);
+    }
   bool parity = true;
   Real lastpos = Real (Staff_symbol_referencer::get_position (heads[0]));
   for (vsize i = 1; i < heads.size (); i++)
@@ -540,13 +561,11 @@ SCM
 Stem::height (SCM smob)
 {
   Grob *me = unsmob_grob (smob);
-
+  if (!is_normal_stem (me))
+    return ly_interval2scm (Interval ());
+  
   Direction dir = get_grob_direction (me);
   
-  /* Trigger callback.
-
-  UGH. Should be automatic
-  */
   Grob *beam = get_beam (me);
   if (beam)
     {
@@ -786,8 +805,16 @@ SCM
 Stem::offset_callback (SCM smob)
 {
   Grob *me = unsmob_grob (smob);
-  Real r = 0.0;
 
+  extract_grob_set (me, "rests", rests);
+  if (rests.size ())
+    {
+      Grob *rest = rests.back ();
+      Real r = rest->extent (rest, X_AXIS).center ();
+      return scm_from_double (r);
+    }
+
+  
   if (Grob *f = first_head (me))
     {
       Interval head_wid = f->extent (f, X_AXIS);
@@ -800,7 +827,7 @@ Stem::offset_callback (SCM smob)
 
       Direction d = get_grob_direction (me);
       Real real_attach = head_wid.linear_combination (d * attach);
-      r = real_attach;
+      Real r = real_attach;
 
       /* If not centered: correct for stem thickness.  */
       if (attach)
@@ -808,17 +835,11 @@ Stem::offset_callback (SCM smob)
          Real rule_thick = thickness (me);
          r += -d * rule_thick * 0.5;
        }
+      return scm_from_double (r);
     }
-  else
-    {
-      extract_grob_set (me, "rests", rests);
-      if (rests.size ())
-       {
-         Grob *rest = rests.back ();
-         r = rest->extent (rest, X_AXIS).center ();
-       }
-    }
-  return scm_from_double (r);
+
+  programming_error ("Weird stem.");
+  return scm_from_double (0.0);
 }
 
 Spanner *
@@ -891,10 +912,14 @@ Stem::calc_stem_info (SCM smob)
   Real height_of_my_trem = 0.0;
   Grob *trem = unsmob_grob (me->get_object ("tremolo-flag"));
   if (trem)
-      height_of_my_trem = trem->extent (trem, Y_AXIS).length ()
+    {
+      height_of_my_trem
+       = Stem_tremolo::vertical_length (trem)
         /* hack a bit of space around the trem. */
         + beam_translation;
+    }
 
+  
   /* UGH
      It seems that also for ideal minimum length, we must use
      the maximum beam count (for this direction):
@@ -980,8 +1005,22 @@ Stem::beam_multiplicity (Grob *stem)
   return le;
 }
 
+bool
+Stem::is_cross_staff (Grob *stem)
+{
+  Grob *beam = unsmob_grob (stem->get_object ("beam"));
+  return beam && Beam::is_cross_staff (beam);
+}
+
+MAKE_SCHEME_CALLBACK (Stem, cross_staff, 1)
+SCM
+Stem::cross_staff (SCM smob)
+{
+  return scm_from_bool (is_cross_staff (unsmob_grob (smob)));
+}
+
 /* FIXME:  Too many properties  */
-ADD_INTERFACE (Stem, "stem-interface",
+ADD_INTERFACE (Stem,
               "The stem represent the graphical stem.  "
               "In addition, it internally connects note heads, beams and"
               "tremolos. "