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 return false; // do not call again (until needed)
428 Editor::hide_all_tracks (bool with_select)
430 TreeModel::Children rows = route_display_model->children();
431 TreeModel::Children::iterator i;
433 no_route_list_redisplay = true;
435 for (i = rows.begin(); i != rows.end(); ++i) {
437 TreeModel::Row row = (*i);
438 TimeAxisView *tv = row[route_display_columns.tv];
444 row[route_display_columns.visible] = false;
447 no_route_list_redisplay = false;
448 redisplay_route_list ();
450 /* XXX this seems like a hack and half, but its not clear where to put this
454 //reset_scrolling_region ();
458 Editor::build_route_list_menu ()
460 using namespace Menu_Helpers;
463 route_list_menu = new Menu;
465 MenuList& items = route_list_menu->items();
466 route_list_menu->set_name ("ArdourContextMenu");
468 items.push_back (MenuElem (_("Show All"), mem_fun(*this, &Editor::show_all_routes)));
469 items.push_back (MenuElem (_("Hide All"), mem_fun(*this, &Editor::hide_all_routes)));
470 items.push_back (MenuElem (_("Show All Audio Tracks"), mem_fun(*this, &Editor::show_all_audiotracks)));
471 items.push_back (MenuElem (_("Hide All Audio Tracks"), mem_fun(*this, &Editor::hide_all_audiotracks)));
472 items.push_back (MenuElem (_("Show All Audio Busses"), mem_fun(*this, &Editor::show_all_audiobus)));
473 items.push_back (MenuElem (_("Hide All Audio Busses"), mem_fun(*this, &Editor::hide_all_audiobus)));
478 Editor::set_all_tracks_visibility (bool yn)
480 TreeModel::Children rows = route_display_model->children();
481 TreeModel::Children::iterator i;
483 no_route_list_redisplay = true;
485 for (i = rows.begin(); i != rows.end(); ++i) {
487 TreeModel::Row row = (*i);
488 TimeAxisView* tv = row[route_display_columns.tv];
494 (*i)[route_display_columns.visible] = yn;
497 no_route_list_redisplay = false;
498 redisplay_route_list ();
502 Editor::set_all_audio_visibility (int tracks, bool yn)
504 TreeModel::Children rows = route_display_model->children();
505 TreeModel::Children::iterator i;
507 no_route_list_redisplay = true;
509 for (i = rows.begin(); i != rows.end(); ++i) {
510 TreeModel::Row row = (*i);
511 TimeAxisView* tv = row[route_display_columns.tv];
512 AudioTimeAxisView* atv;
518 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
521 (*i)[route_display_columns.visible] = yn;
525 if (atv->is_audio_track()) {
526 (*i)[route_display_columns.visible] = yn;
531 if (!atv->is_audio_track()) {
532 (*i)[route_display_columns.visible] = yn;
539 no_route_list_redisplay = false;
540 redisplay_route_list ();
544 Editor::hide_all_routes ()
546 set_all_tracks_visibility (false);
550 Editor::show_all_routes ()
552 set_all_tracks_visibility (true);
556 Editor::show_all_audiobus ()
558 set_all_audio_visibility (2, true);
561 Editor::hide_all_audiobus ()
563 set_all_audio_visibility (2, false);
567 Editor::show_all_audiotracks()
569 set_all_audio_visibility (1, true);
572 Editor::hide_all_audiotracks ()
574 set_all_audio_visibility (1, false);
578 Editor::route_list_display_button_press (GdkEventButton* ev)
580 if (Keyboard::is_context_menu_event (ev)) {
581 show_route_list_menu ();
586 TreeModel::Path path;
587 TreeViewColumn* column;
591 if (!route_list_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
595 switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
597 if ((iter = route_display_model->get_iter (path))) {
598 TimeAxisView* tv = (*iter)[route_display_columns.tv];
600 bool visible = (*iter)[route_display_columns.visible];
601 (*iter)[route_display_columns.visible] = !visible;
607 /* allow normal processing to occur */
618 Editor::show_route_list_menu()
620 if (route_list_menu == 0) {
621 build_route_list_menu ();
624 route_list_menu->popup (1, gtk_get_current_event_time());
628 Editor::route_list_selection_filter (const Glib::RefPtr<TreeModel>& model, const TreeModel::Path& path, bool yn)
633 struct EditorOrderRouteSorter {
634 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
635 /* use of ">" forces the correct sort order */
636 return a->order_key (_order_key) < b->order_key (_order_key);
641 Editor::initial_route_list_display ()
643 boost::shared_ptr<RouteList> routes = session->get_routes();
644 RouteList r (*routes);
645 EditorOrderRouteSorter sorter;
649 no_route_list_redisplay = true;
651 route_display_model->clear ();
653 handle_new_route (r);
655 no_route_list_redisplay = false;
657 redisplay_route_list ();
661 Editor::track_list_reorder (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter, int* new_order)
663 route_redisplay_does_not_sync_order_keys = true;
664 session->set_remote_control_ids();
665 redisplay_route_list ();
666 route_redisplay_does_not_sync_order_keys = false;
670 Editor::route_list_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter)
672 /* never reset order keys because of a property change */
673 route_redisplay_does_not_reset_order_keys = true;
674 session->set_remote_control_ids();
675 redisplay_route_list ();
676 route_redisplay_does_not_reset_order_keys = false;
680 Editor::route_list_delete (const Gtk::TreeModel::Path& path)
682 /* this could require an order reset & sync */
683 session->set_remote_control_ids();
684 ignore_route_list_reorder = true;
685 redisplay_route_list ();
686 ignore_route_list_reorder = false;
690 Editor::route_list_display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
692 const SelectionData& data,
693 guint info, guint time)
695 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
696 route_list_display.on_drag_data_received (context, x, y, data, info, time);
699 context->drag_finish (true, false, time);
703 Editor::get_route_view_by_id (PBD::ID& id)
705 RouteTimeAxisView* v;
707 for(TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
708 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
709 if(v->route()->id() == id) {
719 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
721 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
727 Editor::move_selected_tracks (bool up)
729 if (selection->tracks.empty()) {
733 typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
734 std::list<ViewRoute> view_routes;
735 std::vector<int> neworder;
736 TreeModel::Children rows = route_display_model->children();
737 TreeModel::Children::iterator ri;
739 for (ri = rows.begin(); ri != rows.end(); ++ri) {
740 TimeAxisView* tv = (*ri)[route_display_columns.tv];
741 boost::shared_ptr<Route> route = (*ri)[route_display_columns.route];
743 view_routes.push_back (ViewRoute (tv, route));
746 list<ViewRoute>::iterator trailing;
747 list<ViewRoute>::iterator leading;
751 trailing = view_routes.begin();
752 leading = view_routes.begin();
756 while (leading != view_routes.end()) {
757 if (selection->selected (leading->first)) {
758 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
759 leading = view_routes.erase (leading);
768 /* if we could use reverse_iterator in list::insert, this code
769 would be a beautiful reflection of the code above. but we can't
770 and so it looks like a bit of a mess.
773 trailing = view_routes.end();
774 leading = view_routes.end();
776 --leading; if (leading == view_routes.begin()) { return; }
782 if (selection->selected (leading->first)) {
783 list<ViewRoute>::iterator tmp;
785 /* need to insert *after* trailing, not *before* it,
786 which is what insert (iter, val) normally does.
792 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
794 /* can't use iter = cont.erase (iter); form here, because
795 we need iter to move backwards.
803 if (leading == view_routes.begin()) {
804 /* the one we've just inserted somewhere else
805 was the first in the list. erase this copy,
806 and then break, because we're done.
811 view_routes.erase (leading);
820 if (leading == view_routes.begin()) {
829 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
830 neworder.push_back (leading->second->order_key (_order_key));
833 route_display_model->reorder (neworder);
835 session->sync_order_keys (_order_key);