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>
34 #include <ardour/route_group.h>
39 using namespace ARDOUR
;
44 const char* _order_key
= N_("editor");
47 Editor::handle_new_route (Session::RouteList
& routes
)
49 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_new_route
), routes
));
52 AudioTimeAxisView
*atv
;
53 TreeModel::Row parent
;
56 route_redisplay_does_not_sync_order_keys
= true;
57 no_route_list_redisplay
= true;
59 for (Session::RouteList::iterator x
= routes
.begin(); x
!= routes
.end(); ++x
) {
60 boost::shared_ptr
<Route
> route
= (*x
);
62 if (route
->hidden()) {
66 tv
= new AudioTimeAxisView (*this, *session
, route
, *track_canvas
);
67 //cerr << "Editor::handle_new_route() called on " << route->name() << endl;//DEBUG
68 row
= *(route_display_model
->append ());
70 row
[route_display_columns
.route
] = route
;
71 row
[route_display_columns
.text
] = route
->name();
72 row
[route_display_columns
.visible
] = tv
->marked_for_display();
73 row
[route_display_columns
.tv
] = tv
;
75 RouteGroup
*group
= route
->edit_group();
77 if (tv
->marked_for_display()) {
78 group
->set_hidden(false, this);
79 group_flags_changed(this, group
);
83 track_views
.push_back (tv
);
85 if ((atv
= dynamic_cast<AudioTimeAxisView
*> (tv
)) != 0) {
86 /* added a new fresh one at the end */
87 if (atv
->route()->order_key(_order_key
) == -1) {
88 atv
->route()->set_order_key (_order_key
, route_display_model
->children().size()-1);
90 atv
->effective_gain_display ();
93 route
->gui_changed
.connect (mem_fun(*this, &Editor::handle_gui_changes
));
94 tv
->GoingAway
.connect (bind (mem_fun(*this, &Editor::remove_route
), tv
));
97 no_route_list_redisplay
= false;
99 redisplay_route_list ();
101 if (show_editor_mixer_when_tracks_arrive
) {
102 show_editor_mixer (true);
105 route_redisplay_does_not_sync_order_keys
= false;
109 Editor::handle_gui_changes (const string
& what
, void *src
)
111 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_gui_changes
), what
, src
));
113 if (what
== "track_height") {
114 /* Optional :make tracks change height while it happens, instead
117 //track_canvas->update_now ();
118 redisplay_route_list ();
121 if (what
== "visible_tracks") {
122 redisplay_route_list ();
127 Editor::remove_route (TimeAxisView
*tv
)
129 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::remove_route
), tv
));
131 TrackViewList::iterator i
;
132 TreeModel::Children rows
= route_display_model
->children();
133 TreeModel::Children::iterator ri
;
134 boost::shared_ptr
<Route
> route
;
135 TimeAxisView
* next_tv
= 0;
137 if (tv
== entered_track
) {
141 /* the core model has changed, there is no need to sync
145 route_redisplay_does_not_sync_order_keys
= true;
147 for (ri
= rows
.begin(); ri
!= rows
.end(); ++ri
) {
148 if ((*ri
)[route_display_columns
.tv
] == tv
) {
149 route
= (*ri
)[route_display_columns
.route
];
150 route_display_model
->erase (ri
);
155 route_redisplay_does_not_sync_order_keys
= false;
157 if ((i
= find (track_views
.begin(), track_views
.end(), tv
)) != track_views
.end()) {
158 i
= track_views
.erase (i
);
160 if (track_views
.empty()) {
162 } else if (i
== track_views
.end()) {
163 next_tv
= track_views
.front();
169 if (current_mixer_strip
&& (current_mixer_strip
->route() == route
)) {
172 set_selected_mixer_strip (*next_tv
);
174 /* make the editor mixer strip go away by setting the
175 * button to inactive (which also unticks the menu option)
178 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
184 Editor::route_name_changed (TimeAxisView
*tv
)
186 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::route_name_changed
), tv
));
188 TreeModel::Children rows
= route_display_model
->children();
189 TreeModel::Children::iterator i
;
191 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
192 if ((*i
)[route_display_columns
.tv
] == tv
) {
193 (*i
)[route_display_columns
.text
] = tv
->name();
200 Editor::update_route_visibility ()
202 TreeModel::Children rows
= route_display_model
->children();
203 TreeModel::Children::iterator i
;
205 no_route_list_redisplay
= true;
207 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
208 TimeAxisView
*tv
= (*i
)[route_display_columns
.tv
];
209 (*i
)[route_display_columns
.visible
] = tv
->marked_for_display ();
212 no_route_list_redisplay
= false;
213 redisplay_route_list ();
217 Editor::hide_track_in_display (TimeAxisView
& tv
, bool temponly
)
219 TreeModel::Children rows
= route_display_model
->children();
220 TreeModel::Children::iterator i
;
222 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
223 if ((*i
)[route_display_columns
.tv
] == &tv
) {
224 (*i
)[route_display_columns
.visible
] = false;
229 AudioTimeAxisView
* atv
= dynamic_cast<AudioTimeAxisView
*> (&tv
);
231 if (atv
&& current_mixer_strip
&& (atv
->route() == current_mixer_strip
->route())) {
232 // this will hide the mixer strip
233 set_selected_mixer_strip (tv
);
238 Editor::show_track_in_display (TimeAxisView
& tv
)
240 TreeModel::Children rows
= route_display_model
->children();
241 TreeModel::Children::iterator i
;
243 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
244 if ((*i
)[route_display_columns
.tv
] == &tv
) {
245 (*i
)[route_display_columns
.visible
] = true;
252 Editor::sync_order_keys (const char *src
)
254 vector
<int> neworder
;
255 TreeModel::Children rows
= route_display_model
->children();
256 TreeModel::Children::iterator ri
;
258 if ((strcmp (src
, _order_key
) == 0) || !session
|| (session
->state_of_the_state() & Session::Loading
) || rows
.empty()) {
262 for (ri
= rows
.begin(); ri
!= rows
.end(); ++ri
) {
263 neworder
.push_back (0);
266 bool changed
= false;
269 for (order
= 0, ri
= rows
.begin(); ri
!= rows
.end(); ++ri
, ++order
) {
270 boost::shared_ptr
<Route
> route
= (*ri
)[route_display_columns
.route
];
273 int new_key
= route
->order_key (_order_key
);
275 neworder
[new_key
] = old_key
;
277 if (new_key
!= old_key
) {
283 route_redisplay_does_not_reset_order_keys
= true;
284 route_display_model
->reorder (neworder
);
285 route_redisplay_does_not_reset_order_keys
= false;
290 Editor::redisplay_route_list ()
292 TreeModel::Children rows
= route_display_model
->children();
293 TreeModel::Children::iterator i
;
298 if (no_route_list_redisplay
) {
302 if (session
&& (rows
.size() > session
->nroutes())) {
303 /* temporary condition during a drag-n-drop */
307 for (n
= 0, order
= 0, position
= 0, i
= rows
.begin(); i
!= rows
.end(); ++i
) {
308 TimeAxisView
*tv
= (*i
)[route_display_columns
.tv
];
309 boost::shared_ptr
<Route
> route
= (*i
)[route_display_columns
.route
];
312 // just a "title" row
316 if (!route_redisplay_does_not_reset_order_keys
) {
318 /* this reorder is caused by user action, so reassign sort order keys
322 route
->set_order_key (_order_key
, order
);
325 bool visible
= (*i
)[route_display_columns
.visible
];
328 tv
->set_marked_for_display (true);
329 position
+= tv
->show_at (position
, n
, &edit_controls_vbox
);
330 tv
->clip_to_viewport ();
332 tv
->set_marked_for_display (false);
340 /* whenever we go idle, update the track view list to reflect the new order.
341 we can't do this here, because we could mess up something that is traversing
342 the track order and has caused a redisplay of the list.
345 Glib::signal_idle().connect (mem_fun (*this, &Editor::sync_track_view_list_and_route_list
));
347 full_canvas_height
= position
+ canvas_timebars_vsize
;
348 vertical_adjustment
.set_upper (full_canvas_height
);
349 if ((vertical_adjustment
.get_value() + canvas_height
) > vertical_adjustment
.get_upper()) {
351 We're increasing the size of the canvas while the bottom is visible.
352 We scroll down to keep in step with the controls layout.
354 vertical_adjustment
.set_value (full_canvas_height
- canvas_height
);
357 if (!route_redisplay_does_not_reset_order_keys
&& !route_redisplay_does_not_sync_order_keys
) {
358 session
->sync_order_keys (_order_key
);
363 Editor::sync_track_view_list_and_route_list ()
365 TreeModel::Children rows
= route_display_model
->children();
366 TreeModel::Children::iterator i
;
368 track_views
.clear ();
370 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
371 TimeAxisView
*tv
= (*i
)[route_display_columns
.tv
];
372 track_views
.push_back (tv
);
375 return false; // do not call again (until needed)
379 Editor::hide_all_tracks (bool with_select
)
381 TreeModel::Children rows
= route_display_model
->children();
382 TreeModel::Children::iterator i
;
384 no_route_list_redisplay
= true;
386 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
388 TreeModel::Row row
= (*i
);
389 TimeAxisView
*tv
= row
[route_display_columns
.tv
];
395 row
[route_display_columns
.visible
] = false;
398 no_route_list_redisplay
= false;
399 redisplay_route_list ();
401 /* XXX this seems like a hack and half, but its not clear where to put this
405 //reset_scrolling_region ();
409 Editor::build_route_list_menu ()
411 using namespace Menu_Helpers
;
414 route_list_menu
= new Menu
;
416 MenuList
& items
= route_list_menu
->items();
417 route_list_menu
->set_name ("ArdourContextMenu");
419 items
.push_back (MenuElem (_("Show All"), mem_fun(*this, &Editor::show_all_routes
)));
420 items
.push_back (MenuElem (_("Hide All"), mem_fun(*this, &Editor::hide_all_routes
)));
421 items
.push_back (MenuElem (_("Show All Audio Tracks"), mem_fun(*this, &Editor::show_all_audiotracks
)));
422 items
.push_back (MenuElem (_("Hide All Audio Tracks"), mem_fun(*this, &Editor::hide_all_audiotracks
)));
423 items
.push_back (MenuElem (_("Show All Audio Busses"), mem_fun(*this, &Editor::show_all_audiobus
)));
424 items
.push_back (MenuElem (_("Hide All Audio Busses"), mem_fun(*this, &Editor::hide_all_audiobus
)));
425 items
.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), mem_fun (*this, &Editor::show_tracks_with_regions_at_playhead
)));
429 Editor::set_all_tracks_visibility (bool yn
)
431 TreeModel::Children rows
= route_display_model
->children();
432 TreeModel::Children::iterator i
;
434 no_route_list_redisplay
= true;
436 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
438 TreeModel::Row row
= (*i
);
439 TimeAxisView
* tv
= row
[route_display_columns
.tv
];
445 (*i
)[route_display_columns
.visible
] = yn
;
448 no_route_list_redisplay
= false;
449 redisplay_route_list ();
453 Editor::set_all_audio_visibility (int tracks
, bool yn
)
455 TreeModel::Children rows
= route_display_model
->children();
456 TreeModel::Children::iterator i
;
458 no_route_list_redisplay
= true;
460 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
461 TreeModel::Row row
= (*i
);
462 TimeAxisView
* tv
= row
[route_display_columns
.tv
];
463 AudioTimeAxisView
* atv
;
469 if ((atv
= dynamic_cast<AudioTimeAxisView
*>(tv
)) != 0) {
472 (*i
)[route_display_columns
.visible
] = yn
;
476 if (atv
->is_audio_track()) {
477 (*i
)[route_display_columns
.visible
] = yn
;
482 if (!atv
->is_audio_track()) {
483 (*i
)[route_display_columns
.visible
] = yn
;
490 no_route_list_redisplay
= false;
491 redisplay_route_list ();
495 Editor::hide_all_routes ()
497 set_all_tracks_visibility (false);
501 Editor::show_all_routes ()
503 set_all_tracks_visibility (true);
507 Editor::show_all_audiobus ()
509 set_all_audio_visibility (2, true);
512 Editor::hide_all_audiobus ()
514 set_all_audio_visibility (2, false);
518 Editor::show_all_audiotracks()
520 set_all_audio_visibility (1, true);
523 Editor::hide_all_audiotracks ()
525 set_all_audio_visibility (1, false);
529 Editor::show_tracks_with_regions_at_playhead ()
531 boost::shared_ptr
<Session::RouteList
> const regions
= session
->get_routes_with_regions_at (session
->transport_frame ());
533 //suspend_redisplay ();
535 TreeModel::Children rows
= route_display_model
->children ();
536 for (TreeModel::Children::iterator i
= rows
.begin(); i
!= rows
.end(); ++i
) {
537 boost::shared_ptr
<Route
> route
= (*i
)[route_display_columns
.route
];
540 for (Session::RouteList::iterator x
= (*regions
).begin(); x
!= (*regions
).end(); ++x
) {
545 (*i
)[route_display_columns
.visible
] = found
;
548 no_route_list_redisplay
= false;
549 redisplay_route_list ();
551 //resume_redisplay ();
555 Editor::route_list_display_button_press (GdkEventButton
* ev
)
557 if (Keyboard::is_context_menu_event (ev
)) {
558 show_route_list_menu ();
563 TreeModel::Path path
;
564 TreeViewColumn
* column
;
568 if (!route_list_display
.get_path_at_pos ((int)ev
->x
, (int)ev
->y
, path
, column
, cellx
, celly
)) {
572 switch (GPOINTER_TO_UINT (column
->get_data (X_("colnum")))) {
574 if ((iter
= route_display_model
->get_iter (path
))) {
575 TimeAxisView
* tv
= (*iter
)[route_display_columns
.tv
];
577 bool visible
= (*iter
)[route_display_columns
.visible
];
578 (*iter
)[route_display_columns
.visible
] = !visible
;
584 /* allow normal processing to occur */
595 Editor::show_route_list_menu()
597 if (route_list_menu
== 0) {
598 build_route_list_menu ();
601 route_list_menu
->popup (1, gtk_get_current_event_time());
605 Editor::route_list_selection_filter (const Glib::RefPtr
<TreeModel
>& model
, const TreeModel::Path
& path
, bool yn
)
610 struct EditorOrderRouteSorter
{
611 bool operator() (boost::shared_ptr
<Route
> a
, boost::shared_ptr
<Route
> b
) {
612 /* use of ">" forces the correct sort order */
613 return a
->order_key (_order_key
) < b
->order_key (_order_key
);
618 Editor::initial_route_list_display ()
620 boost::shared_ptr
<Session::RouteList
> routes
= session
->get_routes();
621 Session::RouteList
r (*routes
);
622 EditorOrderRouteSorter sorter
;
626 no_route_list_redisplay
= true;
628 route_display_model
->clear ();
630 handle_new_route (r
);
632 no_route_list_redisplay
= false;
634 redisplay_route_list ();
638 Editor::track_list_reorder (const Gtk::TreeModel::Path
& path
,const Gtk::TreeModel::iterator
& iter
, int* new_order
)
640 route_redisplay_does_not_sync_order_keys
= true;
641 session
->set_remote_control_ids();
642 redisplay_route_list ();
643 route_redisplay_does_not_sync_order_keys
= false;
647 Editor::route_list_change (const Gtk::TreeModel::Path
& path
,const Gtk::TreeModel::iterator
& iter
)
649 /* never reset order keys because of a property change */
650 route_redisplay_does_not_reset_order_keys
= true;
651 session
->set_remote_control_ids();
652 redisplay_route_list ();
653 route_redisplay_does_not_reset_order_keys
= false;
657 Editor::route_list_delete (const Gtk::TreeModel::Path
& path
)
659 /* this could require an order reset & sync */
660 session
->set_remote_control_ids();
661 redisplay_route_list ();
665 Editor::route_list_display_drag_data_received (const RefPtr
<Gdk::DragContext
>& context
,
667 const SelectionData
& data
,
668 guint info
, guint time
)
670 if (data
.get_target() == "GTK_TREE_MODEL_ROW") {
671 route_list_display
.on_drag_data_received (context
, x
, y
, data
, info
, time
);
674 context
->drag_finish (true, false, time
);
678 Editor::foreach_time_axis_view (sigc::slot
<void,TimeAxisView
&> theslot
)
680 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
686 Editor::move_selected_tracks (bool up
)
688 if (selection
->tracks
.empty()) {
692 typedef pair
<TimeAxisView
*,boost::shared_ptr
<Route
> > ViewRoute
;
693 list
<ViewRoute
> view_routes
;
694 vector
<int> neworder
;
695 TreeModel::Children rows
= route_display_model
->children();
696 TreeModel::Children::iterator ri
;
698 for (ri
= rows
.begin(); ri
!= rows
.end(); ++ri
) {
699 TimeAxisView
* tv
= (*ri
)[route_display_columns
.tv
];
700 boost::shared_ptr
<Route
> route
= (*ri
)[route_display_columns
.route
];
702 view_routes
.push_back (ViewRoute (tv
, route
));
705 list
<ViewRoute
>::iterator trailing
;
706 list
<ViewRoute
>::iterator leading
;
710 trailing
= view_routes
.begin();
711 leading
= view_routes
.begin();
715 while (leading
!= view_routes
.end()) {
716 if (selection
->selected (leading
->first
)) {
717 view_routes
.insert (trailing
, ViewRoute (leading
->first
, leading
->second
));
718 leading
= view_routes
.erase (leading
);
727 /* if we could use reverse_iterator in list::insert, this code
728 would be a beautiful reflection of the code above. but we can't
729 and so it looks like a bit of a mess.
732 trailing
= view_routes
.end();
733 leading
= view_routes
.end();
735 --leading
; if (leading
== view_routes
.begin()) { return; }
741 if (selection
->selected (leading
->first
)) {
742 list
<ViewRoute
>::iterator tmp
;
744 /* need to insert *after* trailing, not *before* it,
745 which is what insert (iter, val) normally does.
751 view_routes
.insert (tmp
, ViewRoute (leading
->first
, leading
->second
));
753 /* can't use iter = cont.erase (iter); form here, because
754 we need iter to move backwards.
762 if (leading
== view_routes
.begin()) {
763 /* the one we've just inserted somewhere else
764 was the first in the list. erase this copy,
765 and then break, because we're done.
770 view_routes
.erase (leading
);
779 if (leading
== view_routes
.begin()) {
788 for (leading
= view_routes
.begin(); leading
!= view_routes
.end(); ++leading
) {
789 neworder
.push_back (leading
->second
->order_key (_order_key
));
792 route_display_model
->reorder (neworder
);
794 session
->sync_order_keys (_order_key
);