]> git.donarmstrong.com Git - lilypond.git/blob - lily/new-fingering-engraver.cc
(Lyric_combine_music_iterator): remove superfluous events.
[lilypond.git] / lily / new-fingering-engraver.cc
1 /*   
2   fingering-engraver.cc --  implement New_fingering_engraver
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 1998--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   
8  */
9
10 #include "warn.hh"
11 #include "engraver.hh"
12 #include "side-position-interface.hh"
13 #include "item.hh"
14 #include "event.hh"
15 #include "stem.hh"
16 #include "rhythmic-head.hh"
17 #include "self-alignment-interface.hh"
18 #include "script.hh"
19
20 struct Finger_tuple
21 {
22   Grob *head_;
23   Grob *fingering_;
24   Music *note_event_;
25   Music *finger_event_;
26
27   int position_;
28   
29   static int compare (Finger_tuple const & c1, Finger_tuple const & c2)
30   {
31     return c1.position_-  c2.position_;
32   }
33                
34 };
35
36 class New_fingering_engraver : public Engraver
37 {
38   Array<Finger_tuple> fingerings_;
39 public:
40   TRANSLATOR_DECLARATIONS(New_fingering_engraver);
41 protected:
42   virtual void stop_translation_timestep ();
43   virtual void acknowledge_grob (Grob_info);
44   void add_fingering (Grob*, Music*,Music*);
45   void position_scripts();
46 };
47
48 void
49 New_fingering_engraver::acknowledge_grob (Grob_info inf)
50 {
51   if (Rhythmic_head::has_interface (inf.grob_))
52     {
53       Music * note_ev =inf.music_cause ();
54
55       SCM arts = note_ev->get_mus_property ("articulations");
56
57       for (SCM s = arts; gh_pair_p (s); s = gh_cdr  (s))
58         {
59           Music * m = unsmob_music (gh_car (s));
60
61           if (!m)
62             continue;
63           
64
65           if (m->is_mus_type ("fingering-event"))
66             {
67               add_fingering (inf.grob_ , m, note_ev);
68             }
69           else if (m->is_mus_type ("script-event"))
70             {
71
72             }
73         }
74     }
75 }
76
77 void
78 New_fingering_engraver::add_fingering (Grob * head,
79                                        Music * event,
80                                        Music *hevent)
81 {
82   Finger_tuple ft;
83
84   ft.fingering_ = new Item (get_property ("Fingering"));
85   announce_grob (ft.fingering_, event->self_scm());
86
87    Side_position_interface::add_support (ft.fingering_, head);
88
89   int d = gh_scm2int ( event->get_mus_property ("digit"));
90   
91   /*
92     TODO:
93     
94     Should add support for thumb.  It's a little involved, since
95     the thumb lives in a different font. Maybe it should be moved?
96     
97    */
98
99   if (d > 5)
100     {
101       /*
102         music for the softenon children? 
103        */
104       event->origin()->warning (_("music for the martians."));
105     }
106   SCM sstr = scm_number_to_string (gh_int2scm (d), gh_int2scm (10)) ;
107   ft.fingering_->set_grob_property ("text", sstr);
108        
109   ft.finger_event_ = event;
110   ft.note_event_ = hevent;
111   ft.head_ = head;
112
113   fingerings_.push (ft);
114 }
115
116 void
117 New_fingering_engraver::position_scripts ()
118 {
119
120   /*
121     This is not extremely elegant, but we have to do a little
122     formatting here, because the parent/child relations should be
123     known before we move on to the next time step.
124
125     A more sophisticated approach would be to set both X and Y parents
126     to the note head, and write a more flexible function for
127     positioning the fingerings, setting both X and Y coordinates.
128   */
129
130   
131   for (int i = 0; i < fingerings_.size(); i++)
132     {      
133       fingerings_[i].position_ = gh_scm2int (fingerings_[i].head_ -> get_grob_property( "staff-position"));
134     }
135   
136   Array<Finger_tuple> up, down, horiz;
137   for (int i = fingerings_.size(); i--;)
138     {
139       SCM d = fingerings_[i].finger_event_->get_mus_property ("direction");
140       if (to_dir (d))
141         {
142           if (to_dir (d) == UP)
143             {
144               up.push (fingerings_[i]);
145             }
146           else
147             down.push (fingerings_[i]);
148           fingerings_.del (i);
149         }
150     }
151   
152   fingerings_.sort (&Finger_tuple::compare);
153   if (to_boolean (get_property ("fingersHorizontal")))
154     {
155       up.push (fingerings_.pop());
156       down.push (fingerings_[0]);
157       fingerings_.del(0);
158
159       horiz = fingerings_;
160     }
161   else
162     {
163       int center = fingerings_.size() / 2;
164       down.concat (fingerings_.slice (0,center));
165       up.concat (fingerings_.slice (center, fingerings_.size()));
166     }
167
168   for (int i = 0; i < horiz.size(); i++)
169     {
170       Finger_tuple ft = horiz[i];
171       Grob* f = ft.fingering_;
172       f->set_parent (ft.head_, X_AXIS);
173       f->set_parent (ft.head_, Y_AXIS);
174       f->add_offset_callback (Self_alignment_interface::centered_on_parent_proc, Y_AXIS);
175       f->add_offset_callback (Self_alignment_interface::aligned_on_self_proc, Y_AXIS);
176       f->add_offset_callback (Side_position_interface::aligned_side_proc, X_AXIS);
177       f->set_grob_property( "direction", gh_int2scm (RIGHT));
178       typeset_grob (f);
179     }
180
181   int finger_prio = 200;
182   for (int i = 0; i < up.size(); i++)
183     {
184       Finger_tuple ft = up[i];
185       Grob* f = ft.fingering_;
186       f->set_parent (ft.head_, X_AXIS);
187       f->set_grob_property ("script-priority",
188                             gh_int2scm (finger_prio + i));
189       f->add_offset_callback (Side_position_interface::aligned_side_proc, Y_AXIS);
190       f->add_offset_callback (Self_alignment_interface::centered_on_parent_proc, X_AXIS);
191       f->add_offset_callback (Self_alignment_interface::aligned_on_self_proc, X_AXIS);
192       
193       f->set_grob_property ("direction", gh_int2scm (UP));
194
195       Side_position_interface::add_staff_support (f);
196       typeset_grob (f);
197     }
198   
199   for (int i = 0; i < down.size(); i++)
200     {
201       Finger_tuple ft = down[i];
202       Grob* f =       ft.fingering_;
203       f->set_parent (ft.head_, X_AXIS);
204       f->set_grob_property ("script-priority",
205                             gh_int2scm (finger_prio + down.size() - i));
206
207       f->add_offset_callback (Self_alignment_interface::centered_on_parent_proc, X_AXIS);
208       f->add_offset_callback (Self_alignment_interface::aligned_on_self_proc, X_AXIS);
209       f->add_offset_callback (Side_position_interface::aligned_side_proc, Y_AXIS);
210       f->set_grob_property ("direction", gh_int2scm (DOWN));
211       Side_position_interface::add_staff_support (f);
212       typeset_grob (f);
213     }
214 }
215
216 void
217 New_fingering_engraver::stop_translation_timestep ()
218 {
219   if (!fingerings_.size ())
220     return;
221
222   position_scripts();
223   fingerings_.clear ();
224 }
225
226
227 New_fingering_engraver::New_fingering_engraver()
228 {
229   
230 }
231
232 ENTER_DESCRIPTION(New_fingering_engraver,
233 /* descr */       "Create fingering-scripts for notes in a New Chord.",
234 /* creats*/       "Fingering",
235 /* accepts */     "text-script-event",
236 /* acks  */      "rhythmic-head-interface stem-interface",
237 /* reads */       "fingersHorizontal",
238 /* write */       "");