2 break-align-interface.cc -- implement Break_align_interface
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2003 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 "paper-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
) gh_scm2int (axis
);
34 Grob
*par
= me
->get_parent (a
);
35 if (par
&& !to_boolean (par
->get_grob_property ("break-alignment-done")))
37 par
->set_grob_property ("break-alignment-done", SCM_BOOL_T
);
38 Break_align_interface::do_alignment (par
);
41 return gh_double2scm (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
) gh_scm2int (axis
);
52 Item
* item
= dynamic_cast<Item
*> (me
);
53 Direction bsd
= item
->break_status_dir ();
56 me
->set_grob_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
);
66 Break_align_interface::add_element (Grob
*me
, Grob
*toadd
)
68 Axis_group_interface::add_element (me
, toadd
);
72 Break_align_interface::do_alignment (Grob
*me
)
74 Item
* item
= dynamic_cast<Item
*> (me
);
75 int rank
= Paper_column::get_rank (item
->get_column ());
76 Link_array
<Grob
> elems
77 = Pointer_group_interface__extract_grobs (me
, (Grob
*)0,
79 Array
<Interval
> extents
;
81 int last_nonempty
= -1;
82 for (int i
=0; i
< elems
.size (); i
++)
84 Interval y
= elems
[i
]->extent (elems
[i
], X_AXIS
);
91 while (idx
< extents
.size () && extents
[idx
].empty_b ())
95 offsets
.set_size (elems
.size());
96 for (int i
= 0; i
< offsets
.size();i
++)
100 Real extra_right_space
= 0.0;
102 while (idx
< elems
.size())
104 int next_idx
= idx
+1;
105 while (next_idx
< elems
.size() &&
106 extents
[next_idx
].empty_b()
110 Grob
*l
= elems
[idx
];
113 if (next_idx
< elems
.size())
120 Find the first grob with a space-alist entry.
122 for (SCM s
= l
->get_grob_property ("elements");
123 gh_pair_p (s
) ; s
= gh_cdr (s
))
125 Grob
*elt
= unsmob_grob (gh_car (s
));
128 && elt
->get_grob_property ("break-align-symbol")
129 == ly_symbol2scm( "left-edge"))
132 SCM l
=elt
->get_grob_property ("space-alist");
140 SCM rsym
= r
? SCM_EOL
: ly_symbol2scm ("right-edge");
143 We used to use #'cause to find out the symbol and the spacing
144 table, but that gets icky when that grob is suicided for some
147 for (SCM s
= r
? r
->get_grob_property ("elements") : SCM_EOL
;
148 !gh_symbol_p (rsym
) && gh_pair_p (s
); s
= gh_cdr (s
))
150 Grob
* elt
=unsmob_grob(gh_car (s
));
152 rsym
= elt
->get_grob_property ("break-align-symbol");
155 if (rsym
== ly_symbol2scm("left-edge"))
159 if (gh_symbol_p (rsym
))
160 entry
= scm_assq (rsym
, alist
);
162 bool entry_found
= gh_pair_p (entry
);
166 if(gh_symbol_p (rsym
))
167 sym_string
= ly_symbol2string (rsym
);
170 if (unsmob_grob (l
->get_grob_property ("cause")))
171 orig_string
= unsmob_grob (l
->get_grob_property ("cause"))->name ();
173 programming_error (_f("No spacing entry from %s to `%s'",
174 orig_string
.to_str0 (),
175 sym_string
.to_str0 ()));
179 SCM type
= ly_symbol2scm ("extra-space");
183 entry
= gh_cdr (entry
);
185 distance
= gh_scm2double (gh_cdr (entry
));
186 type
= gh_car (entry
) ;
191 if (type
== ly_symbol2scm ("extra-space"))
192 offsets
[next_idx
] = extents
[idx
][RIGHT
] + distance
;
193 else if (type
== ly_symbol2scm("minimum-space"))
194 offsets
[next_idx
] = extents
[idx
][RIGHT
] >? distance
;
198 extra_right_space
= distance
;
205 Interval total_extent
;
207 Real alignment_off
=0.0;
208 for (int i
=0 ; i
< offsets
.size(); i
++)
212 alignment_off
= -here
;
213 total_extent
.unite (extents
[i
] + here
);
217 if (item
->break_status_dir () == LEFT
)
219 alignment_off
= - total_extent
[RIGHT
] - extra_right_space
;
221 else if (edge_idx
< 0)
222 alignment_off
= -total_extent
[LEFT
];
224 here
= alignment_off
;
225 for (int i
=0 ; i
< offsets
.size(); i
++)
228 elems
[i
]->translate_axis (here
, X_AXIS
);
233 ADD_INTERFACE (Break_aligned_interface
, "break-aligned-interface",
235 "Items that are aligned in prefatory matter.\n"
237 "The spacing of these items is controlled by the space-alist\n"
238 "property. It contains a list break-align-symbols with a specification\n"
239 "of the associated space. The space definition is either (extra-space\n"
240 ". @var{number}), which adds space after the symbol, (minimum-space\n"
241 ". @var{ms}), which pads the space until it it is @var{ms}.\n"
244 "Special keys for the alist are 'first-note and 'next-note, signifyign\n"
245 "the first note on a line, and the next note halfway a line.\n"
247 "Rules for this spacing are much more complicated than this. \n"
248 "See [Wanske] page 126 -- 134, [Ross] pg 143 -- 147\n",
249 "break-align-symbol break-alignment-done space-alist");
251 ADD_INTERFACE (Break_align_interface
, "break-alignment-interface",
252 "See @ref{break-aligned-interface}.",
253 "break-alignment-done");