]> git.donarmstrong.com Git - lilypond.git/blob - lily/spacing-interface.cc
use springs in simple-spacer and scrap separating-group-spanner
[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, Grob *right_col)
25 {
26   /* the logic here is a little convoluted.
27      A {Staff,Note}_spacing doesn't copy left-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
33   Grob *orig = me->original () ? me->original () : me;
34   Drul_array<Direction> break_dirs (dynamic_cast<Item*> (me)->break_status_dir (),
35                                     dynamic_cast<Item*> (right_col)->break_status_dir ());
36   Drul_array<Skyline> skylines = Drul_array<Skyline> (Skyline (RIGHT), Skyline (LEFT));
37   Drul_array<vector<Grob*> > items (ly_scm2link_array (orig->get_object ("left-items")),
38                                     ly_scm2link_array (orig->get_object ("right-items")));
39
40   Direction d = LEFT;
41   do
42     {
43       for (vsize i = 0; i < items[d].size (); i++)
44         {
45           Grob *g = items[d][i];
46           if (Item *it = dynamic_cast<Item*> (g))
47             if (Grob *piece = it->find_prebroken_piece (break_dirs[d]))
48               g = piece;
49
50           if (Separation_item::has_interface (g))
51             {
52               SCM sky_scm = g->get_property ("horizontal-skylines");
53               Skyline_pair *sky = Skyline_pair::unsmob (sky_scm);
54               if (sky)
55                 skylines[d].merge ((*sky)[-d]);
56               else
57                 programming_error ("separation item has no skyline");
58             
59               if (d == RIGHT && items[LEFT].size ())
60                 skylines[d].merge (Separation_item::conditional_skyline (items[d][i], items[LEFT][0]));
61             }
62         }
63     }
64   while (flip (&d) != LEFT);
65
66   return max (0.0, skylines[LEFT].distance (skylines[RIGHT]));
67 }
68
69 /*
70   Compute the column of the right-items.  This is a big function,
71   since RIGHT-ITEMS may span more columns (eg. if a clef is inserted,
72   this will add a new column to RIGHT-ITEMS. Here we look at the
73   columns, and return the left-most. If there are multiple columns, we
74   prune RIGHT-ITEMS.
75 */
76 Item *
77 Spacing_interface::right_column (Grob *me)
78 {
79   if (!me->is_live ())
80     return 0;
81
82   Grob_array *a = unsmob_grob_array (me->get_object ("right-items"));
83   Item *mincol = 0;
84   int min_rank = INT_MAX;
85   bool prune = false;
86   for (vsize i = 0; a && i < a->size (); i++)
87     {
88       Item *ri = a->item (i);
89       Item *col = ri->get_column ();
90
91       int rank = Paper_column::get_rank (col);
92
93       if (rank < min_rank)
94         {
95           min_rank = rank;
96           if (mincol)
97             prune = true;
98
99           mincol = col;
100         }
101     }
102
103   if (prune && a)
104     {
105       vector<Grob*> &right = a->array_reference ();
106       for (vsize i = right.size (); i--;)
107         {
108           if (dynamic_cast<Item *> (right[i])->get_column () != mincol)
109             right.erase (right.begin () + i);
110         }
111     }
112
113   return mincol;
114 }
115
116 Item *
117 Spacing_interface::left_column (Grob *me)
118 {
119   if (!me->is_live ())
120     return 0;
121
122   return dynamic_cast<Item *> (me)->get_column ();
123 }
124
125 static vector<Item*>
126 get_note_columns (vector<Grob*> const &elts)
127 {
128   vector<Item*> ret;
129
130   for (vsize i = 0; i < elts.size (); i++)
131     if (Note_column::has_interface (elts[i]))
132       ret.push_back (dynamic_cast<Item*> (elts[i]));
133
134   return ret;
135 }
136
137 vector<Item*>
138 Spacing_interface::right_note_columns (Grob *me)
139 {
140   extract_grob_set (me, "right-items", elts);
141   return get_note_columns (elts);
142 }
143
144 vector<Item*>
145 Spacing_interface::left_note_columns (Grob *me)
146 {
147   extract_grob_set (me, "left-items", elts);
148   return get_note_columns (elts);
149 }
150
151 ADD_INTERFACE (Spacing_interface,
152                "This object calculates the desired and minimum distances between two columns.",
153
154                "left-items "
155                "right-items "
156                );