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.
26 #include "ardour_ui.h"
27 #include "audio_time_axis.h"
28 #include "mixer_strip.h"
29 #include "gui_thread.h"
32 #include <ardour/route.h>
33 #include <ardour/audio_track.h>
38 using namespace ARDOUR;
43 const char* _order_key = N_("editor");
46 Editor::handle_new_route (Session::RouteList& routes)
48 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_new_route), routes));
51 AudioTimeAxisView *atv;
52 TreeModel::Row parent;
55 route_redisplay_does_not_sync_order_keys = true;
56 no_route_list_redisplay = true;
58 for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
59 boost::shared_ptr<Route> route = (*x);
61 if (route->hidden()) {
65 tv = new AudioTimeAxisView (*this, *session, route, *track_canvas);
66 //cerr << "Editor::handle_new_route() called on " << route->name() << endl;//DEBUG
67 row = *(route_display_model->append ());
69 row[route_display_columns.route] = route;
70 row[route_display_columns.text] = route->name();
71 row[route_display_columns.visible] = tv->marked_for_display();
72 row[route_display_columns.tv] = tv;
74 track_views.push_back (tv);
76 if ((atv = dynamic_cast<AudioTimeAxisView*> (tv)) != 0) {
77 /* added a new fresh one at the end */
78 if (atv->route()->order_key(_order_key) == -1) {
79 atv->route()->set_order_key (_order_key, route_display_model->children().size()-1);
81 atv->effective_gain_display ();
84 route->gui_changed.connect (mem_fun(*this, &Editor::handle_gui_changes));
85 tv->GoingAway.connect (bind (mem_fun(*this, &Editor::remove_route), tv));
88 no_route_list_redisplay = false;
90 redisplay_route_list ();
92 if (show_editor_mixer_when_tracks_arrive) {
93 show_editor_mixer (true);
96 route_redisplay_does_not_sync_order_keys = false;
100 Editor::handle_gui_changes (const string & what, void *src)
102 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_gui_changes), what, src));
104 if (what == "track_height") {
105 /* Optional :make tracks change height while it happens, instead
108 //track_canvas->update_now ();
109 redisplay_route_list ();
112 if (what == "visible_tracks") {
113 redisplay_route_list ();
118 Editor::remove_route (TimeAxisView *tv)
120 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::remove_route), tv));
122 TrackViewList::iterator i;
123 TreeModel::Children rows = route_display_model->children();
124 TreeModel::Children::iterator ri;
125 boost::shared_ptr<Route> route;
126 TimeAxisView* next_tv;
128 if (tv == entered_track) {
132 /* the core model has changed, there is no need to sync
136 route_redisplay_does_not_sync_order_keys = true;
138 for (ri = rows.begin(); ri != rows.end(); ++ri) {
139 if ((*ri)[route_display_columns.tv] == tv) {
140 route = (*ri)[route_display_columns.route];
141 route_display_model->erase (ri);
146 route_redisplay_does_not_sync_order_keys = false;
148 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
149 i = track_views.erase (i);
151 if (track_views.empty()) {
153 } else if (i == track_views.end()) {
154 next_tv = track_views.front();
160 if (current_mixer_strip && (current_mixer_strip->route() == route)) {
163 set_selected_mixer_strip (*next_tv);
165 /* make the editor mixer strip go away by setting the
166 * button to inactive (which also unticks the menu option)
169 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
175 Editor::route_name_changed (TimeAxisView *tv)
177 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::route_name_changed), tv));
179 TreeModel::Children rows = route_display_model->children();
180 TreeModel::Children::iterator i;
182 for (i = rows.begin(); i != rows.end(); ++i) {
183 if ((*i)[route_display_columns.tv] == tv) {
184 (*i)[route_display_columns.text] = tv->name();
191 Editor::update_route_visibility ()
193 TreeModel::Children rows = route_display_model->children();
194 TreeModel::Children::iterator i;
196 no_route_list_redisplay = true;
198 for (i = rows.begin(); i != rows.end(); ++i) {
199 TimeAxisView *tv = (*i)[route_display_columns.tv];
200 (*i)[route_display_columns.visible] = tv->marked_for_display ();
203 no_route_list_redisplay = false;
204 redisplay_route_list ();
208 Editor::hide_track_in_display (TimeAxisView& tv, bool temponly)
210 TreeModel::Children rows = route_display_model->children();
211 TreeModel::Children::iterator i;
213 for (i = rows.begin(); i != rows.end(); ++i) {
214 if ((*i)[route_display_columns.tv] == &tv) {
215 (*i)[route_display_columns.visible] = false;
220 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
222 if (atv && current_mixer_strip && (atv->route() == current_mixer_strip->route())) {
223 // this will hide the mixer strip
224 set_selected_mixer_strip (tv);
229 Editor::show_track_in_display (TimeAxisView& tv)
231 TreeModel::Children rows = route_display_model->children();
232 TreeModel::Children::iterator i;
234 for (i = rows.begin(); i != rows.end(); ++i) {
235 if ((*i)[route_display_columns.tv] == &tv) {
236 (*i)[route_display_columns.visible] = true;
243 Editor::sync_order_keys (const char *src)
245 vector<int> neworder;
246 TreeModel::Children rows = route_display_model->children();
247 TreeModel::Children::iterator ri;
249 if ((strcmp (src, _order_key) == 0) || !session || (session->state_of_the_state() & Session::Loading) || rows.empty()) {
253 for (ri = rows.begin(); ri != rows.end(); ++ri) {
254 neworder.push_back (0);
257 bool changed = false;
260 for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
261 boost::shared_ptr<Route> route = (*ri)[route_display_columns.route];
264 int new_key = route->order_key (_order_key);
266 neworder[new_key] = old_key;
268 if (new_key != old_key) {
274 route_redisplay_does_not_reset_order_keys = true;
275 route_display_model->reorder (neworder);
276 route_redisplay_does_not_reset_order_keys = false;
281 Editor::redisplay_route_list ()
283 TreeModel::Children rows = route_display_model->children();
284 TreeModel::Children::iterator i;
289 if (no_route_list_redisplay) {
293 if (session && (rows.size() > session->nroutes())) {
294 /* temporary condition during a drag-n-drop */
298 for (n = 0, order = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
299 TimeAxisView *tv = (*i)[route_display_columns.tv];
300 boost::shared_ptr<Route> route = (*i)[route_display_columns.route];
303 // just a "title" row
307 if (!route_redisplay_does_not_reset_order_keys) {
309 /* this reorder is caused by user action, so reassign sort order keys
313 route->set_order_key (_order_key, order);
316 bool visible = (*i)[route_display_columns.visible];
319 tv->set_marked_for_display (true);
320 position += tv->show_at (position, n, &edit_controls_vbox);
321 tv->clip_to_viewport ();
323 tv->set_marked_for_display (false);
331 /* whenever we go idle, update the track view list to reflect the new order.
332 we can't do this here, because we could mess up something that is traversing
333 the track order and has caused a redisplay of the list.
336 Glib::signal_idle().connect (mem_fun (*this, &Editor::sync_track_view_list_and_route_list));
338 full_canvas_height = position + canvas_timebars_vsize;
339 vertical_adjustment.set_upper (full_canvas_height);
340 if ((vertical_adjustment.get_value() + canvas_height) > vertical_adjustment.get_upper()) {
342 We're increasing the size of the canvas while the bottom is visible.
343 We scroll down to keep in step with the controls layout.
345 vertical_adjustment.set_value (full_canvas_height - canvas_height);
348 if (!route_redisplay_does_not_reset_order_keys && !route_redisplay_does_not_sync_order_keys) {
349 session->sync_order_keys (_order_key);
354 Editor::sync_track_view_list_and_route_list ()
356 TreeModel::Children rows = route_display_model->children();
357 TreeModel::Children::iterator i;
359 track_views.clear ();
361 for (i = rows.begin(); i != rows.end(); ++i) {
362 TimeAxisView *tv = (*i)[route_display_columns.tv];
363 track_views.push_back (tv);
366 return false; // do not call again (until needed)
370 Editor::hide_all_tracks (bool with_select)
372 TreeModel::Children rows = route_display_model->children();
373 TreeModel::Children::iterator i;
375 no_route_list_redisplay = true;
377 for (i = rows.begin(); i != rows.end(); ++i) {
379 TreeModel::Row row = (*i);
380 TimeAxisView *tv = row[route_display_columns.tv];
386 row[route_display_columns.visible] = false;
389 no_route_list_redisplay = false;
390 redisplay_route_list ();
392 /* XXX this seems like a hack and half, but its not clear where to put this
396 //reset_scrolling_region ();
400 Editor::build_route_list_menu ()
402 using namespace Menu_Helpers;
405 route_list_menu = new Menu;
407 MenuList& items = route_list_menu->items();
408 route_list_menu->set_name ("ArdourContextMenu");
410 items.push_back (MenuElem (_("Show All"), mem_fun(*this, &Editor::show_all_routes)));
411 items.push_back (MenuElem (_("Hide All"), mem_fun(*this, &Editor::hide_all_routes)));
412 items.push_back (MenuElem (_("Show All Audio Tracks"), mem_fun(*this, &Editor::show_all_audiotracks)));
413 items.push_back (MenuElem (_("Hide All Audio Tracks"), mem_fun(*this, &Editor::hide_all_audiotracks)));
414 items.push_back (MenuElem (_("Show All Audio Busses"), mem_fun(*this, &Editor::show_all_audiobus)));
415 items.push_back (MenuElem (_("Hide All Audio Busses"), mem_fun(*this, &Editor::hide_all_audiobus)));
420 Editor::set_all_tracks_visibility (bool yn)
422 TreeModel::Children rows = route_display_model->children();
423 TreeModel::Children::iterator i;
425 no_route_list_redisplay = true;
427 for (i = rows.begin(); i != rows.end(); ++i) {
429 TreeModel::Row row = (*i);
430 TimeAxisView* tv = row[route_display_columns.tv];
436 (*i)[route_display_columns.visible] = yn;
439 no_route_list_redisplay = false;
440 redisplay_route_list ();
444 Editor::set_all_audio_visibility (int tracks, bool yn)
446 TreeModel::Children rows = route_display_model->children();
447 TreeModel::Children::iterator i;
449 no_route_list_redisplay = true;
451 for (i = rows.begin(); i != rows.end(); ++i) {
452 TreeModel::Row row = (*i);
453 TimeAxisView* tv = row[route_display_columns.tv];
454 AudioTimeAxisView* atv;
460 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
463 (*i)[route_display_columns.visible] = yn;
467 if (atv->is_audio_track()) {
468 (*i)[route_display_columns.visible] = yn;
473 if (!atv->is_audio_track()) {
474 (*i)[route_display_columns.visible] = yn;
481 no_route_list_redisplay = false;
482 redisplay_route_list ();
486 Editor::hide_all_routes ()
488 set_all_tracks_visibility (false);
492 Editor::show_all_routes ()
494 set_all_tracks_visibility (true);
498 Editor::show_all_audiobus ()
500 set_all_audio_visibility (2, true);
503 Editor::hide_all_audiobus ()
505 set_all_audio_visibility (2, false);
509 Editor::show_all_audiotracks()
511 set_all_audio_visibility (1, true);
514 Editor::hide_all_audiotracks ()
516 set_all_audio_visibility (1, false);
520 Editor::route_list_display_button_press (GdkEventButton* ev)
522 if (Keyboard::is_context_menu_event (ev)) {
523 show_route_list_menu ();
528 TreeModel::Path path;
529 TreeViewColumn* column;
533 if (!route_list_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
537 switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
539 if ((iter = route_display_model->get_iter (path))) {
540 TimeAxisView* tv = (*iter)[route_display_columns.tv];
542 bool visible = (*iter)[route_display_columns.visible];
543 (*iter)[route_display_columns.visible] = !visible;
549 /* allow normal processing to occur */
560 Editor::show_route_list_menu()
562 if (route_list_menu == 0) {
563 build_route_list_menu ();
566 route_list_menu->popup (1, gtk_get_current_event_time());
570 Editor::route_list_selection_filter (const Glib::RefPtr<TreeModel>& model, const TreeModel::Path& path, bool yn)
575 struct EditorOrderRouteSorter {
576 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
577 /* use of ">" forces the correct sort order */
578 return a->order_key (_order_key) < b->order_key (_order_key);
583 Editor::initial_route_list_display ()
585 boost::shared_ptr<Session::RouteList> routes = session->get_routes();
586 Session::RouteList r (*routes);
587 EditorOrderRouteSorter sorter;
591 no_route_list_redisplay = true;
593 route_display_model->clear ();
595 handle_new_route (r);
597 no_route_list_redisplay = false;
599 redisplay_route_list ();
603 Editor::track_list_reorder (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter, int* new_order)
605 route_redisplay_does_not_sync_order_keys = true;
606 session->set_remote_control_ids();
607 redisplay_route_list ();
608 route_redisplay_does_not_sync_order_keys = false;
612 Editor::route_list_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter)
614 /* never reset order keys because of a property change */
615 route_redisplay_does_not_reset_order_keys = true;
616 session->set_remote_control_ids();
617 redisplay_route_list ();
618 route_redisplay_does_not_reset_order_keys = false;
622 Editor::route_list_delete (const Gtk::TreeModel::Path& path)
624 /* this could require an order reset & sync */
625 session->set_remote_control_ids();
626 redisplay_route_list ();
630 Editor::route_list_display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
632 const SelectionData& data,
633 guint info, guint time)
635 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
636 route_list_display.on_drag_data_received (context, x, y, data, info, time);
639 context->drag_finish (true, false, time);
643 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
645 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
651 Editor::move_selected_tracks (bool up)
653 if (selection->tracks.empty()) {
657 typedef pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
658 list<ViewRoute> view_routes;
659 vector<int> neworder;
660 TreeModel::Children rows = route_display_model->children();
661 TreeModel::Children::iterator ri;
663 for (ri = rows.begin(); ri != rows.end(); ++ri) {
664 TimeAxisView* tv = (*ri)[route_display_columns.tv];
665 boost::shared_ptr<Route> route = (*ri)[route_display_columns.route];
667 view_routes.push_back (ViewRoute (tv, route));
670 list<ViewRoute>::iterator trailing;
671 list<ViewRoute>::iterator leading;
675 trailing = view_routes.begin();
676 leading = view_routes.begin();
680 while (leading != view_routes.end()) {
681 if (selection->selected (leading->first)) {
682 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
683 leading = view_routes.erase (leading);
692 /* if we could use reverse_iterator in list::insert, this code
693 would be a beautiful reflection of the code above. but we can't
694 and so it looks like a bit of a mess.
697 trailing = view_routes.end();
698 leading = view_routes.end();
700 --leading; if (leading == view_routes.begin()) { return; }
706 if (selection->selected (leading->first)) {
707 list<ViewRoute>::iterator tmp;
709 /* need to insert *after* trailing, not *before* it,
710 which is what insert (iter, val) normally does.
716 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
718 /* can't use iter = cont.erase (iter); form here, because
719 we need iter to move backwards.
727 if (leading == view_routes.begin()) {
728 /* the one we've just inserted somewhere else
729 was the first in the list. erase this copy,
730 and then break, because we're done.
735 view_routes.erase (leading);
744 if (leading == view_routes.begin()) {
753 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
754 neworder.push_back (leading->second->order_key (_order_key));
757 route_display_model->reorder (neworder);
759 session->sync_order_keys (_order_key);