lilypond-1.5.9
[lilypond.git] / lily / text-item.cc
blob5441963c0ef54485ee735b13a5d67f8319db0bc6
1 /*
2 text-item.cc -- implement Text_item
4 source file of the GNU LilyPond music typesetter
6 (c) 1998--2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 Jan Nieuwenhuizen <janneke@gnu.org>
8 */
9 #include <math.h>
11 #include "debug.hh"
12 #include "text-item.hh"
13 #include "paper-def.hh"
14 #include "font-interface.hh"
15 #include "staff-symbol-referencer.hh"
16 #include "staff-symbol-referencer.hh"
17 #include "main.hh"
18 #include "all-font-metrics.hh"
19 #include "afm.hh"
24 TEXT: STRING
25 | (MARKUP? TEXT+)
28 HEAD: MARKUP-ITEM | (MARKUP-ITEM+)
30 MARKUP-ITEM: PROPERTY | ABBREV | FONT-STYLE
31 PROPERTY: (key . value)
32 ABBREV: rows lines roman music bold italic named super sub text
36 Molecule
37 Text_item::text2molecule (Grob *me, SCM text, SCM alist_chain)
39 if (gh_string_p (text))
40 return string2molecule (me, text, alist_chain);
41 else if (gh_pair_p (text))
43 /* urg, why not just do this in markup_text2molecule ? */
44 if (gh_string_p (gh_car (text)))
45 return markup_text2molecule (me,
46 gh_append2 (gh_list (SCM_EOL,
47 SCM_UNDEFINED),
48 text),
49 alist_chain);
51 Allow (faulty) texts that are in an extra list:
52 #'(("foo"))
54 else if (scm_ilength (text) <= 1)
55 return text2molecule (me, gh_car (text), alist_chain);
56 else
57 return markup_text2molecule (me, text, alist_chain);
59 return Molecule ();
62 Molecule
63 Text_item::string2molecule (Grob *me, SCM text, SCM alist_chain)
65 SCM style = ly_assoc_chain (ly_symbol2scm ("font-style"),
66 alist_chain);
67 if (gh_pair_p (style) && gh_symbol_p (gh_cdr (style)))
68 alist_chain = Font_interface::add_style (me, gh_cdr (style), alist_chain);
70 Font_metric *fm = Font_interface::get_font (me, alist_chain);
72 SCM lookup = ly_assoc_chain (ly_symbol2scm ("lookup"), alist_chain);
74 Molecule mol;
75 if (gh_pair_p (lookup) && gh_cdr (lookup) ==ly_symbol2scm ("name"))
76 mol = lookup_character (me, fm, text);
77 else
78 mol = lookup_text (me, fm, text);
80 return mol;
83 Molecule
84 Text_item::lookup_character (Grob *, Font_metric*fm, SCM char_name)
86 return fm->find_by_name (ly_scm2string (char_name));
90 Molecule
91 Text_item::lookup_text (Grob *me, Font_metric*fm, SCM text)
93 #if 0
95 Fixme; should be done differently, move to font-interface?
97 differently -- how/why?
100 SCM magnification = me->get_grob_property ("font-magnification");
102 Font_metric* metric = 0;
103 if (gh_number_p (magnification))
106 Real realmag = pow (1.2, gh_scm2int (magnification));
107 metric = all_fonts_global_p->find_scaled (ly_scm2string (font_name), realmag);
109 assert (false);
111 #else
112 SCM magnification = me->get_grob_property ("font-magnification");
114 if (gh_number_p (magnification) && gh_scm2double (magnification) > 1)
115 programming_error ("font-magnification disabled");
116 #endif
119 SCM list = gh_list (ly_symbol2scm ("text"), text, SCM_UNDEFINED);
120 list = fontify_atom (fm, list);
122 return Molecule (fm->text_dimension (ly_scm2string (text)), list);
125 Molecule
126 Text_item::markup_text2molecule (Grob *me, SCM markup_text,
127 SCM alist_chain)
129 SCM sheet = me->paper_l ()->style_sheet_;
130 SCM f = gh_cdr (scm_assoc (ly_symbol2scm ("markup-to-properties"), sheet));
132 SCM markup = gh_car (markup_text);
133 SCM text = gh_cdr (markup_text);
135 SCM p = gh_cons (gh_call2 (f, sheet, markup), alist_chain);
137 Real staff_space = Staff_symbol_referencer::staff_space (me);
140 Line mode is default.
142 Axis axis = X_AXIS;
144 SCM a = ly_assoc_chain (ly_symbol2scm ("axis"), p);
145 if (gh_pair_p (a) && isaxis_b (gh_cdr (a)))
146 axis = (Axis)gh_scm2int (gh_cdr (a));
148 Real baseline_skip = 0;
149 SCM b = ly_assoc_chain (ly_symbol2scm ("baseline-skip"), p);
150 if (gh_pair_p (b) && gh_number_p (gh_cdr (b)))
151 baseline_skip = gh_scm2double (gh_cdr (b)) * staff_space;
153 Real kern[2] = {0,0};
155 SCM k = ly_assoc_chain (ly_symbol2scm ("kern"), p);
156 if (gh_pair_p (k) && gh_number_p (gh_cdr (k)))
157 kern[axis] = gh_scm2double (gh_cdr (k)) * staff_space;
159 Real raise = 0;
160 SCM r = ly_assoc_chain (ly_symbol2scm ("raise"), p);
161 if (gh_pair_p (r) && gh_number_p (gh_cdr (r)))
162 raise = gh_scm2double (gh_cdr (r)) * staff_space;
164 Interval extent;
165 bool extent_b = false;
166 SCM e = ly_assoc_chain (ly_symbol2scm ("extent"), p);
167 if (gh_pair_p (e) && ly_number_pair_p (gh_cdr (e)))
169 extent = Interval (gh_scm2double (gh_cadr (e)) * staff_space,
170 gh_scm2double (gh_cddr (e)) * staff_space);
171 extent_b = true;
174 Offset o (0, (axis == Y_AXIS ? - kern[axis] : 0));
176 Molecule mol;
177 while (gh_pair_p (text))
180 Molecule m = text2molecule (me, gh_car (text), p);
183 TODO: look at padding?
185 Look ahead here for kern and raise.
187 (cols "foo" ((raise . 1) "bar"))
188 (cols "foo" ((bold (raise . 1)) "bar"))
190 When constructing the molecule for bar, all normal extra
191 properties found, such as bold, are used for the construction
192 of bar's molecule. But for kern or raise, it seems that we're
193 too late then, translating bar's molecule has no effect (or
194 maybe the effect of translating gets nullified when bar's
195 molecule is `added_to_edge' of the molecule for foo?)
197 So, while constructing foo's molecule, we look ahead for the
198 raise of bar. The HEAD of the description of bar may be a
199 single property, or a list, so we must check that too.
202 SCM next_p = SCM_EOL;
203 if (gh_pair_p (gh_car (text)))
204 next_p = gh_list (gh_call2 (f, sheet, gh_caar (text)), SCM_UNDEFINED);
205 SCM next_k = ly_assoc_chain (ly_symbol2scm ("kern"), next_p);
206 Real next_kern = kern[axis];
207 if (gh_pair_p (next_k) && gh_number_p (gh_cdr (next_k)))
208 next_kern = gh_scm2double (gh_cdr (next_k)) * staff_space;
210 SCM next_r = ly_assoc_chain (ly_symbol2scm ("raise"), next_p);
211 Real next_raise = 0;
212 if (gh_pair_p (next_r) && gh_number_p (gh_cdr (next_r)))
213 next_raise = gh_scm2double (gh_cdr (next_r)) * staff_space;
215 o[Y_AXIS] = next_raise;
217 if (!m.empty_b ())
219 m.translate (o);
220 if (mol.empty_b ())
221 mol = m;
222 else
224 if (axis == Y_AXIS && baseline_skip)
225 next_kern += baseline_skip - m.extent (Y_AXIS)[UP];
226 mol.add_at_edge (axis, axis == X_AXIS ? RIGHT : DOWN, m, next_kern);
229 text = gh_cdr (text);
232 if (extent_b)
234 #if 0
235 /* Hmm, we're not allowed to change a Molecule's extent? */
236 mol.dim_[axis] = extent;
237 Molecule::ly_set_molecule_extent_x (mol.self_scm (), gh_int2scm (axis),
238 gh_cdr (e));
239 #else
240 // burp: unpredictable names, these...
241 Box b = mol.extent_box ();
242 SCM expr = mol.get_expr ();
244 b[axis] = extent;
245 mol = Molecule (b, expr);
246 #endif
248 return mol;
251 MAKE_SCHEME_CALLBACK (Text_item, brew_molecule, 1);
252 SCM
253 Text_item::brew_molecule (SCM smob)
255 Grob *me = unsmob_grob (smob);
257 SCM text = me->get_grob_property ("text");
259 SCM properties = Font_interface::font_alist_chain (me);
260 Molecule mol = Text_item::text2molecule (me, text, properties);
262 SCM space = me->get_grob_property ("word-space");
263 if (gh_number_p (space))
265 Molecule m;
266 m.set_empty (false);
267 mol.add_at_edge (X_AXIS, RIGHT, m, gh_scm2double (space)
268 * Staff_symbol_referencer::staff_space (me));
270 return mol.smobbed_copy ();