49540fbe0f7cffc92c31f69c7f59309584ba25f7
[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         const gchar *rowdata[1];
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         rowdata[0] = route.name ().c_str();
62
63         ignore_route_list_reorder = true;
64         route_list.rows().push_back (rowdata);
65         route_list.rows().back().set_data (tv);
66         if (tv->marked_for_display()) {
67                 route_list.rows().back().select();
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_list.rows().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
87 void
88 Editor::handle_gui_changes (string what, void *src)
89 {
90         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_gui_changes), what, src));
91         
92         if (what == "track_height") {
93                 route_list_reordered ();
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         TrackViewList::iterator i;
103         CList_Helpers::RowList::iterator ri;
104
105         if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
106                 track_views.erase (i);
107         }
108
109         for (ri  = route_list.rows().begin(); ri != route_list.rows().end(); ++ri) {
110                 if (tv == ri->get_data()) {
111                         route_list.rows().erase (ri);
112                         break;
113                 }
114         }
115         /* since the editor mixer goes away when you remove a route, set the
116          * button to inacttive 
117          */
118         editor_mixer_button.set_active(false);
119
120         /* and disable if all tracks and/or routes are gone */
121
122         if (track_views.size() == 0) {
123                 editor_mixer_button.set_sensitive(false);
124         }
125 }
126
127 void
128 Editor::route_name_changed (TimeAxisView *tv)
129 {
130         CList_Helpers::RowList::iterator i;
131         gint row;
132
133         for (row = 0, i  = route_list.rows().begin(); i != route_list.rows().end(); ++i, ++row) {
134                 if (tv == i->get_data()) {
135                         route_list.cell (row, 0).set_text (tv->name());
136                         break;
137                 }
138         }
139 }
140
141 void
142 Editor::route_list_selected (gint row, gint col, GdkEvent *ev)
143 {
144         TimeAxisView *tv;
145         if ((tv = (TimeAxisView *) route_list.get_row_data (row)) != 0) {
146                 tv->set_marked_for_display (true);
147                 route_list_reordered ();
148         }
149 }
150
151 void
152 Editor::route_list_unselected (gint row, gint col, GdkEvent *ev)
153 {
154         TimeAxisView *tv;
155         AudioTimeAxisView *atv;
156
157         if ((tv = (TimeAxisView *) route_list.get_row_data (row)) != 0) {
158
159                 tv->set_marked_for_display (false);
160
161                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
162                         if (current_mixer_strip && &(atv->route()) == &(current_mixer_strip->route())) {
163                                 /* this will hide the mixer strip */
164                                 set_selected_mixer_strip(*atv);
165                         }
166                 }
167
168                 route_list_reordered ();
169         }
170 }
171
172 void
173 Editor::unselect_strip_in_display (TimeAxisView& tv)
174 {
175         CList_Helpers::RowIterator i;
176
177         if ((i = route_list.rows().find_data (&tv)) != route_list.rows().end()) {
178                 (*i).unselect ();
179         }
180 }
181
182 void
183 Editor::select_strip_in_display (TimeAxisView& tv)
184 {
185         CList_Helpers::RowIterator i;
186
187         if ((i = route_list.rows().find_data (&tv)) != route_list.rows().end()) {
188                 (*i).select ();
189         }
190 }
191
192 void
193 Editor::queue_route_list_reordered (gint arg1, gint arg2)
194
195 {
196         /* the problem here is that we are called *before* the
197            list has been reordered. so just queue up
198            the actual re-drawer to happen once the re-ordering
199            is complete.
200         */
201
202         Main::idle.connect (mem_fun(*this, &Editor::route_list_reordered));
203 }
204
205 void
206 Editor::redisplay_route_list ()
207 {
208         route_list_reordered ();
209 }
210
211 gint
212 Editor::route_list_reordered ()
213 {
214         CList_Helpers::RowList::iterator i;
215         gdouble y;
216         int n;
217
218         for (n = 0, y = 0, i  = route_list.rows().begin(); i != route_list.rows().end(); ++i) {
219
220                 TimeAxisView *tv = (TimeAxisView *) (*i)->get_data ();
221                 
222                 AudioTimeAxisView* at;
223                 
224                 if (!ignore_route_list_reorder) {
225                         
226                                 /* this reorder is caused by user action, so reassign sort order keys
227                                    to tracks.
228                                 */
229                         
230                         if ((at = dynamic_cast<AudioTimeAxisView*> (tv)) != 0) {
231                                 at->route().set_order_key (N_("editor"), n);
232                         }
233                 }
234                 
235                 if (tv->marked_for_display()) {
236                         y += tv->show_at (y, n, &edit_controls_vbox);
237                         y += track_spacing;
238                 } else {
239                         tv->hide ();
240                 }
241                 
242                 n++;
243         }
244
245         edit_controls_scroller.queue_resize ();
246         reset_scrolling_region ();
247
248         //gtk_canvas_item_raise_to_top (time_line_group);
249         gtk_canvas_item_raise_to_top (cursor_group);
250         
251         return FALSE;
252 }
253
254 void
255 Editor::hide_all_tracks (bool with_select)
256 {
257         Gtk::CList_Helpers::RowList::iterator i;
258         Gtk::CList_Helpers::RowList& rowlist = route_list.rows();
259         
260         route_list.freeze ();
261
262         for (i = rowlist.begin(); i != rowlist.end(); ++i) {
263                 TimeAxisView *tv = (TimeAxisView *) i->get_data ();
264
265                 if (with_select) {
266                         i->unselect ();
267                 } else {
268                         tv->set_marked_for_display (false);
269                         tv->hide();
270                 }
271         }
272
273         route_list.thaw ();
274
275         reset_scrolling_region ();
276 }
277
278 void
279 Editor::route_list_column_click (gint col)
280 {
281         if (route_list_menu == 0) {
282                 build_route_list_menu ();
283         }
284
285         route_list_menu->popup (0, 0);
286 }
287
288 void
289 Editor::build_route_list_menu ()
290 {
291         using namespace Gtk::Menu_Helpers;
292
293         route_list_menu = new Menu;
294         
295         MenuList& items = route_list_menu->items();
296         route_list_menu->set_name ("ArdourContextMenu");
297
298         items.push_back (MenuElem (_("Show All"), mem_fun(*this, &Editor::select_all_routes)));
299         items.push_back (MenuElem (_("Hide All"), mem_fun(*this, &Editor::unselect_all_routes)));
300         items.push_back (MenuElem (_("Show All AbstractTracks"), mem_fun(*this, &Editor::select_all_audiotracks)));
301         items.push_back (MenuElem (_("Hide All AbstractTracks"), mem_fun(*this, &Editor::unselect_all_audiotracks)));
302         items.push_back (MenuElem (_("Show All AudioBus"), mem_fun(*this, &Editor::select_all_audiobus)));
303         items.push_back (MenuElem (_("Hide All AudioBus"), mem_fun(*this, &Editor::unselect_all_audiobus)));
304
305 }
306
307 void
308 Editor::unselect_all_routes ()
309 {
310         hide_all_tracks (true);
311 }
312
313 void
314 Editor::select_all_routes ()
315
316 {
317         CList_Helpers::RowList::iterator i;
318
319         for (i = route_list.rows().begin(); i != route_list.rows().end(); ++i) {
320                 i->select ();
321         }
322 }
323
324 void
325 Editor::select_all_audiotracks () 
326 {
327         Gtk::CList_Helpers::RowList::iterator i;
328         Gtk::CList_Helpers::RowList& rowlist = route_list.rows();
329         
330         route_list.freeze ();
331         
332         for (i = rowlist.begin(); i != rowlist.end(); ++i) {
333                 TimeAxisView *tv = (TimeAxisView *) i->get_data ();
334                 AudioTimeAxisView* atv;
335
336                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
337                         if (atv->is_audio_track()) {
338                                 i->select ();
339                         }
340                 }
341         }
342                 
343         route_list.thaw ();
344
345 }
346
347 void 
348 Editor::unselect_all_audiotracks () 
349 {
350         Gtk::CList_Helpers::RowList::iterator i;
351         Gtk::CList_Helpers::RowList& rowlist = route_list.rows();
352         
353         route_list.freeze ();
354
355         for (i = rowlist.begin(); i != rowlist.end(); ++i) {
356                 TimeAxisView *tv = (TimeAxisView *) i->get_data ();
357                 AudioTimeAxisView* atv;
358
359                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
360                         if (atv->is_audio_track()) {
361                                 i->unselect ();
362                         }
363                 }
364         }
365         
366         route_list.thaw ();
367
368 }
369
370 void
371 Editor::select_all_audiobus () 
372 {
373         Gtk::CList_Helpers::RowList::iterator i;
374         Gtk::CList_Helpers::RowList& rowlist = route_list.rows();
375         
376         route_list.freeze ();
377
378         for (i = rowlist.begin(); i != rowlist.end(); ++i) {
379                 TimeAxisView *tv = (TimeAxisView *) i->get_data ();
380                 AudioTimeAxisView* atv;
381
382                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
383                         if (!atv->is_audio_track()) {
384                                 i->select ();
385                         }
386                 }
387         }
388
389         route_list.thaw ();
390
391 }
392
393 void
394 Editor::unselect_all_audiobus () 
395 {
396         Gtk::CList_Helpers::RowList::iterator i;
397         Gtk::CList_Helpers::RowList& rowlist = route_list.rows();
398         
399         route_list.freeze ();
400
401         for (i = rowlist.begin(); i != rowlist.end(); ++i) {
402                 TimeAxisView *tv = (TimeAxisView *) i->get_data ();
403                 AudioTimeAxisView* atv;
404
405                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
406                         if (!atv->is_audio_track()) {
407                                 i->unselect ();
408                         }
409                 }
410         }
411
412         route_list.thaw ();
413
414 }
415
416 gint
417 route_list_compare_func (GtkCList* clist, gconstpointer a, gconstpointer b)
418 {
419         TimeAxisView *tv1;
420         TimeAxisView *tv2;
421         AudioTimeAxisView *atv1;
422         AudioTimeAxisView *atv2;
423         Route* ra;
424         Route* rb;
425
426         GtkCListRow *row1 = (GtkCListRow *) a;
427         GtkCListRow *row2 = (GtkCListRow *) b;
428
429         tv1 = static_cast<TimeAxisView*> (row1->data);
430         tv2 = static_cast<TimeAxisView*> (row2->data);
431
432         if ((atv1 = dynamic_cast<AudioTimeAxisView*>(tv1)) == 0 ||
433             (atv2 = dynamic_cast<AudioTimeAxisView*>(tv2)) == 0) {
434                 return FALSE;
435         }
436
437         ra = &atv1->route();
438         rb = &atv2->route();
439
440         /* use of ">" forces the correct sort order */
441
442         return ra->order_key ("editor") > rb->order_key ("editor");
443 }
444