]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/stencil.cc
(try_music): add moments for
[lilypond.git] / lily / stencil.cc
index 1a6f21e104071939c049219c50db32a98dc26574..bbca94953efb13023a8626d20e8b352102c7585f 100644 (file)
@@ -9,6 +9,7 @@
 #include <math.h>
 #include <libc-extension.hh>   // isinf
 
+#include "input-smob.hh"
 #include "font-metric.hh" 
 #include "dimensions.hh"
 #include "interval.hh"
 
 #include "ly-smobs.icc"
 
-SCM
-Stencil::smobbed_copy () const
+Stencil::Stencil ()
 {
-  Stencil *s = new Stencil (*this);
-  return s->smobbed_self ();
+  expr_ = SCM_EOL;
+  set_empty (true);
 }
 
-Offset
-Stencil::origin () const
+Stencil::Stencil (Box b, SCM func)
 {
-  return origin_;
+  expr_ = func;
+  dim_ = b;
 }
 
+int
+Stencil::print_smob (SCM, SCM port, scm_print_state *)
+{
+  scm_puts ("#<Stencil ", port);
+  scm_puts (" >", port);
+  return 1;
+}
+
+SCM
+Stencil::mark_smob (SCM smob)
+{
+  Stencil *s = (Stencil*) ly_cdr (smob);
+  return s->expr_;
+}
+
+IMPLEMENT_SIMPLE_SMOBS (Stencil);
+IMPLEMENT_TYPE_P (Stencil, "ly:stencil?");
+IMPLEMENT_DEFAULT_EQUAL_P (Stencil);
+
 Interval
 Stencil::extent (Axis a) const
 {
   return dim_[a];
 }
 
-Stencil::Stencil (Box b, SCM func)
+/* Hmm... maybe this is not such a good idea ; stuff can be empty,
+   while expr_ == '()  */
+bool
+Stencil::is_empty () const
 {
-  expr_ = func;
-  dim_ = b;
+  return expr_ == SCM_EOL;
 }
 
-Stencil::Stencil ()
+SCM
+Stencil::expr () const
 {
-  expr_ = SCM_EOL;
-  set_empty (true);
+  return expr_;
+}
+
+Box
+Stencil::extent_box () const
+{
+  return dim_;
+}
+Offset
+Stencil::origin () const
+{
+  return origin_;
 }
 
 void
@@ -83,8 +115,7 @@ Stencil::translate_axis (Real x, Axis a)
 void
 Stencil::add_stencil (Stencil const &s)
 {
-  expr_ = scm_list_n (ly_symbol2scm ("combine-stencil"),
-                     s.expr_, expr_, SCM_UNDEFINED);
+  expr_ = scm_list_3 (ly_symbol2scm ("combine-stencil"), s.expr_, expr_);
   dim_.unite (s.dim_);
 }
 
@@ -113,81 +144,145 @@ Stencil::align_to (Axis a, Real x)
   translate_axis (-i.linear_combination (x), a);
 }
 
-/*
-  TODO: unintuitive naming, you would expect *this to be moved.  Kept
-  API for compat with add_at_edge ().
-*/
+/* FIXME: unintuitive naming, you would expect *this to be moved.
+   Kept (keeping?) API for compat with add_at_edge ().
+
+   What is PADDING, what is MINIMUM, exactly?  */
 Stencil
-Stencil::moved_to_edge (Axis a, Direction d, Stencil const &s, Real padding,
-                       Real minimum) const
+Stencil::moved_to_edge (Axis a, Direction d, Stencil const &s,
+                       Real padding, Real minimum) const
 {
-  Real my_extent= is_empty () ? 0.0 : dim_[a][d];
+  Interval my_extent = dim_[a];
   Interval i (s.extent (a));
   Real his_extent;
   if (i.is_empty ())
     {
-      programming_error ("Stencil::move_to_edge: adding empty stencil.");
+      programming_error ("Stencil::moved_to_edge: adding empty stencil.");
       his_extent = 0.0;
     }
   else
     his_extent = i[-d];
 
-  Real offset = (my_extent -  his_extent) + d * padding;
+  Real offset = (my_extent.is_empty () ? 0.0 : my_extent[d] - his_extent)
+    + d * padding;
 
   Stencil toadd (s);
   toadd.translate_axis (offset,a);
 
-  if (minimum > 0
-      && d *(- origin ()[a] + toadd.origin ()[a]) < minimum)
+  if (minimum > 0 && d * (-origin ()[a] + toadd.origin ()[a]) < minimum)
     toadd.translate_axis ( -toadd.origin ()[a]
-                          + origin ()[a] + d* minimum, a);
-    
+                          + origin ()[a] + d * minimum, a);
+
   return toadd;
 }
 
 /*  See scheme Function.  */
 void
 Stencil::add_at_edge (Axis a, Direction d, Stencil const &s, Real padding,
-                      Real minimum)
+                     Real minimum)
 {
-  add_stencil (moved_to_edge (a,d,s,padding, minimum));
+  add_stencil (moved_to_edge (a, d, s, padding, minimum));
 }
 
-/* Hmm... maybe this is not such a good idea ; stuff can be empty,
-   while expr_ == '()  */
-bool
-Stencil::is_empty () const
-{
-  return expr_ == SCM_EOL;
-}
 
-SCM
-Stencil::get_expr () const
+/****************************************************************/
+
+void
+interpret_stencil_expression (SCM expr,
+                       void (*func) (void*, SCM),
+                       void *func_arg,
+                       Offset o)
 {
-  return expr_;
+  while (1)
+    {
+      if (!ly_c_pair_p (expr))
+       return;
+  
+      SCM head =ly_car (expr);
+      if (unsmob_input (head))
+       {
+         Input *ip = unsmob_input (head);
+         (*func)(func_arg,
+                 scm_list_4 (ly_symbol2scm ("define-origin"),
+                             scm_makfrom0str (ip->file_string ()
+                                              .to_str0 ()),
+                             scm_int2num (ip->line_number ()),
+                             scm_int2num (ip->column_number ())));
+         
+         expr = ly_cadr (expr);
+       }
+      else  if (head ==  ly_symbol2scm ("no-origin"))
+       {
+         (*func) (func_arg, scm_list_1 (head));
+         expr = ly_cadr (expr);
+       }
+      else if (head == ly_symbol2scm ("translate-stencil"))
+       {
+         o += ly_scm2offset (ly_cadr (expr));
+         expr = ly_caddr (expr);
+       }
+      else if (head == ly_symbol2scm ("combine-stencil"))
+       {
+         interpret_stencil_expression (ly_cadr (expr), func, func_arg, o);
+         expr = ly_caddr (expr);
+       }
+      else
+       {
+         (*func) (func_arg, 
+                  scm_list_4 (ly_symbol2scm ("placebox"),
+                              scm_make_real (o[X_AXIS]),
+                              scm_make_real (o[Y_AXIS]),
+                              expr));
+         return;
+       }
+    }
 }
 
-Box
-Stencil::extent_box () const
+
+struct Font_list
 {
-  return dim_;
-}
+  SCM fonts_;
+};
 
-int
-Stencil::print_smob (SCM , SCM port, scm_print_state *)
+static void
+find_font_function (void * fs, SCM x)
 {
-  scm_puts ("#<Stencil ", port);
-  scm_puts (" >", port);
-  return 1;
+  Font_list * me = (Font_list*)fs;
+  
+  if (ly_car (x) == ly_symbol2scm ("placebox"))
+    {
+      SCM args = ly_cdr (x); 
+      SCM what = ly_caddr (args);
+
+      if (ly_c_pair_p (what))
+       {
+         SCM head = ly_car (what);
+         if (ly_symbol2scm ("text")  == head)
+           me->fonts_ = scm_cons (ly_cadr (what), me->fonts_);
+         else  if (head == ly_symbol2scm ("char"))
+           me->fonts_ = scm_cons (ly_cadr (what), me->fonts_);
+       }
+    }
 }
 
 SCM
-Stencil::mark_smob (SCM s)
+find_expression_fonts (SCM expr)
 {
-  Stencil  *r = (Stencil *) ly_cdr (s);
-  return r->expr_;
+  Font_list fl;
+  
+  fl.fonts_ = SCM_EOL;
+  
+  interpret_stencil_expression (expr, &find_font_function, 
+                         (void*) &fl, Offset (0,0));
+
+  return fl.fonts_;
 }
 
-IMPLEMENT_SIMPLE_SMOBS (Stencil);
-IMPLEMENT_TYPE_P (Stencil, "ly:stencil?");
-IMPLEMENT_DEFAULT_EQUAL_P (Stencil);
+LY_DEFINE(ly_stencil_fonts, "ly:stencil-fonts",
+         1, 0, 0, (SCM s),
+         "Analyse @var{s}, and return a list of fonts used in @var{s}.")
+{
+  Stencil *stil =unsmob_stencil (s);
+  SCM_ASSERT_TYPE (stil, s, SCM_ARG1, __FUNCTION__, "Stencil");
+  return find_expression_fonts (stil->expr ());
+}