patch from lucus for long names in trackbus inspector
[ardour2.git] / gtk2_ardour / editor_route_list.cc
blob583b6ec8e724e119dd3833aff29fcb888ffa43a1
1 /*
2 Copyright (C) 2000 Paul Davis
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.
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.
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.
20 #include <algorithm>
21 #include <cstdlib>
22 #include <cmath>
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"
32 #include <ardour/route.h>
33 #include <ardour/audio_track.h>
34 #include <ardour/route_group.h>
36 #include "i18n.h"
38 using namespace sigc;
39 using namespace ARDOUR;
40 using namespace PBD;
41 using namespace Gtk;
42 using namespace Glib;
44 const char* _order_key = N_("editor");
46 void
47 Editor::handle_new_route (Session::RouteList& routes)
49 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_new_route), routes));
51 TimeAxisView *tv;
52 AudioTimeAxisView *atv;
53 TreeModel::Row parent;
54 TreeModel::Row row;
56 route_redisplay_does_not_sync_order_keys = true;
57 no_route_list_redisplay = true;
59 for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
60 boost::shared_ptr<Route> route = (*x);
62 if (route->hidden()) {
63 continue;
66 tv = new AudioTimeAxisView (*this, *session, route, *track_canvas);
67 //cerr << "Editor::handle_new_route() called on " << route->name() << endl;//DEBUG
68 row = *(route_display_model->append ());
70 row[route_display_columns.route] = route;
71 row[route_display_columns.text] = route->name();
72 row[route_display_columns.visible] = tv->marked_for_display();
73 row[route_display_columns.tv] = tv;
75 RouteGroup *group = route->edit_group();
76 if (group) {
77 if (tv->marked_for_display()) {
78 group->set_hidden(false, this);
79 group_flags_changed(this, group);
83 track_views.push_back (tv);
85 if ((atv = dynamic_cast<AudioTimeAxisView*> (tv)) != 0) {
86 /* added a new fresh one at the end */
87 if (atv->route()->order_key(_order_key) == -1) {
88 atv->route()->set_order_key (_order_key, route_display_model->children().size()-1);
90 atv->effective_gain_display ();
93 route->gui_changed.connect (mem_fun(*this, &Editor::handle_gui_changes));
94 tv->GoingAway.connect (bind (mem_fun(*this, &Editor::remove_route), tv));
97 no_route_list_redisplay = false;
99 redisplay_route_list ();
101 if (show_editor_mixer_when_tracks_arrive) {
102 show_editor_mixer (true);
105 route_redisplay_does_not_sync_order_keys = false;
108 void
109 Editor::handle_gui_changes (const string & what, void *src)
111 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_gui_changes), what, src));
113 if (what == "track_height") {
114 /* Optional :make tracks change height while it happens, instead
115 of on first-idle
117 //track_canvas->update_now ();
118 redisplay_route_list ();
121 if (what == "visible_tracks") {
122 redisplay_route_list ();
126 void
127 Editor::remove_route (TimeAxisView *tv)
129 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::remove_route), tv));
131 TrackViewList::iterator i;
132 TreeModel::Children rows = route_display_model->children();
133 TreeModel::Children::iterator ri;
134 boost::shared_ptr<Route> route;
135 TimeAxisView* next_tv = 0;
137 if (tv == entered_track) {
138 entered_track = 0;
141 /* the core model has changed, there is no need to sync
142 view orders.
145 route_redisplay_does_not_sync_order_keys = true;
147 for (ri = rows.begin(); ri != rows.end(); ++ri) {
148 if ((*ri)[route_display_columns.tv] == tv) {
149 route = (*ri)[route_display_columns.route];
150 route_display_model->erase (ri);
151 break;
155 route_redisplay_does_not_sync_order_keys = false;
157 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
158 i = track_views.erase (i);
160 if (track_views.empty()) {
161 next_tv = 0;
162 } else if (i == track_views.end()) {
163 next_tv = track_views.front();
164 } else {
165 next_tv = (*i);
169 if (current_mixer_strip && (current_mixer_strip->route() == route)) {
171 if (next_tv) {
172 set_selected_mixer_strip (*next_tv);
173 } else {
174 /* make the editor mixer strip go away by setting the
175 * button to inactive (which also unticks the menu option)
178 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
183 void
184 Editor::route_name_changed (TimeAxisView *tv)
186 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::route_name_changed), tv));
188 TreeModel::Children rows = route_display_model->children();
189 TreeModel::Children::iterator i;
191 for (i = rows.begin(); i != rows.end(); ++i) {
192 if ((*i)[route_display_columns.tv] == tv) {
193 (*i)[route_display_columns.text] = tv->name();
194 break;
199 void
200 Editor::update_route_visibility ()
202 TreeModel::Children rows = route_display_model->children();
203 TreeModel::Children::iterator i;
205 no_route_list_redisplay = true;
207 for (i = rows.begin(); i != rows.end(); ++i) {
208 TimeAxisView *tv = (*i)[route_display_columns.tv];
209 (*i)[route_display_columns.visible] = tv->marked_for_display ();
212 no_route_list_redisplay = false;
213 redisplay_route_list ();
216 void
217 Editor::hide_track_in_display (TimeAxisView& tv, bool temponly)
219 TreeModel::Children rows = route_display_model->children();
220 TreeModel::Children::iterator i;
222 for (i = rows.begin(); i != rows.end(); ++i) {
223 if ((*i)[route_display_columns.tv] == &tv) {
224 (*i)[route_display_columns.visible] = false;
225 break;
229 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
231 if (atv && current_mixer_strip && (atv->route() == current_mixer_strip->route())) {
232 // this will hide the mixer strip
233 set_selected_mixer_strip (tv);
237 void
238 Editor::show_track_in_display (TimeAxisView& tv)
240 TreeModel::Children rows = route_display_model->children();
241 TreeModel::Children::iterator i;
243 for (i = rows.begin(); i != rows.end(); ++i) {
244 if ((*i)[route_display_columns.tv] == &tv) {
245 (*i)[route_display_columns.visible] = true;
246 break;
251 void
252 Editor::sync_order_keys (const char *src)
254 vector<int> neworder;
255 TreeModel::Children rows = route_display_model->children();
256 TreeModel::Children::iterator ri;
258 if ((strcmp (src, _order_key) == 0) || !session || (session->state_of_the_state() & Session::Loading) || rows.empty()) {
259 return;
262 for (ri = rows.begin(); ri != rows.end(); ++ri) {
263 neworder.push_back (0);
266 bool changed = false;
267 int order;
269 for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
270 boost::shared_ptr<Route> route = (*ri)[route_display_columns.route];
272 int old_key = order;
273 int new_key = route->order_key (_order_key);
275 neworder[new_key] = old_key;
277 if (new_key != old_key) {
278 changed = true;
282 if (changed) {
283 route_redisplay_does_not_reset_order_keys = true;
284 route_display_model->reorder (neworder);
285 route_redisplay_does_not_reset_order_keys = false;
289 void
290 Editor::redisplay_route_list ()
292 TreeModel::Children rows = route_display_model->children();
293 TreeModel::Children::iterator i;
294 uint32_t position;
295 uint32_t order;
296 int n;
298 if (no_route_list_redisplay) {
299 return;
302 if (session && (rows.size() > session->nroutes())) {
303 /* temporary condition during a drag-n-drop */
304 return;
307 for (n = 0, order = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
308 TimeAxisView *tv = (*i)[route_display_columns.tv];
309 boost::shared_ptr<Route> route = (*i)[route_display_columns.route];
311 if (tv == 0) {
312 // just a "title" row
313 continue;
316 if (!route_redisplay_does_not_reset_order_keys) {
318 /* this reorder is caused by user action, so reassign sort order keys
319 to tracks.
322 route->set_order_key (_order_key, order);
325 bool visible = (*i)[route_display_columns.visible];
327 if (visible) {
328 tv->set_marked_for_display (true);
329 position += tv->show_at (position, n, &edit_controls_vbox);
330 tv->clip_to_viewport ();
331 } else {
332 tv->set_marked_for_display (false);
333 tv->hide ();
336 ++order;
337 ++n;
340 /* whenever we go idle, update the track view list to reflect the new order.
341 we can't do this here, because we could mess up something that is traversing
342 the track order and has caused a redisplay of the list.
345 Glib::signal_idle().connect (mem_fun (*this, &Editor::sync_track_view_list_and_route_list));
347 full_canvas_height = position + canvas_timebars_vsize;
348 vertical_adjustment.set_upper (full_canvas_height);
349 if ((vertical_adjustment.get_value() + canvas_height) > vertical_adjustment.get_upper()) {
351 We're increasing the size of the canvas while the bottom is visible.
352 We scroll down to keep in step with the controls layout.
354 vertical_adjustment.set_value (full_canvas_height - canvas_height);
357 if (!route_redisplay_does_not_reset_order_keys && !route_redisplay_does_not_sync_order_keys) {
358 session->sync_order_keys (_order_key);
362 bool
363 Editor::sync_track_view_list_and_route_list ()
365 TreeModel::Children rows = route_display_model->children();
366 TreeModel::Children::iterator i;
368 track_views.clear ();
370 for (i = rows.begin(); i != rows.end(); ++i) {
371 TimeAxisView *tv = (*i)[route_display_columns.tv];
372 track_views.push_back (tv);
375 return false; // do not call again (until needed)
378 void
379 Editor::hide_all_tracks (bool with_select)
381 TreeModel::Children rows = route_display_model->children();
382 TreeModel::Children::iterator i;
384 no_route_list_redisplay = true;
386 for (i = rows.begin(); i != rows.end(); ++i) {
388 TreeModel::Row row = (*i);
389 TimeAxisView *tv = row[route_display_columns.tv];
391 if (tv == 0) {
392 continue;
395 row[route_display_columns.visible] = false;
398 no_route_list_redisplay = false;
399 redisplay_route_list ();
401 /* XXX this seems like a hack and half, but its not clear where to put this
402 otherwise.
405 //reset_scrolling_region ();
408 void
409 Editor::build_route_list_menu ()
411 using namespace Menu_Helpers;
412 using namespace Gtk;
414 route_list_menu = new Menu;
416 MenuList& items = route_list_menu->items();
417 route_list_menu->set_name ("ArdourContextMenu");
419 items.push_back (MenuElem (_("Show All"), mem_fun(*this, &Editor::show_all_routes)));
420 items.push_back (MenuElem (_("Hide All"), mem_fun(*this, &Editor::hide_all_routes)));
421 items.push_back (MenuElem (_("Show All Audio Tracks"), mem_fun(*this, &Editor::show_all_audiotracks)));
422 items.push_back (MenuElem (_("Hide All Audio Tracks"), mem_fun(*this, &Editor::hide_all_audiotracks)));
423 items.push_back (MenuElem (_("Show All Audio Busses"), mem_fun(*this, &Editor::show_all_audiobus)));
424 items.push_back (MenuElem (_("Hide All Audio Busses"), mem_fun(*this, &Editor::hide_all_audiobus)));
425 items.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), mem_fun (*this, &Editor::show_tracks_with_regions_at_playhead)));
428 void
429 Editor::set_all_tracks_visibility (bool yn)
431 TreeModel::Children rows = route_display_model->children();
432 TreeModel::Children::iterator i;
434 no_route_list_redisplay = true;
436 for (i = rows.begin(); i != rows.end(); ++i) {
438 TreeModel::Row row = (*i);
439 TimeAxisView* tv = row[route_display_columns.tv];
441 if (tv == 0) {
442 continue;
445 (*i)[route_display_columns.visible] = yn;
448 no_route_list_redisplay = false;
449 redisplay_route_list ();
452 void
453 Editor::set_all_audio_visibility (int tracks, bool yn)
455 TreeModel::Children rows = route_display_model->children();
456 TreeModel::Children::iterator i;
458 no_route_list_redisplay = true;
460 for (i = rows.begin(); i != rows.end(); ++i) {
461 TreeModel::Row row = (*i);
462 TimeAxisView* tv = row[route_display_columns.tv];
463 AudioTimeAxisView* atv;
465 if (tv == 0) {
466 continue;
469 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
470 switch (tracks) {
471 case 0:
472 (*i)[route_display_columns.visible] = yn;
473 break;
475 case 1:
476 if (atv->is_audio_track()) {
477 (*i)[route_display_columns.visible] = yn;
479 break;
481 case 2:
482 if (!atv->is_audio_track()) {
483 (*i)[route_display_columns.visible] = yn;
485 break;
490 no_route_list_redisplay = false;
491 redisplay_route_list ();
494 void
495 Editor::hide_all_routes ()
497 set_all_tracks_visibility (false);
500 void
501 Editor::show_all_routes ()
503 set_all_tracks_visibility (true);
506 void
507 Editor::show_all_audiobus ()
509 set_all_audio_visibility (2, true);
511 void
512 Editor::hide_all_audiobus ()
514 set_all_audio_visibility (2, false);
517 void
518 Editor::show_all_audiotracks()
520 set_all_audio_visibility (1, true);
522 void
523 Editor::hide_all_audiotracks ()
525 set_all_audio_visibility (1, false);
528 void
529 Editor::show_tracks_with_regions_at_playhead ()
531 boost::shared_ptr<Session::RouteList> const regions = session->get_routes_with_regions_at (session->transport_frame ());
533 //suspend_redisplay ();
535 TreeModel::Children rows = route_display_model->children ();
536 for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
537 boost::shared_ptr<Route> route = (*i)[route_display_columns.route];
539 bool found = false;
540 for (Session::RouteList::iterator x = (*regions).begin(); x != (*regions).end(); ++x) {
541 if ((*x) == route)
542 found = true;
545 (*i)[route_display_columns.visible] = found;
548 no_route_list_redisplay = false;
549 redisplay_route_list ();
551 //resume_redisplay ();
554 bool
555 Editor::route_list_display_button_press (GdkEventButton* ev)
557 if (Keyboard::is_context_menu_event (ev)) {
558 show_route_list_menu ();
559 return true;
562 TreeIter iter;
563 TreeModel::Path path;
564 TreeViewColumn* column;
565 int cellx;
566 int celly;
568 if (!route_list_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
569 return false;
572 switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
573 case 0:
574 if ((iter = route_display_model->get_iter (path))) {
575 TimeAxisView* tv = (*iter)[route_display_columns.tv];
576 if (tv) {
577 bool visible = (*iter)[route_display_columns.visible];
578 (*iter)[route_display_columns.visible] = !visible;
581 return true;
583 case 1:
584 /* allow normal processing to occur */
585 return false;
587 default:
588 break;
591 return false;
594 void
595 Editor::show_route_list_menu()
597 if (route_list_menu == 0) {
598 build_route_list_menu ();
601 route_list_menu->popup (1, gtk_get_current_event_time());
604 bool
605 Editor::route_list_selection_filter (const Glib::RefPtr<TreeModel>& model, const TreeModel::Path& path, bool yn)
607 return true;
610 struct EditorOrderRouteSorter {
611 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
612 /* use of ">" forces the correct sort order */
613 return a->order_key (_order_key) < b->order_key (_order_key);
617 void
618 Editor::initial_route_list_display ()
620 boost::shared_ptr<Session::RouteList> routes = session->get_routes();
621 Session::RouteList r (*routes);
622 EditorOrderRouteSorter sorter;
624 r.sort (sorter);
626 no_route_list_redisplay = true;
628 route_display_model->clear ();
630 handle_new_route (r);
632 no_route_list_redisplay = false;
634 redisplay_route_list ();
637 void
638 Editor::track_list_reorder (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter, int* new_order)
640 route_redisplay_does_not_sync_order_keys = true;
641 session->set_remote_control_ids();
642 redisplay_route_list ();
643 route_redisplay_does_not_sync_order_keys = false;
646 void
647 Editor::route_list_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter)
649 /* never reset order keys because of a property change */
650 route_redisplay_does_not_reset_order_keys = true;
651 session->set_remote_control_ids();
652 redisplay_route_list ();
653 route_redisplay_does_not_reset_order_keys = false;
656 void
657 Editor::route_list_delete (const Gtk::TreeModel::Path& path)
659 /* this could require an order reset & sync */
660 session->set_remote_control_ids();
661 redisplay_route_list ();
664 void
665 Editor::route_list_display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
666 int x, int y,
667 const SelectionData& data,
668 guint info, guint time)
670 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
671 route_list_display.on_drag_data_received (context, x, y, data, info, time);
672 return;
674 context->drag_finish (true, false, time);
677 void
678 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
680 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
681 theslot (**i);
685 void
686 Editor::move_selected_tracks (bool up)
688 if (selection->tracks.empty()) {
689 return;
692 typedef pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
693 list<ViewRoute> view_routes;
694 vector<int> neworder;
695 TreeModel::Children rows = route_display_model->children();
696 TreeModel::Children::iterator ri;
698 for (ri = rows.begin(); ri != rows.end(); ++ri) {
699 TimeAxisView* tv = (*ri)[route_display_columns.tv];
700 boost::shared_ptr<Route> route = (*ri)[route_display_columns.route];
702 view_routes.push_back (ViewRoute (tv, route));
705 list<ViewRoute>::iterator trailing;
706 list<ViewRoute>::iterator leading;
708 if (up) {
710 trailing = view_routes.begin();
711 leading = view_routes.begin();
713 ++leading;
715 while (leading != view_routes.end()) {
716 if (selection->selected (leading->first)) {
717 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
718 leading = view_routes.erase (leading);
719 } else {
720 ++leading;
721 ++trailing;
725 } else {
727 /* if we could use reverse_iterator in list::insert, this code
728 would be a beautiful reflection of the code above. but we can't
729 and so it looks like a bit of a mess.
732 trailing = view_routes.end();
733 leading = view_routes.end();
735 --leading; if (leading == view_routes.begin()) { return; }
736 --leading;
737 --trailing;
739 while (1) {
741 if (selection->selected (leading->first)) {
742 list<ViewRoute>::iterator tmp;
744 /* need to insert *after* trailing, not *before* it,
745 which is what insert (iter, val) normally does.
748 tmp = trailing;
749 tmp++;
751 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
753 /* can't use iter = cont.erase (iter); form here, because
754 we need iter to move backwards.
757 tmp = leading;
758 --tmp;
760 bool done = false;
762 if (leading == view_routes.begin()) {
763 /* the one we've just inserted somewhere else
764 was the first in the list. erase this copy,
765 and then break, because we're done.
767 done = true;
770 view_routes.erase (leading);
772 if (done) {
773 break;
776 leading = tmp;
778 } else {
779 if (leading == view_routes.begin()) {
780 break;
782 --leading;
783 --trailing;
788 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
789 neworder.push_back (leading->second->order_key (_order_key));
792 route_display_model->reorder (neworder);
794 session->sync_order_keys (_order_key);