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));
134 tv->GoingAway.connect (bind (mem_fun(*this, &Editor::remove_route), tv));
137 no_route_list_redisplay = false;
139 redisplay_route_list ();
141 if (show_editor_mixer_when_tracks_arrive) {
142 show_editor_mixer (true);
145 editor_list_button.set_sensitive(true);
146 route_redisplay_does_not_sync_order_keys = false;
150 Editor::handle_gui_changes (const string & what, void *src)
152 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_gui_changes), what, src));
154 if (what == "track_height") {
155 /* Optional :make tracks change height while it happens, instead
158 //track_canvas->update_now ();
159 redisplay_route_list ();
162 if (what == "visible_tracks") {
163 redisplay_route_list ();
168 Editor::remove_route (TimeAxisView *tv)
170 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::remove_route), tv));
172 TrackViewList::iterator i;
173 TreeModel::Children rows = route_display_model->children();
174 TreeModel::Children::iterator ri;
175 boost::shared_ptr<Route> route;
176 TimeAxisView* next_tv;
178 if (tv == entered_track) {
182 /* the core model has changed, there is no need to sync
186 route_redisplay_does_not_sync_order_keys = true;
188 for (ri = rows.begin(); ri != rows.end(); ++ri) {
189 if ((*ri)[route_display_columns.tv] == tv) {
190 route = (*ri)[route_display_columns.route];
191 route_display_model->erase (ri);
196 route_redisplay_does_not_sync_order_keys = false;
198 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
200 i = track_views.erase (i);
202 if (track_views.empty()) {
204 } else if (i == track_views.end()) {
205 next_tv = track_views.front();
211 if (current_mixer_strip && current_mixer_strip->route() == route) {
214 set_selected_mixer_strip (*next_tv);
216 /* make the editor mixer strip go away setting the
217 * button to inactive (which also unticks the menu option)
220 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
226 Editor::route_name_changed (TimeAxisView *tv)
228 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::route_name_changed), tv));
230 TreeModel::Children rows = route_display_model->children();
231 TreeModel::Children::iterator i;
233 for (i = rows.begin(); i != rows.end(); ++i) {
234 if ((*i)[route_display_columns.tv] == tv) {
235 (*i)[route_display_columns.text] = tv->name();
242 Editor::update_route_visibility ()
244 TreeModel::Children rows = route_display_model->children();
245 TreeModel::Children::iterator i;
247 no_route_list_redisplay = true;
249 for (i = rows.begin(); i != rows.end(); ++i) {
250 TimeAxisView *tv = (*i)[route_display_columns.tv];
251 (*i)[route_display_columns.visible] = tv->marked_for_display ();
252 cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
255 no_route_list_redisplay = false;
256 redisplay_route_list ();
260 Editor::hide_track_in_display (TimeAxisView& tv, bool temponly)
262 TreeModel::Children rows = route_display_model->children();
263 TreeModel::Children::iterator i;
265 for (i = rows.begin(); i != rows.end(); ++i) {
266 if ((*i)[route_display_columns.tv] == &tv) {
267 (*i)[route_display_columns.visible] = false;
272 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
274 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
275 // this will hide the mixer strip
276 set_selected_mixer_strip (tv);
281 Editor::show_track_in_display (TimeAxisView& tv)
283 TreeModel::Children rows = route_display_model->children();
284 TreeModel::Children::iterator i;
286 for (i = rows.begin(); i != rows.end(); ++i) {
287 if ((*i)[route_display_columns.tv] == &tv) {
288 (*i)[route_display_columns.visible] = true;
295 Editor::route_list_reordered (const TreeModel::Path& path,const TreeModel::iterator& iter,int* what)
297 redisplay_route_list ();
302 Editor::sync_order_keys (const char *src)
304 vector<int> neworder;
305 TreeModel::Children rows = route_display_model->children();
306 TreeModel::Children::iterator ri;
308 if ((strcmp (src, _order_key) == 0) || !session || (session->state_of_the_state() & Session::Loading) || rows.empty()) {
312 for (ri = rows.begin(); ri != rows.end(); ++ri) {
313 neworder.push_back (0);
316 bool changed = false;
319 for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
320 boost::shared_ptr<Route> route = (*ri)[route_display_columns.route];
323 int new_key = route->order_key (_order_key);
325 neworder[new_key] = old_key;
327 if (new_key != old_key) {
333 route_redisplay_does_not_reset_order_keys = true;
334 route_display_model->reorder (neworder);
335 route_redisplay_does_not_reset_order_keys = false;
340 Editor::redisplay_route_list ()
342 TreeModel::Children rows = route_display_model->children();
343 TreeModel::Children::iterator i;
347 if (no_route_list_redisplay) {
351 for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
352 TimeAxisView *tv = (*i)[route_display_columns.tv];
353 boost::shared_ptr<Route> route = (*i)[route_display_columns.route];
356 // just a "title" row
360 if (!route_redisplay_does_not_reset_order_keys) {
362 /* this reorder is caused by user action, so reassign sort order keys
366 route->set_order_key (_order_key, n);
369 bool visible = (*i)[route_display_columns.visible];
371 /* show or hide the TimeAxisView */
373 tv->set_marked_for_display (true);
374 position += tv->show_at (position, n, &edit_controls_vbox);
375 tv->clip_to_viewport ();
377 tv->set_marked_for_display (false);
385 /* whenever we go idle, update the track view list to reflect the new order.
386 we can't do this here, because we could mess up something that is traversing
387 the track order and has caused a redisplay of the list.
390 Glib::signal_idle().connect (mem_fun (*this, &Editor::sync_track_view_list_and_route_list));
392 full_canvas_height = position + canvas_timebars_vsize;
393 vertical_adjustment.set_upper (full_canvas_height);
394 if ((vertical_adjustment.get_value() + canvas_height) > vertical_adjustment.get_upper()) {
396 We're increasing the size of the canvas while the bottom is visible.
397 We scroll down to keep in step with the controls layout.
399 vertical_adjustment.set_value (full_canvas_height - canvas_height);
402 if (!route_redisplay_does_not_reset_order_keys && !route_redisplay_does_not_sync_order_keys) {
403 session->sync_order_keys (_order_key);
408 Editor::sync_track_view_list_and_route_list ()
410 TreeModel::Children rows = route_display_model->children();
411 TreeModel::Children::iterator i;
413 track_views.clear ();
415 for (i = rows.begin(); i != rows.end(); ++i) {
416 TimeAxisView *tv = (*i)[route_display_columns.tv];
417 track_views.push_back (tv);
420 return false; // do not call again (until needed)
424 Editor::hide_all_tracks (bool with_select)
426 TreeModel::Children rows = route_display_model->children();
427 TreeModel::Children::iterator i;
429 no_route_list_redisplay = true;
431 for (i = rows.begin(); i != rows.end(); ++i) {
433 TreeModel::Row row = (*i);
434 TimeAxisView *tv = row[route_display_columns.tv];
440 row[route_display_columns.visible] = false;
443 no_route_list_redisplay = false;
444 redisplay_route_list ();
446 /* XXX this seems like a hack and half, but its not clear where to put this
450 //reset_scrolling_region ();
454 Editor::build_route_list_menu ()
456 using namespace Menu_Helpers;
459 route_list_menu = new Menu;
461 MenuList& items = route_list_menu->items();
462 route_list_menu->set_name ("ArdourContextMenu");
464 items.push_back (MenuElem (_("Show All"), mem_fun(*this, &Editor::show_all_routes)));
465 items.push_back (MenuElem (_("Hide All"), mem_fun(*this, &Editor::hide_all_routes)));
466 items.push_back (MenuElem (_("Show All Audio Tracks"), mem_fun(*this, &Editor::show_all_audiotracks)));
467 items.push_back (MenuElem (_("Hide All Audio Tracks"), mem_fun(*this, &Editor::hide_all_audiotracks)));
468 items.push_back (MenuElem (_("Show All Audio Busses"), mem_fun(*this, &Editor::show_all_audiobus)));
469 items.push_back (MenuElem (_("Hide All Audio Busses"), mem_fun(*this, &Editor::hide_all_audiobus)));
474 Editor::set_all_tracks_visibility (bool yn)
476 TreeModel::Children rows = route_display_model->children();
477 TreeModel::Children::iterator i;
479 no_route_list_redisplay = true;
481 for (i = rows.begin(); i != rows.end(); ++i) {
483 TreeModel::Row row = (*i);
484 TimeAxisView* tv = row[route_display_columns.tv];
490 (*i)[route_display_columns.visible] = yn;
493 no_route_list_redisplay = false;
494 redisplay_route_list ();
498 Editor::set_all_audio_visibility (int tracks, bool yn)
500 TreeModel::Children rows = route_display_model->children();
501 TreeModel::Children::iterator i;
503 no_route_list_redisplay = true;
505 for (i = rows.begin(); i != rows.end(); ++i) {
506 TreeModel::Row row = (*i);
507 TimeAxisView* tv = row[route_display_columns.tv];
508 AudioTimeAxisView* atv;
514 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
517 (*i)[route_display_columns.visible] = yn;
521 if (atv->is_audio_track()) {
522 (*i)[route_display_columns.visible] = yn;
527 if (!atv->is_audio_track()) {
528 (*i)[route_display_columns.visible] = yn;
535 no_route_list_redisplay = false;
536 redisplay_route_list ();
540 Editor::hide_all_routes ()
542 set_all_tracks_visibility (false);
546 Editor::show_all_routes ()
548 set_all_tracks_visibility (true);
552 Editor::show_all_audiobus ()
554 set_all_audio_visibility (2, true);
557 Editor::hide_all_audiobus ()
559 set_all_audio_visibility (2, false);
563 Editor::show_all_audiotracks()
565 set_all_audio_visibility (1, true);
568 Editor::hide_all_audiotracks ()
570 set_all_audio_visibility (1, false);
574 Editor::route_list_display_button_press (GdkEventButton* ev)
576 if (Keyboard::is_context_menu_event (ev)) {
577 show_route_list_menu ();
582 TreeModel::Path path;
583 TreeViewColumn* column;
587 if (!route_list_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
591 switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
593 if ((iter = route_display_model->get_iter (path))) {
594 TimeAxisView* tv = (*iter)[route_display_columns.tv];
596 bool visible = (*iter)[route_display_columns.visible];
597 (*iter)[route_display_columns.visible] = !visible;
603 /* allow normal processing to occur */
614 Editor::show_route_list_menu()
616 if (route_list_menu == 0) {
617 build_route_list_menu ();
620 route_list_menu->popup (1, gtk_get_current_event_time());
624 Editor::route_list_selection_filter (const Glib::RefPtr<TreeModel>& model, const TreeModel::Path& path, bool yn)
629 struct EditorOrderRouteSorter {
630 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
631 /* use of ">" forces the correct sort order */
632 return a->order_key (_order_key) < b->order_key (_order_key);
637 Editor::initial_route_list_display ()
639 boost::shared_ptr<RouteList> routes = session->get_routes();
640 RouteList r (*routes);
641 EditorOrderRouteSorter sorter;
645 no_route_list_redisplay = true;
647 route_display_model->clear ();
649 handle_new_route (r);
651 no_route_list_redisplay = false;
653 redisplay_route_list ();
657 Editor::track_list_reorder (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter, int* new_order)
659 route_redisplay_does_not_sync_order_keys = true;
660 session->set_remote_control_ids();
661 redisplay_route_list ();
662 route_redisplay_does_not_sync_order_keys = false;
666 Editor::route_list_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter)
668 /* never reset order keys because of a property change */
669 route_redisplay_does_not_reset_order_keys = true;
670 session->set_remote_control_ids();
671 redisplay_route_list ();
672 route_redisplay_does_not_reset_order_keys = false;
676 Editor::route_list_delete (const Gtk::TreeModel::Path& path)
678 /* this could require an order reset & sync */
679 session->set_remote_control_ids();
680 ignore_route_list_reorder = true;
681 redisplay_route_list ();
682 ignore_route_list_reorder = false;
686 Editor::route_list_display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
688 const SelectionData& data,
689 guint info, guint time)
691 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
692 route_list_display.on_drag_data_received (context, x, y, data, info, time);
695 context->drag_finish (true, false, time);
699 Editor::get_route_view_by_id (PBD::ID& id)
701 RouteTimeAxisView* v;
703 for(TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
704 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
705 if(v->route()->id() == id) {
715 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
717 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
723 Editor::move_selected_tracks (bool up)
725 if (selection->tracks.empty()) {
729 typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
730 std::list<ViewRoute> view_routes;
731 std::vector<int> neworder;
732 TreeModel::Children rows = route_display_model->children();
733 TreeModel::Children::iterator ri;
735 for (ri = rows.begin(); ri != rows.end(); ++ri) {
736 TimeAxisView* tv = (*ri)[route_display_columns.tv];
737 boost::shared_ptr<Route> route = (*ri)[route_display_columns.route];
739 view_routes.push_back (ViewRoute (tv, route));
742 list<ViewRoute>::iterator trailing;
743 list<ViewRoute>::iterator leading;
747 trailing = view_routes.begin();
748 leading = view_routes.begin();
752 while (leading != view_routes.end()) {
753 if (selection->selected (leading->first)) {
754 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
755 leading = view_routes.erase (leading);
764 /* if we could use reverse_iterator in list::insert, this code
765 would be a beautiful reflection of the code above. but we can't
766 and so it looks like a bit of a mess.
769 trailing = view_routes.end();
770 leading = view_routes.end();
772 --leading; if (leading == view_routes.begin()) { return; }
778 if (selection->selected (leading->first)) {
779 list<ViewRoute>::iterator tmp;
781 /* need to insert *after* trailing, not *before* it,
782 which is what insert (iter, val) normally does.
788 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
790 /* can't use iter = cont.erase (iter); form here, because
791 we need iter to move backwards.
799 if (leading == view_routes.begin()) {
800 /* the one we've just inserted somewhere else
801 was the first in the list. erase this copy,
802 and then break, because we're done.
807 view_routes.erase (leading);
816 if (leading == view_routes.begin()) {
825 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
826 neworder.push_back (leading->second->order_key (_order_key));
829 route_display_model->reorder (neworder);
831 session->sync_order_keys (_order_key);