X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fstencil.cc;h=7be0b5f8af63b1562984da11a5fea9602552aa6c;hb=3fd5eabae695f90c0cea826bcea33d54a242b01b;hp=833d5be0fd55cb12b732b0725d17738196d5b75f;hpb=a8ac663bf03c250ea84bc499437ffc8d529fc047;p=lilypond.git diff --git a/lily/stencil.cc b/lily/stencil.cc index 833d5be0fd..7be0b5f8af 100644 --- a/lily/stencil.cc +++ b/lily/stencil.cc @@ -1,7 +1,7 @@ /* This file is part of LilyPond, the GNU music typesetter. - Copyright (C) 1997--2012 Han-Wen Nienhuys + Copyright (C) 1997--2014 Han-Wen Nienhuys LilyPond is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,7 +25,6 @@ #include "string-convert.hh" #include "warn.hh" -#include "ly-smobs.icc" Stencil::Stencil () { @@ -39,24 +38,13 @@ Stencil::Stencil (Box b, SCM func) dim_ = b; } -int -Stencil::print_smob (SCM, SCM port, scm_print_state *) -{ - scm_puts ("#", port); - return 1; -} - SCM -Stencil::mark_smob (SCM smob) +Stencil::mark_smob () { - Stencil *s = (Stencil *) SCM_CELL_WORD_1 (smob); - return s->expr_; + return expr_; } -IMPLEMENT_SIMPLE_SMOBS (Stencil); -IMPLEMENT_TYPE_P (Stencil, "ly:stencil?"); -IMPLEMENT_DEFAULT_EQUAL_P (Stencil); +const char Stencil::type_p_name_[] = "ly:stencil?"; Interval Stencil::extent (Axis a) const @@ -71,6 +59,12 @@ Stencil::is_empty () const || dim_.is_empty ()); } +bool +Stencil::is_empty (Axis a) const +{ + return dim_.is_empty (a); +} + SCM Stencil::expr () const { @@ -176,8 +170,7 @@ Stencil::translate (Offset o) expr_ = scm_list_n (ly_symbol2scm ("translate-stencil"), ly_offset2scm (o), expr_, SCM_UNDEFINED); - if (!is_empty ()) - dim_.translate (o); + dim_.translate (o); } void @@ -245,7 +238,7 @@ Stencil::set_empty (bool e) void Stencil::align_to (Axis a, Real x) { - if (is_empty ()) + if (is_empty (a)) return; Interval i (extent (a)); @@ -253,28 +246,155 @@ Stencil::align_to (Axis a, Real x) } /* See scheme Function. */ + +// Any stencil that is empty in the orthogonal axis is spacing. +// Spacing is not subjected to the max (0) rule and can thus be +// negative. + void Stencil::add_at_edge (Axis a, Direction d, Stencil const &s, Real padding) { - Interval my_extent = dim_[a]; - Interval i (s.extent (a)); - Real his_extent; - if (i.is_empty ()) + // Material that is empty in the axis of reference has only limited + // usefulness for combining. We still retain as much information as + // available since there may be uses like setting page links or + // background color or watermarks, and off-axis extents. + + if (is_empty (a)) { - programming_error ("Stencil::add_at_edge: adding empty stencil."); - his_extent = 0.0; + add_stencil (s); + return; } - else - his_extent = i[-d]; - Real offset = (my_extent.is_empty () ? 0.0 : my_extent[d] - his_extent) - + d * padding; + Interval first_extent = extent (a); + + if (s.is_empty (a)) + { + Stencil toadd (s); + // translation does not affect axis-empty extent box. + toadd.translate_axis (first_extent[d], a); + add_stencil (toadd); + return; + } + + Interval next_extent = s.extent (a); + + bool first_is_spacing = is_empty (other_axis (a)); + bool next_is_spacing = s.is_empty (other_axis (a)); + + Real offset = first_extent[d] - next_extent[-d]; + + if (!(first_is_spacing || next_is_spacing)) + { + offset += d * padding; + } Stencil toadd (s); toadd.translate_axis (offset, a); add_stencil (toadd); } +// Stencil::stack is mainly used for assembling lines or columns +// of stencils. For the most common case of adding at the right, the +// reference point of the added stencil is usually placed at the right +// edge of the current one, unless the added stencil has a negative +// left extent in which case its left edge is placed at the right edge +// of the current one. +// +// Spacing is special in that it is applied without padding. Spacing +// at the right edge shifts the right edge accordingly. +// +// For spacing at the left edge, there are several approaches. In +// order to get to predictable behavior, we want to have at least a +// continuous approach. An obvious idea is to do a "translate" by the +// appropriate amount. Doing that while retaining the nominal left +// edge seems like the most straightforward way. + +void +Stencil::stack (Axis a, Direction d, Stencil const &s, Real padding, Real mindist) +{ + // Material that is empty in the axis of reference can't be sensibly + // stacked. We just revert to add_at_edge behavior then. + + if (is_empty (a)) + { + Stencil toadd (s); + toadd.add_stencil (*this); + expr_ = toadd.expr (); + dim_ = toadd.extent_box (); + return; + } + + Interval first_extent = extent (a); + + if (s.is_empty (a)) + { + Stencil toadd (s); + toadd.translate_axis (first_extent[d], a); + toadd.add_stencil (*this); + expr_ = toadd.expr (); + dim_ = toadd.extent_box (); + return; + } + + Interval next_extent = s.extent (a); + + // It is somewhat tedious to special-case all spacing, but it turns + // out that not doing so makes it astonishingly hard to make the + // code do the correct thing. + + // If first is spacing, we translate second accordingly without + // letting this affect its backward edge. + if (is_empty (other_axis (a))) + { + Stencil toadd (s); + Real offset = d * first_extent.delta (); + toadd.translate_axis (offset, a); + toadd.add_stencil (*this); + expr_ = toadd.expr (); + dim_ = toadd.extent_box (); + dim_[a][-d] = next_extent[-d]; + dim_[a][d] = next_extent[d] + offset; + return; + } + + // If next is spacing, similar action: + if (s.is_empty (other_axis (a))) + { + Stencil toadd (s); + Real offset = first_extent [d]; + toadd.translate_axis (offset, a); + toadd.add_stencil (*this); + expr_ = toadd.expr (); + dim_ = toadd.extent_box (); + dim_[a][-d] = first_extent[-d]; + dim_[a][d] = first_extent[d] + d * next_extent.delta (); + return; + } + + + Real offset = first_extent[d]; + + // If the added stencil has a backwardly protruding edge, we make + // room for it when combining. + + if (d * next_extent [-d] < 0) + offset -= next_extent [-d]; + + offset += d * padding; + + if (offset * d < mindist) + offset = d * mindist; + + Stencil toadd (s); + toadd.translate_axis (offset, a); + toadd.add_stencil (*this); + expr_ = toadd.expr (); + dim_ = toadd.extent_box (); + dim_[a][-d] = first_extent [-d]; + dim_[a][d] = next_extent [d] + offset; +} + + Stencil Stencil::in_color (Real r, Real g, Real b) const {