]> git.donarmstrong.com Git - lilypond.git/blob - lily/paper-book.cc
* lily/system.cc (get_paper_system):
[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 "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 ("paper-book-write-midis");
95
96       scm_call_2 (proc, self_scm (), 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   /* Generate all stencils to trigger font loads.  */
140   systems ();
141
142   SCM scopes = SCM_EOL;
143   if (ly_is_module (header_))
144     scopes = scm_cons (header_, scopes);
145
146   if (ly_is_module (header_0_))
147     scopes = scm_cons (header_0_, scopes);
148
149   string format = output_backend_global;
150   string mod_nm = "scm framework-" + format;
151
152   SCM mod = scm_c_resolve_module (mod_nm.c_str ());
153   SCM func = scm_c_module_lookup (mod, "output-classic-framework");
154
155   func = scm_variable_ref (func);
156   scm_apply_0 (func, scm_list_n (output,
157                                  self_scm (),
158                                  scopes,
159                                  dump_fields (),
160                                  SCM_UNDEFINED));
161
162   progress_indication ("\n");
163 }
164
165 /* TODO: resurrect more complex user-tweaks for titling?  */
166 Stencil
167 Paper_book::book_title ()
168 {
169   SCM title_func = paper_->lookup_variable (ly_symbol2scm ("book-title"));
170   Stencil title;
171
172   SCM scopes = SCM_EOL;
173   if (ly_is_module (header_))
174     scopes = scm_cons (header_, scopes);
175
176   SCM tit = SCM_EOL;
177   if (ly_is_procedure (title_func))
178     tit = scm_call_2 (title_func,
179                       paper_->self_scm (),
180                       scopes);
181
182   if (unsmob_stencil (tit))
183     title = *unsmob_stencil (tit);
184
185   if (!title.is_empty ())
186     title.align_to (Y_AXIS, UP);
187
188   return title;
189 }
190
191 Stencil
192 Paper_book::score_title (SCM header)
193 {
194   SCM title_func = paper_->lookup_variable (ly_symbol2scm ("score-title"));
195
196   Stencil title;
197
198   SCM scopes = SCM_EOL;
199   if (ly_is_module (header_))
200     scopes = scm_cons (header_, scopes);
201
202   if (ly_is_module (header))
203     scopes = scm_cons (header, scopes);
204
205   SCM tit = SCM_EOL;
206   if (ly_is_procedure (title_func))
207     tit = scm_call_2 (title_func,
208                       paper_->self_scm (),
209                       scopes);
210
211   if (unsmob_stencil (tit))
212     title = *unsmob_stencil (tit);
213
214   if (!title.is_empty ())
215     title.align_to (Y_AXIS, UP);
216
217   return title;
218 }
219
220 /* read the breakbefore property of a score block and set up the preceding
221    system-spec to honour it. That is, SYM should be the system spec that
222    immediately precedes the score (from which HEADER is taken)
223    in the get_system_specs() list */
224 void
225 set_system_penalty (SCM sys, SCM header)
226 {
227   if (ly_is_module (header))
228     {
229       SCM force = ly_module_lookup (header, ly_symbol2scm ("breakbefore"));
230       if (SCM_VARIABLEP (force)
231           && scm_is_bool (SCM_VARIABLE_REF (force)))
232         {
233           bool b = to_boolean (SCM_VARIABLE_REF (force));
234           SCM sym = b ? ly_symbol2scm ("force") : SCM_EOL;
235
236           if (Paper_score *ps = dynamic_cast<Paper_score*> (unsmob_music_output (sys)))
237             {
238               vector<Grob*> cols = ps->get_columns ();
239               if (cols.size ())
240                 {
241                   Paper_column *col = dynamic_cast<Paper_column*> (cols.back ());
242                   col->set_property ("page-break-permission", sym);
243                   col->find_prebroken_piece (LEFT)->set_property ("page-break-permission", sym);
244                 }
245             }
246           else if (Prob *pb = unsmob_prob (sys))
247             pb->set_property ("page-break-permission", sym);
248         }
249     }
250 }
251
252
253 SCM
254 Paper_book::get_score_title (SCM header)
255 {
256   Stencil title = score_title (header);
257   if (title.is_empty ())
258     title = score_title (header_);
259   if (!title.is_empty ())
260     {
261       /*
262         TODO: this should come from the \layout {} block, which should
263         override settings from \paper {}
264       */
265       SCM props = paper_->lookup_variable (ly_symbol2scm ("score-title-properties"));
266       Prob *ps = make_paper_system (props);
267       paper_system_set_stencil (ps, title);
268
269       return ps->self_scm();
270     }
271
272   return SCM_BOOL_F;
273 }
274
275
276 SCM
277 Paper_book::get_system_specs ()
278 {
279   SCM system_specs = SCM_EOL;
280   
281   Stencil title = book_title ();
282   if (!title.is_empty ())
283     {
284       SCM props = paper_->lookup_variable (ly_symbol2scm ("book-title-properties"));
285       Prob *ps = make_paper_system (props);
286       paper_system_set_stencil (ps, title);
287
288       system_specs = scm_cons (ps->self_scm (), system_specs);
289       ps->unprotect ();
290     }
291
292   SCM page_properties
293     = scm_call_1 (ly_lily_module_constant ("layout-extract-page-properties"),
294                   paper_->self_scm ());
295
296   SCM header = SCM_EOL;
297   for (SCM s = scm_reverse (scores_); scm_is_pair (s); s = scm_cdr (s))
298     {
299       if (ly_is_module (scm_car (s)))
300         {
301           header = scm_car (s);
302           if (header_0_ == SCM_EOL)
303             header_0_ = header;
304         }
305       else if (Music_output *mop = unsmob_music_output (scm_car (s)))
306         {
307           if (Paper_score *pscore = dynamic_cast<Paper_score *> (mop))
308             {
309               SCM title = get_score_title (header);
310
311               if (scm_is_pair (system_specs))
312                 set_system_penalty (scm_car (system_specs), header);
313
314               if (unsmob_prob (title))
315                 {
316                   system_specs = scm_cons (title, system_specs);
317                   unsmob_prob (title)->unprotect ();
318                 }
319
320               header = SCM_EOL;
321               system_specs = scm_cons (pscore->self_scm (), system_specs);
322             }
323           else
324             {
325               /*
326                 Ignore MIDI
327               */
328             }
329         }
330       else if (Text_interface::is_markup (scm_car (s)))
331         {
332           SCM t = Text_interface::interpret_markup (paper_->self_scm (),
333                                                     page_properties,
334                                                     scm_car (s));
335           
336           // TODO: init props
337           Prob *ps = make_paper_system (SCM_EOL);
338           paper_system_set_stencil (ps, *unsmob_stencil (t));
339           ps->set_property ("is-title", SCM_BOOL_T); 
340           system_specs = scm_cons (ps->self_scm (), system_specs);
341           ps->unprotect ();
342           
343           // FIXME: figure out penalty.
344           //set_system_penalty (ps, scores_[i].header_);
345         }
346       else
347         assert (0);
348     }
349
350   system_specs = scm_reverse_x (system_specs, SCM_EOL);
351   return system_specs;
352 }
353
354 SCM
355 Paper_book::systems ()
356 {
357   if (systems_ != SCM_BOOL_F)
358     return systems_;
359
360   systems_ = SCM_EOL;
361   SCM specs = get_system_specs ();
362   for (SCM s = specs; scm_is_pair (s); s = scm_cdr (s))
363     {
364       if (Paper_score *pscore = dynamic_cast<Paper_score*> (unsmob_music_output (scm_car (s))))
365         {
366           SCM system_list = scm_vector_to_list (pscore->get_paper_systems ());
367           system_list = scm_reverse (system_list);
368           systems_ = scm_append (scm_list_2 (system_list, systems_));
369         }
370       else
371         {
372           systems_ = scm_cons (scm_car (s), systems_);
373         }
374     }
375   
376   systems_ = scm_reverse (systems_);
377
378   /* backwards compatibility for the old page breaker */
379   int i = 0;
380   Prob *last = 0;
381   for (SCM s = systems_; scm_is_pair (s); s = scm_cdr (s))
382     {
383       Prob *ps = unsmob_prob (scm_car (s));
384       ps->set_property ("number", scm_from_int (++i));
385
386       if (last
387           && to_boolean (last->get_property ("is-title"))
388           && !scm_is_number (ps->get_property ("penalty")))
389         ps->set_property ("penalty", scm_from_int (10000));
390       last = ps;
391
392       if (scm_is_pair (scm_cdr (s)))
393         {
394           SCM perm = ps->get_property ("page-break-permission");
395           Prob *next = unsmob_prob (scm_cadr (s));
396           if (perm == SCM_EOL)
397             next->set_property ("penalty", scm_from_int (10001));
398           else if (perm == ly_symbol2scm ("force"))
399             next->set_property ("penalty", scm_from_int (-10001));
400         }
401     }
402
403   return systems_;
404 }
405
406 SCM
407 Paper_book::pages ()
408 {
409   if (SCM_BOOL_F != pages_)
410     return pages_;
411
412   pages_ = SCM_EOL;
413   SCM proc = paper_->c_variable ("page-breaking-wrapper");
414   pages_ = scm_apply_0 (proc, scm_list_1(self_scm ()));
415
416   /* set systems_ from the pages */
417   if (systems_ == SCM_BOOL_F)
418     {
419       systems_ = SCM_EOL;
420       for (SCM p = pages_; scm_is_pair (p); p = scm_cdr (p))
421         {
422           Prob *page = unsmob_prob (scm_car (p));
423           SCM systems = page->get_property ("lines");
424
425           systems_ = scm_append (scm_list_2 (systems_, systems));
426         }
427     }
428
429   return pages_;
430 }
431
432 SCM
433 Paper_book::performances () const
434 {
435   return scm_reverse (performances_);
436 }