Make BusSendLevel 1st class citizen (2/2)
[ardour.git] / gtk2_ardour / audio_time_axis.cc
1 /*
2  * Copyright (C) 2005-2006 Nick Mainsbridge <mainsbridge@gmail.com>
3  * Copyright (C) 2005-2006 Sampo Savolainen <v2@iki.fi>
4  * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
5  * Copyright (C) 2005-2007 Doug McLain <doug@nostar.net>
6  * Copyright (C) 2005-2017 Paul Davis <paul@linuxaudiosystems.com>
7  * Copyright (C) 2005 Karsten Wiese <fzuuzf@googlemail.com>
8  * Copyright (C) 2006-2015 David Robillard <d@drobilla.net>
9  * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
10  * Copyright (C) 2013-2014 John Emmas <john@creativepost.co.uk>
11  * Copyright (C) 2014-2019 Robin Gareus <robin@gareus.org>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License along
24  * with this program; if not, write to the Free Software Foundation, Inc.,
25  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26  */
27
28 #include <cstdlib>
29 #include <cmath>
30 #include <cassert>
31
32 #include <algorithm>
33 #include <string>
34 #include <vector>
35
36 #include <sigc++/bind.h>
37
38 #include "pbd/error.h"
39 #include "pbd/stl_delete.h"
40 #include "pbd/memento_command.h"
41
42 #include "gtkmm2ext/gtk_ui.h"
43 #include "gtkmm2ext/utils.h"
44
45 #include "widgets/ardour_button.h"
46
47 #include "ardour/event_type_map.h"
48 #include "ardour/pannable.h"
49 #include "ardour/panner.h"
50 #include "ardour/panner_shell.h"
51
52 #include "audio_time_axis.h"
53 #include "automation_line.h"
54 #include "enums.h"
55 #include "gui_thread.h"
56 #include "automation_time_axis.h"
57 #include "keyboard.h"
58 #include "playlist_selector.h"
59 #include "public_editor.h"
60 #include "audio_region_view.h"
61 #include "audio_streamview.h"
62 #include "ui_config.h"
63 #include "utils.h"
64
65 #include "pbd/i18n.h"
66
67 using namespace std;
68 using namespace ARDOUR;
69 using namespace ArdourWidgets;
70 using namespace ARDOUR_UI_UTILS;
71 using namespace PBD;
72 using namespace Gtk;
73 using namespace Editing;
74
75 AudioTimeAxisView::AudioTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
76         : SessionHandlePtr (sess)
77         , RouteTimeAxisView(ed, sess, canvas)
78 {
79         UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &AudioTimeAxisView::parameter_changed));
80 }
81
82 void
83 AudioTimeAxisView::set_route (boost::shared_ptr<Route> rt)
84 {
85         _route = rt;
86
87         /* RouteTimeAxisView::set_route() sets up some things in the View,
88            so it must be created before RouteTimeAxis::set_route() is
89            called.
90         */
91         _view = new AudioStreamView (*this);
92
93         RouteTimeAxisView::set_route (rt);
94
95         _view->apply_color (gdk_color_to_rgba (color()), StreamView::RegionColor);
96
97         // Make sure things are sane...
98         assert(!is_track() || is_audio_track());
99
100         subplugin_menu.set_name ("ArdourContextMenu");
101
102         ignore_toggle = false;
103
104         if (is_audio_track()) {
105                 controls_ebox.set_name ("AudioTrackControlsBaseUnselected");
106                 time_axis_frame.set_name ("AudioTrackControlsBaseUnselected");
107         } else { // bus
108                 controls_ebox.set_name ("AudioBusControlsBaseUnselected");
109                 time_axis_frame.set_name ("AudioBusControlsBaseUnselected");
110         }
111
112         /* if set_state above didn't create a gain automation child, we need to make one */
113         if (automation_child (GainAutomation) == 0) {
114                 create_automation_child (GainAutomation, false);
115         }
116
117         if (automation_child (TrimAutomation) == 0) {
118                 create_automation_child (TrimAutomation, false);
119         }
120
121         /* if set_state above didn't create a mute automation child, we need to make one */
122         if (automation_child (MuteAutomation) == 0) {
123                 create_automation_child (MuteAutomation, false);
124         }
125
126         if (_route->panner_shell()) {
127                 _route->panner_shell()->Changed.connect (*this, invalidator (*this),
128                                                          boost::bind (&AudioTimeAxisView::ensure_pan_views, this, false), gui_context());
129         }
130
131         /* map current state of the route */
132
133         processors_changed (RouteProcessorChange ());
134         reset_processor_automation_curves ();
135         ensure_pan_views (false);
136         update_control_names ();
137
138         if (is_audio_track()) {
139
140                 /* ask for notifications of any new RegionViews */
141                 _view->RegionViewAdded.connect (sigc::mem_fun(*this, &AudioTimeAxisView::region_view_added));
142
143                 if (!_editor.have_idled()) {
144                         /* first idle will do what we need */
145                 } else {
146                         first_idle ();
147                 }
148
149         } else {
150                 post_construct ();
151         }
152 }
153
154 AudioTimeAxisView::~AudioTimeAxisView ()
155 {
156 }
157
158 void
159 AudioTimeAxisView::first_idle ()
160 {
161         _view->attach ();
162         post_construct ();
163 }
164
165 AudioStreamView*
166 AudioTimeAxisView::audio_view()
167 {
168         return dynamic_cast<AudioStreamView*>(_view);
169 }
170
171 guint32
172 AudioTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
173 {
174         set_gui_property ("visible", true);
175         return TimeAxisView::show_at (y, nth, parent);
176 }
177
178 void
179 AudioTimeAxisView::hide ()
180 {
181         set_gui_property ("visible", false);
182         TimeAxisView::hide ();
183 }
184
185 void
186 AudioTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
187 {
188         if (param.type() == NullAutomation) {
189                 return;
190         }
191
192         AutomationTracks::iterator existing = _automation_tracks.find (param);
193
194         if (existing != _automation_tracks.end()) {
195
196                 /* automation track created because we had existing data for
197                  * the processor, but visibility may need to be controlled
198                  * since it will have been set visible by default.
199                  */
200
201                 existing->second->set_marked_for_display (show);
202
203                 if (!no_redraw) {
204                         request_redraw ();
205                 }
206
207                 return;
208         }
209
210         if (param.type() == GainAutomation) {
211
212                 create_gain_automation_child (param, show);
213
214         } else if (param.type() == BusSendLevel) {
215
216                 create_trim_automation_child (param, show);
217
218         } else if (param.type() == TrimAutomation) {
219
220                 create_trim_automation_child (param, show);
221
222         } else if (param.type() == PanWidthAutomation ||
223                    param.type() == PanElevationAutomation ||
224                    param.type() == PanAzimuthAutomation) {
225
226                 ensure_pan_views (show);
227
228         } else if (param.type() == PluginAutomation) {
229
230                 /* handled elsewhere */
231
232         } else if (param.type() == MuteAutomation) {
233
234                 create_mute_automation_child (param, show);
235
236
237         } else {
238                 error << "AudioTimeAxisView: unknown automation child " << EventTypeMap::instance().to_symbol(param) << endmsg;
239         }
240 }
241
242 void
243 AudioTimeAxisView::show_all_automation (bool apply_to_selection)
244 {
245         if (apply_to_selection) {
246                 _editor.get_selection().tracks.foreach_audio_time_axis (boost::bind (&AudioTimeAxisView::show_all_automation, _1, false));
247         } else {
248
249                 no_redraw = true;
250
251                 RouteTimeAxisView::show_all_automation ();
252
253                 no_redraw = false;
254                 request_redraw ();
255         }
256 }
257
258 void
259 AudioTimeAxisView::show_existing_automation (bool apply_to_selection)
260 {
261         if (apply_to_selection) {
262                 _editor.get_selection().tracks.foreach_audio_time_axis (boost::bind (&AudioTimeAxisView::show_existing_automation, _1, false));
263         } else {
264                 no_redraw = true;
265
266                 RouteTimeAxisView::show_existing_automation ();
267
268                 no_redraw = false;
269
270                 request_redraw ();
271         }
272 }
273
274 void
275 AudioTimeAxisView::hide_all_automation (bool apply_to_selection)
276 {
277         if (apply_to_selection) {
278                 _editor.get_selection().tracks.foreach_audio_time_axis (boost::bind (&AudioTimeAxisView::hide_all_automation, _1, false));
279         } else {
280                 no_redraw = true;
281
282                 RouteTimeAxisView::hide_all_automation();
283
284                 no_redraw = false;
285                 request_redraw ();
286         }
287 }
288
289 void
290 AudioTimeAxisView::route_active_changed ()
291 {
292         update_control_names ();
293 }
294
295 void
296 AudioTimeAxisView::parameter_changed (string const & p)
297 {
298         if (p == "vertical-region-gap") {
299                 _view->update_contents_height ();
300         }
301 }
302
303
304 /**
305  *    Set up the names of the controls so that they are coloured
306  *    correctly depending on whether this route is inactive or
307  *    selected.
308  */
309
310 void
311 AudioTimeAxisView::update_control_names ()
312 {
313         if (is_audio_track()) {
314                 if (_route->active()) {
315                         controls_base_selected_name = "AudioTrackControlsBaseSelected";
316                         controls_base_unselected_name = "AudioTrackControlsBaseUnselected";
317                 } else {
318                         controls_base_selected_name = "AudioTrackControlsBaseInactiveSelected";
319                         controls_base_unselected_name = "AudioTrackControlsBaseInactiveUnselected";
320                 }
321         } else {
322                 if (_route->active()) {
323                         controls_base_selected_name = "BusControlsBaseSelected";
324                         controls_base_unselected_name = "BusControlsBaseUnselected";
325                 } else {
326                         controls_base_selected_name = "BusControlsBaseInactiveSelected";
327                         controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
328                 }
329         }
330
331         if (selected()) {
332                 controls_ebox.set_name (controls_base_selected_name);
333                 time_axis_frame.set_name (controls_base_selected_name);
334         } else {
335                 controls_ebox.set_name (controls_base_unselected_name);
336                 time_axis_frame.set_name (controls_base_unselected_name);
337         }
338 }
339
340 void
341 AudioTimeAxisView::build_automation_action_menu (bool for_selection)
342 {
343         RouteTimeAxisView::build_automation_action_menu (for_selection);
344 }