]> git.donarmstrong.com Git - lilypond.git/blob - lily/custos.cc
patch::: 1.3.136.jcn3
[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 Juergen Reuter <reuterj@ira.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  - make custos direction control configurable
19
20  - decide: do or do not print custos if the next line starts with a rest
21
22 */
23
24
25 #include <stdio.h>
26 #include "staff-symbol-referencer.hh"
27 #include "custos.hh"
28 #include "molecule.hh"
29 #include "lookup.hh"
30 #include "debug.hh"
31 #include "note-head.hh"
32 #include "item.hh"
33 #include "font-interface.hh"
34
35 /*
36    This function is a patched and hopefully much more understandable
37    rewrite of Note_head::ledger_line ().  It still has some
38    bugs/limitations:
39  *
40  (1) The term thick/2 probably should be thick*2 (probably a bug,
41    see the code below).
42  *
43  (2) The minimal width of the resulting ledger line equals the width
44    of the noteheads-ledgerending symbol (a limitation):
45  *
46  (---- left ledger ending
47      ----) right ledger ending
48  (---) resulting ledger line (just ok)
49  *
50    If x_extent ("xwid" in Note_head) is less than the width of the
51    ledger ending, the width of the total ledger line is even *greater*
52    than the width of a ledger ending (I would call this a bug).  In
53    the below code, the condition "if (x_extent.length () >
54    slice_x_extent.length ())" avoids outputting the left ending in such
55    cases (rather a silly workaround, but better than nothing).
56  *
57  (---- left ledger ending
58      ----)   right ledger ending
59  (-)   desired ledger line
60      ------- resulting ledger line (too long)
61      ----)   resulting ledger line with additional "if" (still too long)
62  *
63    The algorithm works properly only for a desired ledger line width
64    greater than the width of the ledger ending:
65  *
66  (----    left ledger ending
67         ----) right ledger ending
68  (------) desired ledger line
69  (------) resulting ledger line (ok)
70  *
71  * (3) The thickness of the ledger line is fixed (limitation).
72  */
73 Molecule
74 Custos::create_ledger_line (Interval x_extent, Grob *me) 
75 {
76   Molecule line;
77   Molecule slice = Font_interface::get_default_font (me)->find_by_name ("noteheads-ledgerending");
78   Interval slice_x_extent = slice.extent (X_AXIS);
79   Interval slice_y_extent = slice.extent (Y_AXIS);
80
81   // Create left ending of ledger line.
82   Molecule left_ending = slice;
83   left_ending.translate_axis (x_extent[LEFT] - slice_x_extent[LEFT], X_AXIS);
84   if (x_extent.length () > slice_x_extent.length ())
85     line.add_molecule (left_ending);
86
87   // Create right ending of ledger line.
88   Molecule right_ending = slice;
89   right_ending.translate_axis (x_extent[RIGHT] - slice_x_extent[RIGHT],
90                                X_AXIS);
91   line.add_molecule (right_ending);
92
93   // Fill out space between left and right ending of ledger line by
94   // lining up a series of slices in a row between them.
95   Molecule fill_out_slice = left_ending;
96   Real thick = slice_y_extent.length ();
97   Real delta_x = slice_x_extent.length () - thick;
98   Real xpos = x_extent [LEFT] + 2*delta_x + thick/2; // TODO: check: thick*2?
99   while (xpos <= x_extent[RIGHT])
100     {
101       fill_out_slice.translate_axis (delta_x, X_AXIS);
102       line.add_molecule (fill_out_slice);
103       xpos += delta_x;
104     }
105
106   return line;
107 }
108
109 void
110 Custos::add_streepjes (Grob* me,
111                    int pos,
112                    int interspaces,
113                    Molecule* custos_p_)
114 {
115   // TODO: This is (almost) duplicated code (see
116   // Note_head::brew_molecule).  Junk me.
117   Real inter_f = Staff_symbol_referencer::staff_space (me)/2;
118   int streepjes_i = abs (pos) < interspaces
119     ? 0
120     : (abs (pos) - interspaces) /2;
121   if (streepjes_i) 
122     {
123       Direction dir = (Direction)sign (pos);
124       Molecule ledger_line (create_ledger_line (custos_p_->extent (X_AXIS),
125                                                 me));
126       ledger_line.set_empty (true);
127       Real offs = (Staff_symbol_referencer::on_staffline (me))
128         ? 0.0
129         : -dir * inter_f;
130       for (int i = 0; i < streepjes_i; i++)
131         {
132           Molecule streep (ledger_line);
133           streep.translate_axis (-dir * inter_f * i * 2 + offs,
134                                  Y_AXIS);
135           custos_p_->add_molecule (streep);
136         }
137     }
138 }
139
140 MAKE_SCHEME_CALLBACK (Custos,brew_molecule,1);
141 SCM
142 Custos::brew_molecule (SCM smob)
143 {
144   Item *me = (Item *)unsmob_grob (smob);
145   SCM scm_style = me->get_grob_property ("style");
146
147   if (gh_symbol_p (scm_style))
148     {
149       String style = ly_scm2string (scm_symbol_to_string (scm_style));
150
151       String idx = "custodes-";
152       int interspaces = Staff_symbol_referencer::line_count (me)-1;
153
154       Real pos = Staff_symbol_referencer::position_f (me);
155       
156       if (pos > (interspaces/2 + 1)) // TODO: make this rule configurable
157         idx += "r";
158       idx += style;
159       Molecule molecule
160         = Font_interface::get_default_font (me)->find_by_name (idx);
161       if (molecule.empty_b ())
162         {
163           String message = "unknown custos style: `" + style + "'";
164           warning (_ (message.ch_C ()));
165           return SCM_EOL;
166         }
167       else
168         {
169           add_streepjes (me, (int)pos, interspaces, &molecule);
170           return  molecule.smobbed_copy ();
171         }
172     }
173   else
174     return SCM_EOL;
175 }
176
177 bool
178 Custos::has_interface (Grob*m)
179 {
180   return m && m->has_interface (ly_symbol2scm ("custos-interface"));
181 }