1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3 
4   Copyright (C) 2004--2021 Han-Wen Nienhuys <hanwen@xs4all.nl>
5 
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10 
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15 
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "pointer-group-interface.hh"
21 #include "spanner.hh"
22 #include "engraver.hh"
23 #include "staff-symbol.hh"
24 
25 #include "translator.icc"
26 
27 using std::vector;
28 
29 class Ledger_line_engraver : public Engraver
30 {
31   Spanner *span_;
32   vector<Grob *> ledgered_grobs_;
33 
34 public:
35   TRANSLATOR_DECLARATIONS (Ledger_line_engraver);
36 
37 protected:
38   void finalize () override;
39   void process_music ();
40 
41   void acknowledge_ledgered (Grob_info);
42   void acknowledge_staff_symbol (Grob_info_t<Spanner>);
43 
44   void start_spanner ();
45   void stop_spanner ();
46   void stop_translation_timestep ();
47 };
48 
Ledger_line_engraver(Context * c)49 Ledger_line_engraver::Ledger_line_engraver (Context *c)
50   : Engraver (c)
51 {
52   span_ = 0;
53 }
54 
55 void
start_spanner()56 Ledger_line_engraver::start_spanner ()
57 {
58   assert (!span_);
59 
60   span_ = make_spanner ("LedgerLineSpanner", SCM_EOL);
61   auto *col = unsmob<Grob> (get_property (this, "currentCommandColumn"));
62   span_->set_bound (LEFT, col);
63 }
64 
65 void
stop_translation_timestep()66 Ledger_line_engraver::stop_translation_timestep ()
67 {
68   if (span_)
69     {
70       for (vsize i = 0; i < ledgered_grobs_.size (); i++)
71         {
72           if (!from_scm<bool> (get_property (ledgered_grobs_[i], "no-ledgers")))
73             Pointer_group_interface::add_grob (span_,
74                                                ly_symbol2scm ("note-heads"),
75                                                ledgered_grobs_[i]);
76         }
77     }
78 
79   ledgered_grobs_.clear ();
80 }
81 
82 void
process_music()83 Ledger_line_engraver::process_music ()
84 {
85   /*
86     Need to do this, otherwise the first note might miss ledgers.
87   */
88   if (!span_)
89     start_spanner ();
90 }
91 
92 void
finalize()93 Ledger_line_engraver::finalize ()
94 {
95   stop_spanner ();
96 }
97 
98 void
stop_spanner()99 Ledger_line_engraver::stop_spanner ()
100 {
101   if (span_)
102     {
103       auto *col = unsmob<Grob> (get_property (this, "currentCommandColumn"));
104       span_->set_bound (RIGHT, col);
105       span_ = 0;
106     }
107 }
108 
109 void
acknowledge_staff_symbol(Grob_info_t<Spanner> s)110 Ledger_line_engraver::acknowledge_staff_symbol (Grob_info_t<Spanner> s)
111 {
112   if (!span_ || (span_->get_bound (LEFT) != s.grob ()->get_bound (LEFT)))
113     {
114       stop_spanner ();
115       start_spanner ();
116     }
117 }
118 
119 void
acknowledge_ledgered(Grob_info s)120 Ledger_line_engraver::acknowledge_ledgered (Grob_info s)
121 {
122   ledgered_grobs_.push_back (s.grob ());
123 }
124 
125 void
boot()126 Ledger_line_engraver::boot ()
127 {
128   ADD_ACKNOWLEDGER (Ledger_line_engraver, ledgered);
129   ADD_ACKNOWLEDGER (Ledger_line_engraver, staff_symbol);
130 }
131 
132 ADD_TRANSLATOR (Ledger_line_engraver,
133                 /* doc */
134                 "Create the spanner to draw ledger lines, and notices"
135                 " objects that need ledger lines.",
136 
137                 /* create */
138                 "LedgerLineSpanner ",
139 
140                 /* read */
141                 "",
142 
143                 /* write */
144                 ""
145                );
146