the return of VST support
[ardour.git] / gtk2_ardour / editor_route_list.cc
1 /*
2     Copyright (C) 2000 Paul Davis 
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
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18     $Id$
19 */
20
21 #include <algorithm>
22 #include <cstdlib>
23 #include <cmath>
24
25 #include "editor.h"
26 #include "ardour_ui.h"
27 #include "audio_time_axis.h"
28 #include "mixer_strip.h"
29 #include "gui_thread.h"
30
31 #include <ardour/route.h>
32 #include <ardour/audio_track.h>
33
34 #include "i18n.h"
35
36 using namespace sigc;
37 using namespace ARDOUR;
38 using namespace PBD;
39 using namespace Gtk;
40
41 void
42 Editor::handle_new_route_p (Route* route)
43 {
44         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_new_route_p), route));
45         handle_new_route (*route);
46 }
47
48 void
49 Editor::handle_new_route (Route& route)
50 {
51         TimeAxisView *tv;
52         AudioTimeAxisView *atv;
53         TreeModel::Row parent;
54         TreeModel::Row row;
55
56         if (route.hidden()) {
57                 return;
58         }
59         
60         tv = new AudioTimeAxisView (*this, *session, route, track_canvas);
61
62 #if 0
63         if (route_display_model->children().size() == 0) {
64                 
65                 /* set up basic entries */
66
67                 TreeModel::Row row;
68                 
69                 row = *(route_display_model->append());  // path = "0"
70                 row[route_display_columns.text] = _("Busses");
71                 row[route_display_columns.tv] = 0;
72                 row = *(route_display_model->append());  // path = "1"
73                 row[route_display_columns.text] = _("Tracks");
74                 row[route_display_columns.tv] = 0;
75
76         }
77
78         if (dynamic_cast<AudioTrack*>(&route) != 0) {
79                 TreeModel::iterator iter = route_display_model->get_iter ("1");  // audio tracks 
80                 parent = *iter;
81         } else {
82                 TreeModel::iterator iter = route_display_model->get_iter ("0");  // busses
83                 parent = *iter;
84         }
85         
86
87         row = *(route_display_model->append (parent.children()));
88 #else 
89         row = *(route_display_model->append ());
90 #endif
91
92         row[route_display_columns.text] = route.name();
93         row[route_display_columns.visible] = tv->marked_for_display();
94         row[route_display_columns.tv] = tv;
95         
96         track_views.push_back (tv);
97
98         ignore_route_list_reorder = true;
99         
100         if ((atv = dynamic_cast<AudioTimeAxisView*> (tv)) != 0) {
101                 /* added a new fresh one at the end */
102                 if (atv->route().order_key(N_("editor")) == -1) {
103                         atv->route().set_order_key (N_("editor"), route_display_model->children().size()-1);
104                 }
105         }
106
107         ignore_route_list_reorder = false;
108         
109         route.gui_changed.connect (mem_fun(*this, &Editor::handle_gui_changes));
110
111         tv->GoingAway.connect (bind (mem_fun(*this, &Editor::remove_route), tv));
112         
113         editor_mixer_button.set_sensitive(true);
114 }
115
116 void
117 Editor::handle_gui_changes (const string & what, void *src)
118 {
119         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_gui_changes), what, src));
120         
121         if (what == "track_height") {
122                 redisplay_route_list ();
123         }
124 }
125
126
127 void
128 Editor::remove_route (TimeAxisView *tv)
129 {
130         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::remove_route), tv));
131
132         
133         TrackViewList::iterator i;
134         TreeModel::Children rows = route_display_model->children();
135         TreeModel::Children::iterator ri;
136
137         if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
138                 track_views.erase (i);
139         }
140
141         for (ri = rows.begin(); ri != rows.end(); ++ri) {
142                 if ((*ri)[route_display_columns.tv] == tv) {
143                         route_display_model->erase (ri);
144                         break;
145                 }
146         }
147         /* since the editor mixer goes away when you remove a route, set the
148          * button to inacttive 
149          */
150         editor_mixer_button.set_active(false);
151
152         /* and disable if all tracks and/or routes are gone */
153
154         if (track_views.size() == 0) {
155                 editor_mixer_button.set_sensitive(false);
156         }
157 }
158
159 void
160 Editor::route_name_changed (TimeAxisView *tv)
161 {
162         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::route_name_changed), tv));
163         
164         TreeModel::Children rows = route_display_model->children();
165         TreeModel::Children::iterator i;
166         
167         for (i = rows.begin(); i != rows.end(); ++i) {
168                 if ((*i)[route_display_columns.tv] == tv) {
169                         (*i)[route_display_columns.text] = tv->name();
170                         break;
171                 }
172         } 
173
174 }
175
176 void
177 Editor::hide_track_in_display (TimeAxisView& tv)
178 {
179         TreeModel::Children rows = route_display_model->children();
180         TreeModel::Children::iterator i;
181
182         for (i = rows.begin(); i != rows.end(); ++i) {
183                 if ((*i)[route_display_columns.tv] == &tv) { 
184                         (*i)[route_display_columns.visible] = false;
185                         break;
186                 }
187         }
188
189         AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
190
191         if (atv && current_mixer_strip && &(atv->route()) == &(current_mixer_strip->route())) {
192                 // this will hide the mixer strip
193                 set_selected_mixer_strip (tv);
194         }
195 }
196
197 void
198 Editor::show_track_in_display (TimeAxisView& tv)
199 {
200         TreeModel::Children rows = route_display_model->children();
201         TreeModel::Children::iterator i;
202         
203         for (i = rows.begin(); i != rows.end(); ++i) {
204                 if ((*i)[route_display_columns.tv] == &tv) { 
205                         (*i)[route_display_columns.visible] = true;
206                         tv.set_marked_for_display (true);
207                         break;
208                 }
209         }
210 }
211
212 void
213 Editor::route_list_reordered (const TreeModel::Path& path,const TreeModel::iterator& iter,int* what)
214 {
215         redisplay_route_list ();
216 }
217
218 void
219 Editor::redisplay_route_list ()
220 {
221         TreeModel::Children rows = route_display_model->children();
222         TreeModel::Children::iterator i;
223         uint32_t position;
224         uint32_t order;
225         int n;
226         
227         if (no_route_list_redisplay) {
228                 return;
229         }
230
231         for (n = 0, order = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
232                 TimeAxisView *tv = (*i)[route_display_columns.tv];
233                 AudioTimeAxisView* at; 
234
235                 if (tv == 0) {
236                         // just a "title" row
237                         continue;
238                 }
239
240                 if (!ignore_route_list_reorder) {
241                         
242                         /* this reorder is caused by user action, so reassign sort order keys
243                            to tracks.
244                         */
245                         
246                         if ((at = dynamic_cast<AudioTimeAxisView*> (tv)) != 0) {
247                                 at->route().set_order_key (N_("editor"), order);
248                                 ++order;
249                         }
250                 }
251
252                 bool visible = (*i)[route_display_columns.visible];
253
254                 if (visible) {
255                         tv->set_marked_for_display (true);
256                         position += tv->show_at (position, n, &edit_controls_vbox);
257                         position += track_spacing;
258                 } else {
259                         tv->hide ();
260                 }
261                 
262                 n++;
263                 
264         }
265
266         reset_scrolling_region ();
267 }
268
269 void
270 Editor::hide_all_tracks (bool with_select)
271 {
272         TreeModel::Children rows = route_display_model->children();
273         TreeModel::Children::iterator i;
274
275         no_route_list_redisplay = true;
276
277         for (i = rows.begin(); i != rows.end(); ++i) {
278                 
279                 TreeModel::Row row = (*i);
280                 TimeAxisView *tv = row[route_display_columns.tv];
281
282                 if (tv == 0) {
283                         continue;
284                 }
285                 
286                 row[route_display_columns.visible] = false;
287         }
288
289         no_route_list_redisplay = false;
290         redisplay_route_list ();
291
292         /* XXX this seems like a hack and half, but its not clear where to put this
293            otherwise.
294         */
295
296         reset_scrolling_region ();
297 }
298
299 void
300 Editor::build_route_list_menu ()
301 {
302         using namespace Menu_Helpers;
303         using namespace Gtk;
304
305         route_list_menu = new Menu;
306         
307         MenuList& items = route_list_menu->items();
308         route_list_menu->set_name ("ArdourContextMenu");
309
310         items.push_back (MenuElem (_("Show All"), mem_fun(*this, &Editor::show_all_routes)));
311         items.push_back (MenuElem (_("Hide All"), mem_fun(*this, &Editor::hide_all_routes)));
312         items.push_back (MenuElem (_("Show All Audio Tracks"), mem_fun(*this, &Editor::show_all_audiotracks)));
313         items.push_back (MenuElem (_("Hide All Audio Tracks"), mem_fun(*this, &Editor::hide_all_audiotracks)));
314         items.push_back (MenuElem (_("Show All Audio Busses"), mem_fun(*this, &Editor::show_all_audiobus)));
315         items.push_back (MenuElem (_("Hide All Audio Busses"), mem_fun(*this, &Editor::hide_all_audiobus)));
316
317 }
318
319 void
320 Editor::set_all_tracks_visibility (bool yn)
321 {
322         TreeModel::Children rows = route_display_model->children();
323         TreeModel::Children::iterator i;
324
325         no_route_list_redisplay = true;
326
327         for (i = rows.begin(); i != rows.end(); ++i) {
328
329                 TreeModel::Row row = (*i);
330                 TimeAxisView* tv = row[route_display_columns.tv];
331
332                 if (tv == 0) {
333                         continue;
334                 }
335                 
336                 (*i)[route_display_columns.visible] = yn;
337         }
338
339         no_route_list_redisplay = false;
340         redisplay_route_list ();
341 }
342
343 void
344 Editor::set_all_audio_visibility (int tracks, bool yn) 
345 {
346         TreeModel::Children rows = route_display_model->children();
347         TreeModel::Children::iterator i;
348
349         no_route_list_redisplay = true;
350
351         for (i = rows.begin(); i != rows.end(); ++i) {
352                 TreeModel::Row row = (*i);
353                 TimeAxisView* tv = row[route_display_columns.tv];
354                 AudioTimeAxisView* atv;
355
356                 if (tv == 0) {
357                         continue;
358                 }
359
360                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
361                         switch (tracks) {
362                         case 0:
363                                 (*i)[route_display_columns.visible] = yn;
364                                 break;
365
366                         case 1:
367                                 if (atv->is_audio_track()) {
368                                         (*i)[route_display_columns.visible] = yn;
369                                 }
370                                 break;
371                                 
372                         case 2:
373                                 if (!atv->is_audio_track()) {
374                                         (*i)[route_display_columns.visible] = yn;
375                                 }
376                                 break;
377                         }
378                 }
379         }
380
381         no_route_list_redisplay = false;
382         redisplay_route_list ();
383 }
384
385 void
386 Editor::hide_all_routes ()
387 {
388         set_all_tracks_visibility (false);
389 }
390
391 void
392 Editor::show_all_routes ()
393 {
394         set_all_tracks_visibility (true);
395 }
396
397 void
398 Editor::show_all_audiobus ()
399 {
400         set_all_audio_visibility (2, true);
401 }
402 void
403 Editor::hide_all_audiobus ()
404 {
405         set_all_audio_visibility (2, false);
406 }
407
408 void
409 Editor::show_all_audiotracks()
410 {
411         set_all_audio_visibility (1, true);
412 }
413 void
414 Editor::hide_all_audiotracks ()
415 {
416         set_all_audio_visibility (1, false);
417 }
418
419 bool
420 Editor::route_list_display_button_press (GdkEventButton* ev)
421 {
422         if (Keyboard::is_context_menu_event (ev)) {
423                 show_route_list_menu ();
424                 return true;
425         }
426
427         TreeIter iter;
428         TreeModel::Path path;
429         TreeViewColumn* column;
430         int cellx;
431         int celly;
432         
433         if (!route_list_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
434                 return false;
435         }
436
437         switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
438         case 0:
439                 if ((iter = route_display_model->get_iter (path))) {
440                         TimeAxisView* tv = (*iter)[route_display_columns.tv];
441                         if (tv) {
442                                 bool visible = (*iter)[route_display_columns.visible];
443                                 (*iter)[route_display_columns.visible] = !visible;
444                         }
445                 }
446                 return true;
447
448         case 1:
449                 /* allow normal processing to occur */
450                 return false;
451
452         default:
453                 break;
454         }
455
456         return false;
457 }
458
459 void
460 Editor::show_route_list_menu()
461 {
462         if (route_list_menu == 0) {
463                 build_route_list_menu ();
464         }
465
466         route_list_menu->popup (1, 0);
467 }
468
469 bool
470 Editor::route_list_selection_filter (const Glib::RefPtr<TreeModel>& model, const TreeModel::Path& path, bool yn)
471 {
472         return true;
473 }
474
475 struct EditorOrderRouteSorter {
476     bool operator() (Route* a, Route* b) {
477             /* use of ">" forces the correct sort order */
478             return a->order_key ("editor") < b->order_key ("editor");
479     }
480 };
481
482 void
483 Editor::initial_route_list_display ()
484 {
485         Session::RouteList routes = session->get_routes();
486         EditorOrderRouteSorter sorter;
487
488         routes.sort (sorter);
489         
490         no_route_list_redisplay = true;
491
492         route_display_model->clear ();
493
494         for (Session::RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
495                 handle_new_route (**i);
496         }
497
498         no_route_list_redisplay = false;
499
500         redisplay_route_list ();
501 }
502
503 void
504 Editor::route_list_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter)
505 {
506         redisplay_route_list ();
507 }
508
509 void
510 Editor::route_list_delete (const Gtk::TreeModel::Path& path)
511 {
512         redisplay_route_list ();
513 }