]> git.donarmstrong.com Git - lilypond.git/blob - lily/new-fingering-engraver.cc
release commit
[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 && m->is_mus_type ("fingering-event"))
62             {
63               add_fingering (inf.grob_ , m, note_ev);
64             }
65         }
66     }
67 }
68
69
70 void
71 New_fingering_engraver::add_fingering (Grob * head,
72                                        Music * event,
73                                        Music *hevent)
74 {
75   Finger_tuple ft;
76
77   ft.fingering_ = new Item (get_property ("Fingering"));
78   announce_grob (ft.fingering_, event->self_scm());
79
80    Side_position_interface::add_support (ft.fingering_, head);
81
82   int d = gh_scm2int ( event->get_mus_property ("digit"));
83   
84   /*
85     TODO:
86     
87     Should add support for thumb.  It's a little involved, since
88     the thumb lives in a different font. Maybe it should be moved?
89     
90    */
91
92   if (d > 5)
93     {
94       /*
95         music for the softenon children? 
96        */
97       event->origin()->warning (_("music for the martians."));
98     }
99   SCM sstr = scm_number_to_string (gh_int2scm (d), gh_int2scm (10)) ;
100   ft.fingering_->set_grob_property ("text", sstr);
101        
102   ft.finger_event_ = event;
103   ft.note_event_ = hevent;
104   ft.head_ = head;
105
106   fingerings_.push (ft);
107 }
108
109 void
110 New_fingering_engraver::position_scripts ()
111 {
112
113   /*
114     This is not extremely elegant, but we have to do a little
115     formatting here, because the parent/child relations should be
116     known before we move on to the next time step.
117
118     A more sophisticated approach would be to set both X and Y parents
119     to the note head, and write a more flexible function for
120     positioning the fingerings, setting both X and Y coordinates.
121   */
122
123   
124   for (int i = 0; i < fingerings_.size(); i++)
125     {      
126       fingerings_[i].position_ = gh_scm2int (fingerings_[i].head_ -> get_grob_property( "staff-position"));
127     }
128   
129
130   
131   Array<Finger_tuple> up, down, horiz;
132
133   for (int i = fingerings_.size(); i--;)
134     {
135       SCM d = fingerings_[i].finger_event_->get_mus_property ("direction");
136       if (to_dir (d))
137         {
138           if (to_dir (d) == UP)
139             {
140               up.push (fingerings_[i]);
141             }
142           else
143             down.push (fingerings_[i]);
144           fingerings_.del (i);
145         }
146     }
147   
148   fingerings_.sort (&Finger_tuple::compare);
149   if (to_boolean (get_property ("fingersHorizontal")))
150     {
151       up.push (fingerings_.pop());
152       down.push (fingerings_[0]);
153       fingerings_.del(0);
154
155       horiz = fingerings_;
156     }
157   else
158     {
159       int center = fingerings_.size() / 2;
160       down.concat (fingerings_.slice (0,center));
161       up.concat (fingerings_.slice (center, fingerings_.size()));
162     }
163
164   for (int i = 0; i < horiz.size(); i++)
165     {
166       Finger_tuple ft = horiz[i];
167       Grob* f = ft.fingering_;
168       f->set_parent (ft.head_, X_AXIS);
169       f->set_parent (ft.head_, Y_AXIS);
170       f->add_offset_callback (Self_alignment_interface::centered_on_parent_proc, Y_AXIS);
171       f->add_offset_callback (Self_alignment_interface::aligned_on_self_proc, Y_AXIS);
172       f->add_offset_callback (Side_position_interface::aligned_side_proc, X_AXIS);
173       f->set_grob_property( "direction", gh_int2scm (RIGHT));
174       typeset_grob (f);
175     }
176
177   int finger_prio = 200;
178   for (int i = 0; i < up.size(); i++)
179     {
180       Finger_tuple ft = up[i];
181       Grob* f = ft.fingering_;
182       f->set_parent (ft.head_, X_AXIS);
183       f->set_grob_property ("script-priority",
184                             gh_int2scm (finger_prio + i));
185       f->add_offset_callback (Side_position_interface::aligned_side_proc, Y_AXIS);
186       f->add_offset_callback (Self_alignment_interface::centered_on_parent_proc, X_AXIS);
187       f->add_offset_callback (Self_alignment_interface::aligned_on_self_proc, X_AXIS);
188       
189       f->set_grob_property ("direction", gh_int2scm (UP));
190
191       Side_position_interface::add_staff_support (f);
192       typeset_grob (f);
193     }
194   
195   for (int i = 0; i < down.size(); i++)
196     {
197       Finger_tuple ft = down[i];
198       Grob* f =       ft.fingering_;
199       f->set_parent (ft.head_, X_AXIS);
200       f->set_grob_property ("script-priority",
201                             gh_int2scm (finger_prio + down.size() - i));
202
203       f->add_offset_callback (Self_alignment_interface::centered_on_parent_proc, X_AXIS);
204       f->add_offset_callback (Self_alignment_interface::aligned_on_self_proc, X_AXIS);
205       f->add_offset_callback (Side_position_interface::aligned_side_proc, Y_AXIS);
206       f->set_grob_property ("direction", gh_int2scm (DOWN));
207       Side_position_interface::add_staff_support (f);
208       typeset_grob (f);
209     }
210 }
211
212 void
213 New_fingering_engraver::stop_translation_timestep ()
214 {
215   if (!fingerings_.size ())
216     return;
217
218   position_scripts();
219   fingerings_.clear ();
220 }
221
222
223 New_fingering_engraver::New_fingering_engraver()
224 {
225   
226 }
227
228 ENTER_DESCRIPTION(New_fingering_engraver,
229 /* descr */       "Create fingering-scripts for notes in a New Chord.",
230 /* creats*/       "Fingering",
231 /* accepts */     "text-script-event",
232 /* acks  */      "rhythmic-head-interface stem-interface",
233 /* reads */       "fingersHorizontal",
234 /* write */       "");