2 break-align-interface.cc -- implement Break_align_interface
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
11 #include <libc-extension.hh> // isinf
13 #include "self-alignment-interface.hh"
14 #include "side-position-interface.hh"
15 #include "axis-group-interface.hh"
17 #include "lily-guile.hh"
18 #include "break-align-interface.hh"
19 #include "dimensions.hh"
20 #include "output-def.hh"
21 #include "paper-column.hh"
22 #include "group-interface.hh"
23 #include "align-interface.hh"
25 MAKE_SCHEME_CALLBACK (Break_align_interface
,alignment_callback
,2);
28 Break_align_interface::alignment_callback (SCM element_smob
, SCM axis
)
30 Grob
*me
= unsmob_grob (element_smob
);
31 Axis a
= (Axis
) ly_scm2int (axis
);
34 Grob
*par
= me
->get_parent (a
);
35 if (par
&& !to_boolean (par
->get_property ("positioning-done")))
37 par
->set_property ("positioning-done", SCM_BOOL_T
);
38 Break_align_interface::do_alignment (par
);
41 return scm_make_real (0);
44 MAKE_SCHEME_CALLBACK (Break_align_interface
,self_align_callback
,2);
46 Break_align_interface::self_align_callback (SCM element_smob
, SCM axis
)
48 Grob
*me
= unsmob_grob (element_smob
);
49 Axis a
= (Axis
) ly_scm2int (axis
);
52 Item
* item
= dynamic_cast<Item
*> (me
);
53 Direction bsd
= item
->break_status_dir ();
56 me
->set_property ("self-alignment-X", scm_int2num (RIGHT
));
60 Force break alignment itself to be done first, in the case
62 return Self_alignment_interface::aligned_on_self (element_smob
, axis
);
67 This is tricky: we cannot modify 'elements, since callers are
68 iterating the same list. Reordering the list in-place, or resetting
69 'elements will skip elements in the loops of callers.
71 So we return the correct order as an array.
74 Break_align_interface::ordered_elements (Grob
*grob
)
76 Item
*me
= dynamic_cast<Item
*> (grob
);
77 SCM elts
= me
->get_property ("elements");
78 SCM order_vec
= me
->get_property ("break-align-orders");
79 if (!ly_c_vector_p (order_vec
)
80 || ly_vector_length (order_vec
) < 3)
81 return Pointer_group_interface__extract_grobs (me
, (Grob
*)0,
83 SCM order
= scm_vector_ref (order_vec
,
84 scm_int2num (me
->break_status_dir() + 1));
88 Copy in order specified in BREAK-ALIGN-ORDER.
90 Link_array
<Grob
> new_elts
;
91 for (; ly_c_pair_p (order
); order
= ly_cdr (order
))
93 SCM sym
= ly_car (order
);
95 for (SCM s
=elts
; ly_c_pair_p (s
); s
= ly_cdr (s
))
97 Grob
*g
= unsmob_grob (ly_car (s
));
98 if (g
&& sym
== g
->get_property ("break-align-symbol"))
101 elts
= scm_delq (g
->self_scm (), elts
);
109 Break_align_interface::add_element (Grob
*me
, Grob
*toadd
)
111 Axis_group_interface::add_element (me
, toadd
);
115 Break_align_interface::do_alignment (Grob
*grob
)
117 Item
* me
= dynamic_cast<Item
*> (grob
);
120 Link_array
<Grob
> elems
= ordered_elements (me
);
121 Array
<Interval
> extents
;
123 int last_nonempty
= -1;
124 for (int i
=0; i
< elems
.size (); i
++)
126 Interval y
= elems
[i
]->extent (elems
[i
], X_AXIS
);
133 while (idx
< extents
.size () && extents
[idx
].is_empty ())
137 offsets
.set_size (elems
.size ());
138 for (int i
= 0; i
< offsets
.size ();i
++)
142 Real extra_right_space
= 0.0;
144 while (idx
< elems
.size ())
146 int next_idx
= idx
+1;
147 while (next_idx
< elems
.size () &&
148 extents
[next_idx
].is_empty () )
151 Grob
*l
= elems
[idx
];
154 if (next_idx
< elems
.size ())
161 Find the first grob with a space-alist entry.
163 for (SCM s
= l
->get_property ("elements");
164 ly_c_pair_p (s
) ; s
= ly_cdr (s
))
166 Grob
*elt
= unsmob_grob (ly_car (s
));
169 && elt
->get_property ("break-align-symbol")
170 == ly_symbol2scm ( "left-edge"))
173 SCM l
=elt
->get_property ("space-alist");
181 SCM rsym
= r
? SCM_EOL
: ly_symbol2scm ("right-edge");
184 We used to use #'cause to find out the symbol and the spacing
185 table, but that gets icky when that grob is suicided for some
188 for (SCM s
= r
? r
->get_property ("elements") : SCM_EOL
;
189 !ly_c_symbol_p (rsym
) && ly_c_pair_p (s
); s
= ly_cdr (s
))
191 Grob
* elt
=unsmob_grob (ly_car (s
));
193 rsym
= elt
->get_property ("break-align-symbol");
196 if (rsym
== ly_symbol2scm ("left-edge"))
200 if (ly_c_symbol_p (rsym
))
201 entry
= scm_assq (rsym
, alist
);
203 bool entry_found
= ly_c_pair_p (entry
);
207 if (ly_c_symbol_p (rsym
))
208 sym_string
= ly_symbol2string (rsym
);
211 if (unsmob_grob (l
->get_property ("cause")))
212 orig_string
= unsmob_grob (l
->get_property ("cause"))->name ();
214 programming_error (_f ("No spacing entry from %s to `%s'",
215 orig_string
.to_str0 (),
216 sym_string
.to_str0 ()));
220 SCM type
= ly_symbol2scm ("extra-space");
224 entry
= ly_cdr (entry
);
226 distance
= ly_scm2double (ly_cdr (entry
));
227 type
= ly_car (entry
) ;
232 if (type
== ly_symbol2scm ("extra-space"))
233 offsets
[next_idx
] = extents
[idx
][RIGHT
] + distance
234 - extents
[next_idx
][LEFT
];
235 /* should probably junk minimum-space */
236 else if (type
== ly_symbol2scm ("minimum-space"))
237 offsets
[next_idx
] = extents
[idx
][RIGHT
] >? distance
;
241 extra_right_space
= distance
;
248 Interval total_extent
;
250 Real alignment_off
=0.0;
251 for (int i
=0 ; i
< offsets
.size (); i
++)
255 alignment_off
= -here
;
256 total_extent
.unite (extents
[i
] + here
);
260 if (me
->break_status_dir () == LEFT
)
262 alignment_off
= - total_extent
[RIGHT
] - extra_right_space
;
264 else if (edge_idx
< 0)
265 alignment_off
= -total_extent
[LEFT
];
267 here
= alignment_off
;
268 for (int i
=0 ; i
< offsets
.size (); i
++)
271 elems
[i
]->translate_axis (here
, X_AXIS
);
276 ADD_INTERFACE (Break_aligned_interface
, "break-aligned-interface",
277 "Items that are aligned in prefatory matter.\n"
279 "The spacing of these items is controlled by the @code{space-alist}\n"
280 "property. It contains a list @code{break-align-symbol}s with a specification\n"
281 "of the associated space. The space specification can be "
283 "@item (minimum-space . @var{spc}))\n"
284 " Pad space until the distance is @var{spc}\n"
285 "@item (fixed-space . @var{spc})\n"
286 " Set a fixed space\n"
287 "@item (semi-fixed-space . @var{spc})\n"
288 " Set a space. Half of it is fixed and half is stretchable. \n"
289 "(does not work at start of line. fixme)\n"
290 "@item (extra-space . @var{spc})\n"
291 " Add @var{spc} amount of space.\n"
294 "Special keys for the alist are @code{first-note} and @code{next-note}, signifying\n"
295 "the first note on a line, and the next note halfway a line.\n"
297 "Rules for this spacing are much more complicated than this. \n"
298 "See [Wanske] page 126 -- 134, [Ross] pg 143 -- 147\n",
299 "break-align-symbol space-alist");
301 ADD_INTERFACE (Break_align_interface
, "break-alignment-interface",
302 "The object that performs break aligment. See @ref{break-aligned-interface}.",
303 "positioning-done break-align-orders");