+/*
+ merge with align-to-extents?
+*/
+void
+Align_interface::align_to_fixed_distance (Grob *me, Axis a)
+{
+ me->set_property ("positioning-done", SCM_BOOL_T);
+
+ SCM d = me->get_property ("stacking-dir");
+
+ Direction stacking_dir = scm_is_number (d) ? to_dir (d) : CENTER;
+ if (!stacking_dir)
+ stacking_dir = DOWN;
+
+ Real dy = robust_scm2double (me->get_property ("forced-distance"), 0.0);
+
+ Link_array<Grob> elems
+ = extract_grob_array (me, ly_symbol2scm ("elements"));
+
+ Real where_f = 0;
+
+ Interval v;
+ v.set_empty ();
+ Array<Real> translates;
+
+ for (int j = elems.size (); j--;)
+ {
+ /*
+ This is not very elegant, in that we need special support for
+ hara-kiri. Unfortunately, the generic wiring of
+ force_hara_kiri_callback () (extent and offset callback) is
+ such that we might get into a loop if we call extent () or
+ offset () the elements.
+
+
+ */
+ if (a == Y_AXIS
+ && Hara_kiri_group_spanner::has_interface (elems[j]))
+ Hara_kiri_group_spanner::consider_suicide (elems[j]);
+
+ if (!elems[j]->is_live ())
+ elems.del (j);
+ }
+
+ for (int j = 0; j < elems.size (); j++)
+ {
+ where_f += stacking_dir * dy;
+ translates.push (where_f);
+ v.unite (Interval (where_f, where_f));
+ }
+
+ /*
+ TODO: support self-alignment-{Y, X}
+ */
+ for (int i = 0; i < translates.size (); i++)
+ {
+ elems[i]->translate_axis (translates[i] - v.center (), a);
+ }
+}