]> git.donarmstrong.com Git - lilypond.git/blob - lily/paper-book.cc
* lily/paper-book.cc (get_pages): Bugfix: set dimensions for titles.
[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 <stdio.h>
10
11 #include "ly-module.hh"
12 #include "main.hh"
13 #include "paper-book.hh"
14 #include "paper-def.hh"
15 #include "paper-outputter.hh"
16 #include "paper-score.hh"
17 #include "stencil.hh"
18
19 // WIP -- simplistic page interface
20 // Do we need this at all?  SCM, smob?
21 class Page
22 {
23 public:
24   Paper_def *paper_;
25
26   SCM lines_;
27   Stencil *header_;
28   Stencil *footer_;
29
30   /* actual height filled with text.  */
31   Real height_;
32   
33   //HMMM all this size stuff to paper/paper-outputter?
34   Real hsize_;
35   Real vsize_;
36   Real foot_sep_;
37   Real head_sep_;
38
39   /* available area for text.  */
40   Real text_height ();
41
42   Page (Paper_def*);
43   void output (Paper_outputter*, bool);
44 };
45
46 Page::Page (Paper_def *paper)
47 {
48   paper_ = paper;
49   height_ = 0;
50   header_ = 0;
51   footer_ = 0;
52   lines_ = SCM_EOL;
53   
54   hsize_ = paper->get_realvar (ly_symbol2scm ("hsize"));
55   vsize_ = paper->get_realvar (ly_symbol2scm ("vsize"));
56   head_sep_ = 0; //paper->get_realvar (ly_symbol2scm ("head-sep"));
57   foot_sep_ = 0; //paper->get_realvar (ly_symbol2scm ("foot-sep"));
58 }
59
60 void
61 Page::output (Paper_outputter *out, bool is_last)
62 {
63   // TODO: header/footer etc
64   out->output_scheme (scm_list_1 (ly_symbol2scm ("start-page")));
65   for (SCM s = lines_; gh_pair_p (s); s = ly_cdr (s))
66     out->output_line (ly_car (s), is_last && gh_pair_p (ly_cdr (s)));
67   out->output_scheme (scm_list_2 (ly_symbol2scm ("stop-page"),
68                                   gh_bool2scm (is_last)));
69 }
70
71 Real
72 Page::text_height ()
73 {
74   Real h = vsize_;
75   if (header_)
76     h -= header_->extent (Y_AXIS).length () + head_sep_;
77   if (footer_)
78     h -= footer_->extent (Y_AXIS).length () + foot_sep_;
79   return h;
80 }
81
82
83 Paper_book *paper_book;
84
85 Paper_book::Paper_book ()
86 {
87   protect_ = SCM_EOL;
88 }
89
90 void
91 Paper_book::output (String outname)
92 {
93   /* Generate all stencils to trigger font loads.  */
94   Link_array<Page> *pages = get_pages ();
95
96   Paper_def *paper = papers_[0];
97   Paper_outputter *out = paper->get_paper_outputter (outname);
98   out->output_metadata (get_scopes (0), paper);
99   out->output_header (paper);
100
101   int page_count = pages->size ();
102   for (int i = 0; i < page_count; i++)
103     (*pages)[i]->output (out, i + 1 == page_count);
104
105   out->output_scheme (scm_list_1 (ly_symbol2scm ("end-output")));
106   progress_indication ("\n");
107 }
108
109 SCM
110 Paper_book::get_scopes (int i)
111 {
112   SCM scopes = SCM_EOL;
113   if (headers_[i])
114     scopes = scm_cons (headers_[i], scopes);
115   if (global_headers_[i] && global_headers_[i] != headers_[i])
116     scopes = scm_cons (global_headers_[i], scopes);
117   return scopes;
118 }
119
120 Stencil*
121 Paper_book::get_title (int i)
122 {
123   SCM make_title = scm_primitive_eval (ly_symbol2scm ("make-title"));
124   SCM field = (i == 0 ? ly_symbol2scm ("bookTitle")
125                : ly_symbol2scm ("scoreTitle"));
126
127   SCM s = ly_modules_lookup (get_scopes (i), field); 
128   if (s != SCM_UNDEFINED && scm_variable_bound_p (s) == SCM_BOOL_T)
129     {
130       Stencil *title = unsmob_stencil (gh_call2 (make_title,
131                                                  papers_[0]->self_scm (),
132                                                  scm_variable_ref (s)));
133       
134       title->align_to (Y_AXIS, UP);
135       return title;
136     }
137   
138   return 0;
139 }
140
141 /*
142   WIP
143
144   FIXME: titling is broken.
145   
146   TODO:
147      * ->SCM?
148      * decent page breaking algorithm
149      * header / footer (generate per Page, with page#)
150      * override: # pages, or pageBreakLines= #'(3 3 4), ?
151      * what about between-system-breaking, can we junk that?
152      
153 */
154 Link_array<Page>*
155 Paper_book::get_pages ()
156 {
157   Link_array<Page> *pages = new Link_array<Page>;
158   int score_count = scores_.size ();
159
160   /* Calculate the full book height.  Hmm, can't we cache system
161      heights while making stencils?  */
162   Real book_height = 0;
163   for (int i = 0; i < score_count; i++)
164     {
165       Stencil *title = get_title (i);
166       if (title)
167         book_height += title->extent (Y_AXIS).length ();
168
169       int line_count = SCM_VECTOR_LENGTH ((SCM) scores_[i]);
170       for (int j = 0; j < line_count; j++)
171         {
172           SCM line = scm_vector_ref ((SCM) scores_[i], scm_int2num (j));
173           book_height += ly_scm2offset (ly_car (line))[Y_AXIS];
174         }
175     }
176
177   Paper_def *paper = papers_[0];
178   Page *page = new Page (paper);
179   fprintf (stderr, "book_height: %f\n", book_height);
180   fprintf (stderr, "vsize: %f\n", page->vsize_);
181   fprintf (stderr, "pages: %f\n", book_height / page->text_height ());
182
183   /* Simplistic page breaking.  */
184   Real text_height = page->text_height ();
185   for (int i = 0; i < score_count; i++)
186     {
187       Stencil *title = get_title (i);
188       if (title)
189         book_height += title->extent (Y_AXIS).length ();
190       Real h = 0;
191       if (title)
192         h = title->extent (Y_AXIS).length ();
193
194       int line_count = SCM_VECTOR_LENGTH ((SCM) scores_[i]);
195       for (int j = 0; j < line_count; j++)
196         {
197           SCM line = scm_vector_ref ((SCM) scores_[i], scm_int2num (j));
198           h += ly_scm2offset (ly_car (line))[Y_AXIS];
199           if (page->height_ + h > text_height)
200             {
201               pages->push (page);
202               page = new Page (paper);
203             }
204           if (page->height_ + h <= text_height || page->height_ == 0)
205             {
206               if (j == 0 && title)
207                 {
208                   Offset dim = Offset (title->extent (X_AXIS).length (),
209                                        title->extent (Y_AXIS).length ());
210                   page->lines_
211                     = ly_snoc (scm_cons (ly_offset2scm (dim),
212                                          scm_list_1
213                                          (scm_cons
214                                           (ly_offset2scm (Offset (0, 0)),
215                                            title->smobbed_copy ()))),
216                              page->lines_);
217                 }
218               page->lines_ = ly_snoc (line, page->lines_);
219               page->height_ += h;
220               h = 0;
221             }
222         }
223     }
224   
225   pages->push (page);
226   return pages;
227 }
228
229 void
230 Paper_book::classic_output (String outname)
231 {
232   Paper_outputter *out = papers_.top ()->get_paper_outputter (outname);
233   int count = scores_.size ();
234   
235   out->output_metadata (get_scopes (count - 1), papers_.top ());
236   out->output_header (papers_.top ());
237
238   int line_count = SCM_VECTOR_LENGTH ((SCM) scores_.top ());
239   for (int i = 0; i < line_count; i++)
240     out->output_line (scm_vector_ref ((SCM) scores_.top (), scm_int2num (i)),
241                       i == line_count - 1);
242   
243   out->output_scheme (scm_list_1 (ly_symbol2scm ("end-output")));
244   progress_indication ("\n");
245 }
246
247
248 #include "ly-smobs.icc"
249
250 IMPLEMENT_DEFAULT_EQUAL_P (Paper_book);
251 IMPLEMENT_SIMPLE_SMOBS (Paper_book)
252 IMPLEMENT_TYPE_P (Paper_book, "ly:paper_book?")
253
254 SCM
255 Paper_book::mark_smob (SCM smob)
256 {
257   Paper_book *b = (Paper_book*) SCM_CELL_WORD_1 (smob);
258
259 #if 0 //TODO
260   scm_gc_mark (b->scores_);
261   scm_gc_mark (b->global_headers_);
262   scm_gc_mark (b->headers_);
263   scm_gc_mark (b->papers_);
264 #endif
265
266   return SCM_EOL;
267 }
268
269 int
270 Paper_book::print_smob (SCM smob, SCM port, scm_print_state*)
271 {
272   Paper_book *b = (Paper_book*) ly_cdr (smob);
273      
274   scm_puts ("#<", port);
275   scm_puts (classname (b), port);
276   scm_puts (" ", port);
277   //scm_puts (b->, port);
278   scm_puts (">", port);
279   return 1;
280 }
281
282 SCM
283 Paper_book::smobbed_copy () const
284 {
285   Paper_book *b = new Paper_book (*this);
286   return b->smobbed_self ();
287 }