]> git.donarmstrong.com Git - lilypond.git/blob - lily/bar-number-engraver.cc
Run astyle 2.02.
[lilypond.git] / lily / bar-number-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <algorithm> // for reverse
21
22 #include "paper-column.hh"
23 #include "output-def.hh"
24 #include "side-position-interface.hh"
25 #include "engraver.hh"
26 #include "context.hh"
27 #include "grob-array.hh"
28 #include "stream-event.hh"
29
30 #include "translator.icc"
31
32 /*
33   TODO: detect the top staff (stavesFound), and acknowledge staff-group
34   system-start-delims. If we find these, and the top staff is in the
35   staff-group, add padding to the bar number.
36 */
37 class Bar_number_engraver : public Engraver
38 {
39 protected:
40   Item *text_;
41   int alternative_starting_bar_number_;
42   int alternative_number_;
43   int alternative_number_increment_;
44   Stream_event *alternative_event_;
45
46 protected:
47   void stop_translation_timestep ();
48   DECLARE_TRANSLATOR_LISTENER (alternative);
49   DECLARE_ACKNOWLEDGER (break_alignment);
50   void process_music ();
51   void create_items ();
52   TRANSLATOR_DECLARATIONS (Bar_number_engraver);
53 };
54
55 IMPLEMENT_TRANSLATOR_LISTENER (Bar_number_engraver, alternative);
56 void
57 Bar_number_engraver::listen_alternative (Stream_event *ev)
58 {
59   if (alternative_event_)
60     return;
61
62   alternative_event_ = ev;
63   int current_barnumber = robust_scm2int (get_property ("currentBarNumber"), 0);
64   Direction alternative_dir = robust_scm2dir (ev->get_property ("alternative-dir"), CENTER);
65   bool make_alternative = get_property ("alternativeNumberingStyle") == ly_symbol2scm ("numbers")
66                           || get_property ("alternativeNumberingStyle") == ly_symbol2scm ("numbers-with-letters");
67   if (make_alternative)
68     {
69       /*
70         if we're starting the first alternative, we set the starting
71         bar number to the current bar number
72       */
73       if (alternative_dir == LEFT)
74         alternative_starting_bar_number_ = current_barnumber;
75
76       /*
77         if the alternative is not the last one, we send the
78         current bar number back to the alternative bar number.
79       */
80       if (alternative_dir < RIGHT)
81         current_barnumber = alternative_starting_bar_number_;
82
83       context ()->set_property ("currentBarNumber", scm_from_int (current_barnumber));
84     }
85 }
86
87 int
88 int_pow (int n, int i)
89 {
90   if (i == 1)
91     return n;
92   if (i <= 0)
93     return 1;
94   return int_pow (n * n, i - 1);
95 }
96
97 void
98 Bar_number_engraver::process_music ()
99 {
100   SCM wb = get_property ("whichBar");
101
102   if (scm_is_string (wb))
103     {
104       Moment mp (robust_scm2moment (get_property ("measurePosition"), Moment (0)));
105       if (mp.main_part_ == Rational (0))
106         {
107           SCM bn = get_property ("currentBarNumber");
108           SCM proc = get_property ("barNumberVisibility");
109           if (scm_is_number (bn) && ly_is_procedure (proc)
110               && to_boolean (scm_call_1 (proc, bn)))
111             {
112               create_items ();
113               SCM alternative_style = get_property ("alternativeNumberingStyle");
114               string text_tag = "";
115               if (alternative_style == ly_symbol2scm ("numbers-with-letters"))
116                 {
117                   if (alternative_event_)
118                     {
119                       Direction alternative_dir = robust_scm2dir (alternative_event_->get_property ("alternative-dir"), RIGHT);
120                       switch (alternative_dir)
121                         {
122                         case LEFT:
123                           alternative_number_ = 0;
124                           break;
125                         case CENTER:
126                           break;
127                         case RIGHT:
128                           alternative_number_ = INT_MIN;
129                           break;
130                         default:
131                           assert (false);
132                         }
133                       alternative_number_ += alternative_number_increment_;
134
135                       alternative_number_increment_ = robust_scm2int (alternative_event_->get_property ("alternative-increment"), 1);
136                     }
137                   if (alternative_number_ >= 0)
138                     {
139                       string alphabet = "abcdefghijklmnopqrstuvwxyz";
140                       int power = 0;
141                       int running_sum = 0;
142                       int scratch = alternative_number_;
143                       while (running_sum <= alternative_number_)
144                         {
145                           power++;
146                           running_sum += int_pow (26, power);
147                         }
148                       scratch += int_pow (26, power) - running_sum;
149                       for (int i = power; i--;)
150                         text_tag += alphabet.at ((scratch / int_pow (26, i)) % 26);
151                     }
152                 }
153               // guh.
154               text_->set_property
155               ("text",
156                scm_string_concatenate (scm_list_2 (scm_number_to_string (bn, scm_from_int (10)),
157                                                    ly_string2scm (text_tag))));
158             }
159         }
160     }
161 }
162
163 Bar_number_engraver::Bar_number_engraver ()
164 {
165   text_ = 0;
166   alternative_starting_bar_number_ = 0;
167   alternative_number_increment_ = 0;
168   alternative_number_ = INT_MIN;
169   alternative_event_ = 0;
170 }
171
172 void
173 Bar_number_engraver::acknowledge_break_alignment (Grob_info inf)
174 {
175   Grob *s = inf.grob ();
176   if (text_
177       && dynamic_cast<Item *> (s))
178     {
179       text_->set_parent (s, X_AXIS);
180     }
181 }
182
183 void
184 Bar_number_engraver::stop_translation_timestep ()
185 {
186   alternative_event_ = 0;
187   if (text_)
188     {
189       text_->set_object ("side-support-elements",
190                          grob_list_to_grob_array (get_property ("stavesFound")));
191       text_ = 0;
192     }
193 }
194
195 void
196 Bar_number_engraver::create_items ()
197 {
198   if (text_)
199     return;
200
201   text_ = make_item ("BarNumber", SCM_EOL);
202 }
203
204 ADD_ACKNOWLEDGER (Bar_number_engraver, break_alignment);
205
206 ADD_TRANSLATOR (Bar_number_engraver,
207                 /* doc */
208                 "A bar number is created whenever @code{measurePosition} is"
209                 " zero and when there is a bar line (i.e., when"
210                 " @code{whichBar} is set).  It is put on top of all staves,"
211                 " and appears only at the left side of the staff.  The staves"
212                 " are taken from @code{stavesFound}, which is maintained by"
213                 " @ref{Staff_collecting_engraver}.",
214
215                 /* create */
216                 "BarNumber ",
217
218                 /* read */
219                 "currentBarNumber "
220                 "whichBar "
221                 "stavesFound "
222                 "barNumberVisibility "
223                 "alternativeNumberingStyle ",
224
225                 /* write */
226                 "currentBarNumber "
227                );