]> git.donarmstrong.com Git - lilypond.git/blob - lily/script-engraver.cc
* lily/new-slur.cc: Resolve conflicts.
[lilypond.git] / lily / script-engraver.cc
1 /*
2   script-engraver.cc -- engrave Scripts: Articulations.
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "context.hh"
10 #include "engraver.hh"
11 #include "event.hh"
12 #include "note-column.hh"
13 #include "rhythmic-head.hh"
14 #include "script-interface.hh"
15 #include "side-position-interface.hh"
16 #include "stem.hh"
17 #include "warn.hh"
18
19 struct Script_tuple
20 {
21   Music *event_;
22   Grob *script_;
23   SCM description_;
24   Script_tuple ()
25   {
26     event_ = 0;
27     script_ = 0;
28     description_ = SCM_EOL;
29   }
30 };
31
32 class Script_engraver : public Engraver
33 {
34   Array<Script_tuple> scripts_;
35
36 protected:
37   virtual bool try_music (Music*);
38   virtual void stop_translation_timestep ();
39   virtual void process_music ();
40   virtual void acknowledge_grob (Grob_info);
41
42 public:
43   TRANSLATOR_DECLARATIONS (Script_engraver);
44 };
45
46 Script_engraver::Script_engraver ()
47 {
48 }
49
50 bool
51 Script_engraver::try_music (Music *r)
52 {
53   if (r->is_mus_type ("articulation-event"))
54     {
55       /* Discard double articulations for part-combining.  */
56       int script_count = scripts_.size ();
57       for (int i = 0; i < script_count; i++)
58         if (ly_c_equal_p (scripts_[i].event_
59                           ->get_property ("articulation-type"),
60                           r->get_property ("articulation-type")))
61           return true;
62
63       Script_tuple t;
64       t.event_ = r;
65       scripts_.push (t);
66       return true;
67     }
68   return false;
69 }
70
71 void
72 copy_property (Grob *g, SCM sym, SCM alist)
73 {
74   if (g->internal_get_property (sym) == SCM_EOL)
75     {
76       SCM entry = scm_assoc (sym, alist);
77       if (ly_c_pair_p (entry))
78         g->internal_set_property (sym, ly_cdr (entry));
79     }
80 }
81
82 /* Add the properties, one by one for each Script.  A little space
83    (memory? --jcn) could be saved by tacking the props onto the Script
84    grob (i.e. make ScriptStaccato , ScriptMarcato, etc. ).  */
85 void make_script_from_event (Grob *p, SCM *descr, Context *tg,
86                              SCM art_type, int index)
87 {
88   SCM alist = tg->get_property ("scriptDefinitions");
89   SCM art = scm_assoc (art_type, alist);
90
91   if (art == SCM_BOOL_F)
92     {
93       /* FIXME: */
94       warning (_ ("Do not know how to interpret articulation: "));
95       warning (_ ("Scheme encoding: "));
96       scm_write (art_type, scm_current_error_port ());
97       return;
98     }
99
100   art = ly_cdr (art);
101   *descr = art;
102
103   copy_property (p, ly_symbol2scm ("script-stencil"), art);
104   copy_property (p, ly_symbol2scm ("direction"), art);
105   copy_property (p, ly_symbol2scm ("side-relative-direction"), art);
106
107   int prio = 0;
108   SCM sprio = scm_assoc (ly_symbol2scm ("script-priority"), art);
109   if (ly_c_pair_p (sprio))
110     prio = ly_scm2int (ly_cdr (sprio));
111
112   /* Make sure they're in order of user input by adding index i.
113      Don't use the direction in this priority. Smaller means closer
114      to the head.  */
115   prio += index;
116
117   Side_position_interface::set_axis (p, Y_AXIS);
118   p->set_property ("script-priority", scm_int2num (prio));
119 }
120
121 void
122 Script_engraver::process_music ()
123 {
124   int script_count = scripts_.size ();
125   for (int i = 0; i < script_count; i++)
126     {
127       Music *m = scripts_[i].event_;
128
129       Grob *p = make_item ("Script", m->self_scm ());
130
131       make_script_from_event (p, &scripts_[i].description_, context (),
132                               m->get_property ("articulation-type"),
133                               i);
134
135       scripts_[i].script_ = p;
136
137       SCM force_dir = m->get_property ("direction");
138       if (is_direction (force_dir) && to_dir (force_dir))
139         p->set_property ("direction", force_dir);
140     }
141 }
142
143 void
144 Script_engraver::acknowledge_grob (Grob_info inf)
145 {
146   int script_count = scripts_.size ();
147   if (Stem::has_interface (inf.grob_))
148     {
149       for (int i = 0; i < script_count; i++)
150         {
151           Grob *e = scripts_[i].script_;
152
153           if (to_dir (e->get_property ("side-relative-direction")))
154             e->set_property ("direction-source", inf.grob_->self_scm ());
155
156           /* FIXME: add dependency */
157           e->add_dependency (inf.grob_);
158           Side_position_interface::add_support (e, inf.grob_);
159         }
160     }
161   else if (Rhythmic_head::has_interface (inf.grob_))
162     {
163       for (int i = 0; i < script_count; i++)
164         {
165           Grob *e = scripts_[i].script_;
166         
167           if (Side_position_interface::get_axis (e) == X_AXIS
168               && !e->get_parent (Y_AXIS))
169             {
170               e->set_parent (inf.grob_, Y_AXIS);
171               e->add_dependency (inf.grob_); // ??
172             }
173           Side_position_interface::add_support (e,inf.grob_);
174         }
175     }
176   else if (Note_column::has_interface (inf.grob_))
177     {
178       /* Make note column the parent of the script.  That is not
179         correct, but due to seconds in a chord, noteheads may be
180         swapped around horizontally.
181
182         As the note head to put it on is not known now, postpone this
183         decision to Script_interface::before_line_breaking ().  */
184       for (int i = 0; i < script_count; i++)
185         {
186           Grob *e = scripts_[i].script_;
187
188           if (!e->get_parent (X_AXIS)
189               && Side_position_interface::get_axis (e) == Y_AXIS)
190             e->set_parent (inf.grob_, X_AXIS);
191         }
192     }
193 }
194
195 void
196 Script_engraver::stop_translation_timestep ()
197 {
198   int script_count = scripts_.size ();
199   for (int i = 0; i < script_count; i++)
200     if (Grob *sc = scripts_[i].script_)
201       {
202         SCM follow = scm_assoc (ly_symbol2scm ("follow-into-staff"),
203                                 scripts_[i].description_);
204         if (ly_c_pair_p (follow) && to_boolean (ly_cdr (follow)))
205           {
206             sc->add_offset_callback (Side_position_interface
207                                      ::quantised_position_proc, Y_AXIS);
208             sc->set_property ("staff-padding", SCM_EOL);
209           }
210       }
211   scripts_.clear ();
212 }
213
214 ENTER_DESCRIPTION (Script_engraver,
215 /* descr */       "Handles note scripted articulations.",
216 /* creats*/       "Script",
217 /* accepts */     "script-event articulation-event",
218 /* acks  */      "stem-interface rhythmic-head-interface note-column-interface",
219 /* reads */       "scriptDefinitions",
220 /* write */       "");