]> git.donarmstrong.com Git - lilypond.git/blob - src/staffcommands.cc
release: 0.0.13
[lilypond.git] / src / staffcommands.cc
1 #include "staffcommands.hh"
2 #include "debug.hh"
3 #include "parseconstruct.hh"
4
5 /*
6   ARG!
7   */
8
9 /*
10   maybe it's time for a "narrowing" cursor?
11   */
12 PCursor<Command*>
13 Staff_commands::first(Real w)
14 {
15     PCursor<Command*> pc(*this);    
16     while (pc.ok() && pc->when < w)
17         pc++;
18     if (!pc.ok() || pc->when != w) {
19         Command *c = new Command(w);
20         c->priority = 10000;
21         if (!pc.ok())
22             pc.add(c);
23         else
24             pc.insert(c);
25     }
26
27     return pc;
28 }
29 /*
30   RETURN: pc->when == w && pc.ok
31  */
32
33 PCursor<Command*>
34 Staff_commands::last_insertion(Real w)
35 {    
36     PCursor<Command*> pc(first(w)), next(pc);    
37     while (next.ok() && next->when == w) {
38         pc=next;
39         next++;
40     }
41     if (pc->priority != -10000) {
42         Command*c = new Command(w);
43         c->priority = -10000;
44         pc.add(c);
45         pc++;
46     }
47         
48     return pc;
49 }
50
51 /*
52  */
53 void
54 Staff_commands::add_seq(svec<Command> com, bool checkbreak)
55 {
56     if (!com.sz())
57         return;
58     
59     Real when = com[0].when;
60
61     PCursor<Command*> begin(first(when));
62     PCursor<Command*> end(last_insertion(when));
63     if (checkbreak && is_breakable(when)) {
64         if (com[0].priority < 0)
65             while (begin->code != BREAK_END)
66                 begin++;
67         else
68             while (end->code != BREAK_PRE)
69                 end--;
70     }
71     for (int i = 0; i < com.sz(); i++) {
72         insert_between(com[i], begin, end);
73     }
74 }
75
76 void
77 Staff_commands::set_breakable(Real when)
78 {
79     bool found_typeset(false);
80     PCursor<Command*> cc = first(when);
81     for (; cc.ok() && cc->when == when; cc++) {
82         if (cc->isbreak())
83             return;
84         if (cc->code == TYPESET)
85             found_typeset=true;
86     }
87
88     assert(!found_typeset);
89     
90     svec<Command> seq;
91     Command k(when);
92     k.priority = 5;
93     k.code = BREAK_PRE;
94     seq.add(k);
95     k.priority = 4;
96     k.code = BREAK_MIDDLE;
97     seq.add(k);
98     k.priority = 3;
99     k.code = BREAK_POST;
100     seq.add(k);
101     k.priority = 2;
102     k.code = BREAK_END;
103     seq.add(k);
104
105     add_seq(seq,false);
106 }
107
108 bool
109 Staff_commands::is_breakable(Real w)
110 {
111     PCursor<Command*> cc = first(w);
112     for (; cc.ok() && cc->when == w; cc++) {
113         if (cc->isbreak())
114             return true;
115     }
116     return false;
117 }
118
119 void
120 Staff_commands::insert_between(Command victim, PCursor<Command*> firstc,
121                                PCursor<Command*> last)
122 {
123     PCursor<Command*> c(firstc+1);
124     assert(last->when==firstc->when&&firstc < last&&last.ok());
125     
126     while (c < last) { 
127         if (c->priority <= victim.priority) {
128             c.insert(new Command(victim));
129             return;
130         }
131         c++;
132     }
133     last.insert(new Command(victim));    
134 }
135
136 void
137 Staff_commands::add_command_to_break(Command pre, Command mid, Command post)
138 {
139     Real w = pre.when;
140     assert(w >= 0);
141     PCursor<Command*> c ( first(w)), f(c), l(c);
142
143     while (!c->isbreak())
144         c++;
145     f = c++;
146     while (!c->isbreak())
147         c++;
148     l = c++;
149     
150     insert_between(pre, f, l);
151     f = l;
152     while (!c->isbreak())
153         c++;
154     l = c++;    
155     insert_between(mid, f, l);
156     f = l;
157     while (!c->isbreak())
158         c++;
159     l = c++;
160     assert(l.ok() && l->when ==w && l->code == BREAK_END);
161     
162     insert_between(post, f, l);
163 }
164
165 void
166 Staff_commands::process_add(Command c)
167 {
168     bool encapsulate =false;
169     Real w = c.when;
170     assert(w >= 0);
171
172     Command pre(w);
173     Command mid(w);
174     Command post(w);
175
176     if (c.code == INTERPRET)
177     {                           // UGH
178         if (c.args[0] == "BAR") {
179             Command typeset(w); // kut met peren
180             typeset.code = TYPESET;
181             typeset.args = c.args;
182             typeset.priority = 100;
183             process_add(typeset);
184         } else if (c.args[0] == "KEY") {
185             Command typeset(w);
186             typeset.code = TYPESET;
187             typeset.args.add("KEY");
188             typeset.priority = 70;
189             process_add(typeset);
190         } else if (c.args[0] == "CLEF") {
191             Command typeset(w);
192             typeset.code = TYPESET;
193             typeset.args=c.args;
194             typeset.priority = 90;
195             process_add(typeset);
196         } else if (c.args[0] == "METER") {
197             Command typeset(w);
198             typeset.code = TYPESET;
199             typeset.args=c.args;
200             typeset.priority = 40;
201             process_add(typeset);
202             return;
203         }
204     }
205
206     // kut en peer
207     if (c.code == TYPESET) {
208         if (c.args[0] == "BAR") {
209             set_breakable(w);
210             encapsulate  = true;
211             mid = c;
212             pre = c;
213             { /* every line a currentkey. */
214                 Command kc(w);
215                 kc.code =TYPESET;
216                 kc.args.add( "CURRENTKEY");
217                 kc.priority = 60;
218                 process_add(kc);
219             }
220             { /* every line a currentclef. */
221                 Command kc(w);
222                 kc.code =TYPESET;
223                 kc.args.add( "CURRENTCLEF");
224                 kc.priority = 80;
225                 process_add(kc);
226             }
227         }else
228         if (c.args[0] == "METER" && is_breakable(w)) {
229             encapsulate = true;
230             mid = c;
231             pre = c;
232             post =c;
233         }else
234         if( c.args[0] == "KEY" && is_breakable(c.when)) {
235             encapsulate = true;
236             mid = c;
237             pre = c;
238             post = c;
239         }else
240         if (c.args[0] == "CURRENTKEY" && is_breakable(w)) {
241             post = c;
242             encapsulate = true;
243         }else
244         if (c.args[0] == "CURRENTCLEF" && is_breakable(w)) {
245             post = c;
246             encapsulate = true;
247         }else
248         if (c.args[0] == "CLEF" && is_breakable(w)) {
249             encapsulate = true;
250             post = c;
251             pre = c;
252             mid = c;                   
253         }
254     }
255     
256     if (encapsulate)
257         add_command_to_break(pre, mid, post);    
258     else {
259         svec<Command> seq;
260         seq.add(c);    
261         add_seq(seq,true);
262     }
263 }
264
265 /*
266     first and last column should be breakable.
267     Remove any command past the last musical column.
268     */
269 void
270 Staff_commands::clean(Real l)
271 {
272     assert(l>0);
273     if (!is_breakable(0.0)) {
274         Command c(0.0);
275         c.code = TYPESET;
276         c.args.add("BAR");
277         c.args.add("empty");
278         process_add(c);
279     }
280     
281     PCursor<Command*> bot(bottom());
282
283     while (bot.ok() && bot->when > l) {
284         mtor <<"removing ";
285         bot->print();
286         bot.del();
287         bot = bottom();
288     }
289
290     if (!is_breakable(l)) {
291         Command c(l);
292         c.code = TYPESET;
293         c.args.add("BAR");
294         c.args.add("||");
295         process_add(c);
296     }
297     OK();
298 }
299
300 void
301 Staff_commands::OK() const
302 {
303     for (PCursor<Command*> cc(*this); cc.ok() && (cc+1).ok(); cc++) {
304         assert(cc->when <= (cc+1)->when);
305         if (cc->when == (cc+1)->when && !cc->isbreak() && !(cc+1)->isbreak())
306             assert(cc->priority >= (cc+1)->priority);
307     }
308 }
309
310 void
311 Staff_commands::print() const
312 {
313 #ifndef NPRINT
314     for (PCursor<Command*> cc(*this); cc.ok() ; cc++) {
315         cc->print();
316     }
317 #endif
318 }