]> git.donarmstrong.com Git - lilypond.git/blob - lily/page.cc
* Documentation/user/changing-defaults.itely (Creating contexts):
[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 "output-def.hh"
13 #include "paper-outputter.hh"
14 #include "paper-line.hh"
15 #include "stencil.hh"
16 #include "warn.hh"
17
18
19 Real Page::MIN_COVERAGE_ = 0.66;
20
21 Page::Page (SCM lines, Output_def *paper, int number)
22 {
23   copyright_ = SCM_EOL;
24   footer_ = SCM_EOL;
25   header_ = SCM_EOL;
26   lines_ = SCM_EOL;
27   tagline_ = SCM_EOL;
28
29   smobify_self ();
30
31   
32   paper_ = paper;
33   number_ = number;
34
35   height_ = 0;
36   line_count_ = 0;
37   is_last_ = false;
38   header_ = scm_call_2 (paper_->c_variable ("make-header"),
39                         paper_->self_scm (),
40                         scm_int2num (number_));
41   if (unsmob_stencil (header_))
42     unsmob_stencil (header_)->align_to (Y_AXIS, UP);
43     
44   footer_ = scm_call_2 (paper_->c_variable ("make-footer"),
45                         paper_->self_scm (),
46                         scm_int2num (number_));
47   if (unsmob_stencil (footer_))
48     unsmob_stencil (footer_)->align_to (Y_AXIS, UP);
49
50   lines_ = lines;
51   for (SCM s = lines; ly_c_pair_p (s); s = ly_cdr (s))
52     {
53       height_ += unsmob_paper_line (ly_car (s))->dim()[Y_AXIS];
54       line_count_ ++;
55     }
56   
57 }
58
59 Page::~Page ()
60 {
61 }
62
63 #include "ly-smobs.icc"
64
65 IMPLEMENT_DEFAULT_EQUAL_P (Page)
66 IMPLEMENT_SMOBS (Page)
67 IMPLEMENT_TYPE_P (Page, "ly:page?")
68
69 SCM
70 Page::mark_smob (SCM smob)
71 {
72   Page *p = (Page*) SCM_CELL_WORD_1 (smob);
73   scm_gc_mark (p->header_);
74   scm_gc_mark (p->footer_);
75
76   if (p->paper_)
77     {
78       scm_gc_mark (p->paper_->self_scm ());
79     }
80   
81   scm_gc_mark (p->copyright_);
82   scm_gc_mark (p->tagline_);
83   //scm_gc_mark (p->lines_);
84   return p->lines_;
85 }
86
87 int
88 Page::print_smob (SCM smob, SCM port, scm_print_state*)
89 {
90   Page *p = (Page*) ly_cdr (smob);
91   scm_puts ("#<", port);
92   scm_puts (classname (p), port);
93   scm_puts (to_string (p->number_).to_str0 (), port);
94   scm_puts (" ", port);
95   scm_puts (">", port);
96   return 1;
97 }
98
99 static Stencil
100 stack_stencils (Stencil a, Stencil b, Offset *origin)
101 {
102   Real height = b.extent (Y_AXIS).length ();
103   if (height > 50 CM)
104     {
105       programming_error (to_string ("Improbable stencil height: %f", height));
106       height = 50 CM;
107     }
108   Offset o = *origin;
109   o.mirror (Y_AXIS);
110   b.translate (o);
111   a.add_stencil (b);
112   (*origin)[Y_AXIS] += height;
113   return a;
114 }
115
116 Stencil
117 Page::to_stencil () const
118 {
119   SCM proc = paper_->lookup_variable (ly_symbol2scm ("page-to-stencil"));
120   return *unsmob_stencil (scm_call_1 (proc, self_scm ()));
121 }
122
123 //urg
124 Real
125 Page::left_margin () const
126 {
127   return (paper_->get_dimension (ly_symbol2scm ("hsize"))
128           - paper_->get_dimension (ly_symbol2scm ("linewidth"))) / 2;
129 }
130
131 LY_DEFINE (ly_page_header_lines_footer_stencil, "ly:page-header-lines-footer-stencil",
132            1, 0, 0, (SCM page),
133            "Simple header, lines, footer stencil from PAGE.")
134 {
135   Page *p = unsmob_page (page);
136   SCM_ASSERT_TYPE (p, page, SCM_ARG1, __FUNCTION__, "page");
137   
138   Stencil stencil;
139   Offset o (p->left_margin (),
140             p->paper_->get_dimension (ly_symbol2scm ("top-margin")));
141
142   Real vfill = (p->line_count_ > 1
143                 ? (p->text_height () - p->height_) / (p->line_count_ - 1)
144                 : 0);
145
146   Real coverage = p->height_ / p->text_height ();
147   if (coverage < p->MIN_COVERAGE_)
148     /* Do not space out a badly filled page.  This is too simplistic
149        (ie broken), because this should not vary too much between
150        (subsequent?) pages in a book.  */
151     vfill = 0;
152
153   if (Stencil *s = unsmob_stencil (p->header_))
154     {
155       stencil = stack_stencils (stencil, *s, &o);
156       o[Y_AXIS] += p->paper_->get_dimension (ly_symbol2scm ("head-sep"));
157     }
158
159   for (SCM s = p->lines_; s != SCM_EOL; s = ly_cdr (s))
160     {
161       Paper_line *p = unsmob_paper_line (ly_car (s));
162       stencil = stack_stencils (stencil, p->to_stencil (), &o);
163       /* Do not put vfill between title and its music, */
164       if (ly_cdr (s) != SCM_EOL
165           && (!p->is_title () || vfill < 0))
166         o[Y_AXIS] += vfill;
167       /* rather put extra just before the title.  */
168       if (ly_cdr (s) != SCM_EOL
169           && (unsmob_paper_line (ly_cadr (s))->is_title () && vfill > 0))
170         o[Y_AXIS] += vfill;
171     }
172
173   o[Y_AXIS] = p->paper_->get_dimension (ly_symbol2scm ("vsize"))
174     - p->paper_->get_dimension (ly_symbol2scm ("bottom-margin"));
175   if (unsmob_stencil (p->copyright_))
176     o[Y_AXIS] -= unsmob_stencil (p->copyright_)->extent (Y_AXIS).length ();
177   if (unsmob_stencil (p->tagline_))
178     o[Y_AXIS] -= unsmob_stencil (p->tagline_)->extent (Y_AXIS).length ();
179   if (unsmob_stencil (p->footer_))
180     o[Y_AXIS] -= unsmob_stencil (p->footer_)->extent (Y_AXIS).length ();
181
182   if (Stencil *s = unsmob_stencil (p->copyright_))
183     stencil = stack_stencils (stencil, *s, &o);
184   if (Stencil *s = unsmob_stencil (p->tagline_))
185     stencil = stack_stencils (stencil, *s, &o);
186   if (Stencil *s = unsmob_stencil (p->footer_))
187     stencil = stack_stencils (stencil, *s, &o);
188
189   return stencil.smobbed_copy ();
190 }
191
192 Real
193 Page::text_height () const
194 {
195   Real h = paper_->get_dimension (ly_symbol2scm ("vsize"))
196     - paper_->get_dimension (ly_symbol2scm ("top-margin"))
197     - paper_->get_dimension (ly_symbol2scm ("bottom-margin"));
198   if (unsmob_stencil (header_))
199     h -= unsmob_stencil (header_)->extent (Y_AXIS).length ()
200       + paper_->get_dimension (ly_symbol2scm ("head-sep"));
201   if (unsmob_stencil (copyright_)
202       || unsmob_stencil (tagline_)
203       || unsmob_stencil (footer_))
204     h -= paper_->get_dimension (ly_symbol2scm ("foot-sep"));
205   if (unsmob_stencil (copyright_))
206     h -= unsmob_stencil (copyright_)->extent (Y_AXIS).length ();
207   if (unsmob_stencil (tagline_))
208     h -= unsmob_stencil (tagline_)->extent (Y_AXIS).length ();
209   if (unsmob_stencil (footer_))
210     h -= unsmob_stencil (footer_)->extent (Y_AXIS).length ();
211   return h;
212 }
213
214
215 /*
216   TODO: unused?
217   
218  */
219 LY_DEFINE (ly_page_paper_lines, "ly:page-paper-lines",
220            1, 0, 0, (SCM page),
221            "Return paper-lines from @var{page}.")
222 {
223   Page *p = unsmob_page (page);
224   SCM_ASSERT_TYPE (p, page, SCM_ARG1, __FUNCTION__, "page");
225   return p->lines_;
226 }
227
228 LY_DEFINE (ly_page_stencil, "ly:page-stencil",
229            1, 0, 0, (SCM page),
230            "Return stencil for @var{page}.")
231 {
232   Page *p = unsmob_page (page);
233   SCM_ASSERT_TYPE (p, page, SCM_ARG1, __FUNCTION__, "page");
234   return p->to_stencil ().smobbed_copy ();
235 }
236
237
238 LY_DEFINE (ly_page_last_p, "ly:page-last?",
239            1, 0, 0, (SCM page),
240            "Is @var{page} the last one?")
241 {
242   Page *p = unsmob_page (page);
243   SCM_ASSERT_TYPE (p, page, SCM_ARG1, __FUNCTION__, "page");
244   return ly_bool2scm (p->is_last_);
245 }