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.
29 #include "ardour_ui.h"
30 #include "audio_time_axis.h"
31 #include "midi_time_axis.h"
32 #include "mixer_strip.h"
33 #include "gui_thread.h"
36 #include "pbd/unknown_type.h"
38 #include "ardour/route.h"
43 using namespace ARDOUR;
48 const char* _order_key = N_("editor");
51 Editor::handle_new_route (RouteList& routes)
53 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_new_route), routes));
56 RouteTimeAxisView *rtv;
57 TreeModel::Row parent;
60 route_redisplay_does_not_sync_order_keys = true;
61 no_route_list_redisplay = true;
63 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
64 boost::shared_ptr<Route> route = (*x);
66 if (route->is_hidden()) {
70 if (route->default_type() == ARDOUR::DataType::AUDIO)
71 tv = new AudioTimeAxisView (*this, *session, route, *track_canvas);
72 else if (route->default_type() == ARDOUR::DataType::MIDI)
73 tv = new MidiTimeAxisView (*this, *session, route, *track_canvas);
77 //cerr << "Editor::handle_new_route() called on " << route->name() << endl;//DEBUG
79 if (route_display_model->children().size() == 0) {
81 /* set up basic entries */
85 row = *(route_display_model->append()); // path = "0"
86 row[route_display_columns.text] = _("Busses");
87 row[route_display_columns.tv] = 0;
88 row = *(route_display_model->append()); // path = "1"
89 row[route_display_columns.text] = _("Tracks");
90 row[route_display_columns.tv] = 0;
94 if (dynamic_cast<AudioTrack*>(route.get()) != 0) {
95 TreeModel::iterator iter = route_display_model->get_iter ("1"); // audio tracks
98 TreeModel::iterator iter = route_display_model->get_iter ("0"); // busses
103 row = *(route_display_model->append (parent.children()));
105 row = *(route_display_model->append ());
108 // cerr << route->name() << " marked for display ? " << tv->marked_for_display() << endl;
110 row[route_display_columns.text] = route->name();
111 row[route_display_columns.visible] = tv->marked_for_display();
112 row[route_display_columns.tv] = tv;
113 row[route_display_columns.route] = route;
115 track_views.push_back (tv);
117 ignore_route_list_reorder = true;
119 if ((rtv = dynamic_cast<RouteTimeAxisView*> (tv)) != 0) {
120 /* added a new fresh one at the end */
121 if (rtv->route()->order_key(_order_key) == -1) {
122 rtv->route()->set_order_key (_order_key, route_display_model->children().size()-1);
124 rtv->effective_gain_display ();
127 ignore_route_list_reorder = false;
129 route->gui_changed.connect (mem_fun(*this, &Editor::handle_gui_changes));
131 tv->GoingAway.connect (bind (mem_fun(*this, &Editor::remove_route), tv));
134 no_route_list_redisplay = false;
136 redisplay_route_list ();
138 if (show_editor_mixer_when_tracks_arrive) {
139 show_editor_mixer (true);
142 editor_list_button.set_sensitive(true);
143 route_redisplay_does_not_sync_order_keys = false;
147 Editor::handle_gui_changes (const string & what, void *src)
149 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_gui_changes), what, src));
151 if (what == "track_height") {
152 /* Optional :make tracks change height while it happens, instead
155 //track_canvas->update_now ();
156 redisplay_route_list ();
159 if (what == "visible_tracks") {
160 redisplay_route_list ();
165 Editor::remove_route (TimeAxisView *tv)
167 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::remove_route), tv));
169 TrackViewList::iterator i;
170 TreeModel::Children rows = route_display_model->children();
171 TreeModel::Children::iterator ri;
172 boost::shared_ptr<Route> route;
173 TimeAxisView* next_tv;
175 if (tv == entered_track) {
179 /* the core model has changed, there is no need to sync
183 route_redisplay_does_not_sync_order_keys = true;
185 for (ri = rows.begin(); ri != rows.end(); ++ri) {
186 if ((*ri)[route_display_columns.tv] == tv) {
187 route = (*ri)[route_display_columns.route];
188 route_display_model->erase (ri);
193 route_redisplay_does_not_sync_order_keys = false;
195 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
197 i = track_views.erase (i);
199 if (track_views.empty()) {
201 } else if (i == track_views.end()) {
202 next_tv = track_views.front();
208 if (current_mixer_strip && current_mixer_strip->route() == route) {
211 set_selected_mixer_strip (*next_tv);
213 /* make the editor mixer strip go away setting the
214 * button to inactive (which also unticks the menu option)
217 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
223 Editor::route_name_changed (TimeAxisView *tv)
225 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::route_name_changed), tv));
227 TreeModel::Children rows = route_display_model->children();
228 TreeModel::Children::iterator i;
230 for (i = rows.begin(); i != rows.end(); ++i) {
231 if ((*i)[route_display_columns.tv] == tv) {
232 (*i)[route_display_columns.text] = tv->name();
239 Editor::update_route_visibility ()
241 TreeModel::Children rows = route_display_model->children();
242 TreeModel::Children::iterator i;
244 no_route_list_redisplay = true;
246 for (i = rows.begin(); i != rows.end(); ++i) {
247 TimeAxisView *tv = (*i)[route_display_columns.tv];
248 (*i)[route_display_columns.visible] = tv->marked_for_display ();
249 cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
252 no_route_list_redisplay = false;
253 redisplay_route_list ();
257 Editor::hide_track_in_display (TimeAxisView& tv, bool temponly)
259 TreeModel::Children rows = route_display_model->children();
260 TreeModel::Children::iterator i;
262 for (i = rows.begin(); i != rows.end(); ++i) {
263 if ((*i)[route_display_columns.tv] == &tv) {
264 (*i)[route_display_columns.visible] = false;
269 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
271 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
272 // this will hide the mixer strip
273 set_selected_mixer_strip (tv);
278 Editor::show_track_in_display (TimeAxisView& tv)
280 TreeModel::Children rows = route_display_model->children();
281 TreeModel::Children::iterator i;
283 for (i = rows.begin(); i != rows.end(); ++i) {
284 if ((*i)[route_display_columns.tv] == &tv) {
285 (*i)[route_display_columns.visible] = true;
292 Editor::route_list_reordered (const TreeModel::Path& path,const TreeModel::iterator& iter,int* what)
294 redisplay_route_list ();
299 Editor::sync_order_keys (const char *src)
301 vector<int> neworder;
302 TreeModel::Children rows = route_display_model->children();
303 TreeModel::Children::iterator ri;
305 if ((strcmp (src, _order_key) == 0) || !session || (session->state_of_the_state() & Session::Loading) || rows.empty()) {
309 for (ri = rows.begin(); ri != rows.end(); ++ri) {
310 neworder.push_back (0);
313 bool changed = false;
316 for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
317 boost::shared_ptr<Route> route = (*ri)[route_display_columns.route];
320 int new_key = route->order_key (_order_key);
322 neworder[new_key] = old_key;
324 if (new_key != old_key) {
330 route_redisplay_does_not_reset_order_keys = true;
331 route_display_model->reorder (neworder);
332 route_redisplay_does_not_reset_order_keys = false;
337 Editor::redisplay_route_list ()
339 TreeModel::Children rows = route_display_model->children();
340 TreeModel::Children::iterator i;
344 if (no_route_list_redisplay) {
348 for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
349 TimeAxisView *tv = (*i)[route_display_columns.tv];
350 boost::shared_ptr<Route> route = (*i)[route_display_columns.route];
353 // just a "title" row
357 if (!route_redisplay_does_not_reset_order_keys) {
359 /* this reorder is caused by user action, so reassign sort order keys
363 route->set_order_key (_order_key, n);
366 bool visible = (*i)[route_display_columns.visible];
368 /* show or hide the TimeAxisView */
370 tv->set_marked_for_display (true);
371 position += tv->show_at (position, n, &edit_controls_vbox);
372 tv->clip_to_viewport ();
374 tv->set_marked_for_display (false);
382 /* whenever we go idle, update the track view list to reflect the new order.
383 we can't do this here, because we could mess up something that is traversing
384 the track order and has caused a redisplay of the list.
387 Glib::signal_idle().connect (mem_fun (*this, &Editor::sync_track_view_list_and_route_list));
389 full_canvas_height = position + canvas_timebars_vsize;
390 vertical_adjustment.set_upper (full_canvas_height);
391 if ((vertical_adjustment.get_value() + canvas_height) > vertical_adjustment.get_upper()) {
393 We're increasing the size of the canvas while the bottom is visible.
394 We scroll down to keep in step with the controls layout.
396 vertical_adjustment.set_value (full_canvas_height - canvas_height);
399 if (!route_redisplay_does_not_reset_order_keys && !route_redisplay_does_not_sync_order_keys) {
400 session->sync_order_keys (_order_key);
405 Editor::sync_track_view_list_and_route_list ()
407 TreeModel::Children rows = route_display_model->children();
408 TreeModel::Children::iterator i;
410 track_views.clear ();
412 for (i = rows.begin(); i != rows.end(); ++i) {
413 TimeAxisView *tv = (*i)[route_display_columns.tv];
414 track_views.push_back (tv);
417 return false; // do not call again (until needed)
421 Editor::hide_all_tracks (bool with_select)
423 TreeModel::Children rows = route_display_model->children();
424 TreeModel::Children::iterator i;
426 no_route_list_redisplay = true;
428 for (i = rows.begin(); i != rows.end(); ++i) {
430 TreeModel::Row row = (*i);
431 TimeAxisView *tv = row[route_display_columns.tv];
437 row[route_display_columns.visible] = false;
440 no_route_list_redisplay = false;
441 redisplay_route_list ();
443 /* XXX this seems like a hack and half, but its not clear where to put this
447 //reset_scrolling_region ();
451 Editor::build_route_list_menu ()
453 using namespace Menu_Helpers;
456 route_list_menu = new Menu;
458 MenuList& items = route_list_menu->items();
459 route_list_menu->set_name ("ArdourContextMenu");
461 items.push_back (MenuElem (_("Show All"), mem_fun(*this, &Editor::show_all_routes)));
462 items.push_back (MenuElem (_("Hide All"), mem_fun(*this, &Editor::hide_all_routes)));
463 items.push_back (MenuElem (_("Show All Audio Tracks"), mem_fun(*this, &Editor::show_all_audiotracks)));
464 items.push_back (MenuElem (_("Hide All Audio Tracks"), mem_fun(*this, &Editor::hide_all_audiotracks)));
465 items.push_back (MenuElem (_("Show All Audio Busses"), mem_fun(*this, &Editor::show_all_audiobus)));
466 items.push_back (MenuElem (_("Hide All Audio Busses"), mem_fun(*this, &Editor::hide_all_audiobus)));
471 Editor::set_all_tracks_visibility (bool yn)
473 TreeModel::Children rows = route_display_model->children();
474 TreeModel::Children::iterator i;
476 no_route_list_redisplay = true;
478 for (i = rows.begin(); i != rows.end(); ++i) {
480 TreeModel::Row row = (*i);
481 TimeAxisView* tv = row[route_display_columns.tv];
487 (*i)[route_display_columns.visible] = yn;
490 no_route_list_redisplay = false;
491 redisplay_route_list ();
495 Editor::set_all_audio_visibility (int tracks, bool yn)
497 TreeModel::Children rows = route_display_model->children();
498 TreeModel::Children::iterator i;
500 no_route_list_redisplay = true;
502 for (i = rows.begin(); i != rows.end(); ++i) {
503 TreeModel::Row row = (*i);
504 TimeAxisView* tv = row[route_display_columns.tv];
505 AudioTimeAxisView* atv;
511 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
514 (*i)[route_display_columns.visible] = yn;
518 if (atv->is_audio_track()) {
519 (*i)[route_display_columns.visible] = yn;
524 if (!atv->is_audio_track()) {
525 (*i)[route_display_columns.visible] = yn;
532 no_route_list_redisplay = false;
533 redisplay_route_list ();
537 Editor::hide_all_routes ()
539 set_all_tracks_visibility (false);
543 Editor::show_all_routes ()
545 set_all_tracks_visibility (true);
549 Editor::show_all_audiobus ()
551 set_all_audio_visibility (2, true);
554 Editor::hide_all_audiobus ()
556 set_all_audio_visibility (2, false);
560 Editor::show_all_audiotracks()
562 set_all_audio_visibility (1, true);
565 Editor::hide_all_audiotracks ()
567 set_all_audio_visibility (1, false);
571 Editor::route_list_display_button_press (GdkEventButton* ev)
573 if (Keyboard::is_context_menu_event (ev)) {
574 show_route_list_menu ();
579 TreeModel::Path path;
580 TreeViewColumn* column;
584 if (!route_list_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
588 switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
590 if ((iter = route_display_model->get_iter (path))) {
591 TimeAxisView* tv = (*iter)[route_display_columns.tv];
593 bool visible = (*iter)[route_display_columns.visible];
594 (*iter)[route_display_columns.visible] = !visible;
600 /* allow normal processing to occur */
611 Editor::show_route_list_menu()
613 if (route_list_menu == 0) {
614 build_route_list_menu ();
617 route_list_menu->popup (1, gtk_get_current_event_time());
621 Editor::route_list_selection_filter (const Glib::RefPtr<TreeModel>& model, const TreeModel::Path& path, bool yn)
626 struct EditorOrderRouteSorter {
627 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
628 /* use of ">" forces the correct sort order */
629 return a->order_key (_order_key) < b->order_key (_order_key);
634 Editor::initial_route_list_display ()
636 boost::shared_ptr<RouteList> routes = session->get_routes();
637 RouteList r (*routes);
638 EditorOrderRouteSorter sorter;
642 no_route_list_redisplay = true;
644 route_display_model->clear ();
646 handle_new_route (r);
648 no_route_list_redisplay = false;
650 redisplay_route_list ();
654 Editor::track_list_reorder (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter, int* new_order)
656 route_redisplay_does_not_sync_order_keys = true;
657 session->set_remote_control_ids();
658 redisplay_route_list ();
659 route_redisplay_does_not_sync_order_keys = false;
663 Editor::route_list_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter)
665 /* never reset order keys because of a property change */
666 route_redisplay_does_not_reset_order_keys = true;
667 session->set_remote_control_ids();
668 redisplay_route_list ();
669 route_redisplay_does_not_reset_order_keys = false;
673 Editor::route_list_delete (const Gtk::TreeModel::Path& path)
675 /* this could require an order reset & sync */
676 session->set_remote_control_ids();
677 ignore_route_list_reorder = true;
678 redisplay_route_list ();
679 ignore_route_list_reorder = false;
683 Editor::route_list_display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
685 const SelectionData& data,
686 guint info, guint time)
688 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
689 route_list_display.on_drag_data_received (context, x, y, data, info, time);
692 context->drag_finish (true, false, time);
696 Editor::get_route_view_by_id (PBD::ID& id)
698 RouteTimeAxisView* v;
700 for(TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
701 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
702 if(v->route()->id() == id) {
712 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
714 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
720 Editor::move_selected_tracks (bool up)
722 if (selection->tracks.empty()) {
726 typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
727 std::list<ViewRoute> view_routes;
728 std::vector<int> neworder;
729 TreeModel::Children rows = route_display_model->children();
730 TreeModel::Children::iterator ri;
732 for (ri = rows.begin(); ri != rows.end(); ++ri) {
733 TimeAxisView* tv = (*ri)[route_display_columns.tv];
734 boost::shared_ptr<Route> route = (*ri)[route_display_columns.route];
736 view_routes.push_back (ViewRoute (tv, route));
739 list<ViewRoute>::iterator trailing;
740 list<ViewRoute>::iterator leading;
744 trailing = view_routes.begin();
745 leading = view_routes.begin();
749 while (leading != view_routes.end()) {
750 if (selection->selected (leading->first)) {
751 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
752 leading = view_routes.erase (leading);
761 /* if we could use reverse_iterator in list::insert, this code
762 would be a beautiful reflection of the code above. but we can't
763 and so it looks like a bit of a mess.
766 trailing = view_routes.end();
767 leading = view_routes.end();
769 --leading; if (leading == view_routes.begin()) { return; }
775 if (selection->selected (leading->first)) {
776 list<ViewRoute>::iterator tmp;
778 /* need to insert *after* trailing, not *before* it,
779 which is what insert (iter, val) normally does.
785 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
787 /* can't use iter = cont.erase (iter); form here, because
788 we need iter to move backwards.
796 if (leading == view_routes.begin()) {
797 /* the one we've just inserted somewhere else
798 was the first in the list. erase this copy,
799 and then break, because we're done.
804 view_routes.erase (leading);
813 if (leading == view_routes.begin()) {
822 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
823 neworder.push_back (leading->second->order_key (_order_key));
826 route_display_model->reorder (neworder);
828 session->sync_order_keys (_order_key);