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