]> git.donarmstrong.com Git - lilypond.git/blob - lily/stem.cc
release: 0.1.9
[lilypond.git] / lily / stem.cc
1 /*
2   stem.cc -- implement Stem
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1996,1997 Han-Wen Nienhuys <hanwen@stack.nl>
7 */
8
9 #include "stem.hh"
10 #include "dimen.hh" 
11 #include "debug.hh"
12 #include "paper-def.hh"
13 #include "note-head.hh"
14 #include "lookup.hh"
15 #include "molecule.hh"
16 #include "p-col.hh"
17 #include "misc.hh"
18
19 const int STEMLEN=7;
20
21 int
22 Stem::min_head_i()const
23 {
24   int m = 1000;
25   for (int i =0; i < head_l_arr_.size(); i++)
26         m = m <? head_l_arr_[i]->position_i_;
27   return m;
28 }
29
30 int
31 Stem::max_head_i() const
32 {
33   int m = -1000;
34   for (int i =0; i < head_l_arr_.size(); i++)
35         m = m >? head_l_arr_[i]->position_i_;
36   return m;
37   
38 }
39
40 Stem::Stem (int c) 
41 {
42   beams_left_i_ = 0;
43   beams_right_i_ = 0;
44
45   stem_bottom_f_ = stem_top_f_ = 0;
46   flag_i_ = 4;
47   dir_i_ =0;
48   staff_size_i_ = c;
49
50   print_flag_b_=true;
51   stem_xoffset_f_ =0;
52 }
53
54
55 IMPLEMENT_IS_TYPE_B1(Stem,Item);
56
57 void
58 Stem::do_print() const
59 {
60 #ifndef NPRINT
61   DOUT << "flag "<< flag_i_ << " print_flag_b_ " << print_flag_b_;
62 #endif
63 }
64
65 Real 
66 Stem::stem_length_f()const
67 {
68   return stem_top_f_-stem_bottom_f_ ;
69 }
70
71 Real
72 Stem::stem_start_f()const
73 {
74   return (dir_i_ < 0)? stem_top_f_ : stem_bottom_f_;
75 }
76
77 Real
78 Stem::stem_end_f() const
79 {
80   return (dir_i_ < 0)? stem_bottom_f_ : stem_top_f_;
81 }
82
83
84 void
85 Stem::set_stemend (Real se)
86 {
87   // todo: margins
88   if (!  ((dir_i_ > 0 && se >= max_head_i()) || 
89             (se <= min_head_i() && dir_i_ <0)) )        
90         warning ("Weird stem size; check for narrow beams");
91
92   stem_top_f_  = (dir_i_ < 0) ? max_head_i()           : se;
93   stem_bottom_f_  = (dir_i_ < 0) ? se  : min_head_i();
94 }
95
96 void
97 Stem::add (Note_head *n)
98 {
99   n->add_dependency (this);
100   if (n->rest_b_) 
101     {
102         rest_l_arr_.push (n);
103     }
104   else if (n->balltype_i_ == 0) 
105     {
106         whole_l_arr_.push (n);
107         return;
108     }
109   else
110     {
111         head_l_arr_.push (n);
112     }
113 }
114
115 bool
116 Stem::invisible_b()const
117 {
118   return !head_l_arr_.size();
119 }
120
121 // if dir_i_ is set we return fake values.
122
123 int
124 Stem::get_center_distance_from_top()
125 {
126   if (dir_i_)
127         return (dir_i_ > 0) ? 0 : 1;
128
129   int staff_center = staff_size_i_ / 2;
130   int max = max_head_i() - staff_center;
131   return max >? 0;
132 }
133
134 // if dir_i_ is set we return fake values.
135 int
136 Stem::get_center_distance_from_bottom()
137 {
138   if (dir_i_)
139         return (dir_i_ > 0) ? 1 : 0;
140
141   int staff_center = staff_size_i_ / 2;
142   int min = staff_center - min_head_i();
143   return min >? 0;
144 }
145
146 int
147 Stem::get_default_dir()
148 {
149   if (dir_i_)
150         return dir_i_;
151   return (get_center_distance_from_top() >=
152         get_center_distance_from_bottom()) ? -1 : 1;
153 }
154
155
156 void
157 Stem::set_default_dir()
158 {
159   dir_i_ = get_default_dir();
160 }
161
162 void
163 Stem::set_default_stemlen()
164 {
165   if (!dir_i_)
166         set_default_dir();
167
168   
169   // ugh... how about non 5-line staffs?
170   if ((max_head_i() < -2 && dir_i_ == 1)
171         ||(min_head_i() > staff_size_i_ && dir_i_ == -1))
172           {
173         set_stemend (staff_size_i_ /2 -1);
174     }
175   else 
176     {
177         set_stemend ((dir_i_ > 0) ? max_head_i() + STEMLEN : 
178                                      min_head_i() - STEMLEN);
179
180     }
181 }
182
183
184 void
185 Stem::set_default_extents()
186 {
187   if (!stem_length_f())
188         set_default_stemlen();
189
190   set_stemend ((dir_i_< 0) ? 
191                 max_head_i()-stem_length_f (): min_head_i () +stem_length_f ());
192   if (dir_i_ > 0){      
193         stem_xoffset_f_ = paper()->note_width ()-paper ()->rule_thickness ();
194     }
195   else
196         stem_xoffset_f_ = 0;
197 }
198
199 /*
200   TODO
201   
202   move into note_column.cc
203
204   */
205 void
206 Stem::set_noteheads()
207 {
208   if (!head_l_arr_.size())
209         return;
210   head_l_arr_.sort (Note_head::compare);
211   if (dir_i_ < 0) 
212         head_l_arr_.reverse();
213   
214   head_l_arr_[0]->extremal_i_ = -1;
215   head_l_arr_.top()->extremal_i_ = 1;
216   int parity=1;
217   int lastpos = head_l_arr_[0]->position_i_;
218   for (int i=1; i < head_l_arr_.size(); i ++) 
219     {
220         int dy =abs (lastpos- head_l_arr_[i]->position_i_);
221         
222         if (dy <= 1) 
223           {
224             if (parity)
225                 head_l_arr_[i]->x_dir_i_ = (stem_xoffset_f_>0) ? 1:-1;
226             parity = !parity;
227           }
228         else
229             parity = 0;
230         lastpos = head_l_arr_[i]->position_i_;
231     }
232 }
233
234 void
235 Stem::do_pre_processing()
236 {
237   if (stem_bottom_f_== stem_top_f_)
238         set_default_extents();
239   set_noteheads();
240   flag_i_ = dir_i_*abs (flag_i_);
241   transparent_b_ = invisible_b();
242   empty_b_ = invisible_b();
243 }
244
245
246 Interval
247 Stem::do_width()const
248 {
249   if (!print_flag_b_ || abs (flag_i_) <= 4)
250         return Interval (0,0);  // TODO!
251   Paper_def*p= paper();
252   Interval r (p->lookup_l()->flag (flag_i_).dim.x ());
253   r+= stem_xoffset_f_;
254   return r;
255 }
256
257 Molecule*
258 Stem::brew_molecule_p()const 
259 {
260   Molecule *out =0;
261       
262   Real bot  = stem_bottom_f_;
263   Real top = stem_top_f_;
264   
265   assert (bot!=top);
266  
267   Paper_def *p =paper();
268
269   Real dy = p->internote_f();
270   Symbol ss =p->lookup_l()->stem (bot*dy,top*dy);
271
272   out = new Molecule (Atom (ss));
273
274   if (print_flag_b_&&abs (flag_i_) > 4)
275     {
276         Symbol fl = p->lookup_l()->flag (flag_i_);
277         Molecule m (fl);
278         if (flag_i_ < -4){              
279             out->add_bottom (m);
280           }
281         else if (flag_i_ > 4) 
282           {
283             out->add_top (m);
284           }
285         else
286             assert (false); 
287     }
288
289   out->translate (stem_xoffset_f_, X_AXIS);
290   return out;
291 }
292
293 Real
294 Stem::hpos_f()const
295 {
296   return Item::hpos_f() + stem_xoffset_f_;
297 }
298
299
300 void
301 Stem::do_substitute_dependency (Score_elem*o,Score_elem*n)
302 {
303   Item * o_l = o->item();
304   Item * n_l = n? n->item():0;
305   whole_l_arr_.substitute ((Note_head*)o_l, (Note_head*)n_l);
306   head_l_arr_.substitute ((Note_head*)o_l, (Note_head*)n_l);
307   rest_l_arr_.substitute ((Note_head*)o_l, (Note_head*)n_l);
308 }