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