Merge big changes (mostly Controllable) from trunk
[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         /* make sure the cursors stay on top of every newly added track */
267
268         cursor_group->raise_to_top ();
269
270         reset_scrolling_region ();
271 }
272
273 void
274 Editor::hide_all_tracks (bool with_select)
275 {
276         TreeModel::Children rows = route_display_model->children();
277         TreeModel::Children::iterator i;
278
279         no_route_list_redisplay = true;
280
281         for (i = rows.begin(); i != rows.end(); ++i) {
282                 
283                 TreeModel::Row row = (*i);
284                 TimeAxisView *tv = row[route_display_columns.tv];
285
286                 if (tv == 0) {
287                         continue;
288                 }
289                 
290                 row[route_display_columns.visible] = false;
291         }
292
293         no_route_list_redisplay = false;
294         redisplay_route_list ();
295
296         /* XXX this seems like a hack and half, but its not clear where to put this
297            otherwise.
298         */
299
300         reset_scrolling_region ();
301 }
302
303 void
304 Editor::build_route_list_menu ()
305 {
306         using namespace Menu_Helpers;
307         using namespace Gtk;
308
309         route_list_menu = new Menu;
310         
311         MenuList& items = route_list_menu->items();
312         route_list_menu->set_name ("ArdourContextMenu");
313
314         items.push_back (MenuElem (_("Show All"), mem_fun(*this, &Editor::show_all_routes)));
315         items.push_back (MenuElem (_("Hide All"), mem_fun(*this, &Editor::hide_all_routes)));
316         items.push_back (MenuElem (_("Show All Audio Tracks"), mem_fun(*this, &Editor::show_all_audiotracks)));
317         items.push_back (MenuElem (_("Hide All Audio Tracks"), mem_fun(*this, &Editor::hide_all_audiotracks)));
318         items.push_back (MenuElem (_("Show All Audio Busses"), mem_fun(*this, &Editor::show_all_audiobus)));
319         items.push_back (MenuElem (_("Hide All Audio Busses"), mem_fun(*this, &Editor::hide_all_audiobus)));
320
321 }
322
323 void
324 Editor::set_all_tracks_visibility (bool yn)
325 {
326         TreeModel::Children rows = route_display_model->children();
327         TreeModel::Children::iterator i;
328
329         no_route_list_redisplay = true;
330
331         for (i = rows.begin(); i != rows.end(); ++i) {
332
333                 TreeModel::Row row = (*i);
334                 TimeAxisView* tv = row[route_display_columns.tv];
335
336                 if (tv == 0) {
337                         continue;
338                 }
339                 
340                 (*i)[route_display_columns.visible] = yn;
341         }
342
343         no_route_list_redisplay = false;
344         redisplay_route_list ();
345 }
346
347 void
348 Editor::set_all_audio_visibility (int tracks, bool yn) 
349 {
350         TreeModel::Children rows = route_display_model->children();
351         TreeModel::Children::iterator i;
352
353         no_route_list_redisplay = true;
354
355         for (i = rows.begin(); i != rows.end(); ++i) {
356                 TreeModel::Row row = (*i);
357                 TimeAxisView* tv = row[route_display_columns.tv];
358                 AudioTimeAxisView* atv;
359
360                 if (tv == 0) {
361                         continue;
362                 }
363
364                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
365                         switch (tracks) {
366                         case 0:
367                                 (*i)[route_display_columns.visible] = yn;
368                                 break;
369
370                         case 1:
371                                 if (atv->is_audio_track()) {
372                                         (*i)[route_display_columns.visible] = yn;
373                                 }
374                                 break;
375                                 
376                         case 2:
377                                 if (!atv->is_audio_track()) {
378                                         (*i)[route_display_columns.visible] = yn;
379                                 }
380                                 break;
381                         }
382                 }
383         }
384
385         no_route_list_redisplay = false;
386         redisplay_route_list ();
387 }
388
389 void
390 Editor::hide_all_routes ()
391 {
392         set_all_tracks_visibility (false);
393 }
394
395 void
396 Editor::show_all_routes ()
397 {
398         set_all_tracks_visibility (true);
399 }
400
401 void
402 Editor::show_all_audiobus ()
403 {
404         set_all_audio_visibility (2, true);
405 }
406 void
407 Editor::hide_all_audiobus ()
408 {
409         set_all_audio_visibility (2, false);
410 }
411
412 void
413 Editor::show_all_audiotracks()
414 {
415         set_all_audio_visibility (1, true);
416 }
417 void
418 Editor::hide_all_audiotracks ()
419 {
420         set_all_audio_visibility (1, false);
421 }
422
423 bool
424 Editor::route_list_display_button_press (GdkEventButton* ev)
425 {
426         if (Keyboard::is_context_menu_event (ev)) {
427                 show_route_list_menu ();
428                 return true;
429         }
430
431         TreeIter iter;
432         TreeModel::Path path;
433         TreeViewColumn* column;
434         int cellx;
435         int celly;
436         
437         if (!route_list_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
438                 return false;
439         }
440
441         switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
442         case 0:
443                 if ((iter = route_display_model->get_iter (path))) {
444                         TimeAxisView* tv = (*iter)[route_display_columns.tv];
445                         if (tv) {
446                                 bool visible = (*iter)[route_display_columns.visible];
447                                 (*iter)[route_display_columns.visible] = !visible;
448                         }
449                 }
450                 return true;
451
452         case 1:
453                 /* allow normal processing to occur */
454                 return false;
455
456         default:
457                 break;
458         }
459
460         return false;
461 }
462
463 void
464 Editor::show_route_list_menu()
465 {
466         if (route_list_menu == 0) {
467                 build_route_list_menu ();
468         }
469
470         route_list_menu->popup (1, 0);
471 }
472
473 bool
474 Editor::route_list_selection_filter (const Glib::RefPtr<TreeModel>& model, const TreeModel::Path& path, bool yn)
475 {
476         return true;
477 }
478
479 struct EditorOrderRouteSorter {
480     bool operator() (Route* a, Route* b) {
481             /* use of ">" forces the correct sort order */
482             return a->order_key ("editor") < b->order_key ("editor");
483     }
484 };
485
486 void
487 Editor::initial_route_list_display ()
488 {
489         Session::RouteList routes = session->get_routes();
490         EditorOrderRouteSorter sorter;
491
492         routes.sort (sorter);
493         
494         no_route_list_redisplay = true;
495
496         route_display_model->clear ();
497
498         for (Session::RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
499                 handle_new_route (**i);
500         }
501
502         no_route_list_redisplay = false;
503
504         redisplay_route_list ();
505 }
506
507 void
508 Editor::route_list_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter)
509 {
510         redisplay_route_list ();
511 }
512
513 void
514 Editor::route_list_delete (const Gtk::TreeModel::Path& path)
515 {
516         redisplay_route_list ();
517 }