- Stencil flag = Stem::flag (stem);
- if (!flag.is_empty ())
- {
- Interval y = flag.extent (Y_AXIS)
- * (2 / ss)
- + Stem::stem_end_position (stem);
-
- Interval x = stem->relative_coordinate (commonx, X_AXIS)
- + flag.extent (X_AXIS);
-
- boxes.push_back (Box (x,y));
- }
+ Grob *flag = Stem::flag (stem);
+ if (flag)
+ {
+ Grob *commony = stem->common_refpoint (flag, Y_AXIS);
+ Interval y = flag->extent (commony, Y_AXIS) * (2 / ss);
+ Interval x = flag->extent (commonx, X_AXIS);
+
+ boxes.push_back (Box (x, y));
+ }
+ }
+
+ /*
+ The use of pure_position_less and pure_get_rounded_position below
+ are due to the fact that this callback is called before line breaking
+ occurs. Because dots' actual Y posiitons may be linked to that of
+ beams (dots are attached to rests, which are shifted to avoid beams),
+ we instead must use their pure Y positions.
+ */
+ vector_sort (dots, pure_position_less);
+
+ SCM chord_dots_limit = me->get_property ("chord-dots-limit");
+ if (scm_is_number (chord_dots_limit))
+ {
+ // Sort dots by stem, then check for dots above the limit for each stem
+ vector <vector <Grob *> > dots_each_stem (parent_stems.size ());
+ for (vsize i = 0; i < dots.size (); i++)
+ if (Grob *stem = unsmob<Grob> (dots[i]->get_parent (Y_AXIS)
+ -> get_object ("stem")))
+ for (vsize j = 0; j < parent_stems.size (); j++)
+ if (stem == parent_stems[j])
+ {
+ dots_each_stem[j].push_back (dots[i]);
+ break;
+ }
+ for (vsize j = 0; j < parent_stems.size (); j++)
+ {
+ Interval chord = Stem::head_positions (parent_stems[j]);
+ int total_room = ((int) chord.length () + 2
+ + scm_to_int (chord_dots_limit)) / 2;
+ int total_dots = dots_each_stem[j].size ();
+ // remove excessive dots from the ends of the stem
+ for (int first_dot = 0; total_dots > total_room; total_dots--)
+ if (0 == (total_dots - total_room) % 2)
+ dots_each_stem[j][first_dot++]->suicide ();
+ else
+ dots_each_stem[j][first_dot + total_dots - 1]->suicide ();
+ }