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"
44 using namespace ARDOUR;
49 const char* _order_key = N_("editor");
52 Editor::handle_new_route (RouteList& routes)
54 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_new_route), routes));
57 RouteTimeAxisView *rtv;
58 TreeModel::Row parent;
61 route_redisplay_does_not_sync_order_keys = true;
62 no_route_list_redisplay = true;
64 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
65 boost::shared_ptr<Route> route = (*x);
67 if (route->is_hidden()) {
71 DataType dt = route->input()->default_type();
73 if (dt == ARDOUR::DataType::AUDIO)
74 tv = new AudioTimeAxisView (*this, *session, route, *track_canvas);
75 else if (dt == ARDOUR::DataType::MIDI)
76 tv = new MidiTimeAxisView (*this, *session, route, *track_canvas);
80 //cerr << "Editor::handle_new_route() called on " << route->name() << endl;//DEBUG
82 if (route_display_model->children().size() == 0) {
84 /* set up basic entries */
88 row = *(route_display_model->append()); // path = "0"
89 row[route_display_columns.text] = _("Busses");
90 row[route_display_columns.tv] = 0;
91 row = *(route_display_model->append()); // path = "1"
92 row[route_display_columns.text] = _("Tracks");
93 row[route_display_columns.tv] = 0;
97 if (dynamic_cast<AudioTrack*>(route.get()) != 0) {
98 TreeModel::iterator iter = route_display_model->get_iter ("1"); // audio tracks
101 TreeModel::iterator iter = route_display_model->get_iter ("0"); // busses
106 row = *(route_display_model->append (parent.children()));
108 row = *(route_display_model->append ());
111 // cerr << route->name() << " marked for display ? " << tv->marked_for_display() << endl;
113 row[route_display_columns.text] = route->name();
114 row[route_display_columns.visible] = tv->marked_for_display();
115 row[route_display_columns.tv] = tv;
116 row[route_display_columns.route] = route;
118 track_views.push_back (tv);
120 ignore_route_list_reorder = true;
122 if ((rtv = dynamic_cast<RouteTimeAxisView*> (tv)) != 0) {
123 /* added a new fresh one at the end */
124 if (rtv->route()->order_key(_order_key) == -1) {
125 rtv->route()->set_order_key (_order_key, route_display_model->children().size()-1);
127 rtv->effective_gain_display ();
130 ignore_route_list_reorder = false;
132 route->gui_changed.connect (mem_fun(*this, &Editor::handle_gui_changes));
133 tv->view()->RegionViewAdded.connect (mem_fun (*this, &Editor::region_view_added));
134 tv->view()->HeightChanged.connect (mem_fun (*this, &Editor::streamview_height_changed));
136 tv->GoingAway.connect (bind (mem_fun(*this, &Editor::remove_route), tv));
139 no_route_list_redisplay = false;
141 redisplay_route_list ();
143 if (show_editor_mixer_when_tracks_arrive) {
144 show_editor_mixer (true);
147 editor_list_button.set_sensitive(true);
148 route_redisplay_does_not_sync_order_keys = false;
150 _summary->set_dirty ();
154 Editor::handle_gui_changes (const string & what, void *src)
156 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_gui_changes), what, src));
158 if (what == "track_height") {
159 /* Optional :make tracks change height while it happens, instead
162 //update_canvas_now ();
163 redisplay_route_list ();
166 if (what == "visible_tracks") {
167 redisplay_route_list ();
172 Editor::remove_route (TimeAxisView *tv)
174 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::remove_route), tv));
176 TrackViewList::iterator i;
177 TreeModel::Children rows = route_display_model->children();
178 TreeModel::Children::iterator ri;
179 boost::shared_ptr<Route> route;
180 TimeAxisView* next_tv;
182 if (tv == entered_track) {
186 /* the core model has changed, there is no need to sync
190 route_redisplay_does_not_sync_order_keys = true;
192 for (ri = rows.begin(); ri != rows.end(); ++ri) {
193 if ((*ri)[route_display_columns.tv] == tv) {
194 route = (*ri)[route_display_columns.route];
195 route_display_model->erase (ri);
200 route_redisplay_does_not_sync_order_keys = false;
202 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
204 i = track_views.erase (i);
206 if (track_views.empty()) {
208 } else if (i == track_views.end()) {
209 next_tv = track_views.front();
215 if (current_mixer_strip && current_mixer_strip->route() == route) {
218 set_selected_mixer_strip (*next_tv);
220 /* make the editor mixer strip go away setting the
221 * button to inactive (which also unticks the menu option)
224 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
230 Editor::route_name_changed (TimeAxisView *tv)
232 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::route_name_changed), tv));
234 TreeModel::Children rows = route_display_model->children();
235 TreeModel::Children::iterator i;
237 for (i = rows.begin(); i != rows.end(); ++i) {
238 if ((*i)[route_display_columns.tv] == tv) {
239 (*i)[route_display_columns.text] = tv->name();
246 Editor::update_route_visibility ()
248 TreeModel::Children rows = route_display_model->children();
249 TreeModel::Children::iterator i;
251 no_route_list_redisplay = true;
253 for (i = rows.begin(); i != rows.end(); ++i) {
254 TimeAxisView *tv = (*i)[route_display_columns.tv];
255 (*i)[route_display_columns.visible] = tv->marked_for_display ();
256 cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
259 no_route_list_redisplay = false;
260 redisplay_route_list ();
264 Editor::hide_track_in_display (TimeAxisView& tv, bool temponly)
266 TreeModel::Children rows = route_display_model->children();
267 TreeModel::Children::iterator i;
269 for (i = rows.begin(); i != rows.end(); ++i) {
270 if ((*i)[route_display_columns.tv] == &tv) {
271 (*i)[route_display_columns.visible] = false;
276 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
278 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
279 // this will hide the mixer strip
280 set_selected_mixer_strip (tv);
285 Editor::show_track_in_display (TimeAxisView& tv)
287 TreeModel::Children rows = route_display_model->children();
288 TreeModel::Children::iterator i;
290 for (i = rows.begin(); i != rows.end(); ++i) {
291 if ((*i)[route_display_columns.tv] == &tv) {
292 (*i)[route_display_columns.visible] = true;
299 Editor::route_list_reordered (const TreeModel::Path& path,const TreeModel::iterator& iter,int* what)
301 redisplay_route_list ();
306 Editor::sync_order_keys (const char *src)
308 vector<int> neworder;
309 TreeModel::Children rows = route_display_model->children();
310 TreeModel::Children::iterator ri;
312 if ((strcmp (src, _order_key) == 0) || !session || (session->state_of_the_state() & Session::Loading) || rows.empty()) {
316 for (ri = rows.begin(); ri != rows.end(); ++ri) {
317 neworder.push_back (0);
320 bool changed = false;
323 for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
324 boost::shared_ptr<Route> route = (*ri)[route_display_columns.route];
327 int new_key = route->order_key (_order_key);
329 neworder[new_key] = old_key;
331 if (new_key != old_key) {
337 route_redisplay_does_not_reset_order_keys = true;
338 route_display_model->reorder (neworder);
339 route_redisplay_does_not_reset_order_keys = false;
344 Editor::redisplay_route_list ()
346 TreeModel::Children rows = route_display_model->children();
347 TreeModel::Children::iterator i;
351 if (no_route_list_redisplay) {
355 for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
356 TimeAxisView *tv = (*i)[route_display_columns.tv];
357 boost::shared_ptr<Route> route = (*i)[route_display_columns.route];
360 // just a "title" row
364 if (!route_redisplay_does_not_reset_order_keys) {
366 /* this reorder is caused by user action, so reassign sort order keys
370 route->set_order_key (_order_key, n);
373 bool visible = (*i)[route_display_columns.visible];
375 /* show or hide the TimeAxisView */
377 tv->set_marked_for_display (true);
378 position += tv->show_at (position, n, &edit_controls_vbox);
379 tv->clip_to_viewport ();
381 tv->set_marked_for_display (false);
389 /* whenever we go idle, update the track view list to reflect the new order.
390 we can't do this here, because we could mess up something that is traversing
391 the track order and has caused a redisplay of the list.
394 Glib::signal_idle().connect (mem_fun (*this, &Editor::sync_track_view_list_and_route_list));
396 full_canvas_height = position + canvas_timebars_vsize;
397 vertical_adjustment.set_upper (full_canvas_height);
398 if ((vertical_adjustment.get_value() + _canvas_height) > vertical_adjustment.get_upper()) {
400 We're increasing the size of the canvas while the bottom is visible.
401 We scroll down to keep in step with the controls layout.
403 vertical_adjustment.set_value (full_canvas_height - _canvas_height);
406 if (!route_redisplay_does_not_reset_order_keys && !route_redisplay_does_not_sync_order_keys) {
407 session->sync_order_keys (_order_key);
412 Editor::sync_track_view_list_and_route_list ()
414 TreeModel::Children rows = route_display_model->children();
415 TreeModel::Children::iterator i;
417 track_views.clear ();
419 for (i = rows.begin(); i != rows.end(); ++i) {
420 TimeAxisView *tv = (*i)[route_display_columns.tv];
421 track_views.push_back (tv);
424 _summary->set_dirty ();
426 return false; // do not call again (until needed)
430 Editor::hide_all_tracks (bool with_select)
432 TreeModel::Children rows = route_display_model->children();
433 TreeModel::Children::iterator i;
435 no_route_list_redisplay = true;
437 for (i = rows.begin(); i != rows.end(); ++i) {
439 TreeModel::Row row = (*i);
440 TimeAxisView *tv = row[route_display_columns.tv];
446 row[route_display_columns.visible] = false;
449 no_route_list_redisplay = false;
450 redisplay_route_list ();
452 /* XXX this seems like a hack and half, but its not clear where to put this
456 //reset_scrolling_region ();
460 Editor::build_route_list_menu ()
462 using namespace Menu_Helpers;
465 route_list_menu = new Menu;
467 MenuList& items = route_list_menu->items();
468 route_list_menu->set_name ("ArdourContextMenu");
470 items.push_back (MenuElem (_("Show All"), mem_fun(*this, &Editor::show_all_routes)));
471 items.push_back (MenuElem (_("Hide All"), mem_fun(*this, &Editor::hide_all_routes)));
472 items.push_back (MenuElem (_("Show All Audio Tracks"), mem_fun(*this, &Editor::show_all_audiotracks)));
473 items.push_back (MenuElem (_("Hide All Audio Tracks"), mem_fun(*this, &Editor::hide_all_audiotracks)));
474 items.push_back (MenuElem (_("Show All Audio Busses"), mem_fun(*this, &Editor::show_all_audiobus)));
475 items.push_back (MenuElem (_("Hide All Audio Busses"), mem_fun(*this, &Editor::hide_all_audiobus)));
480 Editor::set_all_tracks_visibility (bool yn)
482 TreeModel::Children rows = route_display_model->children();
483 TreeModel::Children::iterator i;
485 no_route_list_redisplay = true;
487 for (i = rows.begin(); i != rows.end(); ++i) {
489 TreeModel::Row row = (*i);
490 TimeAxisView* tv = row[route_display_columns.tv];
496 (*i)[route_display_columns.visible] = yn;
499 no_route_list_redisplay = false;
500 redisplay_route_list ();
504 Editor::set_all_audio_visibility (int tracks, bool yn)
506 TreeModel::Children rows = route_display_model->children();
507 TreeModel::Children::iterator i;
509 no_route_list_redisplay = true;
511 for (i = rows.begin(); i != rows.end(); ++i) {
512 TreeModel::Row row = (*i);
513 TimeAxisView* tv = row[route_display_columns.tv];
514 AudioTimeAxisView* atv;
520 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
523 (*i)[route_display_columns.visible] = yn;
527 if (atv->is_audio_track()) {
528 (*i)[route_display_columns.visible] = yn;
533 if (!atv->is_audio_track()) {
534 (*i)[route_display_columns.visible] = yn;
541 no_route_list_redisplay = false;
542 redisplay_route_list ();
546 Editor::hide_all_routes ()
548 set_all_tracks_visibility (false);
552 Editor::show_all_routes ()
554 set_all_tracks_visibility (true);
558 Editor::show_all_audiobus ()
560 set_all_audio_visibility (2, true);
563 Editor::hide_all_audiobus ()
565 set_all_audio_visibility (2, false);
569 Editor::show_all_audiotracks()
571 set_all_audio_visibility (1, true);
574 Editor::hide_all_audiotracks ()
576 set_all_audio_visibility (1, false);
580 Editor::route_list_display_button_press (GdkEventButton* ev)
582 if (Keyboard::is_context_menu_event (ev)) {
583 show_route_list_menu ();
588 TreeModel::Path path;
589 TreeViewColumn* column;
593 if (!route_list_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
597 switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
599 if ((iter = route_display_model->get_iter (path))) {
600 TimeAxisView* tv = (*iter)[route_display_columns.tv];
602 bool visible = (*iter)[route_display_columns.visible];
603 (*iter)[route_display_columns.visible] = !visible;
609 /* allow normal processing to occur */
620 Editor::show_route_list_menu()
622 if (route_list_menu == 0) {
623 build_route_list_menu ();
626 route_list_menu->popup (1, gtk_get_current_event_time());
630 Editor::route_list_selection_filter (const Glib::RefPtr<TreeModel>& model, const TreeModel::Path& path, bool yn)
635 struct EditorOrderRouteSorter {
636 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
637 /* use of ">" forces the correct sort order */
638 return a->order_key (_order_key) < b->order_key (_order_key);
643 Editor::initial_route_list_display ()
645 boost::shared_ptr<RouteList> routes = session->get_routes();
646 RouteList r (*routes);
647 EditorOrderRouteSorter sorter;
651 no_route_list_redisplay = true;
653 route_display_model->clear ();
655 handle_new_route (r);
657 no_route_list_redisplay = false;
659 redisplay_route_list ();
663 Editor::track_list_reorder (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter, int* new_order)
665 route_redisplay_does_not_sync_order_keys = true;
666 session->set_remote_control_ids();
667 redisplay_route_list ();
668 route_redisplay_does_not_sync_order_keys = false;
672 Editor::route_list_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter)
674 /* never reset order keys because of a property change */
675 route_redisplay_does_not_reset_order_keys = true;
676 session->set_remote_control_ids();
677 redisplay_route_list ();
678 route_redisplay_does_not_reset_order_keys = false;
682 Editor::route_list_delete (const Gtk::TreeModel::Path& path)
684 /* this could require an order reset & sync */
685 session->set_remote_control_ids();
686 ignore_route_list_reorder = true;
687 redisplay_route_list ();
688 ignore_route_list_reorder = false;
692 Editor::route_list_display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
694 const SelectionData& data,
695 guint info, guint time)
697 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
698 route_list_display.on_drag_data_received (context, x, y, data, info, time);
701 context->drag_finish (true, false, time);
705 Editor::get_route_view_by_id (PBD::ID& id)
707 RouteTimeAxisView* v;
709 for(TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
710 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
711 if(v->route()->id() == id) {
721 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
723 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
729 Editor::move_selected_tracks (bool up)
731 if (selection->tracks.empty()) {
735 typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
736 std::list<ViewRoute> view_routes;
737 std::vector<int> neworder;
738 TreeModel::Children rows = route_display_model->children();
739 TreeModel::Children::iterator ri;
741 for (ri = rows.begin(); ri != rows.end(); ++ri) {
742 TimeAxisView* tv = (*ri)[route_display_columns.tv];
743 boost::shared_ptr<Route> route = (*ri)[route_display_columns.route];
745 view_routes.push_back (ViewRoute (tv, route));
748 list<ViewRoute>::iterator trailing;
749 list<ViewRoute>::iterator leading;
753 trailing = view_routes.begin();
754 leading = view_routes.begin();
758 while (leading != view_routes.end()) {
759 if (selection->selected (leading->first)) {
760 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
761 leading = view_routes.erase (leading);
770 /* if we could use reverse_iterator in list::insert, this code
771 would be a beautiful reflection of the code above. but we can't
772 and so it looks like a bit of a mess.
775 trailing = view_routes.end();
776 leading = view_routes.end();
778 --leading; if (leading == view_routes.begin()) { return; }
784 if (selection->selected (leading->first)) {
785 list<ViewRoute>::iterator tmp;
787 /* need to insert *after* trailing, not *before* it,
788 which is what insert (iter, val) normally does.
794 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
796 /* can't use iter = cont.erase (iter); form here, because
797 we need iter to move backwards.
805 if (leading == view_routes.begin()) {
806 /* the one we've just inserted somewhere else
807 was the first in the list. erase this copy,
808 and then break, because we're done.
813 view_routes.erase (leading);
822 if (leading == view_routes.begin()) {
831 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
832 neworder.push_back (leading->second->order_key (_order_key));
835 route_display_model->reorder (neworder);
837 session->sync_order_keys (_order_key);