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