2 score-elem.cc -- implement Score_element
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
12 #include "group-interface.hh"
14 #include "paper-score.hh"
15 #include "paper-def.hh"
17 #include "molecule.hh"
18 #include "score-element.hh"
21 #include "line-of-score.hh"
23 #include "paper-column.hh"
24 #include "molecule.hh"
26 #include "paper-outputter.hh"
27 #include "dimension-cache.hh"
28 #include "side-position-interface.hh"
31 Score_element::Score_element()
34 dim_cache_
[X_AXIS
] = new Dimension_cache
;
35 dim_cache_
[Y_AXIS
] = new Dimension_cache
;
36 dim_cache_
[X_AXIS
]->elt_l_
= dim_cache_
[Y_AXIS
]->elt_l_
= this;
40 dim_cache_
[X_AXIS
]->set_callback (molecule_extent
);
41 dim_cache_
[Y_AXIS
]->set_callback (molecule_extent
);
48 element_property_alist_
= SCM_EOL
;
53 set_elt_property ("dependencies", SCM_EOL
);
54 set_elt_property ("interfaces", SCM_EOL
);
58 Score_element::Score_element (Score_element
const&s
)
60 dim_cache_
[X_AXIS
] = new Dimension_cache (*s
.dim_cache_
[X_AXIS
]);
61 dim_cache_
[Y_AXIS
] = new Dimension_cache (*s
.dim_cache_
[Y_AXIS
]);
62 dim_cache_
[X_AXIS
]->elt_l_
= dim_cache_
[Y_AXIS
]->elt_l_
= this;
66 original_l_
=(Score_element
*) &s
;
67 element_property_alist_
= SCM_EOL
; // onstack;
70 status_i_
= s
.status_i_
;
71 lookup_l_
= s
.lookup_l_
;
72 pscore_l_
= s
.pscore_l_
;
77 Score_element::~Score_element()
80 assert (status_i_
>=0);
83 delete dim_cache_
[X_AXIS
];
84 delete dim_cache_
[Y_AXIS
];
89 Score_element::get_real (String s
) const
91 return gh_scm2double (get_elt_property (s
));
95 Score_element::set_real (String s
, Real r
)
97 set_elt_property (s
, gh_double2scm (r
));
100 // should also have one that takes SCM arg.
102 Score_element::get_elt_property (String nm
) const
104 SCM sym
= ly_symbol2scm (nm
.ch_C());
105 SCM s
= scm_assq(sym
, element_property_alist_
);
112 SCM sym2
= ly_symbol2scm ((name () + ("::" + nm
)).ch_C());
115 // should probably check for Type::sym as well.
116 Paper_def
* p
= pscore_l_
->paper_l_
;
117 if (p
->default_properties_
.try_retrieve (sym2
, &val
))
119 else if (p
->default_properties_
.try_retrieve (sym
, &val
))
123 return SCM_UNDEFINED
;
127 Score_element::remove_elt_property (String key
)
129 SCM s
= get_elt_property (key
);
130 SCM sym
= ly_symbol2scm (key
.ch_C());
131 element_property_alist_
= scm_assq_remove_x (element_property_alist_
, sym
);
139 Score_element::set_elt_property (String k
, SCM v
)
141 SCM s
= ly_symbol2scm (k
.ch_C( ));
142 element_property_alist_
= scm_assoc_set_x (element_property_alist_
, s
, v
);
146 Score_element::molecule_extent(Dimension_cache
const *c
)
148 Score_element
*s
= dynamic_cast<Score_element
*>(c
->element_l());
149 Molecule
*m
= s
->do_brew_molecule_p();
151 Interval iv
= m
->extent()[c
->axis ()];
159 Score_element::print() const
162 DEBUG_OUT
<< classname(this) << "{\n";
164 if (flower_dstream
&& !flower_dstream
->silent_b ("Score_element"))
165 ly_display_scm (element_property_alist_
);
168 DEBUG_OUT
<< "Copy ";
176 Score_element::paper_l () const
178 return pscore_l_
? pscore_l_
->paper_l_
: 0;
182 Score_element::lookup_l () const
186 Score_element
* urg
= (Score_element
*)this;
187 SCM sz
= urg
->remove_elt_property ("fontsize");
188 int i
= (gh_number_p (sz
))
192 urg
->lookup_l_
= (Lookup
*)pscore_l_
->paper_l_
->lookup_l (i
);
198 Score_element::add_processing()
200 assert (status_i_
>=0);
209 if (get_elt_property ("self-alignment-X") != SCM_UNDEFINED
210 && !dim_cache_
[X_AXIS
]->off_callback_l_
)
212 dim_cache_
[X_AXIS
]->off_callbacks_
.push (Side_position_interface::aligned_on_self
);
215 if (get_elt_property ("self-alignment-Y") != SCM_UNDEFINED
216 && !dim_cache_
[X_AXIS
]->off_callback_l_
)
219 dim_cache_
[Y_AXIS
]->set_offset_callback (Side_position_interface::aligned_on_self
);
227 Score_element::calculate_dependencies (int final
, int busy
,
228 Score_element_method_pointer funcptr
)
230 assert (status_i_
>=0);
232 if (status_i_
>= final
)
235 assert (status_i_
!= busy
);
238 Link_array
<Score_element
> dependency_arr
=
239 Group_interface__extract_elements (this, (Score_element
*)0, "dependencies");
241 for (int i
=0; i
< dependency_arr
.size(); i
++)
242 dependency_arr
[i
]->calculate_dependencies (final
, busy
, funcptr
);
244 Link_array
<Score_element
> extra (get_extra_dependencies());
245 for (int i
=0; i
< extra
.size(); i
++)
246 extra
[i
]->calculate_dependencies (final
, busy
, funcptr
);
253 Score_element::output_processing ()
255 if (to_boolean (get_elt_property ("transparent")))
258 // we're being silly here.
262 output_p_
= do_brew_molecule_p ();
263 Offset
o (relative_coordinate (0, X_AXIS
), relative_coordinate (0, Y_AXIS
));
265 SCM s
= get_elt_property ("extra-offset");
268 Real il
= paper_l ()->get_var ("interline");
269 o
[X_AXIS
] += il
* gh_scm2double (gh_car (s
));
270 o
[Y_AXIS
] += il
* gh_scm2double (gh_cdr (s
));
273 pscore_l_
->outputter_l_
->output_molecule (output_p_
,
287 Score_element::do_break_processing()
292 Score_element::do_post_processing()
297 Score_element::do_breakable_col_processing()
299 handle_prebroken_dependencies();
303 Score_element::do_pre_processing()
308 Score_element::do_space_processing ()
313 Score_element::do_add_processing()
320 Score_element::do_brew_molecule_p() const
322 SCM glyph
= get_elt_property ("glyph");
323 if (gh_string_p (glyph
))
325 Molecule
*output
= new Molecule (lookup_l ()->afm_find (String (ly_scm2string (glyph
))));
333 Molecule
a (lookup_l ()->fill (Box (emp
,emp
)));
334 return new Molecule (a
);
340 Score_element::line_l() const
346 Score_element::add_dependency (Score_element
*e
)
350 Group_interface
gi (this, "dependencies");
354 programming_error ("Null dependency added");
361 Do break substitution in S, using CRITERION. Return new value.
362 CRITERION is either a SMOB pointer to the desired line, or a number
363 representing the break direction. Do not modify SRC.
366 Score_element::handle_broken_smobs (SCM src
, SCM criterion
)
371 Score_element
*sc
= unsmob_element (src
);
374 if (criterion
== SCM_UNDEFINED
)
375 return SCM_UNDEFINED
;
376 else if (gh_number_p (criterion
))
378 Item
* i
= dynamic_cast<Item
*> (sc
);
379 Direction d
= to_dir (criterion
);
380 if (i
&& i
->break_status_dir () != d
)
382 Item
*br
= i
->find_broken_piece (d
);
383 return (br
) ? br
->self_scm_
: SCM_UNDEFINED
;
388 Score_element
* ln
= unsmob_element ( criterion
);
389 Line_of_score
* line
= dynamic_cast<Line_of_score
*> (ln
);
390 Score_element
* br
=0;
391 Line_of_score
* dep_line
= sc
->line_l ();
392 if (dep_line
!= line
)
394 br
= sc
->find_broken_piece (line
);
395 return (br
) ? br
->self_scm_
: SCM_UNDEFINED
;
398 return SCM_UNDEFINED
;
401 else if (gh_pair_p (src
))
404 UGH! breaks on circular lists.
406 SCM car
= handle_broken_smobs (gh_car (src
), criterion
);
407 SCM cdr
= gh_cdr (src
);
409 if (car
== SCM_UNDEFINED
410 && (gh_pair_p (cdr
) || cdr
== SCM_EOL
))
413 This is tail-recursion, ie.
415 return handle_broken_smobs (cdr, criterion);
417 We don't want to rely on the compiler to do this. */
422 return gh_cons (car
, handle_broken_smobs (cdr
, criterion
));
431 Score_element::handle_broken_dependencies()
433 Spanner
* s
= dynamic_cast<Spanner
*> (this);
434 if (original_l_
&& s
)
439 for (int i
= 0; i
< s
->broken_into_l_arr_
.size (); i
++)
441 Score_element
* sc
= s
->broken_into_l_arr_
[i
];
442 Line_of_score
* l
= sc
->line_l ();
443 s
->broken_into_l_arr_
[i
]->element_property_alist_
=
444 handle_broken_smobs (element_property_alist_
,
445 l
? l
->self_scm_
: SCM_UNDEFINED
);
449 Line_of_score
*line
= line_l();
450 element_property_alist_
451 = handle_broken_smobs (element_property_alist_
,
452 line
? line
->self_scm_
: SCM_UNDEFINED
);
460 Score_element::handle_prebroken_dependencies()
462 if (Item
*i
=dynamic_cast<Item
*> (this))
466 element_property_alist_
467 = handle_broken_smobs (original_l_
->element_property_alist_
,
468 gh_int2scm (i
->break_status_dir ()));
473 Link_array
<Score_element
>
474 Score_element::get_extra_dependencies() const
476 Link_array
<Score_element
> empty
;
481 Score_element::linked_b() const
487 Score_element::do_print () const
492 Score_element::find_broken_piece (Line_of_score
*) const
498 Score_element::translate_axis (Real y
, Axis a
)
500 dim_cache_
[a
]->translate (y
);
504 Score_element::relative_coordinate (Score_element
const*e
, Axis a
) const
506 return dim_cache_
[a
]->relative_coordinate (e
? e
->dim_cache_
[a
] : 0);
510 Score_element::common_refpoint (Score_element
const* s
, Axis a
) const
512 Dimension_cache
*dim
= dim_cache_
[a
]->common_refpoint (s
->dim_cache_
[a
]);
513 return dim
? dim
->element_l () : 0;
517 Score_element::set_empty (Axis a
)
519 dim_cache_
[a
]->callback_l_
=0;
523 Score_element::empty_b (Axis a
)const
525 return !dim_cache_
[a
]->callback_l_
;
529 Score_element::extent (Axis a
) const
531 Dimension_cache
const * d
= dim_cache_
[a
];
533 return d
->get_dim ();
538 Score_element::parent_l (Axis a
) const
540 Dimension_cache
*d
= dim_cache_
[a
]->parent_l_
;
541 return d
? d
->elt_l_
: 0;
545 Score_element::common_refpoint (Link_array
<Score_element
> gs
, Axis a
) const
547 Dimension_cache
* common
= dim_cache_
[a
];
548 for (int i
=0; i
< gs
.size (); i
++)
550 common
= common
->common_refpoint (gs
[i
]->dim_cache_
[a
]);
553 return common
->element_l ();
557 Score_element::name () const
559 return classname (this);
564 Score_element::set_parent (Score_element
*g
, Axis a
)
566 dim_cache_
[a
]->parent_l_
= g
? g
->dim_cache_
[a
]: 0;
570 Score_element::fixup_refpoint ()
572 for (int a
= X_AXIS
; a
< NO_AXES
; a
++)
575 Score_element
* par
= parent_l (ax
);
580 if (par
->line_l () != line_l ())
582 Score_element
* newpar
= par
->find_broken_piece (line_l ());
583 set_parent (newpar
, ax
);
586 if (Item
* i
= dynamic_cast<Item
*> (this))
588 Item
*pari
= dynamic_cast<Item
*> (par
);
592 Direction my_dir
= i
->break_status_dir () ;
593 if (my_dir
!= pari
->break_status_dir())
595 Item
*newpar
= pari
->find_broken_piece (my_dir
);
596 set_parent (newpar
, ax
);
605 /****************************************************
607 ****************************************************/
610 #include "ly-smobs.icc"
612 IMPLEMENT_SMOBS(Score_element
);
613 IMPLEMENT_UNSMOB(Score_element
, element
);
615 Score_element::mark_smob (SCM ses
)
617 Score_element
* s
= SMOB_TO_TYPE (Score_element
, ses
);
618 if (s
->self_scm_
!= ses
)
620 programming_error ("SMOB marking gone awry");
623 return s
->element_property_alist_
;
627 Score_element::print_smob (SCM s
, SCM port
, scm_print_state
*)
629 Score_element
*sc
= (Score_element
*) gh_cdr (s
);
631 scm_puts ("#<Score_element ", port
);
632 scm_puts ((char *)sc
->name (), port
);
635 don't try to print properties, that is too much hassle.
637 scm_puts (" >", port
);
642 Score_element::do_smobify_self ()
647 Score_element::equal_p (SCM a
, SCM b
)
649 return gh_cdr(a
) == gh_cdr(b
) ? SCM_BOOL_T
: SCM_BOOL_F
;
654 Score_element::ly_set_elt_property (SCM elt
, SCM sym
, SCM val
)
656 Score_element
* sc
= unsmob_element (elt
);
658 if (!gh_symbol_p (sym
))
660 error ("Not a symbol");
661 ly_display_scm (sym
);
662 return SCM_UNDEFINED
;
667 sc
->element_property_alist_
= scm_assoc_set_x (sc
->element_property_alist_
, sym
, val
);
671 error ("Not a score element");
672 ly_display_scm (elt
);
675 return SCM_UNDEFINED
;
680 Score_element::ly_get_elt_property (SCM elt
, SCM sym
)
682 Score_element
* sc
= unsmob_element (elt
);
686 SCM s
= scm_assq(sym
, sc
->element_property_alist_
);
691 return SCM_UNDEFINED
;
695 error ("Not a score element");
696 ly_display_scm (elt
);
698 return SCM_UNDEFINED
;
705 scm_make_gsubr ("ly-get-elt-property", 2, 0, 0, (SCM(*)(...))Score_element::ly_get_elt_property
);
706 scm_make_gsubr ("ly-set-elt-property", 3, 0, 0, (SCM(*)(...))Score_element::ly_set_elt_property
);
709 ADD_SCM_INIT_FUNC(scoreelt
, init_functions
);