2 stencil.cc -- implement Stencil
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
10 #include <libc-extension.hh> // isinf
12 #include "input-smob.hh"
13 #include "font-metric.hh"
14 #include "dimensions.hh"
15 #include "interval.hh"
20 #include "ly-smobs.icc"
28 Stencil::Stencil (Box b
, SCM func
)
35 Stencil::print_smob (SCM
, SCM port
, scm_print_state
*)
37 scm_puts ("#<Stencil ", port
);
38 scm_puts (" >", port
);
43 Stencil::mark_smob (SCM smob
)
45 Stencil
*s
= (Stencil
*) ly_cdr (smob
);
49 IMPLEMENT_SIMPLE_SMOBS (Stencil
);
50 IMPLEMENT_TYPE_P (Stencil
, "ly:stencil?");
51 IMPLEMENT_DEFAULT_EQUAL_P (Stencil
);
54 Stencil::extent (Axis a
) const
59 /* Hmm... maybe this is not such a good idea ; stuff can be empty,
62 Stencil::is_empty () const
64 return expr_
== SCM_EOL
;
68 Stencil::expr () const
74 Stencil::extent_box () const
79 Stencil::origin () const
85 Stencil::translate (Offset o
)
90 if (abs (o
[a
]) > 100 CM
91 || isinf (o
[a
]) || isnan (o
[a
]))
93 programming_error ("Improbable offset for translation: setting to zero");
99 expr_
= scm_list_n (ly_symbol2scm ("translate-stencil"),
101 expr_
, SCM_UNDEFINED
);
108 Stencil::translate_axis (Real x
, Axis a
)
116 Stencil::add_stencil (Stencil
const &s
)
118 expr_
= scm_list_3 (ly_symbol2scm ("combine-stencil"), s
.expr_
, expr_
);
125 Stencil::set_empty (bool e
)
129 dim_
[X_AXIS
].set_empty ();
130 dim_
[Y_AXIS
].set_empty ();
134 dim_
[X_AXIS
] = Interval (0,0);
135 dim_
[Y_AXIS
] = Interval (0,0);
140 Stencil::align_to (Axis a
, Real x
)
145 Interval
i (extent (a
));
146 translate_axis (-i
.linear_combination (x
), a
);
149 /* FIXME: unintuitive naming, you would expect *this to be moved.
150 Kept (keeping?) API for compat with add_at_edge ().
152 What is PADDING, what is MINIMUM, exactly? */
154 Stencil::moved_to_edge (Axis a
, Direction d
, Stencil
const &s
,
155 Real padding
, Real minimum
) const
157 Interval my_extent
= dim_
[a
];
158 Interval
i (s
.extent (a
));
162 programming_error ("Stencil::moved_to_edge: adding empty stencil.");
168 Real offset
= (my_extent
.is_empty () ? 0.0 : my_extent
[d
] - his_extent
)
172 toadd
.translate_axis (offset
,a
);
174 if (minimum
> 0 && d
* (-origin ()[a
] + toadd
.origin ()[a
]) < minimum
)
175 toadd
.translate_axis ( -toadd
.origin ()[a
]
176 + origin ()[a
] + d
* minimum
, a
);
181 /* See scheme Function. */
183 Stencil::add_at_edge (Axis a
, Direction d
, Stencil
const &s
, Real padding
,
186 add_stencil (moved_to_edge (a
, d
, s
, padding
, minimum
));
190 /****************************************************************/
194 interpret_stencil_expression (SCM expr
,
195 void (*func
) (void*, SCM
),
201 if (!ly_c_pair_p (expr
))
204 SCM head
= ly_car (expr
);
206 if (head
== ly_symbol2scm ("translate-stencil"))
208 o
+= ly_scm2offset (ly_cadr (expr
));
209 expr
= ly_caddr (expr
);
211 else if (head
== ly_symbol2scm ("combine-stencil"))
213 for (SCM x
= ly_cdr (expr
); ly_c_pair_p (x
); x
= ly_cdr (x
))
214 interpret_stencil_expression (ly_car (x
), func
, func_arg
, o
);
217 else if (head
== ly_symbol2scm ("grob-cause"))
219 SCM grob
= ly_cadr (expr
);
221 (*func
) (func_arg
, scm_list_2 (head
, grob
));
222 interpret_stencil_expression (ly_caddr (expr
), func
, func_arg
, o
);
223 (*func
) (func_arg
, scm_list_1 (ly_symbol2scm ("no-origin")));
230 scm_list_4 (ly_symbol2scm ("placebox"),
231 scm_make_real (o
[X_AXIS
]),
232 scm_make_real (o
[Y_AXIS
]),
246 find_font_function (void *fs
, SCM x
)
248 Font_list
*me
= (Font_list
*) fs
;
250 if (ly_car (x
) == ly_symbol2scm ("placebox"))
252 SCM args
= ly_cdr (x
);
253 SCM what
= ly_caddr (args
);
255 if (ly_c_pair_p (what
))
257 SCM head
= ly_car (what
);
258 if (ly_symbol2scm ("text") == head
)
259 me
->fonts_
= scm_cons (ly_cadr (what
), me
->fonts_
);
260 else if (head
== ly_symbol2scm ("char"))
261 me
->fonts_
= scm_cons (ly_cadr (what
), me
->fonts_
);
267 find_expression_fonts (SCM expr
)
273 interpret_stencil_expression (expr
, &find_font_function
,
274 (void*) &fl
, Offset (0,0));
280 LY_DEFINE (ly_stencil_fonts
, "ly:stencil-fonts",
282 " Analyse @var{s}, and return a list of fonts used in @var{s}.")
284 Stencil
*stil
= unsmob_stencil (s
);
285 SCM_ASSERT_TYPE (stil
, s
, SCM_ARG1
, __FUNCTION__
, "Stencil");
286 return find_expression_fonts (stil
->expr ());
289 struct Stencil_interpret_arguments
295 void stencil_interpret_in_scm (void *p
, SCM expr
)
297 Stencil_interpret_arguments
*ap
= (Stencil_interpret_arguments
*) p
;
298 scm_call_2 (ap
->func
, ap
->arg1
, expr
);
303 LY_DEFINE (ly_interpret_stencil_expression
, "ly:interpret-stencil-expression",
304 4, 0, 0, (SCM expr
, SCM func
, SCM arg1
, SCM offset
),
305 "Parse EXPR, feed bits to FUNC with first arg ARG1")
307 SCM_ASSERT_TYPE (ly_c_procedure_p(func
), func
, SCM_ARG1
, __FUNCTION__
,
310 Stencil_interpret_arguments a
;
313 Offset o
= ly_scm2offset (offset
);
315 interpret_stencil_expression (expr
, stencil_interpret_in_scm
, (void*) &a
, o
);
317 return SCM_UNSPECIFIED
;