473858f8f53bf2e69c2158ea410cd4ea0b45d351
[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 using namespace Glib;
42
43 void
44 Editor::handle_new_route (Session::RouteList& routes)
45 {
46         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_new_route), routes));
47         
48         TimeAxisView *tv;
49         AudioTimeAxisView *atv;
50         TreeModel::Row parent;
51         TreeModel::Row row;
52
53         ignore_route_list_reorder = true;
54         ignore_route_order_sync = true;
55         no_route_list_redisplay = true;
56
57         for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
58                 boost::shared_ptr<Route> route = (*x);
59
60                 if (route->hidden()) {
61                         continue;
62                 }
63                 
64                 tv = new AudioTimeAxisView (*this, *session, route, *track_canvas);
65                 //cerr << "Editor::handle_new_route() called on " << route->name() << endl;//DEBUG
66                 row = *(route_display_model->append ());
67                 
68                 row[route_display_columns.route] = route;
69                 row[route_display_columns.text] = route->name();
70                 row[route_display_columns.visible] = tv->marked_for_display();
71                 row[route_display_columns.tv] = tv;
72
73                 track_views.push_back (tv);
74                 
75                 if ((atv = dynamic_cast<AudioTimeAxisView*> (tv)) != 0) {
76                         /* added a new fresh one at the end */
77                         if (atv->route()->order_key(N_("editor")) == -1) {
78                                 atv->route()->set_order_key (N_("editor"), route_display_model->children().size()-1);
79                         }
80                         atv->effective_gain_display ();
81                 }
82
83                 tv->set_old_order_key (route_display_model->children().size() - 1);
84                 route->gui_changed.connect (mem_fun(*this, &Editor::handle_gui_changes));
85                 tv->GoingAway.connect (bind (mem_fun(*this, &Editor::remove_route), tv));
86         }
87
88         ignore_route_list_reorder = false;
89         ignore_route_order_sync = false;
90         no_route_list_redisplay = false;
91
92         redisplay_route_list ();
93
94         if (show_editor_mixer_when_tracks_arrive) {
95                 show_editor_mixer (true);
96         }
97
98         editor_mixer_button.set_sensitive(true);
99 }
100
101 void
102 Editor::handle_gui_changes (const string & what, void *src)
103 {
104         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_gui_changes), what, src));
105         
106         if (what == "track_height") {
107                 /* make tracks change height while it happens, instead 
108                    of on first-idle
109                 */
110                 track_canvas->update_now ();
111                 redisplay_route_list ();
112         }
113
114         if (what == "visible_tracks") {
115                 redisplay_route_list ();
116         }
117 }
118
119 void
120 Editor::remove_route (TimeAxisView *tv)
121 {
122         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::remove_route), tv));
123
124         TrackViewList::iterator i;
125         TreeModel::Children rows = route_display_model->children();
126         TreeModel::Children::iterator ri;
127
128         if (tv == entered_track) {
129                 entered_track = 0;
130         }
131
132         /* Decrement old order keys for tracks `above' the one that is being removed */
133         for (ri = rows.begin(); ri != rows.end(); ++ri) {
134                 TimeAxisView* v = (*ri)[route_display_columns.tv];
135                 if (v->old_order_key() > tv->old_order_key()) {
136                         v->set_old_order_key (v->old_order_key() - 1);
137                 }
138         }
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 void
182 Editor::update_route_visibility ()
183 {
184         TreeModel::Children rows = route_display_model->children();
185         TreeModel::Children::iterator i;
186         
187         no_route_list_redisplay = true;
188
189         for (i = rows.begin(); i != rows.end(); ++i) {
190                 TimeAxisView *tv = (*i)[route_display_columns.tv];
191                 (*i)[route_display_columns.visible] = tv->marked_for_display ();
192         }
193
194         no_route_list_redisplay = false;
195         redisplay_route_list ();
196 }
197
198 void
199 Editor::hide_track_in_display (TimeAxisView& tv, bool temponly)
200 {
201         TreeModel::Children rows = route_display_model->children();
202         TreeModel::Children::iterator i;
203
204         for (i = rows.begin(); i != rows.end(); ++i) {
205                 if ((*i)[route_display_columns.tv] == &tv) { 
206                         (*i)[route_display_columns.visible] = false;
207                         // if (temponly) {
208                         tv.set_marked_for_display (false);
209                         // }
210                         break;
211                 }
212         }
213
214         AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
215
216         if (atv && current_mixer_strip && (atv->route() == current_mixer_strip->route())) {
217                 // this will hide the mixer strip
218                 set_selected_mixer_strip (tv);
219         }
220 }
221
222 void
223 Editor::show_track_in_display (TimeAxisView& tv)
224 {
225         TreeModel::Children rows = route_display_model->children();
226         TreeModel::Children::iterator i;
227         
228         for (i = rows.begin(); i != rows.end(); ++i) {
229                 if ((*i)[route_display_columns.tv] == &tv) { 
230                         (*i)[route_display_columns.visible] = true;
231                         tv.set_marked_for_display (true);
232                         break;
233                 }
234         }
235 }
236
237 void
238 Editor::sync_order_keys ()
239 {
240         vector<int> neworder;
241         TreeModel::Children rows = route_display_model->children();
242         TreeModel::Children::iterator ri;
243
244         if (ignore_route_order_sync || !session || (session->state_of_the_state() & Session::Loading) || rows.empty()) {
245                 return;
246         }
247
248         for (ri = rows.begin(); ri != rows.end(); ++ri) {
249                 neworder.push_back (0);
250         }
251
252         for (ri = rows.begin(); ri != rows.end(); ++ri) {
253                 TimeAxisView* tv = (*ri)[route_display_columns.tv];
254                 boost::shared_ptr<Route> route = (*ri)[route_display_columns.route];
255                 neworder[route->order_key (X_("editor"))] = tv->old_order_key ();
256         }
257
258         ignore_route_list_reorder = true;
259         route_display_model->reorder (neworder);
260         ignore_route_list_reorder = false;
261 }
262
263 void
264 Editor::redisplay_route_list ()
265 {
266         TreeModel::Children rows = route_display_model->children();
267         TreeModel::Children::iterator i;
268         uint32_t position;
269         uint32_t order;
270         int n;
271
272         if (no_route_list_redisplay) {
273                 return;
274         }
275
276         if (session && (rows.size() > session->nroutes())) {
277                 /* temporary condition during a drag-n-drop */
278                 return;
279         }
280
281         for (n = 0, order = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
282                 TimeAxisView *tv = (*i)[route_display_columns.tv];
283                 boost::shared_ptr<Route> route = (*i)[route_display_columns.route];
284
285                 if (tv == 0) {
286                         // just a "title" row
287                         continue;
288                 }
289
290                 if (!ignore_route_list_reorder) {
291                         
292                         /* this reorder is caused by user action, so reassign sort order keys
293                            to tracks.
294                         */
295                         
296                         route->set_order_key (N_("editor"), order);
297                 }
298
299                 tv->set_old_order_key (order);
300
301                 bool visible = (*i)[route_display_columns.visible];
302
303                 if (visible) {
304                         tv->set_marked_for_display (true);
305                         position += tv->show_at (position, n, &edit_controls_vbox);
306                 } else {
307                         tv->hide ();
308                 }
309                 
310                 ++order;
311                 ++n;
312         }
313
314         full_canvas_height = position;
315
316         /* make sure the cursors stay on top of every newly added track */
317
318         cursor_group->raise_to_top ();
319
320         //reset_scrolling_region ();
321
322         if (Config->get_sync_all_route_ordering() && !ignore_route_list_reorder) {
323                 ignore_route_order_sync = true;
324                 Route::SyncOrderKeys (); // EMIT SIGNAL
325                 ignore_route_order_sync = false;
326         }
327 }
328
329 void
330 Editor::hide_all_tracks (bool with_select)
331 {
332         TreeModel::Children rows = route_display_model->children();
333         TreeModel::Children::iterator i;
334
335         no_route_list_redisplay = true;
336
337         for (i = rows.begin(); i != rows.end(); ++i) {
338                 
339                 TreeModel::Row row = (*i);
340                 TimeAxisView *tv = row[route_display_columns.tv];
341
342                 if (tv == 0) {
343                         continue;
344                 }
345                 
346                 row[route_display_columns.visible] = false;
347         }
348
349         no_route_list_redisplay = false;
350         redisplay_route_list ();
351
352         /* XXX this seems like a hack and half, but its not clear where to put this
353            otherwise.
354         */
355
356         //reset_scrolling_region ();
357 }
358
359 void
360 Editor::build_route_list_menu ()
361 {
362         using namespace Menu_Helpers;
363         using namespace Gtk;
364
365         route_list_menu = new Menu;
366         
367         MenuList& items = route_list_menu->items();
368         route_list_menu->set_name ("ArdourContextMenu");
369
370         items.push_back (MenuElem (_("Show All"), mem_fun(*this, &Editor::show_all_routes)));
371         items.push_back (MenuElem (_("Hide All"), mem_fun(*this, &Editor::hide_all_routes)));
372         items.push_back (MenuElem (_("Show All Audio Tracks"), mem_fun(*this, &Editor::show_all_audiotracks)));
373         items.push_back (MenuElem (_("Hide All Audio Tracks"), mem_fun(*this, &Editor::hide_all_audiotracks)));
374         items.push_back (MenuElem (_("Show All Audio Busses"), mem_fun(*this, &Editor::show_all_audiobus)));
375         items.push_back (MenuElem (_("Hide All Audio Busses"), mem_fun(*this, &Editor::hide_all_audiobus)));
376
377 }
378
379 void
380 Editor::set_all_tracks_visibility (bool yn)
381 {
382         TreeModel::Children rows = route_display_model->children();
383         TreeModel::Children::iterator i;
384
385         no_route_list_redisplay = true;
386
387         for (i = rows.begin(); i != rows.end(); ++i) {
388
389                 TreeModel::Row row = (*i);
390                 TimeAxisView* tv = row[route_display_columns.tv];
391
392                 if (tv == 0) {
393                         continue;
394                 }
395                 
396                 (*i)[route_display_columns.visible] = yn;
397         }
398
399         no_route_list_redisplay = false;
400         redisplay_route_list ();
401 }
402
403 void
404 Editor::set_all_audio_visibility (int tracks, bool yn) 
405 {
406         TreeModel::Children rows = route_display_model->children();
407         TreeModel::Children::iterator i;
408
409         no_route_list_redisplay = true;
410
411         for (i = rows.begin(); i != rows.end(); ++i) {
412                 TreeModel::Row row = (*i);
413                 TimeAxisView* tv = row[route_display_columns.tv];
414                 AudioTimeAxisView* atv;
415
416                 if (tv == 0) {
417                         continue;
418                 }
419
420                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
421                         switch (tracks) {
422                         case 0:
423                                 (*i)[route_display_columns.visible] = yn;
424                                 break;
425
426                         case 1:
427                                 if (atv->is_audio_track()) {
428                                         (*i)[route_display_columns.visible] = yn;
429                                 }
430                                 break;
431                                 
432                         case 2:
433                                 if (!atv->is_audio_track()) {
434                                         (*i)[route_display_columns.visible] = yn;
435                                 }
436                                 break;
437                         }
438                 }
439         }
440
441         no_route_list_redisplay = false;
442         redisplay_route_list ();
443 }
444
445 void
446 Editor::hide_all_routes ()
447 {
448         set_all_tracks_visibility (false);
449 }
450
451 void
452 Editor::show_all_routes ()
453 {
454         set_all_tracks_visibility (true);
455 }
456
457 void
458 Editor::show_all_audiobus ()
459 {
460         set_all_audio_visibility (2, true);
461 }
462 void
463 Editor::hide_all_audiobus ()
464 {
465         set_all_audio_visibility (2, false);
466 }
467
468 void
469 Editor::show_all_audiotracks()
470 {
471         set_all_audio_visibility (1, true);
472 }
473 void
474 Editor::hide_all_audiotracks ()
475 {
476         set_all_audio_visibility (1, false);
477 }
478
479 bool
480 Editor::route_list_display_button_press (GdkEventButton* ev)
481 {
482         if (Keyboard::is_context_menu_event (ev)) {
483                 show_route_list_menu ();
484                 return true;
485         }
486
487         TreeIter iter;
488         TreeModel::Path path;
489         TreeViewColumn* column;
490         int cellx;
491         int celly;
492         
493         if (!route_list_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
494                 return false;
495         }
496
497         switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
498         case 0:
499                 if ((iter = route_display_model->get_iter (path))) {
500                         TimeAxisView* tv = (*iter)[route_display_columns.tv];
501                         if (tv) {
502                                 bool visible = (*iter)[route_display_columns.visible];
503                                 (*iter)[route_display_columns.visible] = !visible;
504                         }
505                 }
506                 return true;
507
508         case 1:
509                 /* allow normal processing to occur */
510                 return false;
511
512         default:
513                 break;
514         }
515
516         return false;
517 }
518
519 void
520 Editor::show_route_list_menu()
521 {
522         if (route_list_menu == 0) {
523                 build_route_list_menu ();
524         }
525
526         route_list_menu->popup (1, gtk_get_current_event_time());
527 }
528
529 bool
530 Editor::route_list_selection_filter (const Glib::RefPtr<TreeModel>& model, const TreeModel::Path& path, bool yn)
531 {
532         return true;
533 }
534
535 struct EditorOrderRouteSorter {
536     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
537             /* use of ">" forces the correct sort order */
538             return a->order_key ("editor") < b->order_key ("editor");
539     }
540 };
541
542 void
543 Editor::initial_route_list_display ()
544 {
545         boost::shared_ptr<Session::RouteList> routes = session->get_routes();
546         Session::RouteList r (*routes);
547         EditorOrderRouteSorter sorter;
548
549         r.sort (sorter);
550         
551         no_route_list_redisplay = true;
552
553         route_display_model->clear ();
554
555         handle_new_route (r);
556
557         no_route_list_redisplay = false;
558
559         redisplay_route_list ();
560 }
561
562 void
563 Editor::track_list_reorder (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter, int* new_order)
564 {
565         session->set_remote_control_ids();
566         redisplay_route_list ();
567 }
568
569 void
570 Editor::route_list_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter)
571 {
572         session->set_remote_control_ids();
573         redisplay_route_list ();
574 }
575
576 void
577 Editor::route_list_delete (const Gtk::TreeModel::Path& path)
578 {
579         session->set_remote_control_ids();
580         ignore_route_list_reorder = true;
581         redisplay_route_list ();
582         ignore_route_list_reorder = false;
583 }
584
585 void  
586 Editor::route_list_display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
587                                                 int x, int y, 
588                                                 const SelectionData& data,
589                                                 guint info, guint time)
590 {
591         cerr << "RouteLD::dddr target = " << data.get_target() << endl;
592         
593         if (data.get_target() == "GTK_TREE_MODEL_ROW") {
594                 cerr << "Delete drag data drop to treeview\n";
595                 route_list_display.on_drag_data_received (context, x, y, data, info, time);
596                 return;
597         }
598         cerr << "some other kind of drag\n";
599         context->drag_finish (true, false, time);
600 }
601
602 void
603 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
604 {
605         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
606                 theslot (**i);
607         }
608 }