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