]> git.donarmstrong.com Git - lilypond.git/blob - lily/paper-book.cc
Update build script.
[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 Jan Nieuwenhuizen <janneke@gnu.org>
7 */
8
9 #include "ly-module.hh"
10 #include "main.hh"
11 #include "page.hh"
12 #include "paper-book.hh"
13 #include "output-def.hh"
14 #include "paper-outputter.hh"
15 #include "paper-line.hh"
16 #include "paper-score.hh"
17 #include "stencil.hh"
18 #include "warn.hh"
19
20
21 /*
22   Ugh. the Function of the Paper_book class is unclear. Trim this
23   file.
24   
25  */
26
27
28 Paper_book::Paper_book ()
29 {
30   pages_ = SCM_EOL;
31   lines_ = SCM_EOL;
32   copyright_ = SCM_EOL;
33   tagline_ = SCM_EOL;
34   header_ = SCM_EOL;
35   
36   bookpaper_ = 0;
37   smobify_self ();
38 }
39
40 Paper_book::~Paper_book ()
41 {
42 }
43
44 #include "ly-smobs.icc"
45
46 IMPLEMENT_DEFAULT_EQUAL_P (Paper_book);
47 IMPLEMENT_SMOBS (Paper_book)
48 IMPLEMENT_TYPE_P (Paper_book, "ly:paper-book?")
49
50 SCM
51 Paper_book::mark_smob (SCM smob)
52 {
53   Paper_book *b = (Paper_book*) SCM_CELL_WORD_1 (smob);
54   for (int i = 0; i < b->score_lines_.size (); i++)
55     b->score_lines_[i].gc_mark ();
56
57   scm_gc_mark (b->copyright_);
58   if (b->bookpaper_)
59     scm_gc_mark (b->bookpaper_->self_scm ());
60   scm_gc_mark (b->header_);
61   scm_gc_mark (b->pages_);
62   scm_gc_mark (b->lines_);
63   return b->tagline_;
64 }
65
66 int
67 Paper_book::print_smob (SCM smob, SCM port, scm_print_state*)
68 {
69   Paper_book *b = (Paper_book*) ly_cdr (smob);
70      
71   scm_puts ("#<", port);
72   scm_puts (classname (b), port);
73   scm_puts (" ", port);
74   //scm_puts (b->, port);
75   scm_puts (">", port);
76   return 1;
77 }
78
79 Array<String>
80 split_string (String s, char c)
81 {
82   Array<String> rv; 
83   while (s.length ())
84     {
85       int i = s.index (c);
86       
87       if (i == 0)
88         {
89           s = s.nomid_string (0, 1);
90           continue;
91         }
92       
93       if (i < 0)
94         i = s.length () ;
95
96       rv.push (s.cut_string (0, i));
97       s = s.nomid_string (0, i);
98     }
99
100   return rv;
101 }
102
103 SCM
104 dump_fields ()
105 {
106   SCM fields = SCM_EOL;
107   for (int i = dump_header_fieldnames_global.size (); i--; )
108     fields
109       = scm_cons (ly_symbol2scm (dump_header_fieldnames_global[i].to_str0 ()),
110                   fields);
111   return fields;
112 }
113
114 LY_DEFINE (ly_output_formats, "ly:output-formats",
115            0, 0, 0, (),
116            "Formats passed to --format as a list of strings, "
117            "used for the output.")
118 {
119   Array<String> output_formats = split_string (output_format_global, ',');
120
121   SCM lst = SCM_EOL;
122   for (int i = 0; i < output_formats.size (); i ++)
123     lst = scm_cons (scm_makfrom0str (output_formats[i].to_str0 ()), lst);
124   
125   return lst; 
126 }
127           
128
129
130 /*
131   TODO: there is too much code dup, and the interface is not
132   clear. FIXME.
133  */
134 void
135 Paper_book::output (String outname)
136 {
137   if (!score_lines_.size ())
138     return;
139     
140   /* Generate all stencils to trigger font loads.  */
141   pages ();
142
143   
144   SCM formats = ly_output_formats();
145   for (SCM s = formats; ly_c_pair_p (s); s = ly_cdr (s)) 
146     {
147       
148       String format = ly_scm2string (ly_car (s));
149       
150       Paper_outputter *out = get_paper_outputter (outname + "." + format, format);
151
152   
153       SCM scopes = SCM_EOL;
154       if (ly_c_module_p (header_))
155         scopes = scm_cons (header_, scopes);
156   
157       String func_nm = format;
158       func_nm = "output-framework-" + func_nm;
159         
160       SCM func = ly_scheme_function (func_nm.to_str0 ());
161       scm_apply_0 (func, scm_list_n (out->self_scm (),
162                                      self_scm (),
163                                      scopes,
164                                      dump_fields (),
165                                      scm_makfrom0str (outname.to_str0 ()),
166                                      SCM_UNDEFINED
167                                      )) ;
168
169       scm_gc_unprotect_object (out->self_scm ());
170     }
171 }
172
173
174 void
175 Paper_book::classic_output (String outname)
176 {
177
178   /* Generate all stencils to trigger font loads.  */
179   lines ();
180
181
182   // ugh code dup
183   SCM scopes = SCM_EOL;
184   if (ly_c_module_p (header_))
185     scopes = scm_cons (header_, scopes);
186
187   if (ly_c_module_p (score_lines_[0].header_))
188     scopes = scm_cons (score_lines_[0].header_, scopes);
189   //end ugh
190
191
192   Array<String> output_formats = split_string (output_format_global, ',');
193
194   for (int i = 0; i < output_formats.size (); i++)
195     {
196       String format = output_formats[i];
197       String func_nm = format;
198       func_nm = "output-classic-framework-" + func_nm;
199       
200       SCM func = ly_scheme_function (func_nm.to_str0 ());
201
202       Paper_outputter *out = get_paper_outputter (outname + "." + format, format);
203
204       scm_apply_0 (func, scm_list_n (out->self_scm (),
205                                      self_scm (),
206                                      scopes,
207                                      dump_fields (),
208                                      scm_makfrom0str (outname.to_str0 ()),
209                                      SCM_UNDEFINED
210                                      )) ;
211
212       scm_gc_unprotect_object (out->self_scm ());
213     }
214   
215   progress_indication ("\n");
216 }
217
218
219
220
221 LY_DEFINE(ly_paper_book_pages, "ly:paper-book-pages",
222           1,0,0,
223           (SCM pb),
224           "Return pages in book PB.")
225 {
226   return unsmob_paper_book(pb)->pages ();
227 }
228
229
230 LY_DEFINE(ly_paper_book_lines, "ly:paper-book-lines",
231           1,0,0,
232           (SCM pb),
233           "Return lines in book PB.")
234 {
235   return unsmob_paper_book (pb)->lines ();
236 }
237
238
239 LY_DEFINE(ly_paper_book_book_paper, "ly:paper-book-book-paper",
240           1,0,0,
241           (SCM pb),
242           "Return pages in book PB.")
243 {
244   return unsmob_paper_book(pb)->bookpaper_->self_scm ();
245 }
246
247 /*
248
249 TODO: resurrect more complex user-tweaks for titling .
250
251 */
252 Stencil
253 Paper_book::book_title ()
254 {
255   SCM title_func = bookpaper_->lookup_variable (ly_symbol2scm ("book-title"));
256   Stencil title;
257
258   SCM scopes = SCM_EOL;
259   if (ly_c_module_p (header_))
260     scopes = scm_cons (header_, scopes);
261
262  
263   SCM tit = SCM_EOL;
264   if (ly_c_procedure_p (title_func))
265     tit = scm_call_2 (title_func,
266                      bookpaper_->self_scm (),
267                      scopes);
268
269   if (unsmob_stencil (tit))
270     title = *unsmob_stencil (tit);
271
272   if (!title.is_empty ())
273     title.align_to (Y_AXIS, UP);
274   
275   return title;
276 }
277
278   
279
280 Stencil
281 Paper_book::score_title (int i)
282 {
283   SCM title_func = bookpaper_->lookup_variable (ly_symbol2scm ("score-title"));
284
285   Stencil title;
286
287   // ugh code dup
288   SCM scopes = SCM_EOL;
289   if (ly_c_module_p (header_))
290     scopes = scm_cons (header_, scopes);
291
292   if (ly_c_module_p (score_lines_[i].header_))
293     scopes = scm_cons (score_lines_[i].header_, scopes);
294   //end ugh
295
296   SCM tit = SCM_EOL;
297   if (ly_c_procedure_p (title_func))
298     tit =scm_call_2 (title_func,
299                      bookpaper_->self_scm (),
300                      scopes);
301
302   if (unsmob_stencil (tit))
303     title = *unsmob_stencil (tit);
304
305
306   if (!title.is_empty ())
307     title.align_to (Y_AXIS, UP);
308   
309   return title;
310 }
311
312   
313
314 SCM
315 Paper_book::lines ()
316 {
317   if (ly_c_pair_p (lines_))
318     return lines_;
319
320   Stencil title = book_title ();      
321   if (!title.is_empty ())
322     {
323       Paper_line *pl = new Paper_line (title, -10001, true);
324       
325       lines_ = scm_cons (pl->self_scm (), lines_);
326       scm_gc_unprotect_object (pl->self_scm ());
327     }
328   
329   int score_count = score_lines_.size ();
330   for (int i = 0; i < score_count; i++)
331     {
332       Stencil title = score_title (i);      
333       if (!title.is_empty ())
334         {
335           Paper_line *pl = new Paper_line (title, -10001, true);
336           lines_ = scm_cons (pl->self_scm (), lines_);
337           scm_gc_unprotect_object (pl->self_scm ());
338         }
339       
340       if (scm_vector_p (score_lines_[i].lines_) == SCM_BOOL_T)
341         {
342           SCM line_list = scm_vector_to_list (score_lines_[i].lines_); // guh.
343           lines_ = scm_append (scm_list_2 (scm_reverse (line_list), lines_));
344         }
345     }
346   
347   lines_ = scm_reverse (lines_);
348
349   int i = 0;
350   for (SCM s = lines_; s != SCM_EOL; s = ly_cdr (s))
351     unsmob_paper_line (ly_car (s))->number_ = ++i;
352   return lines_;
353 }
354
355
356 SCM
357 make_tagline (Output_def*paper, SCM scopes)
358 {
359   SCM make_tagline = paper->c_variable ("make-tagline");
360   SCM tagline = scm_call_2 (make_tagline, paper->self_scm (), scopes);
361   return tagline;
362 }
363
364 SCM
365 make_copyright (Output_def *paper, SCM scopes)
366 {
367   SCM make_copyright = paper->c_variable ("make-copyright");
368   SCM  copyright = scm_call_2 (make_copyright, paper->self_scm (), scopes);
369   return copyright;
370 }
371
372 SCM
373 Paper_book::pages ()
374 {
375   if (ly_c_pair_p (pages_))
376     return pages_;
377
378   Output_def *paper = bookpaper_;
379   Page *page = new Page (paper, 1);
380
381   Real text_height = page->text_height ();
382
383   Real copy_height = 0;
384   if (Stencil *s = unsmob_stencil (copyright_))
385     copy_height = s->extent (Y_AXIS).length ();
386
387   Real tag_height = 0;
388   if (Stencil *s = unsmob_stencil (tagline_))
389     tag_height = s->extent (Y_AXIS).length ();
390
391   SCM all = lines ();
392   SCM proc = paper->c_variable ("page-breaking");
393   SCM breaks = scm_apply_0 (proc, scm_list_n (all,
394                                               self_scm (),
395                                               scm_make_real (text_height),
396                                               scm_make_real (-copy_height),
397                                               scm_make_real (-tag_height),
398                                               SCM_UNDEFINED));
399
400
401   /*
402     UGH - move this out of C++.
403    */
404   SCM scopes = SCM_EOL;
405   if (ly_c_module_p (header_))
406     scopes = scm_cons (header_, scopes);
407   
408   tagline_ = make_tagline (bookpaper_, scopes);
409   copyright_ = make_tagline (bookpaper_, scopes);
410
411   int page_count = SCM_VECTOR_LENGTH ((SCM) breaks);
412   int line = 1;
413
414   for (int i = 0; i < page_count; i++)
415     {
416       if (i)
417         page = new Page (paper, i + 1);
418
419       int next = i + 1 < page_count
420         ? ly_scm2int (scm_vector_ref (breaks, scm_int2num (i))) : 0;
421       while ((!next && all != SCM_EOL) || line <= next)
422         {
423           SCM s = ly_car (all);
424           page->lines_ = ly_snoc (s, page->lines_);
425           page->height_ += unsmob_paper_line (s)->dim ()[Y_AXIS];
426           page->line_count_++;
427           all = ly_cdr (all);
428           line++;
429         }
430       if (i == page_count-1)
431         page->is_last_ = true;
432       
433       pages_ = scm_cons (page->self_scm (), pages_);
434     }
435
436   pages_ =  scm_reverse (pages_);
437   return pages_;
438 }
439
440
441
442 static SCM
443 c_ragged_page_breaks (SCM lines,
444                       Paper_book *book,
445                       Real text_height,
446                       Real first, Real last)
447 {
448   int page_number = 0;
449
450   Real book_height =0.;
451   for (SCM s = lines ; ly_c_pair_p (s);  s = ly_cdr (s))
452     {
453       book_height += unsmob_paper_line (ly_car (s))->dim ()[Y_AXIS];
454     }
455
456   /*
457     UGH. following stuff should go out of C++.
458    */
459   SCM scopes = SCM_EOL;
460   if (ly_c_module_p (book->header_))
461     scopes = scm_cons (book->header_, scopes);
462   
463
464   SCM tag = make_tagline (book->bookpaper_, scopes);
465   if (unsmob_stencil (tag))
466     {
467       book_height += unsmob_stencil (tag)->extent (Y_AXIS).length ();
468     }
469
470   SCM cr = make_copyright (book->bookpaper_, scopes);
471   if (unsmob_stencil (cr))
472     {
473       book_height += unsmob_stencil (cr)->extent (Y_AXIS).length ();
474     }
475
476   int page_count = int (book_height / text_height + 0.5); // ceil?
477   SCM breaks = SCM_EOL;
478   Real page_height = text_height + first;
479   Real h = 0;
480   int number = 0;
481   for (SCM s = lines; ly_c_pair_p (s); s = ly_cdr (s))
482     {
483       Paper_line *pl = unsmob_paper_line (ly_car (s));
484       if (!pl->is_title () && h < page_height)
485         number++;
486       h += pl->dim ()[Y_AXIS];
487       if (!pl->is_title () && h > page_height)
488         {
489           breaks = ly_snoc (scm_int2num (number), breaks);
490           page_number++;
491           page_height = text_height + (page_number == page_count) * last;
492           h = 0;
493         }
494       if (ly_cdr (s) == SCM_EOL)
495         breaks = ly_snoc (scm_int2num (pl->number_), breaks);
496     }
497
498   return scm_vector (breaks);
499 }
500
501 LY_DEFINE (ly_ragged_page_breaks, "ly:ragged-page-breaks",
502            5, 0, 0, (SCM lines, SCM book, SCM text, SCM first, SCM last),
503            "Return a vector with line numbers of page breaks.")
504 {
505   Paper_book* b = unsmob_paper_book (book);
506
507   SCM_ASSERT_TYPE (scm_pair_p (lines), lines, SCM_ARG1, __FUNCTION__, "list");
508   SCM_ASSERT_TYPE (b, book, SCM_ARG2, __FUNCTION__, "Paper_book");
509   SCM_ASSERT_TYPE (ly_c_number_p (text), text, SCM_ARG3, __FUNCTION__, "number");
510   SCM_ASSERT_TYPE (ly_c_number_p (first), first, SCM_ARG4, __FUNCTION__, "number");
511   SCM_ASSERT_TYPE (ly_c_number_p (last), last, SCM_ARG5, __FUNCTION__, "number");
512
513   return c_ragged_page_breaks (lines, b,
514                                ly_scm2double (text),
515                                ly_scm2double (first), ly_scm2double (last));
516 }
517
518 /****************************************************************/
519
520 Score_lines::Score_lines ()
521 {
522   lines_ = SCM_EOL;
523   header_ = SCM_EOL;
524 }
525
526 void
527 Score_lines::gc_mark ()
528 {
529   scm_gc_mark (lines_);
530   scm_gc_mark (header_);
531 }
532