--- /dev/null
+/*
+ custos-engraver.cc -- implement Custos_engraver
+
+ source file of the GNU LilyPond music typesetter
+
+ (C) 2000 Juergen Reuter <reuterj@ira.uka.de>,
+
+ Han-Wen Nienhuys <hanwen@cs.uu.nl>
+
+*/
+
+#include "engraver.hh"
+#include "bar.hh"
+#include "item.hh"
+#include "note-head.hh"
+#include "staff-symbol-referencer.hh"
+#include "warn.hh"
+#include "musical-request.hh"
+
+/*
+ This class implements an engraver for custos symbols.
+*/
+class Custos_engraver : public Engraver
+{
+public:
+ Custos_engraver();
+ virtual void do_post_move_processing();
+ virtual void acknowledge_element(Score_element_info);
+ virtual void do_process_music ();
+ virtual void process_acknowledged ();
+ virtual void do_pre_move_processing ();
+ virtual void do_removal_processing ();
+ VIRTUAL_COPY_CONS(Translator);
+
+private:
+ Item * create_custos();
+ bool custos_permitted;
+ Link_array<Score_element> custos_arr_;
+ Array<Musical_pitch> pitches_;
+};
+
+Custos_engraver::Custos_engraver ()
+{
+ custos_permitted = false;
+}
+
+
+void
+Custos_engraver::do_pre_move_processing()
+{
+ /*
+ delay typeset until we're at the next moment, so we can silence custodes at the end of the piece.
+ */
+}
+
+void
+Custos_engraver::do_post_move_processing ()
+{
+ for (int i = custos_arr_.size (); i--;)
+ {
+ typeset_element (custos_arr_[i]);
+ }
+ custos_arr_.clear ();
+ pitches_.clear ();
+
+ custos_permitted = false;
+}
+
+
+/*
+ TODO check if this works with forced bar lines?
+ */
+void
+Custos_engraver::do_process_music ()
+{
+ if (gh_string_p (get_property( "whichBar")))
+ custos_permitted = true;
+}
+
+void
+Custos_engraver::acknowledge_element (Score_element_info info)
+{
+ Item *item = dynamic_cast <Item *>(info.elem_l_);
+ if (item)
+ {
+ if (Bar::has_interface (info.elem_l_))
+ custos_permitted = true;
+ else if (Note_head::has_interface (info.elem_l_))
+ {
+
+ /*
+ ideally, we'd do custos->set_parent (Y_AXIS, notehead),
+ but since the note head lives on the other system, we can't
+
+ So we copy the position from the note head pitch. We
+ don't look at the staff-position, since we can't be sure
+ whether Clef_engraver already applied a vertical shift.
+ */
+
+ pitches_.push (dynamic_cast<Note_req*> (info.req_l_)->pitch_);
+ }
+ }
+}
+
+void
+Custos_engraver::process_acknowledged ()
+{
+ if (custos_permitted)
+ {
+ for (int i = pitches_.size (); i--;)
+ {
+ Item *c = create_custos ();
+
+ c->set_elt_property ("staff-position",
+ gh_int2scm (pitches_[i].steps ()));
+
+ }
+
+ pitches_.clear ();
+ }
+}
+
+Item*
+Custos_engraver::create_custos()
+{
+ SCM basicProperties = get_property ("Custos");
+ Item* custos = new Item (basicProperties);
+
+ announce_element (custos, 0);
+ custos_arr_.push (custos);
+
+ return custos;
+}
+
+void
+Custos_engraver::do_removal_processing ()
+{
+ for (int i = custos_arr_.size (); i--;)
+ {
+ custos_arr_[i]->suicide ();
+ typeset_element (custos_arr_[i]);
+ }
+ custos_arr_.clear ();
+}
+
+ADD_THIS_TRANSLATOR (Custos_engraver);
+
--- /dev/null
+/*
+ custos.cc -- implement Custos
+
+ source file of the GNU LilyPond music typesetter
+
+ (C) 2000 Juergen Reuter <reuterj@ira.uka.de>
+*/
+
+/* TODO:
+
+ - merge create_ledger_line () and Note_head::create_ledger_line()
+
+
+ - rewrite create_ledger_line() to support short and thin ledger lines
+
+ - do not show if a clef change immediately follows in the next line
+
+ - make custos direction control configurable
+
+ - decide: do or do not print custos if the next line starts with a rest
+
+*/
+
+
+#include <stdio.h>
+#include "staff-symbol-referencer.hh"
+#include "custos.hh"
+#include "molecule.hh"
+#include "lookup.hh"
+#include "debug.hh"
+#include "note-head.hh"
+#include "item.hh"
+#include "font-interface.hh"
+
+/*
+ This function is a patched and hopefully much more understandable
+ rewrite of Note_head::ledger_line(). It still has some
+ bugs/limitations:
+ *
+ (1) The term thick/2 probably should be thick*2 (probably a bug,
+ see the code below).
+ *
+ (2) The minimal width of the resulting ledger line equals the width
+ of the noteheads-ledgerending symbol (a limitation):
+ *
+ (---- left ledger ending
+ ----) right ledger ending
+ (---) resulting ledger line (just ok)
+ *
+ If x_extent ("xwid" in Note_head) is less than the width of the
+ ledger ending, the width of the total ledger line is even *greater*
+ than the width of a ledger ending (I would call this a bug). In
+ the below code, the condition "if (x_extent.length() >
+ slice_x_extent.length())" avoids outputting the left ending in such
+ cases (rather a silly workaround, but better than nothing).
+ *
+ (---- left ledger ending
+ ----) right ledger ending
+ (-) desired ledger line
+ ------- resulting ledger line (too long)
+ ----) resulting ledger line with additional "if" (still too long)
+ *
+ The algorithm works properly only for a desired ledger line width
+ greater than the width of the ledger ending:
+ *
+ (---- left ledger ending
+ ----) right ledger ending
+ (------) desired ledger line
+ (------) resulting ledger line (ok)
+ *
+ * (3) The thickness of the ledger line is fixed (limitation).
+ */
+Molecule create_ledger_line (Interval x_extent, Score_element *me)
+{
+ Molecule line;
+ Molecule slice = Font_interface::get_default_font (me)->find_by_name ("noteheads-ledgerending");
+ Interval slice_x_extent = slice.extent(X_AXIS);
+ Interval slice_y_extent = slice.extent(Y_AXIS);
+
+ // Create left ending of ledger line.
+ Molecule left_ending = slice;
+ left_ending.translate_axis (x_extent[LEFT] - slice_x_extent[LEFT], X_AXIS);
+ if (x_extent.length() > slice_x_extent.length())
+ line.add_molecule (left_ending);
+
+ // Create right ending of ledger line.
+ Molecule right_ending = slice;
+ right_ending.translate_axis (x_extent[RIGHT] - slice_x_extent[RIGHT],
+ X_AXIS);
+ line.add_molecule (right_ending);
+
+ // Fill out space between left and right ending of ledger line by
+ // lining up a series of slices in a row between them.
+ Molecule fill_out_slice = left_ending;
+ Real thick = slice_y_extent.length();
+ Real delta_x = slice_x_extent.length () - thick;
+ Real xpos = x_extent [LEFT] + 2*delta_x + thick/2; // TODO: check: thick*2?
+ while (xpos <= x_extent[RIGHT])
+ {
+ fill_out_slice.translate_axis (delta_x, X_AXIS);
+ line.add_molecule (fill_out_slice);
+ xpos += delta_x;
+ }
+
+ return line;
+}
+
+void add_streepjes(Score_element* me,
+ int pos,
+ int interspaces,
+ Molecule* custos_p_)
+{
+ // TODO: This is (almost) duplicated code (see
+ // Note_head::brew_molecule). Junk me.
+ Real inter_f = Staff_symbol_referencer::staff_space (me)/2;
+ int streepjes_i = abs (pos) < interspaces
+ ? 0
+ : (abs(pos) - interspaces) /2;
+ if (streepjes_i)
+ {
+ Direction dir = (Direction)sign (pos);
+ Molecule ledger_line (create_ledger_line (custos_p_->extent (X_AXIS),
+ me));
+ ledger_line.set_empty (true);
+ Real offs = (Staff_symbol_referencer::on_staffline (me))
+ ? 0.0
+ : -dir * inter_f;
+ for (int i = 0; i < streepjes_i; i++)
+ {
+ Molecule streep (ledger_line);
+ streep.translate_axis (-dir * inter_f * i * 2 + offs,
+ Y_AXIS);
+ custos_p_->add_molecule (streep);
+ }
+ }
+}
+
+MAKE_SCHEME_CALLBACK(Custos,brew_molecule,1);
+SCM
+Custos::brew_molecule (SCM smob)
+{
+ Item *me = (Item *)unsmob_element (smob);
+ SCM scm_style = me->get_elt_property ("style");
+
+ if (gh_string_p (scm_style))
+ {
+ String style = ly_scm2string (scm_style);
+
+ String idx = "custodes-";
+ int interspaces = Staff_symbol_referencer::line_count (me)-1;
+
+ Real pos = Staff_symbol_referencer::position_f (me);
+
+ if (pos > (interspaces/2 + 1)) // TODO: make this rule configurable
+ idx += "r";
+ idx += style;
+ Molecule molecule
+ = Font_interface::get_default_font (me)->find_by_name (idx);
+ if (molecule.empty_b())
+ {
+ String message = "unknown custos style: `" + style + "'";
+ warning(_ (message.ch_C()));
+ return SCM_EOL;
+ }
+ else
+ {
+ add_streepjes(me, (int)pos, interspaces, &molecule);
+ SCM result = molecule.create_scheme();
+ return result;
+ }
+ }
+ else
+ return SCM_EOL;
+}
+
+bool
+Custos::has_interface (Score_element*m)
+{
+ return m && m->has_interface (ly_symbol2scm ("custos-interface"));
+}