]> git.donarmstrong.com Git - lilypond.git/blob - lily/spacing-interface.cc
introduce Spacing_interface for code sharing between Note_spacing and Staff_spacing
[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 "paper-column.hh"
17 #include "separation-item.hh"
18 #include "skyline.hh"
19
20 /* return the minimum distance between the left-items and the right-items of
21    this spacing object */
22 Real
23 Spacing_interface::minimum_distance (Grob *me)
24 {
25   Drul_array<Skyline> skylines = Drul_array<Skyline> (Skyline (RIGHT), Skyline (LEFT));
26   Drul_array<vector<Grob*> > items (ly_scm2link_array (me->get_object ("left-items")),
27                                     ly_scm2link_array (me->get_object ("right-items")));
28
29   Direction d = LEFT;
30   do
31     {
32       for (vsize i = 0; i < items[d].size (); i++)
33         if (Separation_item::has_interface (items[d][i]))
34           {
35             SCM sky_scm = items[d][i]->get_property ("horizontal-skylines");
36             Skyline_pair *sky = Skyline_pair::unsmob (sky_scm);
37             skylines[d].merge ((*sky)[-d]);
38             
39             if (d == RIGHT && items[LEFT].size ())
40               skylines[d].merge (Separation_item::conditional_skyline (items[d][i], items[LEFT][0]));
41           }
42     }
43   while (flip (&d) != LEFT);
44
45   return skylines[LEFT].distance (skylines[RIGHT]);
46 }
47
48 /*
49   Compute the column of the right-items.  This is a big function,
50   since RIGHT-ITEMS may span more columns (eg. if a clef is inserted,
51   this will add a new column to RIGHT-ITEMS. Here we look at the
52   columns, and return the left-most. If there are multiple columns, we
53   prune RIGHT-ITEMS.
54 */
55 Item *
56 Spacing_interface::right_column (Grob *me)
57 {
58   if (!me->is_live ())
59     return 0;
60
61   Grob_array *a = unsmob_grob_array (me->get_object ("right-items"));
62   Item *mincol = 0;
63   int min_rank = INT_MAX;
64   bool prune = false;
65   for (vsize i = 0; a && i < a->size (); i++)
66     {
67       Item *ri = a->item (i);
68       Item *col = ri->get_column ();
69
70       int rank = Paper_column::get_rank (col);
71
72       if (rank < min_rank)
73         {
74           min_rank = rank;
75           if (mincol)
76             prune = true;
77
78           mincol = col;
79         }
80     }
81
82   if (prune && a)
83     {
84       vector<Grob*> &right = a->array_reference ();
85       for (vsize i = right.size (); i--;)
86         {
87           if (dynamic_cast<Item *> (right[i])->get_column () != mincol)
88             right.erase (right.begin () + i);
89         }
90     }
91
92   return mincol;
93 }
94
95 Item *
96 Spacing_interface::left_column (Grob *me)
97 {
98   if (!me->is_live ())
99     return 0;
100
101   return dynamic_cast<Item *> (me)->get_column ();
102 }
103
104 Drul_array<Item*>
105 Spacing_interface::note_columns (Grob *me)
106 {
107   Drul_array<Item*> ret (0, 0);
108   Drul_array<vector<Grob*> > items (ly_scm2link_array (me->get_object ("left-items")),
109                                     ly_scm2link_array (me->get_object ("right-items")));
110
111   Direction d = LEFT;
112   do
113     {
114       for (vsize i = 0; i < items[d].size (); i++)
115         if (Note_column::has_interface (items[d][i]))
116           ret[d] = dynamic_cast<Item*> (items[d][i]);
117     }
118   while (flip (&d) != LEFT);
119
120   return ret;
121 }
122
123 ADD_INTERFACE (Spacing_interface,
124                "This object calculates the desired and minimum distances between two columns.",
125
126                "left-items "
127                "right-items "
128                );