allow diskstream deletion after a track is removed by using weak_ptr<Diskstream>...
[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         TrackViewList::iterator i;
137         TreeModel::Children rows = route_display_model->children();
138         TreeModel::Children::iterator ri;
139
140         for (ri = rows.begin(); ri != rows.end(); ++ri) {
141                 if ((*ri)[route_display_columns.tv] == tv) {
142                         route_display_model->erase (ri);
143                         break;
144                 }
145         }
146
147         if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
148                 track_views.erase (i);
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
155         editor_mixer_button.set_active(false);
156         ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
157
158         /* and disable if all tracks and/or routes are gone */
159
160         if (track_views.size() == 0) {
161                 editor_mixer_button.set_sensitive(false);
162         }
163 }
164
165 void
166 Editor::route_name_changed (TimeAxisView *tv)
167 {
168         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::route_name_changed), tv));
169         
170         TreeModel::Children rows = route_display_model->children();
171         TreeModel::Children::iterator i;
172         
173         for (i = rows.begin(); i != rows.end(); ++i) {
174                 if ((*i)[route_display_columns.tv] == tv) {
175                         (*i)[route_display_columns.text] = tv->name();
176                         break;
177                 }
178         } 
179
180 }
181
182 void
183 Editor::hide_track_in_display (TimeAxisView& tv)
184 {
185         TreeModel::Children rows = route_display_model->children();
186         TreeModel::Children::iterator i;
187
188         for (i = rows.begin(); i != rows.end(); ++i) {
189                 if ((*i)[route_display_columns.tv] == &tv) { 
190                         (*i)[route_display_columns.visible] = false;
191                         break;
192                 }
193         }
194
195         AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
196
197         if (atv && current_mixer_strip && (atv->route() == current_mixer_strip->route())) {
198                 // this will hide the mixer strip
199                 set_selected_mixer_strip (tv);
200         }
201 }
202
203 void
204 Editor::show_track_in_display (TimeAxisView& tv)
205 {
206         TreeModel::Children rows = route_display_model->children();
207         TreeModel::Children::iterator i;
208         
209         for (i = rows.begin(); i != rows.end(); ++i) {
210                 if ((*i)[route_display_columns.tv] == &tv) { 
211                         (*i)[route_display_columns.visible] = true;
212                         tv.set_marked_for_display (true);
213                         break;
214                 }
215         }
216 }
217
218 void
219 Editor::route_list_reordered (const TreeModel::Path& path,const TreeModel::iterator& iter,int* what)
220 {
221         redisplay_route_list ();
222 }
223
224 void
225 Editor::redisplay_route_list ()
226 {
227         TreeModel::Children rows = route_display_model->children();
228         TreeModel::Children::iterator i;
229         uint32_t position;
230         uint32_t order;
231         int n;
232         
233         if (no_route_list_redisplay) {
234                 return;
235         }
236
237         for (n = 0, order = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
238                 TimeAxisView *tv = (*i)[route_display_columns.tv];
239                 AudioTimeAxisView* at; 
240
241                 if (tv == 0) {
242                         // just a "title" row
243                         continue;
244                 }
245
246                 if (!ignore_route_list_reorder) {
247                         
248                         /* this reorder is caused by user action, so reassign sort order keys
249                            to tracks.
250                         */
251                         
252                         if ((at = dynamic_cast<AudioTimeAxisView*> (tv)) != 0) {
253                                 at->route()->set_order_key (N_("editor"), order);
254                                 ++order;
255                         }
256                 }
257
258                 bool visible = (*i)[route_display_columns.visible];
259
260                 if (visible) {
261                         tv->set_marked_for_display (true);
262                         position += tv->show_at (position, n, &edit_controls_vbox);
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 }