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 (
241 begin_line_staff_heights[j].union_disjoint (dims, padding, d));
243 begin_line_heights[j].unite (dims);
245 if (rank_span[RIGHT] > start)
248 mid_line_heights[j].unite (
249 mid_line_staff_heights[j].union_disjoint (dims, padding, d));
251 mid_line_heights[j].unite (dims);
258 // Convert begin_line_heights and min_line_heights to SCM.
259 SCM begin_scm = scm_c_make_vector (ranks.size () - 1, SCM_EOL);
260 SCM mid_scm = scm_c_make_vector (ranks.size () - 1, SCM_EOL);
261 for (vsize i = 0; i < begin_line_heights.size (); ++i)
263 scm_vector_set_x (begin_scm, scm_from_int (i), ly_interval2scm (begin_line_heights[i]));
264 scm_vector_set_x (mid_scm, scm_from_int (i), ly_interval2scm (mid_line_heights[i]));
267 return scm_cons (begin_scm, mid_scm);
271 Axis_group_interface::relative_pure_height (Grob *me, int start, int end)
273 /* It saves a _lot_ of time if we assume a VerticalAxisGroup is additive
274 (ie. height (i, k) = max (height (i, j) height (j, k)) for all i <= j <= k).
275 Unfortunately, it isn't always true, particularly if there is a
276 VerticalAlignment somewhere in the descendants.
278 Usually, the only VerticalAlignment comes from Score. This makes it
279 reasonably safe to assume that if our parent is a VerticalAlignment,
280 we can assume additivity and cache things nicely. */
281 Grob *p = me->get_parent (Y_AXIS);
282 if (p && Align_interface::has_interface (p))
283 return Axis_group_interface::sum_partial_pure_heights (me, start, end);
285 Grob *common = unsmob_grob (me->get_object ("pure-Y-common"));
286 extract_grob_set (me, "pure-relevant-grobs", elts);
289 for (vsize i = 0; i < elts.size (); i++)
292 Interval_t<int> rank_span = g->spanned_rank_interval ();
293 if (rank_span[LEFT] <= end && rank_span[RIGHT] >= start
294 && g->pure_is_visible (start, end)
295 && !to_boolean (g->get_property ("cross-staff")))
297 Interval dims = g->pure_height (common, start, end);
298 if (!dims.is_empty ())
305 MAKE_SCHEME_CALLBACK (Axis_group_interface, width, 1);
307 Axis_group_interface::width (SCM smob)
309 Grob *me = unsmob_grob (smob);
310 return generic_group_extent (me, X_AXIS);
313 MAKE_SCHEME_CALLBACK (Axis_group_interface, height, 1);
315 Axis_group_interface::height (SCM smob)
317 Grob *me = unsmob_grob (smob);
318 return generic_group_extent (me, Y_AXIS);
321 MAKE_SCHEME_CALLBACK (Axis_group_interface, pure_height, 3);
323 Axis_group_interface::pure_height (SCM smob, SCM start_scm, SCM end_scm)
325 int start = robust_scm2int (start_scm, 0);
326 int end = robust_scm2int (end_scm, INT_MAX);
327 Grob *me = unsmob_grob (smob);
329 /* Maybe we are in the second pass of a two-pass spacing run. In that
330 case, the Y-extent of a system is already given to us */
331 System *system = dynamic_cast<System*> (me);
334 SCM line_break_details = system->column (start)->get_property ("line-break-system-details");
335 SCM system_y_extent = scm_assq (ly_symbol2scm ("system-Y-extent"), line_break_details);
336 if (scm_is_pair (system_y_extent))
337 return scm_cdr (system_y_extent);
340 return ly_interval2scm (pure_group_height (me, start, end));
343 MAKE_SCHEME_CALLBACK (Axis_group_interface, calc_skylines, 1);
345 Axis_group_interface::calc_skylines (SCM smob)
347 Grob *me = unsmob_grob (smob);
348 extract_grob_set (me, "elements", elts);
349 Skyline_pair skylines = skyline_spacing (me, elts);
351 return skylines.smobbed_copy ();
354 /* whereas calc_skylines calculates skylines for axis-groups with a lot of
355 visible children, combine_skylines is designed for axis-groups whose only
356 children are other axis-groups (ie. VerticalAlignment). Rather than
357 calculating all the skylines from scratch, we just merge the skylines
360 MAKE_SCHEME_CALLBACK (Axis_group_interface, combine_skylines, 1);
362 Axis_group_interface::combine_skylines (SCM smob)
364 Grob *me = unsmob_grob (smob);
365 extract_grob_set (me, "elements", elements);
366 Grob *y_common = common_refpoint_of_array (elements, me, Y_AXIS);
367 Grob *x_common = common_refpoint_of_array (elements, me, X_AXIS);
370 programming_error ("combining skylines that don't belong to me");
373 for (vsize i = 0; i < elements.size (); i++)
375 SCM skyline_scm = elements[i]->get_property ("vertical-skylines");
376 if (Skyline_pair::unsmob (skyline_scm))
378 Real offset = elements[i]->relative_coordinate (y_common, Y_AXIS);
379 Skyline_pair other = *Skyline_pair::unsmob (skyline_scm);
380 other.raise (offset);
381 other.shift (elements[i]->relative_coordinate (x_common, X_AXIS));
385 return ret.smobbed_copy ();
389 Axis_group_interface::generic_group_extent (Grob *me, Axis a)
391 /* trigger the callback to do skyline-spacing on the children */
393 (void) me->get_property ("vertical-skylines");
395 extract_grob_set (me, "elements", elts);
396 Grob *common = common_refpoint_of_array (elts, me, a);
398 Real my_coord = me->relative_coordinate (common, a);
399 Interval r (relative_group_extent (elts, common, a));
401 return ly_interval2scm (r - my_coord);
404 /* This is like generic_group_extent, but it only counts the grobs that
405 are children of some other axis-group. This is uncached; if it becomes
406 commonly used, it may be necessary to cache it somehow. */
408 Axis_group_interface::staff_extent (Grob *me, Grob *refp, Axis ext_a, Grob *staff, Axis parent_a)
410 extract_grob_set (me, "elements", elts);
411 vector<Grob*> new_elts;
413 for (vsize i = 0; i < elts.size (); i++)
414 if (elts[i]->common_refpoint (staff, parent_a) == staff)
415 new_elts.push_back (elts[i]);
417 return relative_group_extent (new_elts, refp, ext_a);
421 MAKE_SCHEME_CALLBACK (Axis_group_interface, calc_pure_relevant_grobs, 1);
423 Axis_group_interface::calc_pure_relevant_grobs (SCM smob)
425 Grob *me = unsmob_grob (smob);
427 extract_grob_set (me, "elements", elts);
429 vector<Grob*> relevant_grobs;
430 SCM pure_relevant_p = ly_lily_module_constant ("pure-relevant?");
432 for (vsize i = 0; i < elts.size (); i++)
434 if (to_boolean (scm_apply_1 (pure_relevant_p, elts[i]->self_scm (), SCM_EOL)))
435 relevant_grobs.push_back (elts[i]);
437 if (Item *it = dynamic_cast<Item*> (elts[i]))
442 Item *piece = it->find_prebroken_piece (d);
443 if (piece && to_boolean (scm_apply_1 (pure_relevant_p, piece->self_scm (), SCM_EOL)))
444 relevant_grobs.push_back (piece);
446 while (flip (&d) != LEFT);
450 vector_sort (relevant_grobs, pure_staff_priority_less);
451 SCM grobs_scm = Grob_array::make_array ();
452 unsmob_grob_array (grobs_scm)->set_array (relevant_grobs);
457 MAKE_SCHEME_CALLBACK (Axis_group_interface, calc_pure_y_common, 1);
459 Axis_group_interface::calc_pure_y_common (SCM smob)
461 Grob *me = unsmob_grob (smob);
463 extract_grob_set (me, "pure-relevant-grobs", elts);
464 Grob *common = common_refpoint_of_array (elts, me, Y_AXIS);
467 me->programming_error ("No common parent found in calc_pure_y_common.");
471 return common->self_scm ();
475 Axis_group_interface::calc_common (Grob *me, Axis axis)
477 extract_grob_set (me, "elements", elts);
478 Grob *common = common_refpoint_of_array (elts, me, axis);
481 me->programming_error ("No common parent found in calc_common axis.");
485 return common->self_scm ();
489 MAKE_SCHEME_CALLBACK (Axis_group_interface, calc_x_common, 1);
491 Axis_group_interface::calc_x_common (SCM grob)
493 return calc_common (unsmob_grob (grob), X_AXIS);
496 MAKE_SCHEME_CALLBACK (Axis_group_interface, calc_y_common, 1);
498 Axis_group_interface::calc_y_common (SCM grob)
500 return calc_common (unsmob_grob (grob), Y_AXIS);
504 Axis_group_interface::pure_group_height (Grob *me, int start, int end)
506 Grob *common = unsmob_grob (me->get_object ("pure-Y-common"));
510 programming_error ("no pure Y common refpoint");
513 Real my_coord = me->relative_coordinate (common, Y_AXIS);
514 Interval r (relative_pure_height (me, start, end));
520 Axis_group_interface::get_children (Grob *me, vector<Grob*> *found)
522 found->push_back (me);
524 if (!has_interface (me))
527 extract_grob_set (me, "elements", elements);
528 for (vsize i = 0; i < elements.size (); i++)
530 Grob *e = elements[i];
531 Axis_group_interface::get_children (e, found);
536 staff_priority_less (Grob * const &g1, Grob * const &g2)
538 Real priority_1 = robust_scm2double (g1->get_property ("outside-staff-priority"), -infinity_f);
539 Real priority_2 = robust_scm2double (g2->get_property ("outside-staff-priority"), -infinity_f);
541 if (priority_1 < priority_2)
543 else if (priority_1 > priority_2)
546 /* if neither grob has an outside-staff priority, the ordering will have no
547 effect -- we just need to choose a consistent ordering. We do this to
548 avoid the side-effect of calculating extents. */
549 if (isinf (priority_1))
552 /* if there is no preference in staff priority, choose the left-most one */
553 Grob *common = g1->common_refpoint (g2, X_AXIS);
554 Real start_1 = g1->extent (common, X_AXIS)[LEFT];
555 Real start_2 = g2->extent (common, X_AXIS)[LEFT];
556 return start_1 < start_2;
560 pure_staff_priority_less (Grob * const &g1, Grob * const &g2)
562 Real priority_1 = robust_scm2double (g1->get_property ("outside-staff-priority"), -infinity_f);
563 Real priority_2 = robust_scm2double (g2->get_property ("outside-staff-priority"), -infinity_f);
565 return priority_1 < priority_2;
569 add_boxes (Grob *me, Grob *x_common, Grob *y_common, vector<Box> *const boxes, Skyline_pair *skylines)
571 /* if a child has skylines, use them instead of the extent box */
572 if (Skyline_pair *pair = Skyline_pair::unsmob (me->get_property ("vertical-skylines")))
574 Skyline_pair s = *pair;
575 s.shift (me->relative_coordinate (x_common, X_AXIS));
576 s.raise (me->relative_coordinate (y_common, Y_AXIS));
579 else if (Grob_array *elements = unsmob_grob_array (me->get_object ("elements")))
581 for (vsize i = 0; i < elements->size (); i++)
582 add_boxes (elements->grob (i), x_common, y_common, boxes, skylines);
584 else if (!scm_is_number (me->get_property ("outside-staff-priority"))
585 && !to_boolean (me->get_property ("cross-staff")))
587 boxes->push_back (Box (me->extent (x_common, X_AXIS),
588 me->extent (y_common, Y_AXIS)));
592 /* We want to avoid situations like this:
600 The point is that "still more text" should be positioned under
601 "more text". In order to achieve this, we place the grobs in several
602 passes. We keep track of the right-most horizontal position that has been
603 affected by the current pass so far (actually we keep track of 2
604 positions, one for above the staff, one for below).
606 In each pass, we loop through the unplaced grobs from left to right.
607 If the grob doesn't overlap the right-most affected position, we place it
608 (and then update the right-most affected position to point to the right
609 edge of the just-placed grob). Otherwise, we skip it until the next pass.
612 add_grobs_of_one_priority (Skyline_pair *const skylines,
613 vector<Grob*> elements,
618 Drul_array<Real> last_affected_position;
621 while (!elements.empty ())
623 last_affected_position[UP] = -infinity_f;
624 last_affected_position[DOWN] = -infinity_f;
626 for (vsize i = elements.size (); i--;)
628 Direction dir = get_grob_direction (elements[i]);
631 warning (_ ("an outside-staff object should have a direction, defaulting to up"));
635 Box b (elements[i]->extent (x_common, X_AXIS),
636 elements[i]->extent (y_common, Y_AXIS));
637 SCM horizon_padding_scm = elements[i]->get_property ("outside-staff-horizontal-padding");
638 Real horizon_padding = robust_scm2double (horizon_padding_scm, 0.0);
640 if (b[X_AXIS][LEFT] - 2*horizon_padding < last_affected_position[dir])
643 if (!b[X_AXIS].is_empty () && !b[Y_AXIS].is_empty ())
647 Skyline other = Skyline (boxes, horizon_padding, X_AXIS, -dir);
648 Real padding = robust_scm2double (elements[i]->get_property ("outside-staff-padding"), 0.5);
649 Real dist = (*skylines)[dir].distance (other) + padding;
653 b.translate (Offset (0, dir*dist));
654 elements[i]->translate_axis (dir*dist, Y_AXIS);
656 skylines->insert (b, 0, X_AXIS);
657 elements[i]->set_property ("outside-staff-priority", SCM_BOOL_F);
658 last_affected_position[dir] = b[X_AXIS][RIGHT];
662 Ugh: quadratic. --hwn
664 elements.erase (elements.begin () + i);
669 // TODO: it is tricky to correctly handle skyline placement of cross-staff grobs.
670 // For example, cross-staff beams cannot be formatted until the distance between
671 // staves is known and therefore any grobs that depend on the beam cannot be placed
672 // until the skylines are known. On the other hand, the distance between staves should
673 // really depend on position of the cross-staff grobs that lie between them.
674 // Currently, we just leave cross-staff grobs out of the
675 // skyline altogether, but this could mean that staves are placed so close together
676 // that there is no room for the cross-staff grob. It also means, of course, that
677 // we don't get the benefits of skyline placement for cross-staff grobs.
679 Axis_group_interface::skyline_spacing (Grob *me, vector<Grob*> elements)
681 /* For grobs with an outside-staff-priority, the sorting function might
682 call extent and cause suicide. This breaks the contract that is required
683 for the STL sort function. To avoid this, we make sure that any suicides
684 are triggered beforehand.
686 for (vsize i = 0; i < elements.size (); i++)
687 if (scm_is_number (elements[i]->get_property ("outside-staff-priority")))
688 elements[i]->extent (elements[i], X_AXIS);
690 vector_sort (elements, staff_priority_less);
691 Grob *x_common = common_refpoint_of_array (elements, me, X_AXIS);
692 Grob *y_common = common_refpoint_of_array (elements, me, Y_AXIS);
694 assert (y_common == me);
699 Skyline_pair skylines;
700 for (i = 0; i < elements.size ()
701 && !scm_is_number (elements[i]->get_property ("outside-staff-priority")); i++)
702 if (!to_boolean (elements[i]->get_property ("cross-staff")))
703 add_boxes (elements[i], x_common, y_common, &boxes, &skylines);
705 SCM padding_scm = me->get_property ("skyline-horizontal-padding");
706 Real padding = robust_scm2double (padding_scm, 0.1);
707 skylines.merge (Skyline_pair (boxes, padding, X_AXIS));
708 for (; i < elements.size (); i++)
710 if (to_boolean (elements[i]->get_property ("cross-staff")))
713 SCM priority = elements[i]->get_property ("outside-staff-priority");
714 vector<Grob*> current_elts;
715 current_elts.push_back (elements[i]);
716 while (i + 1 < elements.size ()
717 && scm_eq_p (elements[i+1]->get_property ("outside-staff-priority"), priority))
719 if (!to_boolean (elements[i+1]->get_property ("cross-staff")))
720 current_elts.push_back (elements[i+1]);
724 add_grobs_of_one_priority (&skylines, current_elts, x_common, y_common);
726 skylines.shift (-me->relative_coordinate (x_common, X_AXIS));
730 MAKE_SCHEME_CALLBACK (Axis_group_interface, print, 1)
732 Axis_group_interface::print (SCM smob)
737 Grob *me = unsmob_grob (smob);
739 if (Skyline_pair *s = Skyline_pair::unsmob (me->get_property ("vertical-skylines")))
741 ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[UP].to_points (X_AXIS))
742 .in_color (255, 0, 255));
743 ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[DOWN].to_points (X_AXIS))
744 .in_color (0, 255, 255));
746 return ret.smobbed_copy ();
749 MAKE_SCHEME_CALLBACK (Axis_group_interface, calc_pure_staff_staff_spacing, 3)
751 Axis_group_interface::calc_pure_staff_staff_spacing (SCM smob, SCM start, SCM end)
753 return calc_maybe_pure_staff_staff_spacing (unsmob_grob (smob),
759 MAKE_SCHEME_CALLBACK (Axis_group_interface, calc_staff_staff_spacing, 1)
761 Axis_group_interface::calc_staff_staff_spacing (SCM smob)
763 return calc_maybe_pure_staff_staff_spacing (unsmob_grob (smob),
770 Axis_group_interface::calc_maybe_pure_staff_staff_spacing (Grob *me, bool pure, int start, int end)
772 Grob *grouper = unsmob_grob (me->get_object ("staff-grouper"));
776 bool within_group = Staff_grouper_interface::maybe_pure_within_group (grouper, me, pure, start, end);
778 return grouper->get_maybe_pure_property ("staff-staff-spacing", pure, start, end);
780 return grouper->get_maybe_pure_property ("staffgroup-staff-spacing", pure, start, end);
782 return me->get_maybe_pure_property ("default-staff-staff-spacing", pure, start, end);
786 Axis_group_interface::minimum_distance (Grob *g1, Grob *g2, Axis a)
788 SCM sym = ly_symbol2scm ((a == Y_AXIS) ? "vertical-skylines" : "horizontal-skylines");
790 Skyline_pair *s1 = Skyline_pair::unsmob (g1->get_property (sym));
791 Skyline_pair *s2 = Skyline_pair::unsmob (g2->get_property (sym));
793 return (*s1)[DOWN].distance ((*s2)[UP]);
797 ADD_INTERFACE (Axis_group_interface,
798 "An object that groups other layout objects.",
800 // TODO: some of these properties are specific to
801 // VerticalAxisGroup. We should split off a
802 // vertical-axis-group-interface.
804 "adjacent-pure-heights "
806 "default-staff-staff-spacing "
810 "nonstaff-nonstaff-spacing "
811 "nonstaff-relatedstaff-spacing "
812 "nonstaff-unrelatedstaff-spacing "
813 "pure-relevant-grobs "
814 "pure-relevant-items "
815 "pure-relevant-spanners "
819 "staff-staff-spacing "