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