]> git.donarmstrong.com Git - lilypond.git/blob - lily/script-engraver.cc
* input/regression/finger-chords.ly (texidoc): new file.
[lilypond.git] / lily / script-engraver.cc
1 /*
2   script-engraver.cc -- implement Script_engraver
3
4   (c)  1997--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
5 */
6
7 #include "script.hh"
8 #include "side-position-interface.hh"
9 #include "event.hh"
10 #include "stem.hh"
11 #include "rhythmic-head.hh"
12 #include "engraver.hh"
13 #include "note-column.hh"
14
15
16 struct Script_tuple
17 {
18   Music *event_;
19   Grob * script_;
20   SCM description_;
21   Script_tuple ()
22   {
23     event_ = 0;
24     script_ = 0;
25     description_ = SCM_EOL;
26   }
27 };
28
29 class Script_engraver : public Engraver
30 {
31   Array<Script_tuple> scripts_;
32 public:
33   TRANSLATOR_DECLARATIONS(Script_engraver);
34 protected:
35   virtual bool try_music (Music*);
36   virtual void initialize ();
37   virtual void stop_translation_timestep ();
38   virtual void start_translation_timestep ();
39   virtual void process_music ();
40   virtual void acknowledge_grob (Grob_info);
41 };
42
43 void
44 Script_engraver::initialize ()
45 {
46   scripts_.clear ();
47 }
48
49 bool
50 Script_engraver::try_music (Music *r)
51 {
52   if (r->is_mus_type ("articulation-event"))
53     {
54       Script_tuple t;
55       t.event_ =r;
56       scripts_.push (t);
57       return true;
58     }
59   return false;
60 }
61
62 void
63 Script_engraver::process_music ()
64 {
65   for (int i=0; i < scripts_.size (); i++)
66     {
67       Music* l=scripts_[i].event_;
68
69       SCM alist = get_property ("scriptDefinitions");
70       SCM art = scm_assoc (l->get_mus_property ("articulation-type"), alist);
71
72       if (art == SCM_BOOL_F)
73         {
74           String a = ly_scm2string (l->get_mus_property ("articulation-type"));
75           l->origin ()->warning (_f ("Don't know how to interpret articulation `%s'", a.to_str0 ()));
76                         
77           continue;
78         }
79       
80       // todo -> use result of articulation-to-scriptdef directly as basic prop list.
81       Grob *p =new Item (get_property ("Script"));
82       scripts_[i].script_ = p;
83       art = ly_cdr (art);
84
85       scripts_[i].description_ = art;
86       
87       p->set_grob_property ("script-molecule", ly_car (art));
88
89       art = ly_cdr (art);
90       art = ly_cdr (art);
91       SCM relative_stem_dir = ly_car (art);
92       art = ly_cdr (art);
93
94       SCM force_dir = l->get_mus_property ("direction");
95       if (ly_dir_p (force_dir) && !to_dir (force_dir))
96         force_dir = ly_car (art);
97       
98       art = ly_cdr (art);
99       int priority = gh_scm2int (ly_car (art));
100
101       SCM s = p->get_grob_property ("script-priority");
102       if (gh_number_p (s))
103         priority = gh_scm2int (s);
104
105       /*
106         Make sure they're in order of user input by adding index i.
107         Don't use the direction in this priority. Smaller means closer
108         to the head.
109       */
110       priority += i;
111
112       if (ly_dir_p (force_dir) && to_dir (force_dir))
113         p->set_grob_property ("direction", force_dir);
114       else if (to_dir (relative_stem_dir))
115         p->set_grob_property ("side-relative-direction", relative_stem_dir);
116
117
118       Side_position_interface::set_axis (p, Y_AXIS);
119       p->set_grob_property ("script-priority", gh_int2scm (priority));
120
121       
122       announce_grob (p, l->self_scm());
123     }
124 }
125
126 void
127 Script_engraver::acknowledge_grob (Grob_info inf)
128 {
129   if (Stem::has_interface (inf.grob_))
130     {
131       for (int i=0; i < scripts_.size (); i++)
132         {
133           Grob*e = scripts_[i].script_;
134
135           e->set_grob_property ("direction-source", inf.grob_->self_scm ());
136           e->add_dependency (inf.grob_);
137           Side_position_interface::add_support (e, inf.grob_);
138         }
139     }
140   else if (Rhythmic_head::has_interface (inf.grob_))
141     {
142       for (int i=0; i < scripts_.size (); i++)
143         {
144           Grob *e = scripts_[i].script_;
145           
146           if (Side_position_interface::get_axis (e) == X_AXIS
147               && !e->get_parent (Y_AXIS))
148             {
149               e->set_parent (inf.grob_, Y_AXIS);
150               e->add_dependency (inf.grob_); // ??
151             }
152           Side_position_interface::add_support (e,inf.grob_);
153         }
154     }
155   else if (Note_column::has_interface (inf.grob_))
156     {
157
158       /*
159         We make note column the parent of the script. That's not
160         correct, but due to seconds in a chord, noteheads may be
161         swapped around horizontally. We don't know which note head to
162         put it on, so we postpone this decision to
163         Script_interface::before_line_breaking ().
164  
165        */
166       for (int i=0; i < scripts_.size (); i++)
167         {
168           Grob *e = scripts_[i].script_;
169           
170           if (!e->get_parent (X_AXIS) &&
171               Side_position_interface::get_axis (e) == Y_AXIS)
172             {
173               e->set_parent (inf.grob_, X_AXIS);
174             }
175         }
176     }
177 }
178
179 void
180 Script_engraver::stop_translation_timestep ()
181 {
182   for (int i=0; i < scripts_.size (); i++) 
183     {
184       if (!scripts_[i].script_)
185         continue;
186       
187       Grob * sc = scripts_[i].script_;
188       if (to_boolean (gh_cadr (scripts_[i].description_)))
189         sc->add_offset_callback (Side_position_interface::quantised_position_proc, Y_AXIS);
190       else
191         Side_position_interface::add_staff_support (sc);
192       typeset_grob (sc);
193     }
194   scripts_.clear ();
195 }
196
197 void
198 Script_engraver::start_translation_timestep ()
199 {
200   scripts_.clear ();
201 }
202
203
204
205 Script_engraver::Script_engraver(){}
206
207 ENTER_DESCRIPTION(Script_engraver,
208 /* descr */       "Handles note scripted articulations.",
209 /* creats*/       "Script",
210 /* accepts */     "script-event articulation-event",
211 /* acks  */      "stem-interface rhythmic-head-interface note-column-interface",
212 /* reads */       "scriptDefinitions",
213 /* write */       "");