+void
+Staff_spacing::next_notes_correction (Grob *me, Grob *last_grob,
+ Real *compound_space, Real *compound_fixed
+ )
+{
+ Interval bar_size = bar_y_positions (last_grob);
+
+ extract_grob_set (me, "right-items", right_items);
+
+ *compound_fixed = 0.0;
+ *compound_space = 0.0;
+ int wishes;
+
+ for (int i = right_items.size (); i--;)
+ {
+ Grob *g = right_items[i];
+
+ Real space = 0.0;
+ Real fixed = 0.0;
+
+ next_note_correction (me, g, bar_size, &space, &fixed);
+
+ *compound_space += space;
+ *compound_fixed += fixed;
+ wishes ++;
+
+ extract_grob_set (g, "elements", elts);
+ for (int j = elts.size (); j--;)
+ {
+ Real space = 0.0;
+ Real fixed = 0.0;
+ next_note_correction (me, elts[j], bar_size, &space, &fixed);
+ *compound_fixed += fixed;
+ *compound_space += space;
+ wishes ++;
+ }
+ }
+
+ if (wishes)
+ {
+ *compound_space /= wishes;
+ *compound_fixed /= wishes;
+ }
+}
+
+void
+Staff_spacing::get_spacing_params (Grob *me, Real *space, Real *fixed)
+{
+ *space = 1.0;
+ *fixed = 1.0;
+
+ Grob *separation_item = 0;
+ Item *me_item = dynamic_cast<Item *> (me);
+
+ extract_grob_set (me, "left-items", items);
+ for (int i = items.size (); i--;)
+ {
+ Grob *cand = items[i];
+ if (cand && Separation_item::has_interface (cand))
+ separation_item = cand;
+ }
+
+ // printf ("doing col %d\n" , Paper_column::get_rank (left_col));
+ if (!separation_item)
+ {
+ programming_error ("no sep item");
+ return;
+ }
+
+ Interval last_ext;
+ Grob *last_grob = Separation_item::extremal_break_aligned_grob (separation_item, RIGHT,
+ &last_ext);
+ if (!last_grob)
+ {
+ /*
+ TODO:
+
+ Should insert a adjustable space here? For excercises, you might want to
+ use a staff without a clef in the beginning.
+ */
+
+ /*
+ we used to have a warning here, but it generates a lot of
+ spurious error messages.
+ */
+ return;
+ }
+
+ *fixed = last_ext[RIGHT];
+ *space = *fixed + 1.0;
+
+ SCM alist = last_grob->get_property ("space-alist");
+ if (!scm_list_p (alist))
+ return;
+
+ SCM space_def = scm_sloppy_assq (ly_symbol2scm ("first-note"), alist);
+ if (me_item->break_status_dir () == CENTER)
+ {
+ SCM nndef = scm_sloppy_assq (ly_symbol2scm ("next-note"), alist);
+ if (scm_is_pair (nndef))
+ space_def = nndef;
+ }
+
+ if (!scm_is_pair (space_def))
+ {
+ programming_error ("unknown prefatory spacing");
+ return;
+ }
+
+ space_def = scm_cdr (space_def);
+ Real distance = scm_to_double (scm_cdr (space_def));
+ SCM type = scm_car (space_def);
+
+ *fixed = last_ext[RIGHT];
+ if (type == ly_symbol2scm ("fixed-space"))
+ {
+ *fixed += distance;
+ *space = *fixed;
+ }
+ else if (type == ly_symbol2scm ("extra-space"))
+ *space = *fixed + distance;
+ else if (type == ly_symbol2scm ("semi-fixed-space"))
+ {
+ *fixed += distance / 2;
+ *space = *fixed + distance / 2;
+ }
+ else if (type == ly_symbol2scm ("minimum-space"))
+ *space = last_ext[LEFT] + max (last_ext.length (), distance);
+ else if (type == ly_symbol2scm ("minimum-fixed-space"))
+ {
+ *space = last_ext[LEFT] + max (last_ext.length (), distance);
+ *fixed = *space;
+ }
+
+ Real correction_fixed, correction_space;
+ next_notes_correction (me, last_grob, &correction_space, &correction_fixed );
+ *space += correction_space;
+ *fixed += correction_fixed;
+}
+
+ADD_INTERFACE (Staff_spacing, "staff-spacing-interface",
+ "This object calculates spacing details from a "
+ " breakable symbol (left) to another object. For example, it takes care "
+ " of optical spacing from a bar lines to a note.",
+ "stem-spacing-correction left-items right-items");