]> git.donarmstrong.com Git - lilypond.git/blob - lily/custos.cc
release: 1.5.33
[lilypond.git] / lily / custos.cc
1 /*
2   custos.cc -- implement Custos
3
4   source file of the GNU LilyPond music typesetter
5
6  (C) 2000, 2002 Juergen Reuter <reuter@ipd.uka.de>
7 */
8
9 /* TODO:
10
11  - merge create_ledger_line () and Note_head::create_ledger_line ()
12  
13
14  - rewrite create_ledger_line () to support short and thin ledger lines
15
16  - do not show if a clef change immediately follows in the next line
17
18  - decide: do or do not print custos if the next line starts with a rest
19
20 */
21
22
23 #include <stdio.h>
24 #include "direction.hh"
25 #include "staff-symbol-referencer.hh"
26 #include "custos.hh"
27 #include "molecule.hh"
28 #include "debug.hh"
29 #include "note-head.hh"
30 #include "item.hh"
31 #include "font-interface.hh"
32 #include "math.h" // rint
33
34 /*
35    This function is a patched and hopefully much more understandable
36    rewrite of Note_head::ledger_line ().  It still has some
37    bugs/limitations:
38  *
39  (1) The term thick/2 probably should be thick*2 (probably a bug,
40    see the code below).
41  *
42  (2) The minimal width of the resulting ledger line equals the width
43    of the noteheads-ledgerending symbol (a limitation):
44  *
45  (---- left ledger ending
46      ----) right ledger ending
47  (---) resulting ledger line (just ok)
48  *
49    If x_extent ("xwid" in Note_head) is less than the width of the
50    ledger ending, the width of the total ledger line is even *greater*
51    than the width of a ledger ending (I would call this a bug).  In
52    the below code, the condition "if (x_extent.length () >
53    slice_x_extent.length ())" avoids outputting the left ending in such
54    cases (rather a silly workaround, but better than nothing).
55  *
56  (---- left ledger ending
57      ----)   right ledger ending
58  (-)   desired ledger line
59      ------- resulting ledger line (too long)
60      ----)   resulting ledger line with additional "if" (still too long)
61  *
62    The algorithm works properly only for a desired ledger line width
63    greater than the width of the ledger ending:
64  *
65  (----    left ledger ending
66         ----) right ledger ending
67  (------) desired ledger line
68  (------) resulting ledger line (ok)
69  *
70  * (3) The thickness of the ledger line is fixed (limitation).
71  */
72 Molecule
73 Custos::create_ledger_line (Interval x_extent, Grob *me) 
74 {
75   Molecule line;
76   Molecule slice = Font_interface::get_default_font (me)->find_by_name ("noteheads-ledgerending");
77   Interval slice_x_extent = slice.extent (X_AXIS);
78   Interval slice_y_extent = slice.extent (Y_AXIS);
79
80   // Create left ending of ledger line.
81   Molecule left_ending = slice;
82   left_ending.translate_axis (x_extent[LEFT] - slice_x_extent[LEFT], X_AXIS);
83   if (x_extent.length () > slice_x_extent.length ())
84     line.add_molecule (left_ending);
85
86   // Create right ending of ledger line.
87   Molecule right_ending = slice;
88   right_ending.translate_axis (x_extent[RIGHT] - slice_x_extent[RIGHT],
89                                X_AXIS);
90   line.add_molecule (right_ending);
91
92   // Fill out space between left and right ending of ledger line by
93   // lining up a series of slices in a row between them.
94   Molecule fill_out_slice = left_ending;
95   Real thick = slice_y_extent.length ();
96   Real delta_x = slice_x_extent.length () - thick;
97   Real xpos = x_extent [LEFT] + 2*delta_x + thick/2; // TODO: check: thick*2?
98   while (xpos <= x_extent[RIGHT])
99     {
100       fill_out_slice.translate_axis (delta_x, X_AXIS);
101       line.add_molecule (fill_out_slice);
102       xpos += delta_x;
103     }
104
105   return line;
106 }
107
108 void
109 Custos::add_streepjes (Grob* me,
110                    int pos,
111                    int interspaces,
112                    Molecule* custos_p_)
113 {
114   // TODO: This is (almost) duplicated code (see
115   // Note_head::brew_molecule).  Junk me.
116   Real inter_f = Staff_symbol_referencer::staff_space (me)/2;
117   int streepjes_i = abs (pos) < interspaces
118     ? 0
119     : (abs (pos) - interspaces) /2;
120   if (streepjes_i) 
121     {
122       Direction dir = (Direction)sign (pos);
123       Molecule ledger_line (create_ledger_line (custos_p_->extent (X_AXIS),
124                                                 me));
125       ledger_line.set_empty (true);
126       Real offs = (Staff_symbol_referencer::on_staffline (me))
127         ? 0.0
128         : -dir * inter_f;
129       for (int i = 0; i < streepjes_i; i++)
130         {
131           Molecule streep (ledger_line);
132           streep.translate_axis (-dir * inter_f * i * 2 + offs,
133                                  Y_AXIS);
134           custos_p_->add_molecule (streep);
135         }
136     }
137 }
138
139 MAKE_SCHEME_CALLBACK (Custos,brew_molecule,1);
140 SCM
141 Custos::brew_molecule (SCM smob)
142 {
143   Item *me = (Item *)unsmob_grob (smob);
144   SCM scm_style = me->get_grob_property ("style");
145
146   if (gh_symbol_p (scm_style))
147     {
148       String style = ly_scm2string (scm_symbol_to_string (scm_style));
149       bool adjust =
150         to_boolean (me->get_grob_property ("adjust-if-on-staffline"));
151
152       String idx = "custodes-" + style + "-";
153
154       int neutral_pos;
155       SCM ntr_pos = me->get_grob_property ("neutral-position");
156       if (gh_number_p (ntr_pos))
157         neutral_pos = gh_scm2int (ntr_pos);
158       else
159         neutral_pos = 0;
160
161       Direction neutral_direction =
162         to_dir (me->get_grob_property ("neutral-direction"));
163
164       int pos = (int)rint (Staff_symbol_referencer::position_f (me));
165       int sz = Staff_symbol_referencer::line_count (me)-1;
166
167       if (pos < neutral_pos)
168         idx += "u";
169       else if (pos > neutral_pos)
170         idx += "d";
171       else if (neutral_direction == UP)
172         idx += "u";
173       else if (neutral_direction == DOWN)
174         idx += "d";
175       else // auto direction; not yet supported -> use "d"
176         idx += "d";
177
178       if (adjust)
179         {
180           idx += (((pos ^ sz) & 0x1) == 0) ? "1" : "0";
181         }
182       else
183         {
184           idx += "2";
185         }
186
187       Molecule molecule
188         = Font_interface::get_default_font (me)->find_by_name (idx);
189       if (molecule.empty_b ())
190         {
191           String message = "no such custos: `" + idx + "'";
192           warning (_ (message.ch_C ()));
193           return SCM_EOL;
194         }
195       else
196         {
197           add_streepjes (me, (int)pos, sz, &molecule);
198           return  molecule.smobbed_copy ();
199         }
200     }
201   else
202     return SCM_EOL;
203 }
204
205 bool
206 Custos::has_interface (Grob*m)
207 {
208   return m && m->has_interface (ly_symbol2scm ("custos-interface"));
209 }