--- /dev/null
+/*
+ align-interface.cc -- implement Align_interface
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+
+ */
+
+#include "align-interface.hh"
+#include "dimension-cache.hh"
+#include "score-element.hh"
+#include "group-interface.hh"
+#include "axis-group-interface.hh"
+
+/*
+ This callback is set in the children of the align element. It does
+ not compute anything, but a side effect of a->do_side_processing ()
+ is that the elements are placed correctly. */
+Real
+Align_interface::alignment_callback (Dimension_cache const *c)
+{
+ Axis ax = c->axis ();
+ Score_element * sc = c->element_l ()->parent_l (ax);
+
+ if (sc && sc->get_elt_property ("alignment-done") == SCM_UNDEFINED)
+ {
+ Align_interface (sc).do_side_processing (ax);
+ }
+ return 0.0;
+}
+
+/*
+ Hairy function to put elements where they should be. Can be tweaked
+ from the outside by setting minimum-space and extra-space in its
+ children */
+void
+Align_interface::do_side_processing (Axis a)
+{
+ elt_l_->set_elt_property ("alignment-done", SCM_BOOL_T);
+
+ SCM d = elt_l_->get_elt_property ("stacking-dir");
+ Direction stacking_dir = gh_number_p(d) ? to_dir (d) : CENTER;
+ if (!stacking_dir)
+ stacking_dir = DOWN;
+
+
+ Array<Interval> dims;
+
+ Link_array<Score_element> elems;
+ Link_array<Score_element> all_elts
+ = Group_interface__extract_elements ( elt_l_, (Score_element*) 0, "elements");
+ for (int i=0; i < all_elts.size(); i++)
+ {
+ Interval y = all_elts[i]->extent(a) + all_elts[i]->relative_coordinate (elt_l_, a);
+ if (!y.empty_b())
+ {
+ Score_element *e =dynamic_cast<Score_element*>(all_elts[i]);
+
+ // todo: fucks up if item both in Halign & Valign.
+ SCM min_dims = e->remove_elt_property ("minimum-space");
+ if (gh_pair_p (min_dims) &&
+ gh_number_p (gh_car (min_dims))
+ && gh_number_p (gh_cdr (min_dims)))
+ {
+ y.unite (Interval (gh_scm2double (gh_car (min_dims)),
+ gh_scm2double (gh_cdr (min_dims))));
+ }
+
+ SCM extra_dims = e->remove_elt_property ("extra-space");
+ if (gh_pair_p (extra_dims) &&
+ gh_number_p (gh_car (extra_dims))
+ && gh_number_p (gh_cdr (extra_dims)))
+ {
+ y[LEFT] += gh_scm2double (gh_car (extra_dims));
+ y[RIGHT] += gh_scm2double (gh_cdr (extra_dims));
+ }
+
+ elems.push (e);
+ dims.push (y);
+ }
+ }
+
+
+ Interval threshold = Interval (0, Interval::infinity ());
+ SCM thr = elt_l_->get_elt_property ("threshold");
+ if (gh_pair_p (thr))
+ {
+ threshold[SMALLER] = gh_scm2double (gh_car (thr));
+ threshold[BIGGER] = gh_scm2double (gh_cdr (thr));
+ }
+
+ Real where_f=0;
+ for (int i=0 ; i < elems.size(); i++)
+ {
+ Real dy = - stacking_dir * dims[i][-stacking_dir];
+ if (i)
+ dy += stacking_dir * dims[i-1][stacking_dir];
+
+ if (i)
+ {
+ dy = (dy >? threshold[SMALLER] )
+ <? threshold[BIGGER];
+ }
+
+ where_f += stacking_dir * dy;
+ elems[i]->translate_axis (where_f, a);
+ }
+}
+
+
+Axis
+Align_interface::axis ()const
+{
+ return Axis (gh_scm2int (gh_car (elt_l_->get_elt_property ("axes"))));
+}
+
+
+/*
+ should use generic Scm funcs.
+ */
+int
+Align_interface::get_count (Score_element*s)const
+{
+ SCM e = elt_l_->get_elt_property ("elements");
+ int c =0;
+ while (gh_pair_p (e))
+ {
+ if (gh_car (e) == s->self_scm_)
+ break;
+ c++;
+ e = gh_cdr (e);
+ }
+ return c;
+}
+
+void
+Align_interface::add_element (Score_element* s)
+{
+ s->add_offset_callback (alignment_callback, axis ());
+ Axis_group_interface (elt_l_).add_element (s);
+
+}
+
+Align_interface::Align_interface (Score_element const*s)
+{
+ elt_l_ = (Score_element*)s;
+}
+
+void
+Align_interface::set_interface ()
+{
+ Axis_group_interface (elt_l_).set_interface ();
+
+ Group_interface (elt_l_, "interfaces").add_thing (ly_symbol2scm ("Alignment"));
+}
+
+void
+Align_interface::set_axis (Axis a)
+{
+ Axis_group_interface (elt_l_).set_axes (a,a );
+}
+
+bool
+Align_interface::has_interface_b ()
+{
+ SCM memq = scm_memq (ly_symbol2scm ("Alignment"),
+ elt_l_->get_elt_property ("interfaces"));
+
+ return (memq != SCM_BOOL_F);
+}
+
#include "engraver.hh"
#include "grace-align-item.hh"
+#include "align-interface.hh"
#include "note-column.hh"
#include "local-key-item.hh"
#include "warn.hh"
if (now_column_l_)
{
- align_item_p_->add_element (now_column_l_);
+ Align_interface (align_item_p_).add_element (now_column_l_);
now_column_l_ =0;
}
}
#include "dimension-cache.hh"
Axis_group_interface::Axis_group_interface (Score_element*s)
- : Group_interface (s)
{
elt_l_ = s;
}
Axis_group_interface
-axis_group (Score_element*s)
+Axis_group_interface (Score_element*s)
{
return Axis_group_interface (s);
}
e->set_parent (elt_l_, a);
}
- Group_interface::add_element (e);
+ Group_interface (elt_l_).add_element (e);
elt_l_->add_dependency (e);
}
{
Score_element* e = unsmob_element (gh_car (ep));
if (e)
- childs.concat (axis_group (e).get_children ());
+ childs.concat (Axis_group_interface (e).get_children ());
}
return childs;
#include "engraver.hh"
#include "protected-scm.hh"
#include "break-align-item.hh"
-#include "axis-group-item.hh"
+#include "align-interface.hh"
#include "axis-group-interface.hh"
class Break_align_engraver : public Engraver
Break_align_engraver::add_column (SCM smob)
{
Score_element * e = unsmob_element (smob);
- align_l_->add_element (e);
+ Align_interface (align_l_).add_element (e);
typeset_element (e);
}
SCM name = ly_str02scm (inf.elem_l_->name());
SCM s = scm_assoc (name, column_alist_);
- Axis_group_item * group = 0;
+ Item * group = 0;
+
if (s != SCM_BOOL_F)
{
Score_element *e = unsmob_element (gh_cdr(s));
- group = dynamic_cast<Axis_group_item*> (e);
+ group = dynamic_cast<Item*> (e);
}
else
{
- group = new Axis_group_item;
- axis_group(group).set_axes (X_AXIS,X_AXIS);
+ group = new Item;
+
+ Axis_group_interface (group).set_interface ();
+ Axis_group_interface (group).set_axes (X_AXIS,X_AXIS);
+
group->set_elt_property ("origin", name);
group->set_parent (align_l_, Y_AXIS);
announce_element (Score_element_info (group, 0));
column_alist_ = scm_assoc_set_x (column_alist_, name, group->self_scm_);
}
- axis_group (group).add_element (item_l);
+ Axis_group_interface (group).add_element (item_l);
}
}
#include "paper-def.hh"
#include "paper-column.hh"
#include "group-interface.hh"
-
-/*
- Handle spacing for prefatory matter.
-
- TODO: rewrite this. It is kludgy
-*/
+#include "align-interface.hh"
void
Break_align_item::before_line_breaking ()
for (int i=0; i < all_elems.size(); i++)
{
- Interval y = all_elems[i]->extent(axis ());
+ Interval y = all_elems[i]->extent(X_AXIS);
if (!y.empty_b())
elems.push (dynamic_cast<Score_element*> (all_elems[i]));
}
scm_set_car_x (first_pair, gh_double2scm (-dists[0]));
elems[0]->set_elt_property ("minimum-space", first_pair);
-
- Axis_align_item::before_line_breaking ();
+ /*
+ Force callbacks for alignment to be called
+ */
+ Real unused = elems[0]->relative_coordinate (this, X_AXIS);
Real pre_space = elems[0]->relative_coordinate (column_l (), X_AXIS);
Real xl = elems[0]->extent (X_AXIS)[LEFT];
Break_align_item::Break_align_item ()
{
set_elt_property ("stacking-dir" , gh_int2scm (RIGHT));
- set_axis (X_AXIS);
+
+ Align_interface (this).set_interface ();
+ Align_interface (this).set_axis (X_AXIS);
add_offset_callback (Side_position_interface::aligned_on_self, X_AXIS);
}
#include "cross-staff.hh"
#include "item.hh"
-#include "align-element.hh"
+#include "align-interface.hh"
#include "spanner.hh"
#include "warn.hh"
{
Real interstaff = 0.0;
Score_element *common = item->common_refpoint (span, Y_AXIS);
- Align_element * align = dynamic_cast<Align_element*> (common);
- if (align && align->axis() == Y_AXIS)
+ Align_interface align(common);
+
+ if (align.has_interface_b () && align.axis() == Y_AXIS)
{
- SCM threshold = align->get_elt_property ("threshold");
+ SCM threshold = common->get_elt_property ("threshold");
if (!gh_pair_p (threshold)
|| !scm_equal_p (gh_car (threshold), gh_cdr (threshold)))
warning (_ ("minVerticalAlign != maxVerticalAlign: cross staff spanners may be broken"));
note_refpoint = note_refpoint->parent_l (Y_AXIS);
int span_prio =
- align->get_count ((Score_element*) dynamic_cast<Score_element const*> (span_refpoint));
+ align.get_count ((Score_element*) dynamic_cast<Score_element const*> (span_refpoint));
int item_prio =
- align->get_count ((Score_element*) dynamic_cast<Score_element const *> (note_refpoint));
+ align.get_count ((Score_element*) dynamic_cast<Score_element const *> (note_refpoint));
/*
our staff is lower -> interstaff *= -1
warning (_("Unattached grace notes. Attaching to last musical column."));
align_l_->set_parent (0, X_AXIS);
- axis_group(last_musical_col_l_).add_element (align_l_);
+ Axis_group_interface (last_musical_col_l_).add_element (align_l_);
}
last_musical_col_l_ = get_staff_info ().musical_pcol_l ();
--- /dev/null
+/*
+ align-interface.hh -- declare Align_interface
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+
+ */
+
+#ifndef ALIGN_INTERFACE_HH
+#define ALIGN_INTERFACE_HH
+
+#include "axes.hh"
+#include "lily-proto.hh"
+
+/*
+ TODO: rewrite this comment.
+
+
+ Order elements top to bottom/left to right/right to left etc..
+
+ TODO: implement padding.
+
+ document usage of this.
+
+
+
+ *******
+
+ element properties
+
+ stacking-dir
+
+ Which side to align? -1: left side, 0: centered (around
+ center_l_ if not nil, or around center of width), 1: right side
+ */
+struct Align_interface {
+ Score_element * elt_l_;
+
+ Align_interface (Score_element const*);
+ static Real alignment_callback (Dimension_cache const *);
+ void do_side_processing (Axis a);
+ void set_axis (Axis);
+ Axis axis () const;
+ void add_element (Score_element*);
+ int get_count (Score_element*)const;
+ void set_interface ();
+ bool has_interface_b ();
+};
+
+#endif /* ALIGN_INTERFACE_HH */
+
#include "group-interface.hh"
-struct Axis_group_interface : Group_interface
+/**
+ Treat a group of elements as a union. This sets the parent of any S
+ added to ELT_L_ to ELT_L_.
+
+ Properties:
+
+ axes -- list of axis (number) in which this group works
+
+ transparent -- an Axis_group is transparent by default
+
+ elements -- contains list of pointers to other elements
+
+ interfaces -- Axis_group is added to this list.
+*/
+struct Axis_group_interface
{
+ Score_element *elt_l_;
Axis_group_interface (Score_element*);
+
static Interval group_extent_callback (Dimension_cache const*);
+
void add_element (Score_element*);
void set_axes (Axis,Axis);
bool axis_b (Axis)const;
void set_interface ();
};
-Axis_group_interface
-axis_group (Score_element*);
-
#endif /* AXIS_GROUP_INTERFACE_HH */
class Context_specced_music : public Music_wrapper
{
public:
- /** The kind of translation needed for this music. This doesn't
- make sense for simple (ie non-list) music, but it does no harm
- here. Yes, it did harm Music_sequence: you can forget to copy it.
-
- */
+ /// The kind of translation needed for this music.
String translator_type_str_;
/// what identification for the translation unit
#define GRACE_ALIGN_ITEM_HH
-#include "axis-align-item.hh"
+#include "item.hh"
-class Grace_align_item : public Axis_align_item
+class Grace_align_item : public Item
{
public:
VIRTUAL_COPY_CONS (Score_element);
#include "lily-guile.hh"
#include "smobs.hh"
-/*
- rename to list interface?
- */
-
/**
Look at Score element ELT as thing which has a list property called
NAME_. Normally the list would contain Score_elements, but
sometimes it can be different things.
+
+ todo: reename as list_interface?
*/
+
struct Group_interface
{
Score_element * elt_l_;
typedef void (Score_element::*Score_element_method_pointer) (void);
-/** Both Spanner and Item are Score_element's. Most Score_element's depend
- on other Score_element's, eg, Beam needs to know and set direction of
- Stem. So the Beam has to be calculated *before* Stem. This is
- accomplished with the dependencies fields of struct Score_element,
- which are implemented in the Directed_graph_node class: all elements
- form an acyclic graph.
+/**
+ Basic output object.
- (elem)
+ Element Properties:
+ transparent -- boolean: if true, do not print anything black.
-Element Properties:
+ dependencies -- list of score-element pointers that indicate who to
+ compute first.
-Boolean (true iff defined)
+ interfaces -- list of symbols indicating the interfaces supported
+ by this object.
- break_helper_only -- if defined try to junk this after calcing breakpoints.
-
- transparent -- do not calc. output
+ extra-offset -- pair of reals (a cons) forcing an extra offset
+ before outputting
+ glyph -- afm character name to output.
+
*/
class Score_element {
/**
/**
Set this if anyone points to me, or if I point to anyone.
+
+ JUNKME.
*/
bool used_b_;
#include "spanner.hh"
#include "item.hh"
+
+/**
+ Position victim object (ELT_L_) next to other objects (the support).
+
+ side-support -- list of score elements
+
+ direction -- where to put the victim object (left or right?)
+
+ side-relative-direction -- if set: get the direction from a different object, and multiply by this.
+
+ direction-source -- in case side-relative-direction is set, where
+ to get the direction
+
+ minimum-space -- minimum distance that the victim should move
+ (after padding)
+
+ padding -- add this much extra space between victim and support
+
+ TODO: move out unrelated callbacks.
+
+ */
struct Side_position_interface
{
Score_element * elt_l_;
VIRTUAL_COPY_CONS(Score_element);
void add_bar (Score_element*);
- void set_align (Align_element *);
protected:
void evaluate_empty ();
broken_to_drul_[LEFT] = broken_to_drul_[RIGHT]=0;
}
+/**
+ Item copy ctor. Copy nothing: everything should be a elt property
+ or a special purpose poitner (such as broken_to_drul_[]) */
+Item::Item (Item const &s)
+ : Score_element (s)
+{
+ broken_to_drul_[LEFT] = broken_to_drul_[RIGHT] =0;
+}
+
+
+
bool
Item::breakable_b () const
{
return (i) ? i->breakable_b () : to_boolean (get_elt_property( "breakable"));
}
-Real
-Item::hpos_f() const
-{
- return relative_coordinate (0, X_AXIS);
-}
-
Line_of_score *
Item::line_l() const
{
return dynamic_cast<Item*> (parent_l (X_AXIS))->column_l ();
}
-Item::Item (Item const &s)
- : Score_element (s)
-{
- broken_to_drul_[LEFT] = broken_to_drul_[RIGHT] =0;
-}
-
Direction
Item::break_status_dir () const
{
}
}
if (!elem_p->parent_l(Y_AXIS))
- axis_group (scoreline_l_).add_element (elem_p);
+ Axis_group_interface (scoreline_l_).add_element (elem_p);
}
elem_p_arr_.clear();
}
if (!stem_l)
{
warning (_ ("Slur over rest?"));
- o[X_AXIS] = col->hpos_f ();
+ o[X_AXIS] = col->relative_coordinate (0, X_AXIS);
o[Y_AXIS] = col->extent (Y_AXIS)[dir];
return o;
}
Direction stem_dir = directional_element (stem_l).get ();
- o[X_AXIS] = stem_l->hpos_f ();
+ o[X_AXIS] = stem_l->relative_coordinate (0, X_AXIS);
/*
Simply set x to middle of notehead
*/
else
{
- dx_f_drul_[d] = stem_l->hpos_f ()
+ dx_f_drul_[d] = stem_l->relative_coordinate (0, X_AXIS)
- get_bound (d)->relative_coordinate (0, X_AXIS);
/*
side attached to beamed stem
#include "dimensions.hh"
#include "paper-def.hh"
#include "molecule.hh"
-#include "align-element.hh"
#include "warn.hh"
#include "group-interface.hh"
SCM s = beam->get_elt_property ("height");
if (gh_number_p (s))
dy = gh_scm2double (s);
- Real dx = beam->last_visible_stem ()->hpos_f ()
- - beam->first_visible_stem ()->hpos_f ();
+ Real dx = beam->last_visible_stem ()->relative_coordinate (0, X_AXIS)
+ - beam->first_visible_stem ()->relative_coordinate (0, X_AXIS);
dydx = dx ? dy/dx : 0;
}
else
{
// ugh, rather calc from Stem_tremolo_req
int beams_i = stem->beam_count(RIGHT) >? stem->beam_count (LEFT);
- mol.translate (Offset(stem->hpos_f () - hpos_f (),
+ mol.translate (Offset(stem->relative_coordinate (0, X_AXIS) - relative_coordinate (0, X_AXIS),
stem->stem_end_position () * half_space -
directional_element (beam).get () * beams_i * interbeam_f));
}
else
whole_note_correction = 0;
- mol.translate (Offset (stem->hpos_f () - hpos_f () +
+ mol.translate (Offset (stem->relative_coordinate (0, X_AXIS) - relative_coordinate (0, X_AXIS) +
whole_note_correction, dy));
}
*offset = - d * infinity_f;
- Real x0 = column_arr[0]->hpos_f ();
- Real x1 = column_arr.top ()->hpos_f ();
+ Real x0 = column_arr[0]->relative_coordinate (0, X_AXIS);
+ Real x1 = column_arr.top ()->relative_coordinate (0, X_AXIS);
Real factor = column_arr.size () > 1 ? 1/(x1 - x0) : 1.0;
for (int i = 0; i < column_arr.size (); i++)
{
Real notey = column_arr[i]->extent (Y_AXIS)[d];
- Real x = column_arr[i]->hpos_f () - x0;
+ Real x = column_arr[i]->relative_coordinate (0, X_AXIS) - x0;
Real tuplety = *dy * x * factor;
if (notey * d > (*offset + tuplety) * d)