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 redisplay_route_list ();
120 if (what
== "visible_tracks") {
121 redisplay_route_list ();
126 Editor::remove_route (TimeAxisView
*tv
)
128 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::remove_route
), tv
));
130 TrackViewList::iterator i
;
131 TreeModel::Children rows
= route_display_model
->children();
132 TreeModel::Children::iterator ri
;
133 boost::shared_ptr
<Route
> route
;
134 TimeAxisView
* next_tv
= 0;
136 if (tv
== entered_track
) {
140 /* the core model has changed, there is no need to sync
144 route_redisplay_does_not_sync_order_keys
= true;
146 for (ri
= rows
.begin(); ri
!= rows
.end(); ++ri
) {
147 if ((*ri
)[route_display_columns
.tv
] == tv
) {
148 route
= (*ri
)[route_display_columns
.route
];
149 route_display_model
->erase (ri
);
154 route_redisplay_does_not_sync_order_keys
= false;
156 if ((i
= find (track_views
.begin(), track_views
.end(), tv
)) != track_views
.end()) {
157 i
= track_views
.erase (i
);
159 if (track_views
.empty()) {
161 } else if (i
== track_views
.end()) {
162 next_tv
= track_views
.front();
168 if (current_mixer_strip
&& (current_mixer_strip
->route() == route
)) {
171 set_selected_mixer_strip (*next_tv
);
173 /* make the editor mixer strip go away by setting the
174 * button to inactive (which also unticks the menu option)
177 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
183 Editor::route_name_changed (TimeAxisView
*tv
)
185 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::route_name_changed
), tv
));
187 TreeModel::Children rows
= route_display_model
->children();
188 TreeModel::Children::iterator i
;
190 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
191 if ((*i
)[route_display_columns
.tv
] == tv
) {
192 (*i
)[route_display_columns
.text
] = tv
->name();
199 Editor::update_route_visibility ()
201 TreeModel::Children rows
= route_display_model
->children();
202 TreeModel::Children::iterator i
;
204 no_route_list_redisplay
= true;
206 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
207 TimeAxisView
*tv
= (*i
)[route_display_columns
.tv
];
208 (*i
)[route_display_columns
.visible
] = tv
->marked_for_display ();
211 no_route_list_redisplay
= false;
212 redisplay_route_list ();
216 Editor::hide_track_in_display (TimeAxisView
& tv
, bool temponly
)
218 TreeModel::Children rows
= route_display_model
->children();
219 TreeModel::Children::iterator i
;
221 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
222 if ((*i
)[route_display_columns
.tv
] == &tv
) {
223 (*i
)[route_display_columns
.visible
] = false;
228 AudioTimeAxisView
* atv
= dynamic_cast<AudioTimeAxisView
*> (&tv
);
230 if (atv
&& current_mixer_strip
&& (atv
->route() == current_mixer_strip
->route())) {
231 // this will hide the mixer strip
232 set_selected_mixer_strip (tv
);
237 Editor::show_track_in_display (TimeAxisView
& tv
)
239 TreeModel::Children rows
= route_display_model
->children();
240 TreeModel::Children::iterator i
;
242 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
243 if ((*i
)[route_display_columns
.tv
] == &tv
) {
244 (*i
)[route_display_columns
.visible
] = true;
251 Editor::sync_order_keys (const char *src
)
253 vector
<int> neworder
;
254 TreeModel::Children rows
= route_display_model
->children();
255 TreeModel::Children::iterator ri
;
257 if ((strcmp (src
, _order_key
) == 0) || !session
|| (session
->state_of_the_state() & Session::Loading
) || rows
.empty()) {
261 for (ri
= rows
.begin(); ri
!= rows
.end(); ++ri
) {
262 neworder
.push_back (0);
265 bool changed
= false;
268 for (order
= 0, ri
= rows
.begin(); ri
!= rows
.end(); ++ri
, ++order
) {
269 boost::shared_ptr
<Route
> route
= (*ri
)[route_display_columns
.route
];
272 int new_key
= route
->order_key (_order_key
);
274 neworder
[new_key
] = old_key
;
276 if (new_key
!= old_key
) {
282 route_redisplay_does_not_reset_order_keys
= true;
283 route_display_model
->reorder (neworder
);
284 route_redisplay_does_not_reset_order_keys
= false;
289 Editor::redisplay_route_list ()
291 TreeModel::Children rows
= route_display_model
->children();
292 TreeModel::Children::iterator i
;
297 if (no_route_list_redisplay
) {
301 if (session
&& (rows
.size() > session
->nroutes())) {
302 /* temporary condition during a drag-n-drop */
306 for (n
= 0, order
= 0, position
= 0, i
= rows
.begin(); i
!= rows
.end(); ++i
) {
307 TimeAxisView
*tv
= (*i
)[route_display_columns
.tv
];
308 boost::shared_ptr
<Route
> route
= (*i
)[route_display_columns
.route
];
311 // just a "title" row
315 if (!route_redisplay_does_not_reset_order_keys
) {
317 /* this reorder is caused by user action, so reassign sort order keys
321 route
->set_order_key (_order_key
, order
);
324 bool visible
= (*i
)[route_display_columns
.visible
];
327 tv
->set_marked_for_display (true);
328 position
+= tv
->show_at (position
, n
, &edit_controls_vbox
);
329 tv
->clip_to_viewport ();
331 tv
->set_marked_for_display (false);
339 /* whenever we go idle, update the track view list to reflect the new order.
340 we can't do this here, because we could mess up something that is traversing
341 the track order and has caused a redisplay of the list.
344 Glib::signal_idle().connect (mem_fun (*this, &Editor::sync_track_view_list_and_route_list
));
346 full_canvas_height
= position
+ canvas_timebars_vsize
;
347 vertical_adjustment
.set_upper (full_canvas_height
);
348 if ((vertical_adjustment
.get_value() + canvas_height
) > vertical_adjustment
.get_upper()) {
350 We're increasing the size of the canvas while the bottom is visible.
351 We scroll down to keep in step with the controls layout.
353 vertical_adjustment
.set_value (full_canvas_height
- canvas_height
);
356 if (!route_redisplay_does_not_reset_order_keys
&& !route_redisplay_does_not_sync_order_keys
) {
357 session
->sync_order_keys (_order_key
);
362 Editor::sync_track_view_list_and_route_list ()
364 TreeModel::Children rows
= route_display_model
->children();
365 TreeModel::Children::iterator i
;
367 track_views
.clear ();
369 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
370 TimeAxisView
*tv
= (*i
)[route_display_columns
.tv
];
371 track_views
.push_back (tv
);
374 return false; // do not call again (until needed)
378 Editor::hide_all_tracks (bool with_select
)
380 TreeModel::Children rows
= route_display_model
->children();
381 TreeModel::Children::iterator i
;
383 no_route_list_redisplay
= true;
385 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
387 TreeModel::Row row
= (*i
);
388 TimeAxisView
*tv
= row
[route_display_columns
.tv
];
394 row
[route_display_columns
.visible
] = false;
397 no_route_list_redisplay
= false;
398 redisplay_route_list ();
400 /* XXX this seems like a hack and half, but its not clear where to put this
404 //reset_scrolling_region ();
408 Editor::build_route_list_menu ()
410 using namespace Menu_Helpers
;
413 route_list_menu
= new Menu
;
415 MenuList
& items
= route_list_menu
->items();
416 route_list_menu
->set_name ("ArdourContextMenu");
418 items
.push_back (MenuElem (_("Show All"), mem_fun(*this, &Editor::show_all_routes
)));
419 items
.push_back (MenuElem (_("Hide All"), mem_fun(*this, &Editor::hide_all_routes
)));
420 items
.push_back (MenuElem (_("Show All Audio Tracks"), mem_fun(*this, &Editor::show_all_audiotracks
)));
421 items
.push_back (MenuElem (_("Hide All Audio Tracks"), mem_fun(*this, &Editor::hide_all_audiotracks
)));
422 items
.push_back (MenuElem (_("Show All Audio Busses"), mem_fun(*this, &Editor::show_all_audiobus
)));
423 items
.push_back (MenuElem (_("Hide All Audio Busses"), mem_fun(*this, &Editor::hide_all_audiobus
)));
424 items
.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), mem_fun (*this, &Editor::show_tracks_with_regions_at_playhead
)));
428 Editor::set_all_tracks_visibility (bool yn
)
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 (*i
)[route_display_columns
.visible
] = yn
;
447 no_route_list_redisplay
= false;
448 redisplay_route_list ();
452 Editor::set_all_audio_visibility (int tracks
, bool yn
)
454 TreeModel::Children rows
= route_display_model
->children();
455 TreeModel::Children::iterator i
;
457 no_route_list_redisplay
= true;
459 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
460 TreeModel::Row row
= (*i
);
461 TimeAxisView
* tv
= row
[route_display_columns
.tv
];
462 AudioTimeAxisView
* atv
;
468 if ((atv
= dynamic_cast<AudioTimeAxisView
*>(tv
)) != 0) {
471 (*i
)[route_display_columns
.visible
] = yn
;
475 if (atv
->is_audio_track()) {
476 (*i
)[route_display_columns
.visible
] = yn
;
481 if (!atv
->is_audio_track()) {
482 (*i
)[route_display_columns
.visible
] = yn
;
489 no_route_list_redisplay
= false;
490 redisplay_route_list ();
494 Editor::hide_all_routes ()
496 set_all_tracks_visibility (false);
500 Editor::show_all_routes ()
502 set_all_tracks_visibility (true);
506 Editor::show_all_audiobus ()
508 set_all_audio_visibility (2, true);
511 Editor::hide_all_audiobus ()
513 set_all_audio_visibility (2, false);
517 Editor::show_all_audiotracks()
519 set_all_audio_visibility (1, true);
522 Editor::hide_all_audiotracks ()
524 set_all_audio_visibility (1, false);
528 Editor::show_tracks_with_regions_at_playhead ()
530 boost::shared_ptr
<Session::RouteList
> const regions
= session
->get_routes_with_regions_at (session
->transport_frame ());
532 //suspend_redisplay ();
534 TreeModel::Children rows
= route_display_model
->children ();
535 for (TreeModel::Children::iterator i
= rows
.begin(); i
!= rows
.end(); ++i
) {
536 boost::shared_ptr
<Route
> route
= (*i
)[route_display_columns
.route
];
539 for (Session::RouteList::iterator x
= (*regions
).begin(); x
!= (*regions
).end(); ++x
) {
544 (*i
)[route_display_columns
.visible
] = found
;
547 no_route_list_redisplay
= false;
548 redisplay_route_list ();
550 //resume_redisplay ();
554 Editor::route_list_display_button_press (GdkEventButton
* ev
)
556 if (Keyboard::is_context_menu_event (ev
)) {
557 show_route_list_menu ();
562 TreeModel::Path path
;
563 TreeViewColumn
* column
;
567 if (!route_list_display
.get_path_at_pos ((int)ev
->x
, (int)ev
->y
, path
, column
, cellx
, celly
)) {
571 switch (GPOINTER_TO_UINT (column
->get_data (X_("colnum")))) {
573 if ((iter
= route_display_model
->get_iter (path
))) {
574 TimeAxisView
* tv
= (*iter
)[route_display_columns
.tv
];
576 bool visible
= (*iter
)[route_display_columns
.visible
];
577 (*iter
)[route_display_columns
.visible
] = !visible
;
583 /* allow normal processing to occur */
594 Editor::show_route_list_menu()
596 if (route_list_menu
== 0) {
597 build_route_list_menu ();
600 route_list_menu
->popup (1, gtk_get_current_event_time());
604 Editor::route_list_selection_filter (const Glib::RefPtr
<TreeModel
>& model
, const TreeModel::Path
& path
, bool yn
)
609 struct EditorOrderRouteSorter
{
610 bool operator() (boost::shared_ptr
<Route
> a
, boost::shared_ptr
<Route
> b
) {
611 /* use of ">" forces the correct sort order */
612 return a
->order_key (_order_key
) < b
->order_key (_order_key
);
617 Editor::initial_route_list_display ()
619 boost::shared_ptr
<Session::RouteList
> routes
= session
->get_routes();
620 Session::RouteList
r (*routes
);
621 EditorOrderRouteSorter sorter
;
625 no_route_list_redisplay
= true;
627 route_display_model
->clear ();
629 handle_new_route (r
);
631 no_route_list_redisplay
= false;
633 redisplay_route_list ();
637 Editor::track_list_reorder (const Gtk::TreeModel::Path
& path
,const Gtk::TreeModel::iterator
& iter
, int* new_order
)
639 route_redisplay_does_not_sync_order_keys
= true;
640 session
->set_remote_control_ids();
641 redisplay_route_list ();
642 route_redisplay_does_not_sync_order_keys
= false;
646 Editor::route_list_change (const Gtk::TreeModel::Path
& path
,const Gtk::TreeModel::iterator
& iter
)
648 /* never reset order keys because of a property change */
649 route_redisplay_does_not_reset_order_keys
= true;
650 session
->set_remote_control_ids();
651 redisplay_route_list ();
652 route_redisplay_does_not_reset_order_keys
= false;
656 Editor::route_list_delete (const Gtk::TreeModel::Path
& path
)
658 /* this could require an order reset & sync */
659 session
->set_remote_control_ids();
660 redisplay_route_list ();
664 Editor::route_list_display_drag_data_received (const RefPtr
<Gdk::DragContext
>& context
,
666 const SelectionData
& data
,
667 guint info
, guint time
)
669 if (data
.get_target() == "GTK_TREE_MODEL_ROW") {
670 route_list_display
.on_drag_data_received (context
, x
, y
, data
, info
, time
);
673 context
->drag_finish (true, false, time
);
677 Editor::foreach_time_axis_view (sigc::slot
<void,TimeAxisView
&> theslot
)
679 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
685 Editor::move_selected_tracks (bool up
)
687 if (selection
->tracks
.empty()) {
691 typedef pair
<TimeAxisView
*,boost::shared_ptr
<Route
> > ViewRoute
;
692 list
<ViewRoute
> view_routes
;
693 vector
<int> neworder
;
694 TreeModel::Children rows
= route_display_model
->children();
695 TreeModel::Children::iterator ri
;
697 for (ri
= rows
.begin(); ri
!= rows
.end(); ++ri
) {
698 TimeAxisView
* tv
= (*ri
)[route_display_columns
.tv
];
699 boost::shared_ptr
<Route
> route
= (*ri
)[route_display_columns
.route
];
701 view_routes
.push_back (ViewRoute (tv
, route
));
704 list
<ViewRoute
>::iterator trailing
;
705 list
<ViewRoute
>::iterator leading
;
709 trailing
= view_routes
.begin();
710 leading
= view_routes
.begin();
714 while (leading
!= view_routes
.end()) {
715 if (selection
->selected (leading
->first
)) {
716 view_routes
.insert (trailing
, ViewRoute (leading
->first
, leading
->second
));
717 leading
= view_routes
.erase (leading
);
726 /* if we could use reverse_iterator in list::insert, this code
727 would be a beautiful reflection of the code above. but we can't
728 and so it looks like a bit of a mess.
731 trailing
= view_routes
.end();
732 leading
= view_routes
.end();
734 --leading
; if (leading
== view_routes
.begin()) { return; }
740 if (selection
->selected (leading
->first
)) {
741 list
<ViewRoute
>::iterator tmp
;
743 /* need to insert *after* trailing, not *before* it,
744 which is what insert (iter, val) normally does.
750 view_routes
.insert (tmp
, ViewRoute (leading
->first
, leading
->second
));
752 /* can't use iter = cont.erase (iter); form here, because
753 we need iter to move backwards.
761 if (leading
== view_routes
.begin()) {
762 /* the one we've just inserted somewhere else
763 was the first in the list. erase this copy,
764 and then break, because we're done.
769 view_routes
.erase (leading
);
778 if (leading
== view_routes
.begin()) {
787 for (leading
= view_routes
.begin(); leading
!= view_routes
.end(); ++leading
) {
788 neworder
.push_back (leading
->second
->order_key (_order_key
));
791 route_display_model
->reorder (neworder
);
793 session
->sync_order_keys (_order_key
);