* stepmake/stepmake/metafont-rules.make: backport 1.7 fixes.
[lilypond.git] / lily / molecule.cc
blob15cc8f2f07c37e5d281144eed8fa14b2226b77c0
1 /*
2 molecule.cc -- implement Molecule
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
9 #include <math.h>
10 #include <libc-extension.hh> // isinf
12 #include "font-metric.hh"
13 #include "dimensions.hh"
14 #include "interval.hh"
15 #include "string.hh"
16 #include "molecule.hh"
17 #include "warn.hh"
20 #include "ly-smobs.icc"
23 SCM
24 Molecule::smobbed_copy () const
26 Molecule * m = new Molecule (*this);
28 return m->smobbed_self ();
31 Interval
32 Molecule::extent (Axis a) const
34 return dim_[a];
37 Molecule::Molecule (Box b, SCM func)
39 expr_ = func;
40 dim_ = b;
43 Molecule::Molecule ()
45 expr_ = SCM_EOL;
46 set_empty (true);
49 void
50 Molecule::translate (Offset o)
52 Axis a = X_AXIS;
53 while (a < NO_AXES)
55 if (abs (o[a]) > 100 CM
56 || isinf (o[a]) || isnan (o[a]))
58 programming_error ("Improbable offset for translation: setting to zero");
59 o[a] = 0.0;
61 incr (a);
64 expr_ = scm_list_n (ly_symbol2scm ("translate-molecule"),
65 ly_offset2scm (o),
66 expr_, SCM_UNDEFINED);
67 if (!empty_b ())
68 dim_.translate (o);
72 void
73 Molecule::translate_axis (Real x,Axis a)
75 Offset o (0,0);
76 o[a] = x;
77 translate (o);
82 void
83 Molecule::add_molecule (Molecule const &m)
85 expr_ = scm_list_n (ly_symbol2scm ("combine-molecule"),
86 m.expr_,
87 expr_, SCM_UNDEFINED);
88 dim_.unite (m.dim_);
91 void
92 Molecule::set_empty (bool e)
94 if (e)
96 dim_[X_AXIS].set_empty ();
97 dim_[Y_AXIS].set_empty ();
99 else
101 dim_[X_AXIS] = Interval (0,0);
102 dim_[Y_AXIS] = Interval (0,0);
107 void
108 Molecule::align_to (Axis a, Direction d)
110 if (empty_b())
111 return ;
113 Interval i (extent (a));
114 Real r = (d == CENTER) ? i.center () : i[d];
115 translate_axis (-r, a);
118 void
119 Molecule::add_at_edge (Axis a, Direction d, Molecule const &m, Real padding)
121 Real my_extent= empty_b () ? 0.0 : dim_[a][d];
122 Interval i (m.extent (a));
123 Real his_extent;
124 if (i.empty_b ())
126 programming_error ("Molecule::add_at_edge: adding empty molecule.");
127 his_extent = 0.0;
129 else
130 his_extent = i[-d];
132 Real offset = my_extent - his_extent;
133 Molecule toadd (m);
134 toadd.translate_axis (offset + d * padding, a);
135 add_molecule (toadd);
138 LY_DEFINE(ly_set_molecule_extent_x,"ly-set-molecule-extent!", 3 , 0, 0,
139 (SCM mol, SCM axis, SCM np),
140 "Set the extent (@var{extent} must be a pair of numbers) of @var{mol} in
141 @var{axis} direction (0 or 1 for x- and y-axis respectively).
143 Note that an extent @code{(A . B)} is an interval and hence @code{A} is
144 smaller than @code{B}, and is often negative.
147 Molecule* m = unsmob_molecule (mol);
148 SCM_ASSERT_TYPE (m, mol, SCM_ARG1, __FUNCTION__, "molecule");
149 SCM_ASSERT_TYPE (ly_axis_p (axis), axis, SCM_ARG2, __FUNCTION__, "axis");
150 SCM_ASSERT_TYPE (ly_number_pair_p (np), np, SCM_ARG3, __FUNCTION__, "number pair");
152 Interval iv = ly_scm2interval (np);
153 m->dim_[Axis (gh_scm2int (axis))] = iv;
155 return SCM_UNDEFINED;
158 LY_DEFINE(ly_get_molecule_extent,
159 "ly-get-molecule-extent", 2 , 0, 0, (SCM mol, SCM axis),
160 "Return a pair of numbers signifying the extent of @var{mol} in
161 @var{axis} direction (0 or 1 for x and y axis respectively).
164 Molecule *m = unsmob_molecule (mol);
165 SCM_ASSERT_TYPE (m, mol, SCM_ARG1, __FUNCTION__, "molecule");
166 SCM_ASSERT_TYPE (ly_axis_p (axis), axis, SCM_ARG2, __FUNCTION__, "axis");
168 return ly_interval2scm (m->extent (Axis (gh_scm2int (axis))));
172 LY_DEFINE(ly_molecule_combined_at_edge,
173 "ly-combine-molecule-at-edge",
174 5 , 0, 0, (SCM first, SCM axis, SCM direction,
175 SCM second, SCM padding),
176 "Construct a molecule by putting @var{second} next to
177 @var{first}. @var{axis} can be 0 (x-axis) or 1 (y-axis), @var{direction} can be
178 -1 (left or down) or 1 (right or up). @var{padding} specifies extra
179 space to add in between measured in global staff space.")
182 Molecule * m1 = unsmob_molecule (first);
183 Molecule * m2 = unsmob_molecule (second);
184 Molecule result;
187 SCM_ASSERT_TYPE(ly_axis_p (axis), axis, SCM_ARG2, __FUNCTION__, "axis");
188 SCM_ASSERT_TYPE(ly_dir_p (direction), direction, SCM_ARG3, __FUNCTION__, "dir");
189 SCM_ASSERT_TYPE(gh_number_p (padding), padding, SCM_ARG4, __FUNCTION__, "number");
191 if (m1)
192 result = *m1;
193 if (m2)
194 result.add_at_edge (Axis (gh_scm2int (axis)), Direction (gh_scm2int (direction)),
195 *m2, gh_scm2double (padding));
197 return result.smobbed_copy ();
201 FIXME: support variable number of arguments "
203 LY_DEFINE(ly_add_molecule ,
204 "ly-add-molecule", 2, 0,0,(SCM first, SCM second),
205 "Combine two molecules."
208 Molecule * m1 = unsmob_molecule (first);
209 Molecule * m2 = unsmob_molecule (second);
210 Molecule result;
213 if (m1)
214 result = *m1;
215 if (m2)
216 result.add_molecule (*m2);
218 return result.smobbed_copy ();
221 LY_DEFINE(ly_make_molecule,
222 "ly-make-molecule", 3, 0, 0, (SCM expr, SCM xext, SCM yext),
224 The objective of any typesetting system is to put ink on paper in the
225 right places. For LilyPond, this final stage is left to the @TeX{} and
226 the printer subsystem. For lily, the last stage in processing a score is
227 outputting a description of what to put where. This description roughly
228 looks like
229 @example
230 PUT glyph AT (x,y)
231 PUT glyph AT (x,y)
232 PUT glyph AT (x,y)
233 @end example
234 you merely have to look at the tex output of lily to see this.
235 Internally these instructions are encoded in Molecules.@footnote{At some
236 point LilyPond also contained Atom-objects, but they have been replaced
237 by Scheme expressions, making the name outdated.} A molecule is
238 what-to-print-where information that also contains dimension information
239 (how large is this glyph?).
241 Conceptually, Molecules can be constructed from Scheme code, by
242 translating a Molecule and by combining two molecules. In BNF
243 notation:
245 @example
246 Molecule :: COMBINE Molecule Molecule
247 | TRANSLATE Offset Molecule
248 | GLYPH-DESCRIPTION
250 @end example
252 If you are interested in seeing how this information is stored, you
253 can run with the @code{-f scm} option. The scheme expressions are then
254 dumped in the output file.")
256 SCM_ASSERT_TYPE (ly_number_pair_p (xext), xext, SCM_ARG2, __FUNCTION__, "number pair");
257 SCM_ASSERT_TYPE (ly_number_pair_p (yext), yext, SCM_ARG3, __FUNCTION__, "number pair");
259 Box b (ly_scm2interval (xext), ly_scm2interval(yext));
260 Molecule m (b, expr);
261 return m.smobbed_copy ();
265 fontify_atom (Font_metric const * met, SCM f)
267 if (f == SCM_EOL)
268 return f;
269 else
270 return scm_list_n (ly_symbol2scm ("fontify"),
271 ly_quote_scm (met->description_), f, SCM_UNDEFINED);
274 LY_DEFINE(ly_fontify_atom,"ly-fontify-atom", 2, 0, 0,
275 (SCM met, SCM f),
276 "Add a font selection command for the font metric @var{met} to @var{f}.")
278 SCM_ASSERT_TYPE(unsmob_metrics (met), met, SCM_ARG1, __FUNCTION__, "font metric");
280 return fontify_atom (unsmob_metrics (met), f);
282 LY_DEFINE(ly_align_to_x,"ly-align-to!", 3, 0, 0, (SCM mol, SCM axis, SCM dir),
283 "Align @var{mol} using its own extents.")
285 SCM_ASSERT_TYPE(unsmob_molecule (mol), mol, SCM_ARG1, __FUNCTION__, "molecule");
286 SCM_ASSERT_TYPE(ly_axis_p (axis), axis, SCM_ARG2, __FUNCTION__, "axis");
287 SCM_ASSERT_TYPE(ly_dir_p (dir), dir, SCM_ARG3, __FUNCTION__, "dir");
289 unsmob_molecule (mol)->align_to ((Axis)gh_scm2int (axis), Direction (gh_scm2int (dir)));
291 return SCM_UNDEFINED;
297 Hmm... maybe this is not such a good idea ; stuff can be empty,
298 while expr_ == '()
300 bool
301 Molecule::empty_b () const
303 return expr_ == SCM_EOL;
307 Molecule::get_expr () const
309 return expr_;
315 Molecule::extent_box () const
317 return dim_;
319 IMPLEMENT_SIMPLE_SMOBS (Molecule);
323 Molecule::print_smob (SCM , SCM port, scm_print_state *)
325 scm_puts ("#<Molecule ", port);
326 #if 0
327 Molecule *r = (Molecule *) ly_cdr (s);
328 String string (r->string ());
329 scm_puts ((char *)str.to_str0 (), port);
330 #endif
331 scm_puts (" >", port);
333 return 1;
338 Molecule::mark_smob (SCM s)
340 Molecule *r = (Molecule *) ly_cdr (s);
342 return r->expr_;
345 IMPLEMENT_TYPE_P (Molecule, "molecule?");
346 IMPLEMENT_DEFAULT_EQUAL_P (Molecule);