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