]> git.donarmstrong.com Git - lilypond.git/blob - lily/paper-book.cc
Fix some bugs in the dynamic engraver and PostScript backend
[lilypond.git] / lily / paper-book.cc
1 /*
2   paper-book.cc -- implement Paper_book
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2004--2006 Jan Nieuwenhuizen <janneke@gnu.org>
7 */
8
9 #include "paper-book.hh"
10
11 #include "main.hh"
12 #include "output-def.hh"
13 #include "paper-score.hh"
14 #include "paper-system.hh"
15 #include "text-interface.hh"
16 #include "warn.hh"
17
18 #include "ly-smobs.icc"
19
20 Paper_book::Paper_book ()
21 {
22   header_ = SCM_EOL;
23   header_0_ = SCM_EOL;
24   pages_ = SCM_BOOL_F;
25   scores_ = SCM_EOL;
26   performances_ = SCM_EOL;
27   systems_ = SCM_BOOL_F;
28
29   paper_ = 0;
30   smobify_self ();
31 }
32
33 Paper_book::~Paper_book ()
34 {
35 }
36
37 IMPLEMENT_DEFAULT_EQUAL_P (Paper_book);
38 IMPLEMENT_SMOBS (Paper_book);
39 IMPLEMENT_TYPE_P (Paper_book, "ly:paper-book?");
40
41 SCM
42 Paper_book::mark_smob (SCM smob)
43 {
44   Paper_book *b = (Paper_book *) SCM_CELL_WORD_1 (smob);
45   if (b->paper_)
46     scm_gc_mark (b->paper_->self_scm ());
47   scm_gc_mark (b->header_);
48   scm_gc_mark (b->header_0_);
49   scm_gc_mark (b->pages_);
50   scm_gc_mark (b->performances_);
51   scm_gc_mark (b->scores_);
52   return b->systems_;
53 }
54
55 int
56 Paper_book::print_smob (SCM smob, SCM port, scm_print_state*)
57 {
58   Paper_book *b = (Paper_book *) SCM_CELL_WORD_1 (smob);
59   (void)b;
60   scm_puts ("#<Paper_book>", port);
61   return 1;
62 }
63
64 SCM
65 dump_fields ()
66 {
67   SCM fields = SCM_EOL;
68   for (vsize i = dump_header_fieldnames_global.size (); i--;)
69     fields
70       = scm_cons (ly_symbol2scm (dump_header_fieldnames_global[i].c_str ()),
71                   fields);
72   return fields;
73 }
74
75 void
76 Paper_book::add_score (SCM s)
77 {
78   scores_ = scm_cons (s, scores_);
79 }
80
81 void
82 Paper_book::add_performance (SCM s)
83 {
84   performances_ = scm_cons (s, performances_);
85 }
86
87 void
88 Paper_book::output (SCM output_channel)
89 {
90   if (scm_is_pair (performances_))
91     {
92       SCM proc = ly_lily_module_constant ("paper-book-write-midis");
93
94       scm_call_2 (proc, self_scm (), output_channel);
95     }
96
97   if (scores_ == SCM_EOL)
98     return;
99
100   /* Generate all stencils to trigger font loads.  */
101   pages ();
102
103   SCM scopes = SCM_EOL;
104   if (ly_is_module (header_))
105     scopes = scm_cons (header_, scopes);
106
107   string mod_nm = "scm framework-" + output_backend_global;
108
109   SCM mod = scm_c_resolve_module (mod_nm.c_str ());
110   if (make_print)
111     {
112       SCM func = scm_c_module_lookup (mod, "output-framework");
113
114       func = scm_variable_ref (func);
115       scm_apply_0 (func, scm_list_n (output_channel,
116                                      self_scm (),
117                                      scopes,
118                                      dump_fields (),
119                                      SCM_UNDEFINED));
120     }
121
122   if (make_preview)
123     {
124       SCM func = scm_c_module_lookup (mod, "output-preview-framework");
125       func = scm_variable_ref (func);
126       scm_apply_0 (func, scm_list_n (output_channel,
127                                      self_scm (),
128                                      scopes,
129                                      dump_fields (),
130                                      SCM_UNDEFINED));
131     }
132 }
133
134 void
135 Paper_book::classic_output (SCM output)
136 {
137   /* Generate all stencils to trigger font loads.  */
138   systems ();
139
140   SCM scopes = SCM_EOL;
141   if (ly_is_module (header_))
142     scopes = scm_cons (header_, scopes);
143
144   if (ly_is_module (header_0_))
145     scopes = scm_cons (header_0_, scopes);
146
147   string format = output_backend_global;
148   string mod_nm = "scm framework-" + format;
149
150   SCM mod = scm_c_resolve_module (mod_nm.c_str ());
151   SCM func = scm_c_module_lookup (mod, "output-classic-framework");
152
153   func = scm_variable_ref (func);
154   scm_apply_0 (func, scm_list_n (output,
155                                  self_scm (),
156                                  scopes,
157                                  dump_fields (),
158                                  SCM_UNDEFINED));
159
160   progress_indication ("\n");
161 }
162
163 /* TODO: resurrect more complex user-tweaks for titling?  */
164 Stencil
165 Paper_book::book_title ()
166 {
167   SCM title_func = paper_->lookup_variable (ly_symbol2scm ("book-title"));
168   Stencil title;
169
170   SCM scopes = SCM_EOL;
171   if (ly_is_module (header_))
172     scopes = scm_cons (header_, scopes);
173
174   SCM tit = SCM_EOL;
175   if (ly_is_procedure (title_func))
176     tit = scm_call_2 (title_func,
177                       paper_->self_scm (),
178                       scopes);
179
180   if (unsmob_stencil (tit))
181     title = *unsmob_stencil (tit);
182
183   if (!title.is_empty ())
184     title.align_to (Y_AXIS, UP);
185
186   return title;
187 }
188
189 Stencil
190 Paper_book::score_title (SCM header)
191 {
192   SCM title_func = paper_->lookup_variable (ly_symbol2scm ("score-title"));
193
194   Stencil title;
195
196   SCM scopes = SCM_EOL;
197   if (ly_is_module (header_))
198     scopes = scm_cons (header_, scopes);
199
200   if (ly_is_module (header))
201     scopes = scm_cons (header, scopes);
202
203   SCM tit = SCM_EOL;
204   if (ly_is_procedure (title_func))
205     tit = scm_call_2 (title_func,
206                       paper_->self_scm (),
207                       scopes);
208
209   if (unsmob_stencil (tit))
210     title = *unsmob_stencil (tit);
211
212   if (!title.is_empty ())
213     title.align_to (Y_AXIS, UP);
214
215   return title;
216 }
217
218 void
219 set_system_penalty (Prob *ps, SCM header)
220 {
221   if (ly_is_module (header))
222     {
223       SCM force = ly_module_lookup (header, ly_symbol2scm ("breakbefore"));
224       if (SCM_VARIABLEP (force)
225           && scm_is_bool (SCM_VARIABLE_REF (force)))
226         {
227           ps->set_property ("penalty",
228                             scm_from_int(to_boolean (SCM_VARIABLE_REF (force))
229                                          ? -10000
230                                          : 10000));
231         }
232     }
233 }
234
235
236 SCM
237 Paper_book::get_score_title (SCM header)
238 {
239   Stencil title = score_title (header);
240   if (title.is_empty ())
241     title = score_title (header_);
242   if (!title.is_empty ())
243     {
244       /*
245         TODO: this should come from the \layout {} block, which should
246         override settings from \paper {}
247       */
248       SCM props = paper_->lookup_variable (ly_symbol2scm ("score-title-properties"));
249       Prob *ps = make_paper_system (props);
250       paper_system_set_stencil (ps, title);
251       set_system_penalty (ps, header);
252
253       return ps->self_scm();
254     }
255
256   return SCM_BOOL_F;
257 }
258
259
260 SCM
261 Paper_book::get_system_specs ()
262 {
263   SCM system_specs = SCM_EOL;
264   
265   Stencil title = book_title ();
266   if (!title.is_empty ())
267     {
268       SCM props = paper_->lookup_variable (ly_symbol2scm ("book-title-properties"));
269       Prob *ps = make_paper_system (props);
270       paper_system_set_stencil (ps, title);
271       set_system_penalty (ps, header_);
272
273       system_specs = scm_cons (ps->self_scm (), system_specs);
274       ps->unprotect ();
275     }
276
277   SCM page_properties
278     = scm_call_1 (ly_lily_module_constant ("layout-extract-page-properties"),
279                   paper_->self_scm ());
280
281   SCM header = SCM_EOL;
282   for (SCM s = scm_reverse (scores_); s != SCM_EOL; s = scm_cdr (s))
283     {
284       if (ly_is_module (scm_car (s)))
285         {
286           header = scm_car (s);
287           if (header_0_ == SCM_EOL)
288             header_0_ = header;
289         }
290       else if (Music_output *mop = unsmob_music_output (scm_car (s)))
291         {
292           if (Paper_score *pscore = dynamic_cast<Paper_score *> (mop))
293             {
294               SCM title = get_score_title (header);
295               if (unsmob_prob (title))
296                 {
297                   system_specs = scm_cons (title, system_specs);
298                   unsmob_prob (title)->unprotect ();
299                 }
300
301               header = SCM_EOL;
302               system_specs = scm_cons (pscore->self_scm (), system_specs);
303             }
304           else
305             {
306               /*
307                 Ignore MIDI
308               */
309             }
310         }
311       else if (Text_interface::is_markup (scm_car (s)))
312         {
313           SCM t = Text_interface::interpret_markup (paper_->self_scm (),
314                                                     page_properties,
315                                                     scm_car (s));
316           
317           // TODO: init props
318           Prob *ps = make_paper_system (SCM_EOL);
319           paper_system_set_stencil (ps, *unsmob_stencil (t));
320           ps->set_property ("is-title", SCM_BOOL_T); 
321           system_specs = scm_cons (ps->self_scm (), system_specs);
322           ps->unprotect ();
323           
324           // FIXME: figure out penalty.
325           //set_system_penalty (ps, scores_[i].header_);
326         }
327       else
328         assert (0);
329     }
330
331   system_specs = scm_reverse_x (system_specs, SCM_EOL);
332   return system_specs;
333 }
334
335 SCM
336 Paper_book::systems ()
337 {
338   if (systems_ != SCM_BOOL_F)
339     return systems_;
340
341   systems_ = SCM_EOL;
342   SCM specs = get_system_specs ();
343   for (SCM s = specs; scm_is_pair (s); s = scm_cdr (s))
344     {
345       if (Paper_score *pscore = dynamic_cast<Paper_score*> (unsmob_music_output (scm_car (s))))
346         {
347           SCM system_list = scm_vector_to_list (pscore->get_paper_systems ());
348           system_list = scm_reverse (system_list);
349           systems_ = scm_append (scm_list_2 (system_list, systems_));
350         }
351       else
352         {
353           systems_ = scm_cons (scm_car (s), systems_);
354         }
355     }
356   
357   systems_ = scm_reverse (systems_);
358
359   int i = 0;
360   Prob *last = 0;
361   for (SCM s = systems_; s != SCM_EOL; s = scm_cdr (s))
362     {
363       Prob *ps = unsmob_prob (scm_car (s));
364       ps->set_property ("number", scm_from_int (++i));
365
366       if (last
367           && to_boolean (last->get_property ("is-title"))
368           && !scm_is_number (ps->get_property ("penalty")))
369         ps->set_property ("penalty", scm_from_int (10000));
370       last = ps;
371     }
372
373   return systems_;
374 }
375
376 SCM
377 Paper_book::pages ()
378 {
379   if (SCM_BOOL_F != pages_)
380     return pages_;
381
382   pages_ = SCM_EOL;
383   SCM proc = paper_->c_variable ("page-breaking");
384   pages_ = scm_apply_0 (proc, scm_list_2 (systems (), self_scm ()));
385   return pages_;
386 }
387
388 SCM
389 Paper_book::performances () const
390 {
391   return scm_reverse (performances_);
392 }