]> git.donarmstrong.com Git - lilypond.git/blob - lily/page.cc
* lily/book.cc (to_stencil): New method.
[lilypond.git] / lily / page.cc
1 /*
2   page.cc -- implement Page
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2004 Jan Nieuwenhuizen <janneke@gnu.org>
7 */
8
9 #include "dimensions.hh"
10 #include "ly-module.hh"
11 #include "page.hh"
12 #include "paper-def.hh"
13 #include "paper-outputter.hh"
14 #include "paper-line.hh"
15 #include "stencil.hh"
16 #include "warn.hh"
17
18 int Page::page_count_ = 0;
19 Real Page::MIN_COVERAGE_ = 0.66;
20
21 Page::Page (Paper_def *paper, int number)
22 {
23   paper_ = paper;
24   number_ = number;
25
26   copyright_ = SCM_EOL;
27   footer_ = SCM_EOL;
28   header_ = SCM_EOL;
29   lines_ = SCM_EOL;
30   tagline_ = SCM_EOL;
31   
32   height_ = 0;
33   line_count_ = 0;
34   
35   page_count_++;
36
37   hsize_ = paper->get_dimension (ly_symbol2scm ("hsize"));
38   vsize_ = paper->get_dimension (ly_symbol2scm ("vsize"));
39   top_margin_ = paper->get_dimension (ly_symbol2scm ("top-margin"));
40   bottom_margin_ = paper->get_dimension (ly_symbol2scm ("bottom-margin"));
41   head_sep_ = paper->get_dimension (ly_symbol2scm ("head-sep"));
42   foot_sep_ = paper->get_dimension (ly_symbol2scm ("foot-sep"));
43   text_width_ = paper->get_dimension (ly_symbol2scm ("linewidth"));
44   left_margin_ = (hsize_ - text_width_) / 2;
45   
46   SCM make_header = ly_scheme_function ("make-header");
47   SCM make_footer = ly_scheme_function ("make-footer");
48
49   header_ = scm_call_2 (make_header, paper_->self_scm (),
50                         scm_int2num (number_));
51   if (unsmob_stencil (header_))
52     unsmob_stencil (header_)->align_to (Y_AXIS, UP);
53     
54   footer_ = scm_call_2 (make_footer, paper_->self_scm (),
55                         scm_int2num (number_));
56   if (unsmob_stencil (footer_))
57     unsmob_stencil (footer_)->align_to (Y_AXIS, UP);
58
59   smobify_self ();
60 }
61
62 Page::~Page ()
63 {
64 }
65
66 #include "ly-smobs.icc"
67
68 IMPLEMENT_DEFAULT_EQUAL_P (Page)
69 IMPLEMENT_SMOBS (Page)
70 IMPLEMENT_TYPE_P (Page, "ly:page?")
71
72 SCM
73 Page::mark_smob (SCM smob)
74 {
75   Page *p = (Page*) SCM_CELL_WORD_1 (smob);
76   scm_gc_mark (p->lines_);
77   scm_gc_mark (p->header_);
78   scm_gc_mark (p->footer_);
79   scm_gc_mark (p->copyright_);
80   scm_gc_mark (p->tagline_);
81   return p->lines_;
82 }
83
84 int
85 Page::print_smob (SCM smob, SCM port, scm_print_state*)
86 {
87   Page *p = (Page*) ly_cdr (smob);
88   scm_puts ("#<", port);
89   scm_puts (classname (p), port);
90   scm_puts (to_string (p->number_).to_str0 (), port);
91   scm_puts (" ", port);
92   scm_puts (">", port);
93   return 1;
94 }
95
96 static void
97 stack_stencils (Stencil &a, Stencil *b, Offset *origin)
98 {
99   Real height = b->extent (Y_AXIS).length ();
100   if (height > 50 CM)
101     {
102       programming_error (to_string ("Improbable stencil height: %f", height));
103       height = 50 CM;
104     }
105   Offset o = *origin;
106   o.mirror (Y_AXIS);
107   b->translate (o);
108   a.add_stencil (*b);
109   (*origin)[Y_AXIS] += height;
110 }
111
112 SCM
113 Page::to_stencil () const
114 {
115   SCM proc = ly_scheme_function ("page-to-stencil");
116   return scm_call_1 (proc, self_scm ());
117 }
118
119 LY_DEFINE (ly_page_header_lines_footer_stencil, "ly:page-header-lines-footer-stencil",
120            1, 0, 0, (SCM page),
121            "Simple header, lines, footer stencil from PAGE.")
122 {
123   Page *p = unsmob_page (page);
124   SCM_ASSERT_TYPE (p, page, SCM_ARG1, __FUNCTION__, "page");
125   
126   Stencil stencil;
127   Offset o (p->left_margin_, p->top_margin_);
128   Real vfill = (p->line_count_ > 1
129                 ? (p->text_height () - p->height_) / (p->line_count_ - 1)
130                 : 0);
131
132   Real coverage = p->height_ / p->text_height ();
133   if (coverage < p->MIN_COVERAGE_)
134     /* Do not space out a badly filled page.  This is too simplistic
135        (ie broken), because this should not vary too much between
136        (subsequent?) pages in a book.  */
137     vfill = 0;
138
139   if (Stencil *s = unsmob_stencil (p->header_))
140     {
141       stack_stencils (stencil, s, &o);
142       o[Y_AXIS] += p->head_sep_;
143     }
144   for (SCM s = p->lines_; s != SCM_EOL; s = ly_cdr (s))
145     {
146       Paper_line *p = unsmob_paper_line (ly_car (s));
147 #if 0 // ugh, parse error?
148       Stencil line (Box (Interval (0, p->dim ()[X_AXIS]),
149                          Interval (0, p->dim ()[Y_AXIS])), SCM_EOL);
150 #else
151       Box x (Interval (0, p->dim ()[X_AXIS]),
152              Interval (0, p->dim ()[Y_AXIS]));
153       Stencil line (x, SCM_EOL);
154 #endif
155       line.add_stencil (*unsmob_stencil (p->to_stencil ()));
156       stack_stencils (stencil, &line, &o);
157       
158       /* Do not put vfill between title and its music, */
159       if (ly_cdr (s) != SCM_EOL
160           && (!p->is_title () || vfill < 0))
161         o[Y_AXIS] += vfill;
162       /* rather put extra just before the title.  */
163       if (ly_cdr (s) != SCM_EOL
164           && (unsmob_paper_line (ly_cadr (s))->is_title () && vfill > 0))
165         o[Y_AXIS] += vfill;
166     }
167
168   o[Y_AXIS] = p->vsize_ - p->bottom_margin_;
169   if (unsmob_stencil (p->copyright_))
170     o[Y_AXIS] -= unsmob_stencil (p->copyright_)->extent (Y_AXIS).length ();
171   if (unsmob_stencil (p->tagline_))
172     o[Y_AXIS] -= unsmob_stencil (p->tagline_)->extent (Y_AXIS).length ();
173   if (unsmob_stencil (p->footer_))
174     o[Y_AXIS] -= unsmob_stencil (p->footer_)->extent (Y_AXIS).length ();
175
176   if (Stencil *s = unsmob_stencil (p->copyright_))
177     stack_stencils (stencil, s, &o);
178   if (Stencil *s = unsmob_stencil (p->tagline_))
179     stack_stencils (stencil, s, &o);
180   if (Stencil *s = unsmob_stencil (p->footer_))
181     stack_stencils (stencil, s, &o);
182
183   return stencil.smobbed_copy ();
184 }
185
186 Real
187 Page::text_height () const
188 {
189   Real h = vsize_ - top_margin_ - bottom_margin_;
190   if (unsmob_stencil (header_))
191     h -= unsmob_stencil (header_)->extent (Y_AXIS).length () + head_sep_;
192   if (unsmob_stencil (copyright_) || unsmob_stencil (tagline_) || unsmob_stencil (footer_))
193     h -= foot_sep_;
194   if (unsmob_stencil (copyright_))
195     h -= unsmob_stencil (copyright_)->extent (Y_AXIS).length ();
196   if (unsmob_stencil (tagline_))
197     h -= unsmob_stencil (tagline_)->extent (Y_AXIS).length ();
198   if (unsmob_stencil (footer_))
199     h -= unsmob_stencil (footer_)->extent (Y_AXIS).length ();
200   return h;
201 }
202