4
4
source file of the GNU LilyPond music typesetter
6
(c) 1997--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
6
(c) 1997--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
9
10
#include "font-metric.hh"
11
#include "libc-extension.hh"
10
13
#include "stencil.hh"
13
16
TODO: naming add/combine.
19
LY_DEFINE (ly_stencil_set_extent_x, "ly:stencil-set-extent!",
20
3, 0, 0, (SCM stil, SCM axis, SCM np),
21
"Set the extent of @var{stil} "
22
"(@var{extent} must be a pair of numbers) "
23
"in @var{axis} direction (0 or 1 for x- and y-axis respectively).")
25
Stencil *s = unsmob_stencil (stil);
26
SCM_ASSERT_TYPE (s, stil, SCM_ARG1, __FUNCTION__, "stencil");
27
SCM_ASSERT_TYPE (is_axis (axis), axis, SCM_ARG2, __FUNCTION__, "axis");
28
SCM_ASSERT_TYPE (is_number_pair (np), np, SCM_ARG3, __FUNCTION__,
31
Interval iv = ly_scm2interval (np);
32
s->dim_[Axis (gh_scm2int (axis))] = iv;
37
19
LY_DEFINE (ly_translate_stencil_axis, "ly:stencil-translate-axis",
38
20
3, 0, 0, (SCM stil, SCM amount, SCM axis),
84
73
SCM_ASSERT_TYPE (s, stil, SCM_ARG1, __FUNCTION__, "stencil");
85
74
SCM_ASSERT_TYPE (is_axis (axis), axis, SCM_ARG2, __FUNCTION__, "axis");
87
return ly_interval2scm (s->extent (Axis (gh_scm2int (axis))));
76
return ly_interval2scm (s->extent (Axis (scm_to_int (axis))));
79
LY_DEFINE (ly_stencil_empty_p, "ly:stencil-empty?",
81
"Return whether @var{stil} is empty ")
83
Stencil *s = unsmob_stencil (stil);
84
SCM_ASSERT_TYPE (s, stil, SCM_ARG1, __FUNCTION__, "stencil");
85
return scm_from_bool (s->is_empty ());
88
LY_DEFINE (ly_stencil_origin, "ly:stencil-origin",
89
2, 0, 0, (SCM stil, SCM axis),
90
"Return a pair of numbers signifying the origin @var{stil} in "
91
"@var{axis} direction (0 or 1 for x and y axis respectively).")
93
Stencil *s = unsmob_stencil (stil);
94
SCM_ASSERT_TYPE (s, stil, SCM_ARG1, __FUNCTION__, "stencil");
95
SCM_ASSERT_TYPE (is_axis (axis), axis, SCM_ARG2, __FUNCTION__, "axis");
97
return scm_from_double (s->origin ()[Axis (scm_to_int (axis))]);
90
100
LY_DEFINE (ly_stencil_moved_to_edge, "ly:stencil-moved-to-edge",
107
117
if (padding != SCM_UNDEFINED)
109
SCM_ASSERT_TYPE (gh_number_p (padding), padding, SCM_ARG5, __FUNCTION__, "number");
110
p = gh_scm2double (padding);
119
SCM_ASSERT_TYPE (scm_is_number (padding), padding, SCM_ARG5, __FUNCTION__, "number");
120
p = scm_to_double (padding);
113
123
if (minimum != SCM_UNDEFINED)
115
SCM_ASSERT_TYPE (gh_number_p (minimum), minimum, SCM_ARG6, __FUNCTION__, "number");
116
m = gh_scm2double (minimum);
125
SCM_ASSERT_TYPE (scm_is_number (minimum), minimum, SCM_ARG6, __FUNCTION__, "number");
126
m = scm_to_double (minimum);
120
130
first_stencil = *s1;
123
return first_stencil.moved_to_edge (Axis (gh_scm2int (axis)),
124
Direction (gh_scm2int (direction)),
133
return first_stencil.moved_to_edge (Axis (scm_to_int (axis)),
134
Direction (scm_to_int (direction)),
125
135
*s2, p, m).smobbed_copy ();
127
return Stencil().smobbed_copy ();
137
return Stencil ().smobbed_copy ();
132
140
LY_DEFINE (ly_stencil_combine_at_edge, "ly:stencil-combine-at-edge",
133
4, 2, 0, (SCM first, SCM axis, SCM direction,
141
4, 2, 0, (SCM first, SCM axis, SCM direction,
137
145
"Construct a stencil by putting @var{second} next to @var{first}. "
138
146
"@var{axis} can be 0 (x-axis) or 1 (y-axis), "
139
147
"@var{direction} can be -1 (left or down) or 1 (right or up). "
140
148
"The stencils are juxtaposed with @var{padding} as extra space. "
141
149
"If this puts the reference points closer than @var{minimum}, "
142
"they are moved by the latter amount.")
150
"they are moved by the latter amount."
151
"@var{first} and @var{second} may also be '() or #f.")
144
153
Stencil *s1 = unsmob_stencil (first);
145
154
Stencil *s2 = unsmob_stencil (second);
148
SCM_ASSERT_TYPE (is_axis (axis), axis, SCM_ARG3, __FUNCTION__, "axis");
149
SCM_ASSERT_TYPE (is_direction (direction), direction, SCM_ARG4, __FUNCTION__, "dir");
157
SCM_ASSERT_TYPE (s1 || first == SCM_BOOL_F || first == SCM_EOL,
158
first, SCM_ARG1, __FUNCTION__, "Stencil, #f or ()");
159
SCM_ASSERT_TYPE (s2 || second == SCM_BOOL_F || second == SCM_EOL,
160
second, SCM_ARG4, __FUNCTION__, "Stencil, #f or ()");
161
SCM_ASSERT_TYPE (is_axis (axis), axis, SCM_ARG2, __FUNCTION__, "axis");
162
SCM_ASSERT_TYPE (is_direction (direction), direction, SCM_ARG3, __FUNCTION__, "dir");
152
165
if (padding != SCM_UNDEFINED)
154
SCM_ASSERT_TYPE (gh_number_p (padding), padding, SCM_ARG5, __FUNCTION__, "number");
155
p = gh_scm2double (padding);
167
SCM_ASSERT_TYPE (scm_is_number (padding), padding, SCM_ARG5, __FUNCTION__, "number");
168
p = scm_to_double (padding);
158
171
if (minimum != SCM_UNDEFINED)
160
SCM_ASSERT_TYPE (gh_number_p (minimum), minimum, SCM_ARG6, __FUNCTION__, "number");
161
m = gh_scm2double (minimum);
173
SCM_ASSERT_TYPE (scm_is_number (minimum), minimum, SCM_ARG6, __FUNCTION__, "number");
174
m = scm_to_double (minimum);
167
result.add_at_edge (Axis (gh_scm2int (axis)),
168
Direction (gh_scm2int (direction)), *s2, p, m);
181
result.add_at_edge (Axis (scm_to_int (axis)),
182
Direction (scm_to_int (direction)), *s2, p, m);
170
184
return result.smobbed_copy ();
173
LY_DEFINE (ly_stencil_add , "ly:stencil-add",
187
LY_DEFINE (ly_stencil_add, "ly:stencil-add",
174
188
0, 0, 1, (SCM args),
175
189
"Combine stencils. Takes any number of arguments.")
177
191
#define FUNC_NAME __FUNCTION__
178
192
SCM_VALIDATE_REST_ARGUMENT (args);
182
199
while (!SCM_NULLP (args))
184
Stencil *s = unsmob_stencil (gh_car (args));
201
Stencil *s = unsmob_stencil (scm_car (args));
186
SCM_ASSERT_TYPE (s, gh_car (args), SCM_ARGn, __FUNCTION__, "Stencil");
203
SCM_ASSERT_TYPE (s, scm_car (args), SCM_ARGn, __FUNCTION__, "Stencil");
188
result.add_stencil (*s);
189
args = gh_cdr (args);
205
extent.unite (s->extent_box ());
206
*tail = scm_cons (s->expr (), SCM_EOL);
207
tail = SCM_CDRLOC (*tail);
208
args = scm_cdr (args);
192
return result.smobbed_copy ();
211
expr = scm_cons (ly_symbol2scm ("combine-stencil"), expr);
212
return Stencil (extent, expr).smobbed_copy ();
195
215
LY_DEFINE (ly_make_stencil, "ly:make-stencil",
196
3, 0, 0, (SCM expr, SCM xext, SCM yext),
216
3, 0, 0, (SCM expr, SCM xext, SCM yext),
198
218
"Stencils are a device independent output expressions."
199
219
"They carry two pieces of information: \n\n"
200
220
"1: a specification of how to print this object. "
201
221
"This specification is processed by the output backends, "
202
" for example @file{scm/output-tex.scm}.\n\n"
222
" for example @file{scm/output-ps.scm}.\n\n"
203
223
"2: the vertical and horizontal extents of the object.\n\n")
225
SCM_ASSERT_TYPE (!scm_is_pair (expr)
226
|| is_stencil_head (scm_car (expr)),
227
expr, SCM_ARG1, __FUNCTION__, "registered stencil expression");
205
229
SCM_ASSERT_TYPE (is_number_pair (xext), xext, SCM_ARG2, __FUNCTION__, "number pair");
206
230
SCM_ASSERT_TYPE (is_number_pair (yext), yext, SCM_ARG3, __FUNCTION__, "number pair");
210
234
return s.smobbed_copy ();
214
fontify_atom (Font_metric const *met, SCM f)
219
return scm_list_n (ly_symbol2scm ("fontify"),
220
ly_quote_scm (met->description_), f, SCM_UNDEFINED);
223
LY_DEFINE (ly_fontify_atom,"ly:fontify-atom",
224
2, 0, 0, (SCM met, SCM f),
225
"Add a font selection command for the font metric @var{met} "
228
SCM_ASSERT_TYPE (unsmob_metrics (met), met, SCM_ARG1, __FUNCTION__, "font metric");
230
return fontify_atom (unsmob_metrics (met), f);
233
LY_DEFINE (ly_align_to_x, "ly:stencil-align-to!",
237
LY_DEFINE (ly_stencil_aligned_to, "ly:stencil-aligned-to",
234
238
3, 0, 0, (SCM stil, SCM axis, SCM dir),
235
239
"Align @var{stil} using its own extents. "
236
240
"@var{dir} is a number -1, 1 are left and right respectively. "
237
"Other values are interpolated (so 0 means the center. ")
241
"Other values are interpolated (so 0 means the center).")
239
243
SCM_ASSERT_TYPE (unsmob_stencil (stil), stil, SCM_ARG1, __FUNCTION__, "stencil");
240
244
SCM_ASSERT_TYPE (is_axis (axis), axis, SCM_ARG2, __FUNCTION__, "axis");
241
SCM_ASSERT_TYPE (gh_number_p (dir), dir, SCM_ARG3, __FUNCTION__, "number");
243
unsmob_stencil (stil)->align_to ((Axis)gh_scm2int (axis),
244
gh_scm2double (dir));
245
return SCM_UNDEFINED;
245
SCM_ASSERT_TYPE (scm_is_number (dir), dir, SCM_ARG3, __FUNCTION__, "number");
247
Stencil target = *unsmob_stencil (stil);
249
target.align_to ((Axis)scm_to_int (axis),
250
scm_to_double (dir));
251
return target.smobbed_copy ();
254
LY_DEFINE (ly_stencil_fonts, "ly:stencil-fonts",
256
" Analyse @var{s}, and return a list of fonts used in @var{s}.")
258
Stencil *stil = unsmob_stencil (s);
259
SCM_ASSERT_TYPE (stil, s, SCM_ARG1, __FUNCTION__, "Stencil");
260
return find_expression_fonts (stil->expr ());
263
LY_DEFINE (ly_stencil_in_color, "ly:stencil-in-color",
264
4, 0, 0, (SCM stc, SCM r, SCM g, SCM b),
265
"Put @var{stc} in a different color.")
267
Stencil *stil = unsmob_stencil (stc);
268
SCM_ASSERT_TYPE (stil, stc, SCM_ARG1, __FUNCTION__, "Stencil");
269
return Stencil (stil->extent_box (),
270
scm_list_3 (ly_symbol2scm ("color"),
271
scm_list_3 (r, g, b),
272
stil->expr ())).smobbed_copy ();
275
struct Stencil_interpret_arguments
281
void stencil_interpret_in_scm (void *p, SCM expr)
283
Stencil_interpret_arguments *ap = (Stencil_interpret_arguments *) p;
284
scm_call_2 (ap->func, ap->arg1, expr);
287
LY_DEFINE (ly_interpret_stencil_expression, "ly:interpret-stencil-expression",
288
4, 0, 0, (SCM expr, SCM func, SCM arg1, SCM offset),
289
"Parse EXPR, feed bits to FUNC with first arg ARG1")
291
SCM_ASSERT_TYPE (ly_is_procedure (func), func, SCM_ARG1, __FUNCTION__,
294
Stencil_interpret_arguments a;
297
Offset o = ly_scm2offset (offset);
299
interpret_stencil_expression (expr, stencil_interpret_in_scm, (void *) & a, o);
301
return SCM_UNSPECIFIED;
304
LY_DEFINE (ly_bracket, "ly:bracket",
306
(SCM a, SCM iv, SCM t, SCM p),
307
"Make a bracket in direction @var{a}. The extent of the bracket is "
308
"given by @var{iv}. The wings protude by an amount of @var{p}, which "
309
"may be negative. The thickness is given by @var{t}.")
311
SCM_ASSERT_TYPE (is_axis (a), a, SCM_ARG1, __FUNCTION__, "axis");
312
SCM_ASSERT_TYPE (is_number_pair (iv), iv, SCM_ARG2, __FUNCTION__, "number pair");
313
SCM_ASSERT_TYPE (scm_is_number (t), a, SCM_ARG3, __FUNCTION__, "number");
314
SCM_ASSERT_TYPE (scm_is_number (p), a, SCM_ARG4, __FUNCTION__, "number");
316
return Lookup::bracket ((Axis)scm_to_int (a), ly_scm2interval (iv),
319
0.95 * scm_to_double (t)).smobbed_copy ();
322
LY_DEFINE (ly_filled_box, "ly:round-filled-box",
324
(SCM xext, SCM yext, SCM blot),
325
"Make a @code{Stencil} "
326
"that prints a black box of dimensions @var{xext}, "
327
"@var{yext} and roundness @var{blot}.")
329
SCM_ASSERT_TYPE (is_number_pair (xext), xext, SCM_ARG1, __FUNCTION__, "number pair");
330
SCM_ASSERT_TYPE (is_number_pair (yext), yext, SCM_ARG2, __FUNCTION__, "number pair");
331
SCM_ASSERT_TYPE (scm_is_number (blot), blot, SCM_ARG3, __FUNCTION__, "number");
333
return Lookup::round_filled_box (Box (ly_scm2interval (xext), ly_scm2interval (yext)),
334
scm_to_double (blot)).smobbed_copy ();
337
LY_DEFINE (ly_register_stencil_expression, "ly:register-stencil-expression",
340
"Add @var{symbol} as head of a stencil expression")
342
SCM_ASSERT_TYPE (scm_is_symbol (symbol), symbol,
343
SCM_ARG1, __FUNCTION__, "Symbol");
344
register_stencil_head (symbol);
345
return SCM_UNSPECIFIED;
348
LY_DEFINE (ly_all_stencil_expressions, "ly:all-stencil-expressions",
351
"Return all symbols recognized as stencil expressions.")
353
return all_stencil_heads ();