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