Drop references held by any GUI Lua script after execution
[ardour.git] / gtk2_ardour / tempo_curve.cc
1 /*
2  * Copyright (C) 2016-2017 Nick Mainsbridge <mainsbridge@gmail.com>
3  * Copyright (C) 2016-2017 Paul Davis <paul@linuxaudiosystems.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 #include <sigc++/bind.h>
21 #include "ardour/tempo.h"
22
23 #include "canvas/rectangle.h"
24 #include "canvas/container.h"
25 #include "canvas/curve.h"
26 #include "canvas/canvas.h"
27 #include "canvas/debug.h"
28
29 #include "ui_config.h"
30
31 #include "tempo_curve.h"
32 #include "public_editor.h"
33 #include "utils.h"
34 #include "rgb_macros.h"
35
36 #include <gtkmm2ext/utils.h>
37
38 #include "pbd/i18n.h"
39
40 PBD::Signal1<void,TempoCurve*> TempoCurve::CatchDeletion;
41
42 static double curve_height = 13.0;
43
44 void TempoCurve::setup_sizes(const double timebar_height)
45 {
46         curve_height = floor (timebar_height) - 2.5;
47 }
48 /* ignores Tempo note type - only note_types_per_minute is potentially curved */
49 TempoCurve::TempoCurve (PublicEditor& ed, ArdourCanvas::Container& parent, guint32 rgba, ARDOUR::TempoSection& temp, samplepos_t sample, bool handle_events)
50
51         : editor (ed)
52         , _parent (&parent)
53         , _curve (0)
54         , _shown (false)
55         , _color (rgba)
56         , _min_tempo (temp.note_types_per_minute())
57         , _max_tempo (temp.note_types_per_minute())
58         , _tempo (temp)
59         , _start_text (0)
60         , _end_text (0)
61 {
62         sample_position = sample;
63         unit_position = editor.sample_to_pixel (sample);
64
65         group = new ArdourCanvas::Container (&parent, ArdourCanvas::Duple (unit_position, 1));
66 #ifdef CANVAS_DEBUG
67         group->name = string_compose ("TempoCurve::group for %1", _tempo.note_types_per_minute());
68 #endif
69
70         _curve = new ArdourCanvas::FramedCurve (group);
71 #ifdef CANVAS_DEBUG
72         _curve->name = string_compose ("TempoCurve::curve for %1", _tempo.note_types_per_minute());
73 #endif
74         _curve->set_points_per_segment (3);
75         points = new ArdourCanvas::Points ();
76         _curve->set (*points);
77
78         _start_text = new ArdourCanvas::Text (group);
79         _end_text = new ArdourCanvas::Text (group);
80         _start_text->set_font_description (ARDOUR_UI_UTILS::get_font_for_style (N_("MarkerText")));
81         _end_text->set_font_description (ARDOUR_UI_UTILS::get_font_for_style (N_("MarkerText")));
82         _start_text->set_color (RGBA_TO_UINT (255,255,255,255));
83         _end_text->set_color (RGBA_TO_UINT (255,255,255,255));
84         char buf[10];
85         snprintf (buf, sizeof (buf), "%.3f/%.0f", _tempo.note_types_per_minute(), _tempo.note_type());
86         _start_text->set (buf);
87         snprintf (buf, sizeof (buf), "%.3f", _tempo.end_note_types_per_minute());
88         _end_text->set (buf);
89
90         set_color_rgba (rgba);
91
92         editor.ZoomChanged.connect (sigc::mem_fun (*this, &TempoCurve::reposition));
93
94         /* events will be handled by both the group and the mark itself, so
95          * make sure they can both be used to lookup this object.
96          */
97
98         _curve->set_data ("tempo curve", this);
99
100         if (handle_events) {
101                 //group->Event.connect (sigc::bind (sigc::mem_fun (editor, &PublicEditor::canvas_marker_event), group, this));
102         }
103
104         group->Event.connect (sigc::bind (sigc::mem_fun (editor, &PublicEditor::canvas_tempo_curve_event), _curve, this));
105
106 }
107
108 TempoCurve::~TempoCurve ()
109 {
110         CatchDeletion (this); /* EMIT SIGNAL */
111
112         /* destroying the parent group destroys its contents, namely any polygons etc. that we added */
113         delete group;
114 }
115
116 void TempoCurve::reparent(ArdourCanvas::Container & parent)
117 {
118         group->reparent (&parent);
119         _parent = &parent;
120 }
121
122 void
123 TempoCurve::canvas_height_set (double h)
124 {
125         _canvas_height = h;
126 }
127
128 ArdourCanvas::Item&
129 TempoCurve::the_item() const
130 {
131         return *group;
132 }
133
134 void
135 TempoCurve::set_position (samplepos_t sample, samplepos_t end_sample)
136 {
137         unit_position = editor.sample_to_pixel (sample);
138         group->set_x_position (unit_position);
139         sample_position = sample;
140         _end_sample = end_sample;
141
142         points->clear();
143         points = new ArdourCanvas::Points ();
144
145         points->push_back (ArdourCanvas::Duple (0.0, curve_height));
146
147         if (sample >= end_sample) {
148                 /* shouldn't happen but ..*/
149                 const double tempo_at = _tempo.note_types_per_minute();
150                 const double y_pos =  (curve_height) - (((tempo_at - _min_tempo) / (_max_tempo - _min_tempo)) * curve_height);
151
152                 points->push_back (ArdourCanvas::Duple (0.0, y_pos));
153                 points->push_back (ArdourCanvas::Duple (1.0, y_pos));
154
155         } else if (_tempo.type() == ARDOUR::TempoSection::Constant || _tempo.c() == 0.0) {
156                 const double tempo_at = _tempo.note_types_per_minute();
157                 const double y_pos =  (curve_height) - (((tempo_at - _min_tempo) / (_max_tempo - _min_tempo)) * curve_height);
158
159                 points->push_back (ArdourCanvas::Duple (0.0, y_pos));
160                 points->push_back (ArdourCanvas::Duple (editor.sample_to_pixel (end_sample - sample), y_pos));
161         } else {
162
163                 const samplepos_t sample_step = max ((end_sample - sample) / 5, (samplepos_t) 1);
164                 samplepos_t current_sample = sample;
165
166                 while (current_sample < end_sample) {
167                         const double tempo_at = _tempo.tempo_at_minute (_tempo.minute_at_sample (current_sample)).note_types_per_minute();
168                         const double y_pos = max ((curve_height) - (((tempo_at - _min_tempo) / (_max_tempo - _min_tempo)) * curve_height), 0.0);
169
170                         points->push_back (ArdourCanvas::Duple (editor.sample_to_pixel (current_sample - sample), min (y_pos, curve_height)));
171
172                         current_sample += sample_step;
173                 }
174
175                 const double tempo_at = _tempo.tempo_at_minute (_tempo.minute_at_sample (end_sample)).note_types_per_minute();
176                 const double y_pos = max ((curve_height) - (((tempo_at - _min_tempo) / (_max_tempo - _min_tempo)) * curve_height), 0.0);
177
178                 points->push_back (ArdourCanvas::Duple (editor.sample_to_pixel (end_sample - sample), min (y_pos, curve_height)));
179         }
180
181         _curve->set (*points);
182
183         char buf[10];
184         snprintf (buf, sizeof (buf), "%.3f/%.0f", _tempo.note_types_per_minute(), _tempo.note_type());
185         _start_text->set (buf);
186         snprintf (buf, sizeof (buf), "%.3f", _tempo.end_note_types_per_minute());
187         _end_text->set (buf);
188
189         _start_text->set_position (ArdourCanvas::Duple (10, .5 ));
190         _end_text->set_position (ArdourCanvas::Duple (editor.sample_to_pixel (end_sample - sample) - _end_text->text_width() - 10, .5 ));
191
192         if (_end_text->text_width() + _start_text->text_width() + 20 > editor.sample_to_pixel (end_sample - sample)) {
193                 _start_text->hide();
194                 _end_text->hide();
195         } else {
196                 _start_text->show();
197                 _end_text->show();
198         }
199 }
200
201 void
202 TempoCurve::reposition ()
203 {
204         set_position (sample_position, _end_sample);
205 }
206
207 void
208 TempoCurve::show ()
209 {
210         _shown = true;
211
212         group->show ();
213 }
214
215 void
216 TempoCurve::hide ()
217 {
218         _shown = false;
219
220         group->hide ();
221 }
222
223 void
224 TempoCurve::set_color_rgba (uint32_t c)
225 {
226         _color = c;
227         _curve->set_fill_color (UIConfiguration::instance().color_mod (_color, "selection rect"));
228         _curve->set_outline_color (_color);
229
230 }