]> git.donarmstrong.com Git - lilypond.git/blob - lily/paper-book.cc
999fd0255b80035c6be2b398acd50f08b1a24813
[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
84
85 Paper_book *paper_book;         // huh? global var? --hwn
86
87 Paper_book::Paper_book ()
88 {
89   smobify_self ();
90 }
91
92 void
93 Paper_book::output (String outname)
94 {
95   /* Generate all stencils to trigger font loads.  */
96   Link_array<Page> *pages = get_pages ();
97
98   Paper_def *paper = papers_[0];
99   Paper_outputter *out = paper->get_paper_outputter (outname);
100   out->output_metadata (get_scopes (0), paper);
101   out->output_header (paper);
102
103   int page_count = pages->size ();
104   for (int i = 0; i < page_count; i++)
105     (*pages)[i]->output (out, i + 1 == page_count);
106
107   out->output_scheme (scm_list_1 (ly_symbol2scm ("end-output")));
108   progress_indication ("\n");
109 }
110
111 SCM
112 Paper_book::get_scopes (int i)
113 {
114   SCM scopes = SCM_EOL;
115   if (headers_[i])
116     scopes = scm_cons (headers_[i], scopes);
117   if (global_headers_[i] && global_headers_[i] != headers_[i])
118     scopes = scm_cons (global_headers_[i], scopes);
119   return scopes;
120 }
121
122 Stencil*
123 Paper_book::get_title (int i)
124 {
125   SCM make_title = scm_primitive_eval (ly_symbol2scm ("make-title"));
126   SCM field = (i == 0 ? ly_symbol2scm ("bookTitle")
127                : ly_symbol2scm ("scoreTitle"));
128
129   SCM s = ly_modules_lookup (get_scopes (i), field); 
130   if (s != SCM_UNDEFINED && scm_variable_bound_p (s) == SCM_BOOL_T)
131     {
132       Stencil *title = unsmob_stencil (gh_call2 (make_title,
133                                                  papers_[0]->self_scm (),
134                                                  scm_variable_ref (s)));
135       
136       title->align_to (Y_AXIS, UP);
137       return title;
138     }
139   
140   return 0;
141 }
142
143 /*
144   WIP
145
146   FIXME: titling is broken.
147   
148   TODO:
149      * ->SCM?
150      * decent page breaking algorithm
151      * header / footer (generate per Page, with page#)
152      * override: # pages, or pageBreakLines= #'(3 3 4), ?
153      * what about between-system-breaking, can we junk that?
154      
155 */
156 Link_array<Page>*
157 Paper_book::get_pages ()
158 {
159   Link_array<Page> *pages = new Link_array<Page>;
160   int score_count = scores_.size ();
161
162   /* Calculate the full book height.  Hmm, can't we cache system
163      heights while making stencils?  */
164   Real book_height = 0;
165   for (int i = 0; i < score_count; i++)
166     {
167       Stencil *title = get_title (i);
168       if (title)
169         book_height += title->extent (Y_AXIS).length ();
170
171       int line_count = SCM_VECTOR_LENGTH ((SCM) scores_[i]);
172       for (int j = 0; j < line_count; j++)
173         {
174           SCM line = scm_vector_ref ((SCM) scores_[i], scm_int2num (j));
175           book_height += ly_scm2offset (ly_car (line))[Y_AXIS];
176         }
177     }
178
179   Paper_def *paper = papers_[0];
180   Page *page = new Page (paper);
181   fprintf (stderr, "book_height: %f\n", book_height);
182   fprintf (stderr, "vsize: %f\n", page->vsize_);
183   fprintf (stderr, "pages: %f\n", book_height / page->text_height ());
184
185   /* Simplistic page breaking.  */
186   Real text_height = page->text_height ();
187   for (int i = 0; i < score_count; i++)
188     {
189       Stencil *title = get_title (i);
190       if (title)
191         book_height += title->extent (Y_AXIS).length ();
192       Real h = 0;
193       if (title)
194         h = title->extent (Y_AXIS).length ();
195
196       int line_count = SCM_VECTOR_LENGTH ((SCM) scores_[i]);
197       for (int j = 0; j < line_count; j++)
198         {
199           SCM line = scm_vector_ref ((SCM) scores_[i], scm_int2num (j));
200           h += ly_scm2offset (ly_car (line))[Y_AXIS];
201           if (page->height_ + h > text_height)
202             {
203               pages->push (page);
204               page = new Page (paper);
205             }
206           if (page->height_ + h <= text_height || page->height_ == 0)
207             {
208               if (j == 0 && title)
209                 {
210                   Offset dim = Offset (title->extent (X_AXIS).length (),
211                                        title->extent (Y_AXIS).length ());
212                   page->lines_
213                     = ly_snoc (scm_cons (ly_offset2scm (dim),
214                                          scm_list_1
215                                          (scm_cons
216                                           (ly_offset2scm (Offset (0, 0)),
217                                            title->smobbed_copy ()))),
218                              page->lines_);
219                 }
220               page->lines_ = ly_snoc (line, page->lines_);
221               page->height_ += h;
222               h = 0;
223             }
224         }
225     }
226   
227   pages->push (page);
228   return pages;
229 }
230
231 void
232 Paper_book::classic_output (String outname)
233 {
234   Paper_outputter *out = papers_.top ()->get_paper_outputter (outname);
235   int count = scores_.size ();
236   
237   out->output_metadata (get_scopes (count - 1), papers_.top ());
238   out->output_header (papers_.top ());
239
240   int line_count = SCM_VECTOR_LENGTH ((SCM) scores_.top ());
241   for (int i = 0; i < line_count; i++)
242     out->output_line (scm_vector_ref ((SCM) scores_.top (), scm_int2num (i)),
243                       i == line_count - 1);
244   
245   out->output_scheme (scm_list_1 (ly_symbol2scm ("end-output")));
246   progress_indication ("\n");
247 }
248
249
250 #include "ly-smobs.icc"
251
252 IMPLEMENT_DEFAULT_EQUAL_P (Paper_book);
253 IMPLEMENT_SMOBS (Paper_book)
254 IMPLEMENT_TYPE_P (Paper_book, "ly:paper-book?")
255
256 SCM
257 Paper_book::mark_smob (SCM smob)
258 {
259   Paper_book *pb = (Paper_book*) SCM_CELL_WORD_1 (smob);
260   for (int i = 0; i < pb->headers_.size (); i++)
261     scm_gc_mark (pb->headers_[i]);
262   for (int i = 0; i < pb->global_headers_.size (); i++)
263     scm_gc_mark (pb->global_headers_[i]);
264   for (int i = 0; i < pb->papers_.size (); i++)
265     scm_gc_mark (pb->papers_[i]->self_scm ());
266   for (int i = 0; i < pb->scores_.size (); i++)
267     scm_gc_mark (pb->scores_[i]);
268   return SCM_EOL;
269 }
270
271 int
272 Paper_book::print_smob (SCM smob, SCM port, scm_print_state*)
273 {
274   Paper_book *b = (Paper_book*) ly_cdr (smob);
275      
276   scm_puts ("#<", port);
277   scm_puts (classname (b), port);
278   scm_puts (" ", port);
279   //scm_puts (b->, port);
280   scm_puts (">", port);
281   return 1;
282 }
283
284 Paper_book::~Paper_book ()
285 {
286 }
287