2 break-align-item.cc -- implement Break_align_interface
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
11 #include <libc-extension.hh> // isinf
13 #include "side-position-interface.hh"
14 #include "axis-group-interface.hh"
16 #include "lily-guile.hh"
17 #include "break-align-item.hh"
18 #include "dimensions.hh"
19 #include "paper-def.hh"
20 #include "paper-column.hh"
21 #include "group-interface.hh"
22 #include "align-interface.hh"
24 MAKE_SCHEME_CALLBACK (Break_align_interface
,before_line_breaking
,1);
27 Break_align_interface::before_line_breaking (SCM smob
)
29 Grob
* me
= unsmob_grob (smob
);
31 return SCM_UNSPECIFIED
;
33 MAKE_SCHEME_CALLBACK (Break_align_interface
,alignment_callback
,2);
36 Break_align_interface::alignment_callback (SCM element_smob
, SCM axis
)
38 Grob
*me
= unsmob_grob (element_smob
);
39 Axis a
= (Axis
) gh_scm2int (axis
);
42 Grob
*par
= me
->parent_l (a
);
43 if (par
&& !to_boolean (par
->get_grob_property ("break-alignment-done")))\
45 par
->set_grob_property ("break-alignment-done", SCM_BOOL_T
);
46 Break_align_interface::do_alignment (par
);
49 return gh_double2scm (0);
52 MAKE_SCHEME_CALLBACK (Break_align_interface
,self_align_callback
,2);
54 Break_align_interface::self_align_callback (SCM element_smob
, SCM axis
)
56 Grob
*me
= unsmob_grob (element_smob
);
57 Axis a
= (Axis
) gh_scm2int (axis
);
60 Item
* item
= dynamic_cast<Item
*> (me
);
61 Direction bsd
= item
->break_status_dir ();
64 me
->set_grob_property ("self-alignment-X", gh_int2scm (RIGHT
));
68 Force break alignment itself to be done first, in the case
72 return Side_position_interface::aligned_on_self (element_smob
, axis
);
76 Break_align_interface::add_element (Grob
*me
, Grob
*toadd
)
78 Axis_group_interface::add_element (me
, toadd
);
82 Break_align_interface::do_alignment (Grob
*me
)
84 Item
* item
= dynamic_cast<Item
*> (me
);
85 Item
*column
= item
->column_l ();
87 Link_array
<Grob
> elems
;
88 Link_array
<Grob
> all_elems
89 = Pointer_group_interface__extract_elements (me
, (Grob
*)0,
92 for (int i
=0; i
< all_elems
.size (); i
++)
94 Interval y
= all_elems
[i
]->extent (all_elems
[i
], X_AXIS
);
96 elems
.push (dynamic_cast<Grob
*> (all_elems
[i
]));
102 SCM symbol_list
= SCM_EOL
;
104 SCM current_origin
= ly_symbol2scm ("none");
105 for (int i
=0; i
<= elems
.size (); i
++)
107 Grob
*next_elt
= i
< elems
.size ()
115 next_origin
= next_elt
->get_grob_property ("break-align-symbol");
117 gh_symbol_p (next_origin
)?
118 next_origin
: ly_symbol2scm ("none")
122 next_origin
= ly_symbol2scm ("begin-of-note");
124 SCM alist
= me
->get_grob_property ("space-alist");
125 SCM e
= scm_assoc (scm_list_n (current_origin
,
127 SCM_UNDEFINED
), alist
);
132 extra_space
= gh_cdr (e
);
136 warning (_f ("unknown spacing pair `%s', `%s'",
137 ly_symbol2string (current_origin
),
138 ly_symbol2string (next_origin
)));
139 extra_space
= scm_list_n (ly_symbol2scm ("minimum-space"), gh_double2scm (0.0), SCM_UNDEFINED
);
142 SCM symbol
= gh_car (extra_space
);
143 Real spc
= gh_scm2double (gh_cadr (extra_space
));
146 symbol_list
= gh_cons (symbol
, symbol_list
);
147 current_origin
= next_origin
;
151 // skip the first sym.
152 symbol_list
= gh_cdr (scm_reverse (symbol_list
));
153 for (int i
=0; i
<elems
.size ()-1; i
++)
155 elems
[i
]->set_grob_property (gh_car (symbol_list
),
156 scm_cons (gh_double2scm (0),
157 gh_double2scm (dists
[i
+1])));
159 symbol_list
= gh_cdr (symbol_list
);
164 SCM first_pair
= elems
[0]->get_grob_property ("minimum-space");
165 if (gh_pair_p (first_pair
))
166 first_pair
= first_pair
;
168 first_pair
= gh_cons (gh_double2scm (0.0), gh_double2scm (0.0));
170 scm_set_car_x (first_pair
, gh_double2scm (-dists
[0]));
171 elems
[0]->set_grob_property ("minimum-space", first_pair
);
173 Direction bsd
= item
->break_status_dir ();
176 me
->set_grob_property ("self-alignment-X", gh_int2scm (RIGHT
));
180 Force callbacks for alignment to be called
182 Align_interface::align_elements_to_extents (me
, X_AXIS
);
184 Real pre_space
= elems
[0]->relative_coordinate (column
, X_AXIS
);
186 Real xl
= elems
[0]->extent (elems
[0],X_AXIS
)[LEFT
];
190 programming_error ("Infinity reached. ");
192 Real xr
= elems
.top ()->extent (elems
.top (), X_AXIS
)[RIGHT
];
193 Real spring_len
= elems
.top ()->relative_coordinate (column
, X_AXIS
);
197 programming_error ("Infinity reached.");
199 Real stretch_distance
=0.;
201 if (gh_car (symbol_list
) == ly_symbol2scm ("extra-space"))
203 spring_len
+= dists
.top ();
204 stretch_distance
= dists
.top ();
206 else if (gh_car (symbol_list
) == ly_symbol2scm ("minimum-space"))
208 spring_len
= spring_len
>? dists
.top ();
209 stretch_distance
= spring_len
;
214 Hint the spacing engine how much space to put in.
216 The pairs are in the format of an interval (ie. CAR < CDR).
221 This is a side effect, and there is no guarantee that this info is
222 computed at a "sane" moment.
224 (just spent some time tracking a bug that was caused by this info
225 being written halfway:
227 self_alignment_callback (*)
228 -> child->relative_coordinate (self)
230 -> child->relative_coordinate (column)
232 the last call incorporates the value that should've been computed
233 in (*), but--of course-- is not yet.
235 The result is that an offsets of align_elements_to_extents () are
236 not compensated for, and spring_len is completely off.
240 column
->set_grob_property ("extra-space",
241 scm_cons (gh_double2scm (pre_space
),
242 gh_double2scm (spring_len
)));
244 column
->set_grob_property ("stretch-distance",
245 gh_cons (gh_double2scm (-dists
[0]),
246 gh_double2scm (stretch_distance
)));
251 Break_align_interface::set_interface (Grob
*me
)
253 Align_interface::set_interface (me
);
254 Align_interface::set_axis (me
,X_AXIS
);