]> git.donarmstrong.com Git - lilypond.git/blob - lily/spacing-interface.cc
more cleanups, convert-to-springs and code removals
[lilypond.git] / lily / spacing-interface.cc
1 /*
2   spacing-interface.cc -- functionality that is shared between Note_spacing
3   and Staff_spacing
4
5   source file of the GNU LilyPond music typesetter
6
7   (c) 2007 Joe Neeman <joeneeman@gmail.com>
8 */
9
10 #include "spacing-interface.hh"
11
12 #include "grob.hh"
13 #include "grob-array.hh"
14 #include "item.hh"
15 #include "note-column.hh"
16 #include "pointer-group-interface.hh"
17 #include "paper-column.hh"
18 #include "separation-item.hh"
19 #include "skyline.hh"
20
21 /* return the minimum distance between the left-items and the right-items of
22    this spacing object */
23 Real
24 Spacing_interface::minimum_distance (Grob *me)
25 {
26   /* the logic here is a little convoluted.
27      A {Staff,Note}_spacing doesn't copy {left-,right-}items when it clones,
28      so in order to find the separation items, we need to use the original
29      spacing grob. But once we find the separation items, we need to get back
30      the broken piece.
31
32      FIXME: this only works for the left column. There is only one spacing
33      grob for both the original and non-original right columns and we have no way
34      to tell which one we need */
35
36   Grob *orig = me->original () ? me->original () : me;
37   Direction break_dir = dynamic_cast<Item*> (me)->break_status_dir ();
38   Drul_array<Skyline> skylines = Drul_array<Skyline> (Skyline (RIGHT), Skyline (LEFT));
39   Drul_array<vector<Grob*> > items (ly_scm2link_array (orig->get_object ("left-items")),
40                                     ly_scm2link_array (orig->get_object ("right-items")));
41
42   Direction d = LEFT;
43   do
44     {
45       for (vsize i = 0; i < items[d].size (); i++)
46         {
47           Grob *g = items[d][i];
48           if (d == LEFT)
49             if (Item *it = dynamic_cast<Item*> (g))
50               if (Grob *piece = it->find_prebroken_piece (break_dir))
51                 g = piece;
52
53           if (Separation_item::has_interface (g))
54             {
55               SCM sky_scm = g->get_property ("horizontal-skylines");
56               Skyline_pair *sky = Skyline_pair::unsmob (sky_scm);
57               if (sky)
58                 skylines[d].merge ((*sky)[-d]);
59               else
60                 programming_error ("separation item has no skyline");
61             
62               if (d == RIGHT && items[LEFT].size ())
63                 skylines[d].merge (Separation_item::conditional_skyline (items[d][i], items[LEFT][0]));
64             }
65         }
66     }
67   while (flip (&d) != LEFT);
68
69   return max (0.0, skylines[LEFT].distance (skylines[RIGHT]));
70 }
71
72 /*
73   Compute the column of the right-items.  This is a big function,
74   since RIGHT-ITEMS may span more columns (eg. if a clef is inserted,
75   this will add a new column to RIGHT-ITEMS. Here we look at the
76   columns, and return the left-most. If there are multiple columns, we
77   prune RIGHT-ITEMS.
78 */
79 Item *
80 Spacing_interface::right_column (Grob *me)
81 {
82   if (!me->is_live ())
83     return 0;
84
85   Grob_array *a = unsmob_grob_array (me->get_object ("right-items"));
86   Item *mincol = 0;
87   int min_rank = INT_MAX;
88   bool prune = false;
89   for (vsize i = 0; a && i < a->size (); i++)
90     {
91       Item *ri = a->item (i);
92       Item *col = ri->get_column ();
93
94       int rank = Paper_column::get_rank (col);
95
96       if (rank < min_rank)
97         {
98           min_rank = rank;
99           if (mincol)
100             prune = true;
101
102           mincol = col;
103         }
104     }
105
106   if (prune && a)
107     {
108       vector<Grob*> &right = a->array_reference ();
109       for (vsize i = right.size (); i--;)
110         {
111           if (dynamic_cast<Item *> (right[i])->get_column () != mincol)
112             right.erase (right.begin () + i);
113         }
114     }
115
116   return mincol;
117 }
118
119 Item *
120 Spacing_interface::left_column (Grob *me)
121 {
122   if (!me->is_live ())
123     return 0;
124
125   return dynamic_cast<Item *> (me)->get_column ();
126 }
127
128 static vector<Item*>
129 get_note_columns (vector<Grob*> const &elts)
130 {
131   vector<Item*> ret;
132
133   for (vsize i = 0; i < elts.size (); i++)
134     if (Note_column::has_interface (elts[i]))
135       ret.push_back (dynamic_cast<Item*> (elts[i]));
136
137   return ret;
138 }
139
140 vector<Item*>
141 Spacing_interface::right_note_columns (Grob *me)
142 {
143   extract_grob_set (me, "right-items", elts);
144   return get_note_columns (elts);
145 }
146
147 vector<Item*>
148 Spacing_interface::left_note_columns (Grob *me)
149 {
150   extract_grob_set (me, "left-items", elts);
151   return get_note_columns (elts);
152 }
153
154 ADD_INTERFACE (Spacing_interface,
155                "This object calculates the desired and minimum distances between two columns.",
156
157                "left-items "
158                "right-items "
159                );