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