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