~ubuntu-branches/ubuntu/precise/lilypond/precise

« back to all changes in this revision

Viewing changes to lily/spacing-determine-loose-columns.cc

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Bushnell, BSG
  • Date: 2006-12-19 10:18:12 UTC
  • mfrom: (3.1.4 feisty)
  • Revision ID: james.westby@ubuntu.com-20061219101812-7awtjkp0i393wxty
Tags: 2.8.7-3
scripts/midi2ly.py: When setting DATADIR, find Lilypond python files
in the @TOPLEVEL_VERSION@ directory, not 'current'.  Patch thanks to
Chris Lamb (chris@chris-lamb.co.uk).  (Closes: #400550)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  spacing-determine-loose-columns.cc -- implement Spacing_spanner
 
3
  methods that decide which columns to turn loose.
 
4
 
 
5
  source file of the GNU LilyPond music typesetter
 
6
 
 
7
  (c) 2005--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
 
8
*/
 
9
 
 
10
#include "staff-spacing.hh"
 
11
 
 
12
#include "system.hh"
 
13
#include "paper-column.hh"
 
14
#include "column-x-positions.hh"
 
15
#include "pointer-group-interface.hh"
 
16
#include "spacing-spanner.hh"
 
17
#include "note-spacing.hh"
 
18
#include "moment.hh"
 
19
#include "break-align-interface.hh"
 
20
#include "warn.hh"
 
21
 
 
22
/*
 
23
  Return whether COL is fixed to its neighbors by some kind of spacing
 
24
  constraint.
 
25
 
 
26
 
 
27
  If in doubt, then we're not loose; the spacing engine should space
 
28
  for it, risking suboptimal spacing.
 
29
 
 
30
  (Otherwise, we might risk core dumps, and other weird stuff.)
 
31
*/
 
32
static bool
 
33
is_loose_column (Grob *l, Grob *c, Grob *r, Spacing_options const *options)
 
34
{
 
35
  if (options->float_nonmusical_columns_
 
36
      && Paper_column::when_mom (c).grace_part_)
 
37
    return true;
 
38
 
 
39
  if (Paper_column::is_musical (c)
 
40
      || Item::is_breakable (c))
 
41
    return false;
 
42
 
 
43
  extract_grob_set (c, "right-neighbors", rns);
 
44
  extract_grob_set (c, "left-neighbors", lns);
 
45
 
 
46
  /*
 
47
    If this column doesn't have a proper neighbor, we should really
 
48
    make it loose, but spacing it correctly is more than we can
 
49
    currently can handle.
 
50
 
 
51
    (this happens in the following situation:
 
52
 
 
53
    |
 
54
    |    clef G
 
55
    *
 
56
 
 
57
    |               |      ||
 
58
    |               |      ||
 
59
    O               O       ||
 
60
 
 
61
 
 
62
    the column containing the clef is really loose, and should be
 
63
    attached right to the first column, but that is a lot of work for
 
64
    such a borderline case.)
 
65
 
 
66
  */
 
67
  if (lns.empty () || rns.empty ())
 
68
    return false;
 
69
 
 
70
  Item *l_neighbor = dynamic_cast<Item *> (lns[0]);
 
71
  Item *r_neighbor = dynamic_cast<Item *> (rns[0]);
 
72
 
 
73
  if (!l_neighbor || !r_neighbor)
 
74
    return false;
 
75
 
 
76
  l_neighbor = l_neighbor->get_column ();
 
77
  r_neighbor = dynamic_cast<Item *> (Note_spacing::right_column (r_neighbor));
 
78
 
 
79
  if (l == l_neighbor && r == r_neighbor)
 
80
    return false;
 
81
 
 
82
  if (!l_neighbor || !r_neighbor)
 
83
    return false;
 
84
 
 
85
  /*
 
86
    Only declare loose if the bounds make a little sense.  This means
 
87
    some cases (two isolated, consecutive clef changes) won't be
 
88
    nicely folded, but hey, then don't do that.
 
89
  */
 
90
  if (! ((Paper_column::is_musical (l_neighbor) || Item::is_breakable (l_neighbor))
 
91
         && (Paper_column::is_musical (r_neighbor) || Item::is_breakable (r_neighbor))))
 
92
    return false;
 
93
 
 
94
  /*
 
95
    A rather hairy check, but we really only want to move around
 
96
    clefs. (anything else?)
 
97
 
 
98
    in any case, we don't want to move bar lines.
 
99
  */
 
100
  extract_grob_set (c, "elements", elts);
 
101
  for (vsize i = elts.size (); i--;)
 
102
    {
 
103
      Grob *g = elts[i];
 
104
      if (g && Break_align_interface::has_interface (g))
 
105
        {
 
106
          extract_grob_set (g, "elements", gelts);
 
107
          for (vsize j = gelts.size (); j--;)
 
108
            {
 
109
              Grob *h = gelts[j];
 
110
 
 
111
              /*
 
112
                ugh. -- fix staff-bar name?
 
113
              */
 
114
              if (h && h->get_property ("break-align-symbol") == ly_symbol2scm ("staff-bar"))
 
115
                return false;
 
116
            }
 
117
        }
 
118
    }
 
119
 
 
120
  return true;
 
121
}
 
122
 
 
123
/*
 
124
  Remove columns that are not tightly fitting from COLS. In the
 
125
  removed columns, set 'between-cols to the columns where it is in
 
126
  between.
 
127
*/
 
128
void
 
129
Spacing_spanner::prune_loose_columns (Grob *me, vector<Grob*> *cols,
 
130
                                      Spacing_options const *options)
 
131
{
 
132
  vector<Grob*> newcols;
 
133
 
 
134
  for (vsize i = 0; i < cols->size (); i++)
 
135
    {
 
136
      Grob *c = cols->at (i);
 
137
 
 
138
      bool loose = (i > 0 && i < cols->size () - 1)
 
139
        && is_loose_column (cols->at (i - 1), c, cols->at (i + 1), options);
 
140
 
 
141
      if (loose)
 
142
        {
 
143
          extract_grob_set (c, "right-neighbors", rns_arr);
 
144
          extract_grob_set (c, "left-neighbors", lns_arr);
 
145
 
 
146
          SCM lns = lns_arr.size () ? lns_arr.back ()->self_scm () : SCM_BOOL_F;
 
147
          SCM rns = rns_arr.size () ? rns_arr.back ()->self_scm () : SCM_BOOL_F;
 
148
 
 
149
          /*
 
150
            Either object can be non existent, if the score ends
 
151
            prematurely.
 
152
          */
 
153
 
 
154
          extract_grob_set (unsmob_grob (rns), "right-items", right_items);
 
155
          c->set_object ("between-cols", scm_cons (lns,
 
156
                                                   right_items[0]->self_scm ()));
 
157
 
 
158
          /*
 
159
            Set distance constraints for loose columns
 
160
          */
 
161
          Drul_array<Grob *> next_door;
 
162
          next_door[LEFT] = cols->at (i - 1);
 
163
          next_door[RIGHT] = cols->at (i + 1);
 
164
          Direction d = LEFT;
 
165
          Drul_array<Real> dists (0, 0);
 
166
 
 
167
          do
 
168
            {
 
169
              dists[d] = 0.0;
 
170
              Item *lc = dynamic_cast<Item *> ((d == LEFT) ? next_door[LEFT] : c);
 
171
              Item *rc = dynamic_cast<Item *> (d == LEFT ? c : next_door[RIGHT]);
 
172
 
 
173
              extract_grob_set (lc, "spacing-wishes", wishes);
 
174
              for (vsize k = wishes.size (); k--;)
 
175
                {
 
176
                  Grob *sp = wishes[k];
 
177
                  if (Note_spacing::left_column (sp) != lc
 
178
                      || Note_spacing::right_column (sp) != rc)
 
179
                    continue;
 
180
 
 
181
                  Real space, fixed;
 
182
                  fixed = 0.0;
 
183
                  bool dummy;
 
184
 
 
185
                  if (Note_spacing::has_interface (sp))
 
186
                    {
 
187
                      /*
 
188
                        The note spacing should be taken from the musical
 
189
                        columns.
 
190
 
 
191
                      */
 
192
                      Real base = note_spacing (me, lc, rc, options, &dummy);
 
193
                      Note_spacing::get_spacing (sp, rc, base, options->increment_, &space, &fixed);
 
194
 
 
195
                      space -= options->increment_;
 
196
 
 
197
                      dists[d] = max (dists[d], space);
 
198
                    }
 
199
                  else if (Staff_spacing::has_interface (sp))
 
200
                    {
 
201
                      Real space, fixed_space;
 
202
                      Staff_spacing::get_spacing_params (sp,
 
203
                                                         &space, &fixed_space);
 
204
 
 
205
                      dists[d] = max (dists[d], fixed_space);
 
206
                    }
 
207
                  else
 
208
                    programming_error ("Subversive spacing wish");
 
209
                }
 
210
            }
 
211
          while (flip (&d) != LEFT);
 
212
 
 
213
          Rod r;
 
214
          r.distance_ = dists[LEFT] + dists[RIGHT];
 
215
          r.item_drul_[LEFT] = dynamic_cast<Item *> (cols->at (i - 1));
 
216
          r.item_drul_[RIGHT] = dynamic_cast<Item *> (cols->at (i + 1));
 
217
 
 
218
          r.add_to_cols ();
 
219
        }
 
220
      else
 
221
        newcols.push_back (c);
 
222
    }
 
223
 
 
224
  *cols = newcols;
 
225
}
 
226
 
 
227
/*
 
228
  Set neighboring columns determined by the spacing-wishes grob property.
 
229
*/
 
230
void
 
231
Spacing_spanner::set_explicit_neighbor_columns (vector<Grob*> const &cols)
 
232
{
 
233
  for (vsize i = 0; i < cols.size (); i++)
 
234
    {
 
235
      SCM right_neighbors = Grob_array::make_array ();
 
236
      Grob_array *rn_arr = unsmob_grob_array (right_neighbors);
 
237
      int min_rank = 100000;    // inf.
 
238
 
 
239
      extract_grob_set (cols[i], "spacing-wishes", wishes);
 
240
      for (vsize k = wishes.size (); k--;)
 
241
        {
 
242
          Item *wish = dynamic_cast<Item *> (wishes[k]);
 
243
 
 
244
          Item *lc = wish->get_column ();
 
245
          Grob *right = Note_spacing::right_column (wish);
 
246
 
 
247
          if (!right)
 
248
            continue;
 
249
 
 
250
          Item *rc = dynamic_cast<Item *> (right);
 
251
 
 
252
          int right_rank = Paper_column::get_rank (rc);
 
253
          int left_rank = Paper_column::get_rank (lc);
 
254
 
 
255
          /*
 
256
            update the left column.
 
257
          */
 
258
          if (right_rank <= min_rank)
 
259
            {
 
260
              if (right_rank < min_rank)
 
261
                rn_arr->clear ();
 
262
 
 
263
              min_rank = right_rank;
 
264
              rn_arr->add (wish);
 
265
            }
 
266
 
 
267
          /*
 
268
            update the right column of the wish.
 
269
          */
 
270
          int maxrank = 0;
 
271
 
 
272
          extract_grob_set (rc, "left-neighbors", lns_arr);
 
273
          if (lns_arr.size ())
 
274
            {
 
275
              Item *it = dynamic_cast<Item *> (lns_arr.back ());
 
276
              maxrank = Paper_column::get_rank (it->get_column ());
 
277
            }
 
278
 
 
279
          if (left_rank >= maxrank)
 
280
            {
 
281
 
 
282
              if (left_rank > maxrank)
 
283
                {
 
284
                  Grob_array *ga = unsmob_grob_array (rc->get_object ("left-neighbors"));
 
285
                  if (ga)
 
286
                    ga->clear ();
 
287
                }
 
288
 
 
289
              Pointer_group_interface::add_grob (rc, ly_symbol2scm ("left-neighbors"), wish);
 
290
            }
 
291
        }
 
292
 
 
293
      if (rn_arr->size ())
 
294
        cols[i]->set_object ("right-neighbors", right_neighbors);
 
295
    }
 
296
}
 
297
 
 
298
/*
 
299
  Set neighboring columns that have no left/right-neighbor set
 
300
  yet. Only do breakable non-musical columns, and musical columns.
 
301
*/
 
302
void
 
303
Spacing_spanner::set_implicit_neighbor_columns (vector<Grob*> const &cols)
 
304
{
 
305
  for (vsize i = 0; i < cols.size (); i++)
 
306
    {
 
307
      Item *it = dynamic_cast<Item *> (cols[i]);
 
308
      if (!Item::is_breakable (it) && !Paper_column::is_musical (it))
 
309
        continue;
 
310
 
 
311
      // it->breakable || it->musical
 
312
 
 
313
      /*
 
314
        sloppy with typing left/right-neighbors should take list, but paper-column found instead.
 
315
      */
 
316
      extract_grob_set (cols[i], "left-neighbors", lns);
 
317
      if (lns.empty () && i)
 
318
        {
 
319
          SCM ga_scm = Grob_array::make_array ();
 
320
          Grob_array *ga = unsmob_grob_array (ga_scm);
 
321
          ga->add (cols[i - 1]);
 
322
          cols[i]->set_object ("left-neighbors", ga_scm);
 
323
        }
 
324
      extract_grob_set (cols[i], "right-neighbors", rns);
 
325
      if (rns.empty () && i < cols.size () - 1)
 
326
        {
 
327
          SCM ga_scm = Grob_array::make_array ();
 
328
          Grob_array *ga = unsmob_grob_array (ga_scm);
 
329
          ga->add (cols[i + 1]);
 
330
          cols[i]->set_object ("right-neighbors", ga_scm);
 
331
        }
 
332
    }
 
333
}