2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2000--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 #include "axis-group-interface.hh"
22 #include "align-interface.hh"
23 #include "directional-element-interface.hh"
24 #include "grob-array.hh"
25 #include "hara-kiri-group-spanner.hh"
26 #include "international.hh"
28 #include "paper-column.hh"
29 #include "paper-score.hh"
30 #include "pointer-group-interface.hh"
31 #include "separation-item.hh"
32 #include "skyline-pair.hh"
33 #include "staff-grouper-interface.hh"
39 pure_staff_priority_less (Grob *const &g1, Grob *const &g2);
42 Axis_group_interface::add_element (Grob *me, Grob *e)
44 SCM axes = me->get_property ("axes");
45 if (!scm_is_pair (axes))
46 programming_error ("axes should be nonempty");
48 for (SCM ax = axes; scm_is_pair (ax); ax = scm_cdr (ax))
50 Axis a = (Axis) scm_to_int (scm_car (ax));
52 if (!e->get_parent (a))
53 e->set_parent (me, a);
55 e->set_object ((a == X_AXIS)
56 ? ly_symbol2scm ("axis-group-parent-X")
57 : ly_symbol2scm ("axis-group-parent-Y"),
61 /* must be ordered, because Align_interface also uses
62 Axis_group_interface */
63 Pointer_group_interface::add_grob (me, ly_symbol2scm ("elements"), e);
67 Axis_group_interface::has_axis (Grob *me, Axis a)
69 SCM axes = me->get_property ("axes");
71 return (SCM_BOOL_F != scm_memq (scm_from_int (a), axes));
75 Axis_group_interface::relative_group_extent (vector<Grob *> const &elts,
79 for (vsize i = 0; i < elts.size (); i++)
82 if (!to_boolean (se->get_property ("cross-staff")))
84 Interval dims = se->extent (common, a);
85 if (!dims.is_empty ())
93 Axis_group_interface::sum_partial_pure_heights (Grob *me, int start, int end)
95 Interval iv = begin_of_line_pure_height (me, start);
96 iv.unite (rest_of_line_pure_height (me, start, end));
102 Axis_group_interface::part_of_line_pure_height (Grob *me, bool begin, int start, int end)
104 Spanner *sp = dynamic_cast<Spanner *> (me);
105 SCM cache_symbol = begin
106 ? ly_symbol2scm ("begin-of-line-pure-height")
107 : ly_symbol2scm ("rest-of-line-pure-height");
108 SCM cached = sp->get_cached_pure_property (cache_symbol, start, end);
109 if (scm_is_pair (cached))
110 return robust_scm2interval (cached, Interval (0, 0));
112 SCM adjacent_pure_heights = me->get_property ("adjacent-pure-heights");
115 if (!scm_is_pair (adjacent_pure_heights))
116 ret = Interval (0, 0);
119 SCM these_pure_heights = begin
120 ? scm_car (adjacent_pure_heights)
121 : scm_cdr (adjacent_pure_heights);
123 if (scm_is_vector (these_pure_heights))
124 ret = combine_pure_heights (me, these_pure_heights, start, end);
126 ret = Interval (0, 0);
129 sp->cache_pure_property (cache_symbol, start, end, ly_interval2scm (ret));
134 Axis_group_interface::begin_of_line_pure_height (Grob *me, int start)
136 return part_of_line_pure_height (me, true, start, start + 1);
140 Axis_group_interface::rest_of_line_pure_height (Grob *me, int start, int end)
142 return part_of_line_pure_height (me, false, start, end);
146 Axis_group_interface::combine_pure_heights (Grob *me, SCM measure_extents, int start, int end)
148 Paper_score *ps = get_root_system (me)->paper_score ();
149 vector<vsize> breaks = ps->get_break_indices ();
150 vector<Grob *> cols = ps->get_columns ();
153 for (vsize i = 0; i + 1 < breaks.size (); i++)
155 int r = Paper_column::get_rank (cols[breaks[i]]);
160 ext.unite (ly_scm2interval (scm_c_vector_ref (measure_extents, i)));
166 // adjacent-pure-heights is a pair of vectors, each of which has one element
167 // for every measure in the score. The first vector stores, for each measure,
168 // the combined height of the elements that are present only when the bar
169 // is at the beginning of a line. The second vector stores, for each measure,
170 // the combined height of the elements that are present only when the bar
171 // is not at the beginning of a line.
172 MAKE_SCHEME_CALLBACK (Axis_group_interface, adjacent_pure_heights, 1)
174 Axis_group_interface::adjacent_pure_heights (SCM smob)
176 Grob *me = unsmob_grob (smob);
178 Grob *common = unsmob_grob (me->get_object ("pure-Y-common"));
179 extract_grob_set (me, "pure-relevant-grobs", elts);
181 Paper_score *ps = get_root_system (me)->paper_score ();
182 vector<vsize> ranks = ps->get_break_ranks ();
184 vector<Interval> begin_line_heights;
185 vector<Interval> mid_line_heights;
186 vector<Interval> begin_line_staff_heights;
187 vector<Interval> mid_line_staff_heights;
188 begin_line_heights.resize (ranks.size () - 1);
189 mid_line_heights.resize (ranks.size () - 1);
191 for (vsize i = 0; i < elts.size (); ++i)
195 if (to_boolean (g->get_property ("cross-staff")))
198 bool outside_staff = scm_is_number (g->get_property ("outside-staff-priority"));
199 Real padding = robust_scm2double (g->get_property ("outside-staff-padding"), 0.5);
201 // When we encounter the first outside-staff grob, make a copy
202 // of the current heights to use as an estimate for the staff heights.
203 // Note that the outside-staff approximation that we use here doesn't
204 // consider any collisions that might occur between outside-staff grobs,
205 // but only the fact that outside-staff grobs may need to be raised above
207 if (outside_staff && begin_line_staff_heights.empty ())
209 begin_line_staff_heights = begin_line_heights;
210 mid_line_staff_heights = mid_line_heights;
213 // TODO: consider a pure version of get_grob_direction?
214 Direction d = to_dir (g->get_property_data ("direction"));
215 d = (d == CENTER) ? UP : d;
217 Interval_t<int> rank_span = g->spanned_rank_interval ();
218 vsize first_break = lower_bound (ranks, (vsize)rank_span[LEFT], less<vsize> ());
219 if (first_break > 0 && ranks[first_break] >= (vsize)rank_span[LEFT])
222 for (vsize j = first_break; j + 1 < ranks.size () && (int)ranks[j] <= rank_span[RIGHT]; ++j)
224 int start = ranks[j];
225 int end = ranks[j + 1];
227 // Take grobs that are visible with respect to a slightly longer line.
228 // Otherwise, we will never include grobs at breakpoints which aren't
229 // end-of-line-visible.
230 int visibility_end = j + 2 < ranks.size () ? ranks[j + 2] : end;
232 if (g->pure_is_visible (start, visibility_end))
234 Interval dims = g->pure_height (common, start, end);
235 if (!dims.is_empty ())
237 if (rank_span[LEFT] <= start)
240 begin_line_heights[j].unite (begin_line_staff_heights[j].union_disjoint (dims, padding, d));
242 begin_line_heights[j].unite (dims);
244 if (rank_span[RIGHT] > start)
247 mid_line_heights[j].unite (mid_line_staff_heights[j].union_disjoint (dims, padding, d));
249 mid_line_heights[j].unite (dims);
256 // Convert begin_line_heights and min_line_heights to SCM.
257 SCM begin_scm = scm_c_make_vector (ranks.size () - 1, SCM_EOL);
258 SCM mid_scm = scm_c_make_vector (ranks.size () - 1, SCM_EOL);
259 for (vsize i = 0; i < begin_line_heights.size (); ++i)
261 scm_vector_set_x (begin_scm, scm_from_int (i), ly_interval2scm (begin_line_heights[i]));
262 scm_vector_set_x (mid_scm, scm_from_int (i), ly_interval2scm (mid_line_heights[i]));
265 return scm_cons (begin_scm, mid_scm);
269 Axis_group_interface::relative_pure_height (Grob *me, int start, int end)
271 /* It saves a _lot_ of time if we assume a VerticalAxisGroup is additive
272 (ie. height (i, k) = max (height (i, j) height (j, k)) for all i <= j <= k).
273 Unfortunately, it isn't always true, particularly if there is a
274 VerticalAlignment somewhere in the descendants.
276 Usually, the only VerticalAlignment comes from Score. This makes it
277 reasonably safe to assume that if our parent is a VerticalAlignment,
278 we can assume additivity and cache things nicely. */
279 Grob *p = me->get_parent (Y_AXIS);
280 if (p && Align_interface::has_interface (p))
281 return Axis_group_interface::sum_partial_pure_heights (me, start, end);
283 Grob *common = unsmob_grob (me->get_object ("pure-Y-common"));
284 extract_grob_set (me, "pure-relevant-grobs", elts);
287 for (vsize i = 0; i < elts.size (); i++)
290 Interval_t<int> rank_span = g->spanned_rank_interval ();
291 if (rank_span[LEFT] <= end && rank_span[RIGHT] >= start
292 && g->pure_is_visible (start, end)
293 && !to_boolean (g->get_property ("cross-staff")))
295 Interval dims = g->pure_height (common, start, end);
296 if (!dims.is_empty ())
303 MAKE_SCHEME_CALLBACK (Axis_group_interface, width, 1);
305 Axis_group_interface::width (SCM smob)
307 Grob *me = unsmob_grob (smob);
308 return generic_group_extent (me, X_AXIS);
311 MAKE_SCHEME_CALLBACK (Axis_group_interface, height, 1);
313 Axis_group_interface::height (SCM smob)
315 Grob *me = unsmob_grob (smob);
316 return generic_group_extent (me, Y_AXIS);
319 MAKE_SCHEME_CALLBACK (Axis_group_interface, pure_height, 3);
321 Axis_group_interface::pure_height (SCM smob, SCM start_scm, SCM end_scm)
323 int start = robust_scm2int (start_scm, 0);
324 int end = robust_scm2int (end_scm, INT_MAX);
325 Grob *me = unsmob_grob (smob);
327 /* Maybe we are in the second pass of a two-pass spacing run. In that
328 case, the Y-extent of a system is already given to us */
329 System *system = dynamic_cast<System *> (me);
332 SCM line_break_details = system->column (start)->get_property ("line-break-system-details");
333 SCM system_y_extent = scm_assq (ly_symbol2scm ("system-Y-extent"), line_break_details);
334 if (scm_is_pair (system_y_extent))
335 return scm_cdr (system_y_extent);
338 return ly_interval2scm (pure_group_height (me, start, end));
341 MAKE_SCHEME_CALLBACK (Axis_group_interface, calc_skylines, 1);
343 Axis_group_interface::calc_skylines (SCM smob)
345 Grob *me = unsmob_grob (smob);
346 extract_grob_set (me, "elements", elts);
347 Skyline_pair skylines = skyline_spacing (me, elts);
349 return skylines.smobbed_copy ();
352 /* whereas calc_skylines calculates skylines for axis-groups with a lot of
353 visible children, combine_skylines is designed for axis-groups whose only
354 children are other axis-groups (ie. VerticalAlignment). Rather than
355 calculating all the skylines from scratch, we just merge the skylines
358 MAKE_SCHEME_CALLBACK (Axis_group_interface, combine_skylines, 1);
360 Axis_group_interface::combine_skylines (SCM smob)
362 Grob *me = unsmob_grob (smob);
363 extract_grob_set (me, "elements", elements);
364 Grob *y_common = common_refpoint_of_array (elements, me, Y_AXIS);
365 Grob *x_common = common_refpoint_of_array (elements, me, X_AXIS);
368 programming_error ("combining skylines that don't belong to me");
371 for (vsize i = 0; i < elements.size (); i++)
373 SCM skyline_scm = elements[i]->get_property ("vertical-skylines");
374 if (Skyline_pair::unsmob (skyline_scm))
376 Real offset = elements[i]->relative_coordinate (y_common, Y_AXIS);
377 Skyline_pair other = *Skyline_pair::unsmob (skyline_scm);
378 other.raise (offset);
379 other.shift (elements[i]->relative_coordinate (x_common, X_AXIS));
383 return ret.smobbed_copy ();
387 Axis_group_interface::generic_group_extent (Grob *me, Axis a)
389 /* trigger the callback to do skyline-spacing on the children */
391 (void) me->get_property ("vertical-skylines");
393 extract_grob_set (me, "elements", elts);
394 Grob *common = common_refpoint_of_array (elts, me, a);
396 Real my_coord = me->relative_coordinate (common, a);
397 Interval r (relative_group_extent (elts, common, a));
399 return ly_interval2scm (r - my_coord);
402 /* This is like generic_group_extent, but it only counts the grobs that
403 are children of some other axis-group. This is uncached; if it becomes
404 commonly used, it may be necessary to cache it somehow. */
406 Axis_group_interface::staff_extent (Grob *me, Grob *refp, Axis ext_a, Grob *staff, Axis parent_a)
408 extract_grob_set (me, "elements", elts);
409 vector<Grob *> new_elts;
411 for (vsize i = 0; i < elts.size (); i++)
412 if (elts[i]->common_refpoint (staff, parent_a) == staff)
413 new_elts.push_back (elts[i]);
415 return relative_group_extent (new_elts, refp, ext_a);
418 MAKE_SCHEME_CALLBACK (Axis_group_interface, calc_pure_relevant_grobs, 1);
420 Axis_group_interface::calc_pure_relevant_grobs (SCM smob)
422 Grob *me = unsmob_grob (smob);
424 extract_grob_set (me, "elements", elts);
426 vector<Grob *> relevant_grobs;
427 SCM pure_relevant_p = ly_lily_module_constant ("pure-relevant?");
429 for (vsize i = 0; i < elts.size (); i++)
431 if (to_boolean (scm_apply_1 (pure_relevant_p, elts[i]->self_scm (), SCM_EOL)))
432 relevant_grobs.push_back (elts[i]);
434 if (Item *it = dynamic_cast<Item *> (elts[i]))
439 Item *piece = it->find_prebroken_piece (d);
440 if (piece && to_boolean (scm_apply_1 (pure_relevant_p, piece->self_scm (), SCM_EOL)))
441 relevant_grobs.push_back (piece);
443 while (flip (&d) != LEFT);
447 vector_sort (relevant_grobs, pure_staff_priority_less);
448 SCM grobs_scm = Grob_array::make_array ();
449 unsmob_grob_array (grobs_scm)->set_array (relevant_grobs);
454 MAKE_SCHEME_CALLBACK (Axis_group_interface, calc_pure_y_common, 1);
456 Axis_group_interface::calc_pure_y_common (SCM smob)
458 Grob *me = unsmob_grob (smob);
460 extract_grob_set (me, "pure-relevant-grobs", elts);
461 Grob *common = common_refpoint_of_array (elts, me, Y_AXIS);
464 me->programming_error ("No common parent found in calc_pure_y_common.");
468 return common->self_scm ();
472 Axis_group_interface::calc_common (Grob *me, Axis axis)
474 extract_grob_set (me, "elements", elts);
475 Grob *common = common_refpoint_of_array (elts, me, axis);
478 me->programming_error ("No common parent found in calc_common axis.");
482 return common->self_scm ();
485 MAKE_SCHEME_CALLBACK (Axis_group_interface, calc_x_common, 1);
487 Axis_group_interface::calc_x_common (SCM grob)
489 return calc_common (unsmob_grob (grob), X_AXIS);
492 MAKE_SCHEME_CALLBACK (Axis_group_interface, calc_y_common, 1);
494 Axis_group_interface::calc_y_common (SCM grob)
496 return calc_common (unsmob_grob (grob), Y_AXIS);
500 Axis_group_interface::pure_group_height (Grob *me, int start, int end)
502 Grob *common = unsmob_grob (me->get_object ("pure-Y-common"));
506 programming_error ("no pure Y common refpoint");
509 Real my_coord = me->relative_coordinate (common, Y_AXIS);
510 Interval r (relative_pure_height (me, start, end));
516 Axis_group_interface::get_children (Grob *me, vector<Grob *> *found)
518 found->push_back (me);
520 if (!has_interface (me))
523 extract_grob_set (me, "elements", elements);
524 for (vsize i = 0; i < elements.size (); i++)
526 Grob *e = elements[i];
527 Axis_group_interface::get_children (e, found);
532 staff_priority_less (Grob *const &g1, Grob *const &g2)
534 Real priority_1 = robust_scm2double (g1->get_property ("outside-staff-priority"), -infinity_f);
535 Real priority_2 = robust_scm2double (g2->get_property ("outside-staff-priority"), -infinity_f);
537 if (priority_1 < priority_2)
539 else if (priority_1 > priority_2)
542 /* if neither grob has an outside-staff priority, the ordering will have no
543 effect -- we just need to choose a consistent ordering. We do this to
544 avoid the side-effect of calculating extents. */
545 if (isinf (priority_1))
548 /* if there is no preference in staff priority, choose the left-most one */
549 Grob *common = g1->common_refpoint (g2, X_AXIS);
550 Real start_1 = g1->extent (common, X_AXIS)[LEFT];
551 Real start_2 = g2->extent (common, X_AXIS)[LEFT];
552 return start_1 < start_2;
556 pure_staff_priority_less (Grob *const &g1, Grob *const &g2)
558 Real priority_1 = robust_scm2double (g1->get_property ("outside-staff-priority"), -infinity_f);
559 Real priority_2 = robust_scm2double (g2->get_property ("outside-staff-priority"), -infinity_f);
561 return priority_1 < priority_2;
565 add_boxes (Grob *me, Grob *x_common, Grob *y_common, vector<Box> *const boxes, Skyline_pair *skylines)
567 /* if a child has skylines, use them instead of the extent box */
568 if (Skyline_pair *pair = Skyline_pair::unsmob (me->get_property ("vertical-skylines")))
570 Skyline_pair s = *pair;
571 s.shift (me->relative_coordinate (x_common, X_AXIS));
572 s.raise (me->relative_coordinate (y_common, Y_AXIS));
575 else if (Grob_array *elements = unsmob_grob_array (me->get_object ("elements")))
577 for (vsize i = 0; i < elements->size (); i++)
578 add_boxes (elements->grob (i), x_common, y_common, boxes, skylines);
580 else if (!scm_is_number (me->get_property ("outside-staff-priority"))
581 && !to_boolean (me->get_property ("cross-staff")))
583 boxes->push_back (Box (me->extent (x_common, X_AXIS),
584 me->extent (y_common, Y_AXIS)));
588 /* We want to avoid situations like this:
596 The point is that "still more text" should be positioned under
597 "more text". In order to achieve this, we place the grobs in several
598 passes. We keep track of the right-most horizontal position that has been
599 affected by the current pass so far (actually we keep track of 2
600 positions, one for above the staff, one for below).
602 In each pass, we loop through the unplaced grobs from left to right.
603 If the grob doesn't overlap the right-most affected position, we place it
604 (and then update the right-most affected position to point to the right
605 edge of the just-placed grob). Otherwise, we skip it until the next pass.
608 add_grobs_of_one_priority (Skyline_pair *const skylines,
609 vector<Grob *> elements,
614 Drul_array<Real> last_affected_position;
617 while (!elements.empty ())
619 last_affected_position[UP] = -infinity_f;
620 last_affected_position[DOWN] = -infinity_f;
622 for (vsize i = elements.size (); i--;)
624 Direction dir = get_grob_direction (elements[i]);
627 warning (_ ("an outside-staff object should have a direction, defaulting to up"));
631 Box b (elements[i]->extent (x_common, X_AXIS),
632 elements[i]->extent (y_common, Y_AXIS));
633 SCM horizon_padding_scm = elements[i]->get_property ("outside-staff-horizontal-padding");
634 Real horizon_padding = robust_scm2double (horizon_padding_scm, 0.0);
636 if (b[X_AXIS][LEFT] - 2 * horizon_padding < last_affected_position[dir])
639 if (!b[X_AXIS].is_empty () && !b[Y_AXIS].is_empty ())
643 Skyline other = Skyline (boxes, horizon_padding, X_AXIS, -dir);
644 Real padding = robust_scm2double (elements[i]->get_property ("outside-staff-padding"), 0.5);
645 Real dist = (*skylines)[dir].distance (other) + padding;
649 b.translate (Offset (0, dir * dist));
650 elements[i]->translate_axis (dir * dist, Y_AXIS);
652 skylines->insert (b, 0, X_AXIS);
653 elements[i]->set_property ("outside-staff-priority", SCM_BOOL_F);
654 last_affected_position[dir] = b[X_AXIS][RIGHT];
658 Ugh: quadratic. --hwn
660 elements.erase (elements.begin () + i);
666 Axis_group_interface::has_outside_staff_parent (Grob *me)
669 ? (scm_is_number (me->get_property ("outside-staff-priority"))
670 || has_outside_staff_parent (me->get_parent (Y_AXIS)))
674 // TODO: it is tricky to correctly handle skyline placement of cross-staff grobs.
675 // For example, cross-staff beams cannot be formatted until the distance between
676 // staves is known and therefore any grobs that depend on the beam cannot be placed
677 // until the skylines are known. On the other hand, the distance between staves should
678 // really depend on position of the cross-staff grobs that lie between them.
679 // Currently, we just leave cross-staff grobs out of the
680 // skyline altogether, but this could mean that staves are placed so close together
681 // that there is no room for the cross-staff grob. It also means, of course, that
682 // we don't get the benefits of skyline placement for cross-staff grobs.
684 Axis_group_interface::skyline_spacing (Grob *me, vector<Grob *> elements)
686 /* For grobs with an outside-staff-priority, the sorting function might
687 call extent and cause suicide. This breaks the contract that is required
688 for the STL sort function. To avoid this, we make sure that any suicides
689 are triggered beforehand.
691 for (vsize i = 0; i < elements.size (); i++)
692 if (scm_is_number (elements[i]->get_property ("outside-staff-priority")))
693 elements[i]->extent (elements[i], X_AXIS);
695 vector_sort (elements, staff_priority_less);
696 Grob *x_common = common_refpoint_of_array (elements, me, X_AXIS);
697 Grob *y_common = common_refpoint_of_array (elements, me, Y_AXIS);
699 assert (y_common == me);
704 Skyline_pair skylines;
705 for (i = 0; i < elements.size ()
706 && !scm_is_number (elements[i]->get_property ("outside-staff-priority")); i++)
707 if (!(to_boolean (elements[i]->get_property ("cross-staff")) || has_outside_staff_parent (elements[i])))
708 add_boxes (elements[i], x_common, y_common, &boxes, &skylines);
710 SCM padding_scm = me->get_property ("skyline-horizontal-padding");
711 Real padding = robust_scm2double (padding_scm, 0.1);
712 skylines.merge (Skyline_pair (boxes, padding, X_AXIS));
713 for (; i < elements.size (); i++)
715 if (to_boolean (elements[i]->get_property ("cross-staff")))
718 SCM priority = elements[i]->get_property ("outside-staff-priority");
719 vector<Grob *> current_elts;
720 current_elts.push_back (elements[i]);
721 while (i + 1 < elements.size ()
722 && scm_eq_p (elements[i + 1]->get_property ("outside-staff-priority"), priority))
724 if (!to_boolean (elements[i + 1]->get_property ("cross-staff")))
725 current_elts.push_back (elements[i + 1]);
729 add_grobs_of_one_priority (&skylines, current_elts, x_common, y_common);
731 skylines.shift (-me->relative_coordinate (x_common, X_AXIS));
735 MAKE_SCHEME_CALLBACK (Axis_group_interface, print, 1)
737 Axis_group_interface::print (SCM smob)
742 Grob *me = unsmob_grob (smob);
744 if (Skyline_pair *s = Skyline_pair::unsmob (me->get_property ("vertical-skylines")))
746 ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[UP].to_points (X_AXIS))
747 .in_color (255, 0, 255));
748 ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[DOWN].to_points (X_AXIS))
749 .in_color (0, 255, 255));
751 return ret.smobbed_copy ();
754 MAKE_SCHEME_CALLBACK (Axis_group_interface, calc_pure_staff_staff_spacing, 3)
756 Axis_group_interface::calc_pure_staff_staff_spacing (SCM smob, SCM start, SCM end)
758 return calc_maybe_pure_staff_staff_spacing (unsmob_grob (smob),
764 MAKE_SCHEME_CALLBACK (Axis_group_interface, calc_staff_staff_spacing, 1)
766 Axis_group_interface::calc_staff_staff_spacing (SCM smob)
768 return calc_maybe_pure_staff_staff_spacing (unsmob_grob (smob),
775 Axis_group_interface::calc_maybe_pure_staff_staff_spacing (Grob *me, bool pure, int start, int end)
777 Grob *grouper = unsmob_grob (me->get_object ("staff-grouper"));
781 bool within_group = Staff_grouper_interface::maybe_pure_within_group (grouper, me, pure, start, end);
783 return grouper->get_maybe_pure_property ("staff-staff-spacing", pure, start, end);
785 return grouper->get_maybe_pure_property ("staffgroup-staff-spacing", pure, start, end);
787 return me->get_maybe_pure_property ("default-staff-staff-spacing", pure, start, end);
791 Axis_group_interface::minimum_distance (Grob *g1, Grob *g2, Axis a)
793 SCM sym = ly_symbol2scm ((a == Y_AXIS) ? "vertical-skylines" : "horizontal-skylines");
795 Skyline_pair *s1 = Skyline_pair::unsmob (g1->get_property (sym));
796 Skyline_pair *s2 = Skyline_pair::unsmob (g2->get_property (sym));
798 return (*s1)[DOWN].distance ((*s2)[UP]);
802 ADD_INTERFACE (Axis_group_interface,
803 "An object that groups other layout objects.",
805 // TODO: some of these properties are specific to
806 // VerticalAxisGroup. We should split off a
807 // vertical-axis-group-interface.
809 "adjacent-pure-heights "
811 "default-staff-staff-spacing "
815 "nonstaff-nonstaff-spacing "
816 "nonstaff-relatedstaff-spacing "
817 "nonstaff-unrelatedstaff-spacing "
818 "pure-relevant-grobs "
819 "pure-relevant-items "
820 "pure-relevant-spanners "
824 "staff-staff-spacing "