1 /*
2  * Copyright (C) 2017 Robin Gareus <robin@gareus.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 #include <gtkmm/menu.h>
20 #include <gtkmm/menuitem.h>
21 
22 #include "ardour/parameter_descriptor.h"
23 #include "ardour/parameter_types.h"
24 #include "ardour/stripable.h"
25 
26 #include "public_editor.h"
27 #include "stripable_time_axis.h"
28 #include "automation_line.h"
29 
30 #include "pbd/i18n.h"
31 
32 using namespace PBD;
33 using namespace ARDOUR;
34 using namespace Gtk;
35 
StripableTimeAxisView(PublicEditor & ed,ARDOUR::Session * s,ArdourCanvas::Canvas & canvas)36 StripableTimeAxisView::StripableTimeAxisView (PublicEditor& ed, ARDOUR::Session* s, ArdourCanvas::Canvas& canvas)
37 	: TimeAxisView(s, ed, (TimeAxisView*) 0, canvas)
38 	, gain_automation_item(NULL)
39 	, trim_automation_item(NULL)
40 	, mute_automation_item(NULL)
41 	, parent_canvas (canvas)
42 	, no_redraw (false)
43 {
44 }
45 
~StripableTimeAxisView()46 StripableTimeAxisView::~StripableTimeAxisView ()
47 {
48 }
49 
50 void
set_stripable(boost::shared_ptr<ARDOUR::Stripable> s)51 StripableTimeAxisView::set_stripable (boost::shared_ptr<ARDOUR::Stripable> s)
52 {
53 	_stripable = s;
54 	_editor.ZoomChanged.connect (sigc::mem_fun(*this, &StripableTimeAxisView::reset_samples_per_pixel));
55 }
56 
57 void
reset_samples_per_pixel()58 StripableTimeAxisView::reset_samples_per_pixel ()
59 {
60 	set_samples_per_pixel (_editor.get_current_zoom());
61 }
62 
63 void
set_samples_per_pixel(double fpp)64 StripableTimeAxisView::set_samples_per_pixel (double fpp)
65 {
66 	TimeAxisView::set_samples_per_pixel (fpp);
67 }
68 
69 
70 void
add_automation_child(Evoral::Parameter param,boost::shared_ptr<AutomationTimeAxisView> track,bool show)71 StripableTimeAxisView::add_automation_child (Evoral::Parameter param, boost::shared_ptr<AutomationTimeAxisView> track, bool show)
72 {
73 	using namespace Menu_Helpers;
74 
75 	add_child (track);
76 
77 	if (param.type() != PluginAutomation) {
78 		/* PluginAutomation is handled by
79 		 * - RouteTimeAxisView::processor_automation_track_hidden
80 		 * - RouteTimeAxisView::processor_automation
81 		 */
82 		track->Hiding.connect (sigc::bind (sigc::mem_fun (*this, &StripableTimeAxisView::automation_track_hidden), param));
83 		_automation_tracks[param] = track;
84 	}
85 
86 	/* existing state overrides "show" argument */
87 	bool visible;
88 	if (track->get_gui_property ("visible", visible)) {
89 		show = visible;
90 	}
91 
92 	/* this might or might not change the visibility status, so don't rely on it */
93 	track->set_marked_for_display (show);
94 
95 	if (show && !no_redraw) {
96 		request_redraw ();
97 	}
98 }
99 
100 void
update_gain_track_visibility()101 StripableTimeAxisView::update_gain_track_visibility ()
102 {
103 	bool const showit = gain_automation_item->get_active();
104 
105 	bool visible;
106 	if (gain_track->get_gui_property ("visible", visible) && visible != showit) {
107 		gain_track->set_marked_for_display (showit);
108 
109 		/* now trigger a redisplay */
110 
111 		if (!no_redraw) {
112 			 _stripable->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
113 		}
114 	}
115 }
116 
117 void
update_trim_track_visibility()118 StripableTimeAxisView::update_trim_track_visibility ()
119 {
120 	bool const showit = trim_automation_item->get_active();
121 
122 	bool visible;
123 	if (trim_track->get_gui_property ("visible", visible) && visible != showit) {
124 		trim_track->set_marked_for_display (showit);
125 
126 		/* now trigger a redisplay */
127 
128 		if (!no_redraw) {
129 			 _stripable->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
130 		}
131 	}
132 }
133 
134 void
update_mute_track_visibility()135 StripableTimeAxisView::update_mute_track_visibility ()
136 {
137 	bool const showit = mute_automation_item->get_active();
138 
139 	bool visible;
140 	if (mute_track->get_gui_property ("visible", visible) && visible != showit) {
141 		mute_track->set_marked_for_display (showit);
142 
143 		/* now trigger a redisplay */
144 
145 		if (!no_redraw) {
146 			 _stripable->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
147 		}
148 	}
149 }
150 
151 Gtk::CheckMenuItem*
automation_child_menu_item(Evoral::Parameter param)152 StripableTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
153 {
154 	assert (param.type() != PluginAutomation);
155 	ParameterMenuMap::iterator i = _main_automation_menu_map.find (param);
156 	if (i != _main_automation_menu_map.end()) {
157 		return i->second;
158 	}
159 
160 	return 0;
161 }
162 
163 void
automation_track_hidden(Evoral::Parameter param)164 StripableTimeAxisView::automation_track_hidden (Evoral::Parameter param)
165 {
166 	boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
167 
168 	if (!track) {
169 		return;
170 	}
171 
172 	Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
173 
174 	if (menu && !_hidden && menu->get_active()) {
175 		menu->set_active (false);
176 	}
177 
178 	if (_stripable && !no_redraw) {
179 		request_redraw ();
180 	}
181 }
182 
183 boost::shared_ptr<AutomationTimeAxisView>
automation_child(Evoral::Parameter param,PBD::ID)184 StripableTimeAxisView::automation_child(Evoral::Parameter param, PBD::ID)
185 {
186 	assert (param.type() != PluginAutomation);
187 	AutomationTracks::iterator i = _automation_tracks.find(param);
188 	if (i != _automation_tracks.end()) {
189 		return i->second;
190 	} else {
191 		return boost::shared_ptr<AutomationTimeAxisView>();
192 	}
193 }
194 
195 boost::shared_ptr<AutomationLine>
automation_child_by_alist_id(PBD::ID alist_id)196 StripableTimeAxisView::automation_child_by_alist_id (PBD::ID alist_id)
197 {
198 	for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
199 		boost::shared_ptr<AutomationTimeAxisView> atv (i->second);
200 		std::list<boost::shared_ptr<AutomationLine> > lines = atv->lines();
201 		for (std::list<boost::shared_ptr<AutomationLine> >::const_iterator li = lines.begin(); li != lines.end(); ++li) {
202 			if ((*li)->the_list()->id() == alist_id) {
203 				return *li;
204 			}
205 		}
206 	}
207 	return boost::shared_ptr<AutomationLine> ();
208 }
209 
210 void
request_redraw()211 StripableTimeAxisView::request_redraw ()
212 {
213 	if (_stripable) {
214 		_stripable->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
215 	}
216 }
217 
218 void
show_all_automation(bool apply_to_selection)219 StripableTimeAxisView::show_all_automation (bool apply_to_selection)
220 {
221 	/* this protected member should not be called directly */
222 	assert (!apply_to_selection);
223 	assert (no_redraw);
224 
225 	for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
226 		i->second->set_marked_for_display (true);
227 
228 		Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
229 
230 		if (menu) {
231 			menu->set_active(true);
232 		}
233 	}
234 }
235 
236 void
show_existing_automation(bool apply_to_selection)237 StripableTimeAxisView::show_existing_automation (bool apply_to_selection)
238 {
239 	/* this protected member should not be called directly */
240 	assert (!apply_to_selection);
241 	assert (no_redraw);
242 
243 	for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
244 		if (i->second->has_automation()) {
245 			i->second->set_marked_for_display (true);
246 
247 			Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
248 			if (menu) {
249 				menu->set_active(true);
250 			}
251 		}
252 	}
253 }
254 
255 void
hide_all_automation(bool apply_to_selection)256 StripableTimeAxisView::hide_all_automation (bool apply_to_selection)
257 {
258 	/* this protected member should not be called directly */
259 	assert (!apply_to_selection);
260 	assert (no_redraw);
261 
262 	for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
263 		i->second->set_marked_for_display (false);
264 
265 		Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
266 
267 		if (menu) {
268 			menu->set_active (false);
269 		}
270 	}
271 }
272