Plugin output meters are now vertical. It still needs a rotateable text
[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
33 #include "i18n.h"
34
35 using namespace sigc;
36 using namespace ARDOUR;
37 using namespace Gtk;
38
39 void
40 Editor::handle_new_route_p (Route* route)
41 {
42         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_new_route_p), route));
43         handle_new_route (*route);
44 }
45
46 void
47 Editor::handle_new_route (Route& route)
48 {
49         TimeAxisView *tv;
50         AudioTimeAxisView *atv;
51         TreeModel::Row row = *(route_display_model->append());
52
53         if (route.hidden()) {
54                 return;
55         }
56                 
57         tv = new AudioTimeAxisView (*this, *session, route, track_canvas);
58
59         track_views.push_back (tv);
60
61         row[route_display_columns.text] = route.name();
62         row[route_display_columns.tv] = tv;
63
64         ignore_route_list_reorder = true;
65         
66         if (!no_route_list_redisplay && tv->marked_for_display()) {
67                 route_list_display.get_selection()->select (row);
68         }
69
70         if ((atv = dynamic_cast<AudioTimeAxisView*> (tv)) != 0) {
71                 /* added a new fresh one at the end */
72                 if (atv->route().order_key(N_("editor")) == -1) {
73                         atv->route().set_order_key (N_("editor"), route_display_model->children().size()-1);
74                 }
75         }
76
77         ignore_route_list_reorder = false;
78         
79         route.gui_changed.connect (mem_fun(*this, &Editor::handle_gui_changes));
80
81         tv->GoingAway.connect (bind (mem_fun(*this, &Editor::remove_route), tv));
82         
83         editor_mixer_button.set_sensitive(true);
84 }
85
86 void
87 Editor::handle_gui_changes (const string & what, void *src)
88 {
89         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_gui_changes), what, src));
90         
91         if (what == "track_height") {
92                 redisplay_route_list ();
93         }
94 }
95
96
97 void
98 Editor::remove_route (TimeAxisView *tv)
99 {
100         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::remove_route), tv));
101
102         
103         TrackViewList::iterator i;
104         TreeModel::Children rows = route_display_model->children();
105         TreeModel::Children::iterator ri;
106
107         if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
108                 track_views.erase (i);
109         }
110
111         for (ri = rows.begin(); ri != rows.end(); ++ri) {
112                 if ((*ri)[route_display_columns.tv] == tv) {
113                         route_display_model->erase (ri);
114                         break;
115                 }
116         }
117         /* since the editor mixer goes away when you remove a route, set the
118          * button to inacttive 
119          */
120         editor_mixer_button.set_active(false);
121
122         /* and disable if all tracks and/or routes are gone */
123
124         if (track_views.size() == 0) {
125                 editor_mixer_button.set_sensitive(false);
126         }
127 }
128
129 void
130 Editor::route_name_changed (TimeAxisView *tv)
131 {
132         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::route_name_changed), tv));
133         
134         TreeModel::Children rows = route_display_model->children();
135         TreeModel::Children::iterator i;
136         
137         for (i = rows.begin(); i != rows.end(); ++i) {
138                 if ((*i)[route_display_columns.tv] == tv) {
139                         (*i)[route_display_columns.text] = tv->name();
140                         break;
141                 }
142         } 
143
144 }
145
146 void
147 Editor::route_display_selection_changed ()
148 {
149         TimeAxisView *tv;
150         TreeModel::Children rows = route_display_model->children();
151         TreeModel::Children::iterator i;
152         Glib::RefPtr<TreeSelection> selection = route_list_display.get_selection();
153
154         for (i = rows.begin(); i != rows.end(); ++i) {
155                 tv = (*i)[route_display_columns.tv];
156
157                 if (!selection->is_selected (i)) {
158                         tv->set_marked_for_display  (false);
159                 } else {
160                         AudioTimeAxisView *atv;
161                         tv->set_marked_for_display (true);
162                         if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
163                                 if (current_mixer_strip && &(atv->route()) == &(current_mixer_strip->route())) {
164                                         // this will hide the mixer strip
165                                         set_selected_mixer_strip(*atv);
166                                 }
167                         }
168                 }
169         }
170         
171         redisplay_route_list ();
172 }
173
174 void
175 Editor::unselect_strip_in_display (TimeAxisView& tv)
176 {
177         TreeModel::Children rows = route_display_model->children();
178         TreeModel::Children::iterator i;
179         Glib::RefPtr<TreeSelection> selection = route_list_display.get_selection();
180         
181         for (i = rows.begin(); i != rows.end(); ++i) {
182                 if ((*i)[route_display_columns.tv] == &tv) { 
183                        selection->unselect (*i);
184                 }
185         }
186 }
187
188 void
189 Editor::select_strip_in_display (TimeAxisView* tv)
190 {
191         TreeModel::Children rows = route_display_model->children();
192         TreeModel::Children::iterator i;
193         Glib::RefPtr<TreeSelection> selection = route_list_display.get_selection();
194         
195         for (i = rows.begin(); i != rows.end(); ++i) {
196                 if ((*i)[route_display_columns.tv] == tv) { 
197                        selection->select (*i);
198                 }
199         }
200 }
201
202 void
203 Editor::route_list_reordered (const TreeModel::Path& path,const TreeModel::iterator& iter,int* what)
204 {
205         redisplay_route_list ();
206 }
207
208 void
209 Editor::redisplay_route_list ()
210 {
211         TreeModel::Children rows = route_display_model->children();
212         TreeModel::Children::iterator i;
213         uint32_t position;
214         uint32_t order;
215         int n;
216
217         if (no_route_list_redisplay) {
218                 return;
219         }
220
221         for (n = 0, order = 0, position = 0, i = rows.begin(); i != rows.end(); ++i, ++order) {
222                 TimeAxisView *tv = (*i)[route_display_columns.tv];
223                 AudioTimeAxisView* at; 
224
225                 if (!ignore_route_list_reorder) {
226                         
227                         /* this reorder is caused by user action, so reassign sort order keys
228                            to tracks.
229                         */
230                         
231                         if ((at = dynamic_cast<AudioTimeAxisView*> (tv)) != 0) {
232                                 at->route().set_order_key (N_("editor"), order);
233                         }
234                 }
235                 if (tv->marked_for_display()) {
236                         position += tv->show_at (position, n, &edit_controls_vbox);
237                         position += track_spacing;
238                 } else {
239                         tv->hide ();
240                 }
241                 
242                 n++;
243                 
244         }
245
246         controls_layout.queue_resize ();
247         reset_scrolling_region ();
248 }
249
250 void
251 Editor::hide_all_tracks (bool with_select)
252 {
253         TreeModel::Children rows = route_display_model->children();
254         TreeModel::Children::iterator i;
255
256         // GTK2FIX
257         // track_display_list.freeze ();
258         
259         for (i = rows.begin(); i != rows.end(); ++i) {
260                 
261                 TreeModel::Row row = (*i);
262                 TimeAxisView *tv = row[route_display_columns.tv];
263                 
264                 if (with_select) {
265                         route_list_display.get_selection()->unselect (i);
266                 } else {
267                         tv->set_marked_for_display (false);
268                         tv->hide();
269                 
270                 }
271         }
272         //route_list_display.thaw ();
273         reset_scrolling_region ();
274 }
275
276 void
277 Editor::build_route_list_menu ()
278 {
279         using namespace Menu_Helpers;
280         using namespace Gtk;
281
282
283         route_list_menu = new Menu;
284         
285         MenuList& items = route_list_menu->items();
286         route_list_menu->set_name ("ArdourContextMenu");
287
288         items.push_back (MenuElem (_("Show All"), mem_fun(*this, &Editor::select_all_routes)));
289         items.push_back (MenuElem (_("Hide All"), mem_fun(*this, &Editor::unselect_all_routes)));
290         items.push_back (MenuElem (_("Show All AbstractTracks"), mem_fun(*this, &Editor::select_all_audiotracks)));
291         items.push_back (MenuElem (_("Hide All AbstractTracks"), mem_fun(*this, &Editor::unselect_all_audiotracks)));
292         items.push_back (MenuElem (_("Show All AudioBus"), mem_fun(*this, &Editor::select_all_audiobus)));
293         items.push_back (MenuElem (_("Hide All AudioBus"), mem_fun(*this, &Editor::unselect_all_audiobus)));
294
295 }
296
297 void
298 Editor::unselect_all_routes ()
299 {
300         hide_all_tracks (true);
301 }
302
303 void
304 Editor::select_all_routes ()
305
306 {
307         TreeModel::Children rows = route_display_model->children();
308         TreeModel::Children::iterator i;
309
310         for (i = rows.begin(); i != rows.end(); ++i) {
311                 route_list_display.get_selection()->select (i);
312         }
313 }
314
315 void
316 Editor::select_all_audiotracks () 
317 {
318         TreeModel::Children rows = route_display_model->children();
319         TreeModel::Children::iterator i;
320
321         for (i = rows.begin(); i != rows.end(); ++i) {
322         TreeModel::Row row = (*i);
323                 TimeAxisView* tv = row[route_display_columns.tv];
324                 AudioTimeAxisView* atv;
325
326                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
327                         if (atv->is_audio_track()) {
328                                 route_list_display.get_selection()->select (i);
329
330                         }
331                 }
332         }
333
334 }
335
336 void
337 Editor::unselect_all_audiotracks () 
338 {
339         TreeModel::Children rows = route_display_model->children();
340         TreeModel::Children::iterator i;
341
342         for (i = rows.begin(); i != rows.end(); ++i) {
343                 TreeModel::Row row = (*i);
344                 TimeAxisView *tv = row[route_display_columns.tv];
345                 AudioTimeAxisView* atv;
346
347                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
348                         if (atv->is_audio_track()) {
349                                 route_list_display.get_selection()->unselect (i);
350
351                         }
352                 }
353         }
354
355 }
356
357 void
358 Editor::select_all_audiobus () 
359 {
360         TreeModel::Children rows = route_display_model->children();
361         TreeModel::Children::iterator i;
362
363         for (i = rows.begin(); i != rows.end(); ++i) {
364                 TreeModel::Row row = (*i);
365                 TimeAxisView* tv = row[route_display_columns.tv];
366                 AudioTimeAxisView* atv;
367
368                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
369                         if (!atv->is_audio_track()) {
370                                 route_list_display.get_selection()->select (i);
371
372                         }
373                 }
374         }
375
376 }
377
378 void
379 Editor::unselect_all_audiobus () 
380 {
381         TreeModel::Children rows = route_display_model->children();
382         TreeModel::Children::iterator i;
383
384         for (i = rows.begin(); i != rows.end(); ++i) {
385                 TreeModel::Row row = (*i);
386                 TimeAxisView* tv = row[route_display_columns.tv];
387                 AudioTimeAxisView* atv;
388
389                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
390                         if (!atv->is_audio_track()) {
391                                 route_list_display.get_selection()->unselect (i);
392
393                         }
394                 }
395         }
396
397 }
398
399 gint
400 Editor::route_list_compare_func (TreeModel::iterator a, TreeModel::iterator b)
401 {
402         TimeAxisView *tv1;
403         TimeAxisView *tv2;
404         AudioTimeAxisView *atv1;
405         AudioTimeAxisView *atv2;
406         Route* ra;
407         Route* rb;
408
409         tv1 = (*a)[route_display_columns.tv];
410         tv2 = (*b)[route_display_columns.tv];
411
412         if ((atv1 = dynamic_cast<AudioTimeAxisView*>(tv1)) == 0 ||
413             (atv2 = dynamic_cast<AudioTimeAxisView*>(tv2)) == 0) {
414                 return FALSE;
415         }
416
417         ra = &atv1->route();
418         rb = &atv2->route();
419
420         /* use of ">" forces the correct sort order */
421
422         return ra->order_key ("editor") > rb->order_key ("editor");
423 }
424