X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor_route_list.cc;h=00b4a3656d400327a2f6f1b03e8a8701bfa2f9f8;hb=73a6b8ef25bb90ad6c66b25b17da5962a38291d2;hp=49540fbe0f7cffc92c31f69c7f59309584ba25f7;hpb=d38e2213d79b1c8952c776a3b60f7709457edc0c;p=ardour.git diff --git a/gtk2_ardour/editor_route_list.cc b/gtk2_ardour/editor_route_list.cc index 49540fbe0f..00b4a3656d 100644 --- a/gtk2_ardour/editor_route_list.cc +++ b/gtk2_ardour/editor_route_list.cc @@ -15,82 +15,150 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id$ */ +#include +#include #include #include #include +#include #include "editor.h" +#include "keyboard.h" #include "ardour_ui.h" #include "audio_time_axis.h" +#include "midi_time_axis.h" #include "mixer_strip.h" #include "gui_thread.h" +#include "actions.h" -#include +#include "pbd/unknown_type.h" + +#include "ardour/route.h" #include "i18n.h" +using namespace std; using namespace sigc; using namespace ARDOUR; +using namespace PBD; using namespace Gtk; +using namespace Glib; -void -Editor::handle_new_route_p (Route* route) -{ - ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_new_route_p), route)); - handle_new_route (*route); -} +const char* _order_key = N_("editor"); void -Editor::handle_new_route (Route& route) +Editor::handle_new_route (RouteList& routes) { + ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_new_route), routes)); + TimeAxisView *tv; - AudioTimeAxisView *atv; - const gchar *rowdata[1]; + RouteTimeAxisView *rtv; + TreeModel::Row parent; + TreeModel::Row row; - if (route.hidden()) { - return; - } - - tv = new AudioTimeAxisView (*this, *session, route, track_canvas); + route_redisplay_does_not_sync_order_keys = true; + no_route_list_redisplay = true; - track_views.push_back (tv); + for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) { + boost::shared_ptr route = (*x); - rowdata[0] = route.name ().c_str(); + if (route->is_hidden()) { + continue; + } + + if (route->default_type() == ARDOUR::DataType::AUDIO) + tv = new AudioTimeAxisView (*this, *session, route, *track_canvas); + else if (route->default_type() == ARDOUR::DataType::MIDI) + tv = new MidiTimeAxisView (*this, *session, route, *track_canvas); + else + throw unknown_type(); + + //cerr << "Editor::handle_new_route() called on " << route->name() << endl;//DEBUG +#if 0 + if (route_display_model->children().size() == 0) { + + /* set up basic entries */ + + TreeModel::Row row; + + row = *(route_display_model->append()); // path = "0" + row[route_display_columns.text] = _("Busses"); + row[route_display_columns.tv] = 0; + row = *(route_display_model->append()); // path = "1" + row[route_display_columns.text] = _("Tracks"); + row[route_display_columns.tv] = 0; + + } + + if (dynamic_cast(route.get()) != 0) { + TreeModel::iterator iter = route_display_model->get_iter ("1"); // audio tracks + parent = *iter; + } else { + TreeModel::iterator iter = route_display_model->get_iter ("0"); // busses + parent = *iter; + } + + + row = *(route_display_model->append (parent.children())); +#else + row = *(route_display_model->append ()); +#endif - ignore_route_list_reorder = true; - route_list.rows().push_back (rowdata); - route_list.rows().back().set_data (tv); - if (tv->marked_for_display()) { - route_list.rows().back().select(); - } + // cerr << route->name() << " marked for display ? " << tv->marked_for_display() << endl; + + row[route_display_columns.text] = route->name(); + row[route_display_columns.visible] = tv->marked_for_display(); + row[route_display_columns.tv] = tv; + row[route_display_columns.route] = route; - if ((atv = dynamic_cast (tv)) != 0) { - /* added a new fresh one at the end */ - if (atv->route().order_key(N_("editor")) == -1) { - atv->route().set_order_key (N_("editor"), route_list.rows().size()-1); + track_views.push_back (tv); + + ignore_route_list_reorder = true; + + if ((rtv = dynamic_cast (tv)) != 0) { + /* added a new fresh one at the end */ + if (rtv->route()->order_key(_order_key) == -1) { + rtv->route()->set_order_key (_order_key, route_display_model->children().size()-1); + } + rtv->effective_gain_display (); } + + ignore_route_list_reorder = false; + + route->gui_changed.connect (mem_fun(*this, &Editor::handle_gui_changes)); + + tv->GoingAway.connect (bind (mem_fun(*this, &Editor::remove_route), tv)); } - ignore_route_list_reorder = false; - - route.gui_changed.connect (mem_fun(*this, &Editor::handle_gui_changes)); + no_route_list_redisplay = false; - tv->GoingAway.connect (bind (mem_fun(*this, &Editor::remove_route), tv)); - - editor_mixer_button.set_sensitive(true); - + redisplay_route_list (); + + if (show_editor_mixer_when_tracks_arrive) { + show_editor_mixer (true); + } + + editor_list_button.set_sensitive(true); + route_redisplay_does_not_sync_order_keys = false; } void -Editor::handle_gui_changes (string what, void *src) +Editor::handle_gui_changes (const string & what, void *src) { ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_gui_changes), what, src)); - + if (what == "track_height") { - route_list_reordered (); + /* Optional :make tracks change height while it happens, instead + of on first-idle + */ + //track_canvas->update_now (); + redisplay_route_list (); + } + + if (what == "visible_tracks") { + redisplay_route_list (); } } @@ -98,347 +166,665 @@ void Editor::remove_route (TimeAxisView *tv) { ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::remove_route), tv)); - + TrackViewList::iterator i; - CList_Helpers::RowList::iterator ri; + TreeModel::Children rows = route_display_model->children(); + TreeModel::Children::iterator ri; + boost::shared_ptr route; + TimeAxisView* next_tv; - if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) { - track_views.erase (i); + if (tv == entered_track) { + entered_track = 0; } - for (ri = route_list.rows().begin(); ri != route_list.rows().end(); ++ri) { - if (tv == ri->get_data()) { - route_list.rows().erase (ri); + /* the core model has changed, there is no need to sync + view orders. + */ + + route_redisplay_does_not_sync_order_keys = true; + + for (ri = rows.begin(); ri != rows.end(); ++ri) { + if ((*ri)[route_display_columns.tv] == tv) { + route = (*ri)[route_display_columns.route]; + route_display_model->erase (ri); break; } } - /* since the editor mixer goes away when you remove a route, set the - * button to inacttive - */ - editor_mixer_button.set_active(false); - /* and disable if all tracks and/or routes are gone */ + route_redisplay_does_not_sync_order_keys = false; - if (track_views.size() == 0) { - editor_mixer_button.set_sensitive(false); + if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) { + + i = track_views.erase (i); + + if (track_views.empty()) { + next_tv = 0; + } else if (i == track_views.end()) { + next_tv = track_views.front(); + } else { + next_tv = (*i); + } } + + if (current_mixer_strip && current_mixer_strip->route() == route) { + + if (next_tv) { + set_selected_mixer_strip (*next_tv); + } else { + /* make the editor mixer strip go away setting the + * button to inactive (which also unticks the menu option) + */ + + ActionManager::uncheck_toggleaction ("/Editor/show-editor-mixer"); + } + } } void Editor::route_name_changed (TimeAxisView *tv) { - CList_Helpers::RowList::iterator i; - gint row; - - for (row = 0, i = route_list.rows().begin(); i != route_list.rows().end(); ++i, ++row) { - if (tv == i->get_data()) { - route_list.cell (row, 0).set_text (tv->name()); + ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::route_name_changed), tv)); + + TreeModel::Children rows = route_display_model->children(); + TreeModel::Children::iterator i; + + for (i = rows.begin(); i != rows.end(); ++i) { + if ((*i)[route_display_columns.tv] == tv) { + (*i)[route_display_columns.text] = tv->name(); break; } - } + } } void -Editor::route_list_selected (gint row, gint col, GdkEvent *ev) +Editor::update_route_visibility () { - TimeAxisView *tv; - if ((tv = (TimeAxisView *) route_list.get_row_data (row)) != 0) { - tv->set_marked_for_display (true); - route_list_reordered (); + TreeModel::Children rows = route_display_model->children(); + TreeModel::Children::iterator i; + + no_route_list_redisplay = true; + + for (i = rows.begin(); i != rows.end(); ++i) { + TimeAxisView *tv = (*i)[route_display_columns.tv]; + (*i)[route_display_columns.visible] = tv->marked_for_display (); + cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl; } + + no_route_list_redisplay = false; + redisplay_route_list (); } void -Editor::route_list_unselected (gint row, gint col, GdkEvent *ev) +Editor::hide_track_in_display (TimeAxisView& tv, bool temponly) { - TimeAxisView *tv; - AudioTimeAxisView *atv; - - if ((tv = (TimeAxisView *) route_list.get_row_data (row)) != 0) { - - tv->set_marked_for_display (false); + TreeModel::Children rows = route_display_model->children(); + TreeModel::Children::iterator i; - if ((atv = dynamic_cast(tv)) != 0) { - if (current_mixer_strip && &(atv->route()) == &(current_mixer_strip->route())) { - /* this will hide the mixer strip */ - set_selected_mixer_strip(*atv); - } + for (i = rows.begin(); i != rows.end(); ++i) { + if ((*i)[route_display_columns.tv] == &tv) { + (*i)[route_display_columns.visible] = false; + break; } + } - route_list_reordered (); + RouteTimeAxisView* rtv = dynamic_cast (&tv); + + if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) { + // this will hide the mixer strip + set_selected_mixer_strip (tv); } } void -Editor::unselect_strip_in_display (TimeAxisView& tv) +Editor::show_track_in_display (TimeAxisView& tv) { - CList_Helpers::RowIterator i; - - if ((i = route_list.rows().find_data (&tv)) != route_list.rows().end()) { - (*i).unselect (); + TreeModel::Children rows = route_display_model->children(); + TreeModel::Children::iterator i; + + for (i = rows.begin(); i != rows.end(); ++i) { + if ((*i)[route_display_columns.tv] == &tv) { + (*i)[route_display_columns.visible] = true; + break; + } } } void -Editor::select_strip_in_display (TimeAxisView& tv) +Editor::route_list_reordered (const TreeModel::Path& path,const TreeModel::iterator& iter,int* what) { - CList_Helpers::RowIterator i; - - if ((i = route_list.rows().find_data (&tv)) != route_list.rows().end()) { - (*i).select (); - } + redisplay_route_list (); } -void -Editor::queue_route_list_reordered (gint arg1, gint arg2) +void +Editor::sync_order_keys (const char *src) { - /* the problem here is that we are called *before* the - list has been reordered. so just queue up - the actual re-drawer to happen once the re-ordering - is complete. - */ + vector neworder; + TreeModel::Children rows = route_display_model->children(); + TreeModel::Children::iterator ri; + + if ((strcmp (src, _order_key) == 0) || !session || (session->state_of_the_state() & Session::Loading) || rows.empty()) { + return; + } + + for (ri = rows.begin(); ri != rows.end(); ++ri) { + neworder.push_back (0); + } + + bool changed = false; + int order; + + for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) { + boost::shared_ptr route = (*ri)[route_display_columns.route]; + + int old_key = order; + int new_key = route->order_key (_order_key); + + neworder[new_key] = old_key; - Main::idle.connect (mem_fun(*this, &Editor::route_list_reordered)); + if (new_key != old_key) { + changed = true; + } + } + + if (changed) { + route_redisplay_does_not_reset_order_keys = true; + route_display_model->reorder (neworder); + route_redisplay_does_not_reset_order_keys = false; + } } void Editor::redisplay_route_list () { - route_list_reordered (); -} - -gint -Editor::route_list_reordered () -{ - CList_Helpers::RowList::iterator i; - gdouble y; + TreeModel::Children rows = route_display_model->children(); + TreeModel::Children::iterator i; + uint32_t position; int n; - for (n = 0, y = 0, i = route_list.rows().begin(); i != route_list.rows().end(); ++i) { + if (no_route_list_redisplay) { + return; + } - TimeAxisView *tv = (TimeAxisView *) (*i)->get_data (); - - AudioTimeAxisView* at; - - if (!ignore_route_list_reorder) { + for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) { + TimeAxisView *tv = (*i)[route_display_columns.tv]; + boost::shared_ptr route = (*i)[route_display_columns.route]; + + if (tv == 0) { + // just a "title" row + continue; + } + + if (!route_redisplay_does_not_reset_order_keys) { - /* this reorder is caused by user action, so reassign sort order keys - to tracks. - */ + /* this reorder is caused by user action, so reassign sort order keys + to tracks. + */ - if ((at = dynamic_cast (tv)) != 0) { - at->route().set_order_key (N_("editor"), n); - } + route->set_order_key (_order_key, n); } - - if (tv->marked_for_display()) { - y += tv->show_at (y, n, &edit_controls_vbox); - y += track_spacing; + + bool visible = (*i)[route_display_columns.visible]; + + /* show or hide the TimeAxisView */ + if (visible) { + tv->set_marked_for_display (true); + position += tv->show_at (position, n, &edit_controls_vbox); + tv->clip_to_viewport (); } else { + tv->set_marked_for_display (false); tv->hide (); } - + n++; + } - edit_controls_scroller.queue_resize (); - reset_scrolling_region (); + /* whenever we go idle, update the track view list to reflect the new order. + we can't do this here, because we could mess up something that is traversing + the track order and has caused a redisplay of the list. + */ - //gtk_canvas_item_raise_to_top (time_line_group); - gtk_canvas_item_raise_to_top (cursor_group); + Glib::signal_idle().connect (mem_fun (*this, &Editor::sync_track_view_list_and_route_list)); - return FALSE; + full_canvas_height = position + canvas_timebars_vsize; + vertical_adjustment.set_upper (full_canvas_height); + if ((vertical_adjustment.get_value() + canvas_height) > vertical_adjustment.get_upper()) { + /* + We're increasing the size of the canvas while the bottom is visible. + We scroll down to keep in step with the controls layout. + */ + vertical_adjustment.set_value (full_canvas_height - canvas_height); + } + + if (!route_redisplay_does_not_reset_order_keys && !route_redisplay_does_not_sync_order_keys) { + session->sync_order_keys (_order_key); + } } -void -Editor::hide_all_tracks (bool with_select) +bool +Editor::sync_track_view_list_and_route_list () { - Gtk::CList_Helpers::RowList::iterator i; - Gtk::CList_Helpers::RowList& rowlist = route_list.rows(); - - route_list.freeze (); + TreeModel::Children rows = route_display_model->children(); + TreeModel::Children::iterator i; - for (i = rowlist.begin(); i != rowlist.end(); ++i) { - TimeAxisView *tv = (TimeAxisView *) i->get_data (); + track_views.clear (); - if (with_select) { - i->unselect (); - } else { - tv->set_marked_for_display (false); - tv->hide(); - } - } + for (i = rows.begin(); i != rows.end(); ++i) { + TimeAxisView *tv = (*i)[route_display_columns.tv]; + track_views.push_back (tv); + } - route_list.thaw (); - - reset_scrolling_region (); + return false; // do not call again (until needed) } void -Editor::route_list_column_click (gint col) +Editor::hide_all_tracks (bool with_select) { - if (route_list_menu == 0) { - build_route_list_menu (); + TreeModel::Children rows = route_display_model->children(); + TreeModel::Children::iterator i; + + no_route_list_redisplay = true; + + for (i = rows.begin(); i != rows.end(); ++i) { + + TreeModel::Row row = (*i); + TimeAxisView *tv = row[route_display_columns.tv]; + + if (tv == 0) { + continue; + } + + row[route_display_columns.visible] = false; } - route_list_menu->popup (0, 0); + no_route_list_redisplay = false; + redisplay_route_list (); + + /* XXX this seems like a hack and half, but its not clear where to put this + otherwise. + */ + + //reset_scrolling_region (); } void Editor::build_route_list_menu () { - using namespace Gtk::Menu_Helpers; + using namespace Menu_Helpers; + using namespace Gtk; route_list_menu = new Menu; MenuList& items = route_list_menu->items(); route_list_menu->set_name ("ArdourContextMenu"); - items.push_back (MenuElem (_("Show All"), mem_fun(*this, &Editor::select_all_routes))); - items.push_back (MenuElem (_("Hide All"), mem_fun(*this, &Editor::unselect_all_routes))); - items.push_back (MenuElem (_("Show All AbstractTracks"), mem_fun(*this, &Editor::select_all_audiotracks))); - items.push_back (MenuElem (_("Hide All AbstractTracks"), mem_fun(*this, &Editor::unselect_all_audiotracks))); - items.push_back (MenuElem (_("Show All AudioBus"), mem_fun(*this, &Editor::select_all_audiobus))); - items.push_back (MenuElem (_("Hide All AudioBus"), mem_fun(*this, &Editor::unselect_all_audiobus))); + items.push_back (MenuElem (_("Show All"), mem_fun(*this, &Editor::show_all_routes))); + items.push_back (MenuElem (_("Hide All"), mem_fun(*this, &Editor::hide_all_routes))); + items.push_back (MenuElem (_("Show All Audio Tracks"), mem_fun(*this, &Editor::show_all_audiotracks))); + items.push_back (MenuElem (_("Hide All Audio Tracks"), mem_fun(*this, &Editor::hide_all_audiotracks))); + items.push_back (MenuElem (_("Show All Audio Busses"), mem_fun(*this, &Editor::show_all_audiobus))); + items.push_back (MenuElem (_("Hide All Audio Busses"), mem_fun(*this, &Editor::hide_all_audiobus))); } void -Editor::unselect_all_routes () +Editor::set_all_tracks_visibility (bool yn) { - hide_all_tracks (true); -} + TreeModel::Children rows = route_display_model->children(); + TreeModel::Children::iterator i; -void -Editor::select_all_routes () + no_route_list_redisplay = true; -{ - CList_Helpers::RowList::iterator i; + for (i = rows.begin(); i != rows.end(); ++i) { + + TreeModel::Row row = (*i); + TimeAxisView* tv = row[route_display_columns.tv]; - for (i = route_list.rows().begin(); i != route_list.rows().end(); ++i) { - i->select (); + if (tv == 0) { + continue; + } + + (*i)[route_display_columns.visible] = yn; } + + no_route_list_redisplay = false; + redisplay_route_list (); } void -Editor::select_all_audiotracks () +Editor::set_all_audio_visibility (int tracks, bool yn) { - Gtk::CList_Helpers::RowList::iterator i; - Gtk::CList_Helpers::RowList& rowlist = route_list.rows(); - - route_list.freeze (); - - for (i = rowlist.begin(); i != rowlist.end(); ++i) { - TimeAxisView *tv = (TimeAxisView *) i->get_data (); + TreeModel::Children rows = route_display_model->children(); + TreeModel::Children::iterator i; + + no_route_list_redisplay = true; + + for (i = rows.begin(); i != rows.end(); ++i) { + TreeModel::Row row = (*i); + TimeAxisView* tv = row[route_display_columns.tv]; AudioTimeAxisView* atv; + if (tv == 0) { + continue; + } + if ((atv = dynamic_cast(tv)) != 0) { - if (atv->is_audio_track()) { - i->select (); + switch (tracks) { + case 0: + (*i)[route_display_columns.visible] = yn; + break; + + case 1: + if (atv->is_audio_track()) { + (*i)[route_display_columns.visible] = yn; + } + break; + + case 2: + if (!atv->is_audio_track()) { + (*i)[route_display_columns.visible] = yn; + } + break; } } } - - route_list.thaw (); + no_route_list_redisplay = false; + redisplay_route_list (); } -void -Editor::unselect_all_audiotracks () +void +Editor::hide_all_routes () { - Gtk::CList_Helpers::RowList::iterator i; - Gtk::CList_Helpers::RowList& rowlist = route_list.rows(); - - route_list.freeze (); + set_all_tracks_visibility (false); +} - for (i = rowlist.begin(); i != rowlist.end(); ++i) { - TimeAxisView *tv = (TimeAxisView *) i->get_data (); - AudioTimeAxisView* atv; +void +Editor::show_all_routes () +{ + set_all_tracks_visibility (true); +} - if ((atv = dynamic_cast(tv)) != 0) { - if (atv->is_audio_track()) { - i->unselect (); +void +Editor::show_all_audiobus () +{ + set_all_audio_visibility (2, true); +} +void +Editor::hide_all_audiobus () +{ + set_all_audio_visibility (2, false); +} + +void +Editor::show_all_audiotracks() +{ + set_all_audio_visibility (1, true); +} +void +Editor::hide_all_audiotracks () +{ + set_all_audio_visibility (1, false); +} + +bool +Editor::route_list_display_button_press (GdkEventButton* ev) +{ + if (Keyboard::is_context_menu_event (ev)) { + show_route_list_menu (); + return true; + } + + TreeIter iter; + TreeModel::Path path; + TreeViewColumn* column; + int cellx; + int celly; + + if (!route_list_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) { + return false; + } + + switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) { + case 0: + if ((iter = route_display_model->get_iter (path))) { + TimeAxisView* tv = (*iter)[route_display_columns.tv]; + if (tv) { + bool visible = (*iter)[route_display_columns.visible]; + (*iter)[route_display_columns.visible] = !visible; } } + return true; + + case 1: + /* allow normal processing to occur */ + return false; + + default: + break; } - - route_list.thaw (); + return false; } void -Editor::select_all_audiobus () +Editor::show_route_list_menu() { - Gtk::CList_Helpers::RowList::iterator i; - Gtk::CList_Helpers::RowList& rowlist = route_list.rows(); + if (route_list_menu == 0) { + build_route_list_menu (); + } + + route_list_menu->popup (1, gtk_get_current_event_time()); +} + +bool +Editor::route_list_selection_filter (const Glib::RefPtr& model, const TreeModel::Path& path, bool yn) +{ + return true; +} + +struct EditorOrderRouteSorter { + bool operator() (boost::shared_ptr a, boost::shared_ptr b) { + /* use of ">" forces the correct sort order */ + return a->order_key (_order_key) < b->order_key (_order_key); + } +}; + +void +Editor::initial_route_list_display () +{ + boost::shared_ptr routes = session->get_routes(); + RouteList r (*routes); + EditorOrderRouteSorter sorter; + + r.sort (sorter); - route_list.freeze (); + no_route_list_redisplay = true; - for (i = rowlist.begin(); i != rowlist.end(); ++i) { - TimeAxisView *tv = (TimeAxisView *) i->get_data (); - AudioTimeAxisView* atv; + route_display_model->clear (); - if ((atv = dynamic_cast(tv)) != 0) { - if (!atv->is_audio_track()) { - i->select (); - } - } - } + handle_new_route (r); - route_list.thaw (); + no_route_list_redisplay = false; + redisplay_route_list (); } void -Editor::unselect_all_audiobus () +Editor::track_list_reorder (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter, int* new_order) { - Gtk::CList_Helpers::RowList::iterator i; - Gtk::CList_Helpers::RowList& rowlist = route_list.rows(); - - route_list.freeze (); + route_redisplay_does_not_sync_order_keys = true; + session->set_remote_control_ids(); + redisplay_route_list (); + route_redisplay_does_not_sync_order_keys = false; +} - for (i = rowlist.begin(); i != rowlist.end(); ++i) { - TimeAxisView *tv = (TimeAxisView *) i->get_data (); - AudioTimeAxisView* atv; +void +Editor::route_list_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter) +{ + /* never reset order keys because of a property change */ + route_redisplay_does_not_reset_order_keys = true; + session->set_remote_control_ids(); + redisplay_route_list (); + route_redisplay_does_not_reset_order_keys = false; +} - if ((atv = dynamic_cast(tv)) != 0) { - if (!atv->is_audio_track()) { - i->unselect (); +void +Editor::route_list_delete (const Gtk::TreeModel::Path& path) +{ + /* this could require an order reset & sync */ + session->set_remote_control_ids(); + ignore_route_list_reorder = true; + redisplay_route_list (); + ignore_route_list_reorder = false; +} + +void +Editor::route_list_display_drag_data_received (const RefPtr& context, + int x, int y, + const SelectionData& data, + guint info, guint time) +{ + if (data.get_target() == "GTK_TREE_MODEL_ROW") { + route_list_display.on_drag_data_received (context, x, y, data, info, time); + return; + } + context->drag_finish (true, false, time); +} + +RouteTimeAxisView* +Editor::get_route_view_by_id (PBD::ID& id) +{ + RouteTimeAxisView* v; + + for(TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + if((v = dynamic_cast(*i)) != 0) { + if(v->route()->id() == id) { + return v; } } } - route_list.thaw (); + return 0; +} +void +Editor::foreach_time_axis_view (sigc::slot theslot) +{ + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + theslot (**i); + } } -gint -route_list_compare_func (GtkCList* clist, gconstpointer a, gconstpointer b) +void +Editor::move_selected_tracks (bool up) { - TimeAxisView *tv1; - TimeAxisView *tv2; - AudioTimeAxisView *atv1; - AudioTimeAxisView *atv2; - Route* ra; - Route* rb; + if (selection->tracks.empty()) { + return; + } - GtkCListRow *row1 = (GtkCListRow *) a; - GtkCListRow *row2 = (GtkCListRow *) b; + typedef std::pair > ViewRoute; + std::list view_routes; + std::vector neworder; + TreeModel::Children rows = route_display_model->children(); + TreeModel::Children::iterator ri; - tv1 = static_cast (row1->data); - tv2 = static_cast (row2->data); + for (ri = rows.begin(); ri != rows.end(); ++ri) { + TimeAxisView* tv = (*ri)[route_display_columns.tv]; + boost::shared_ptr route = (*ri)[route_display_columns.route]; - if ((atv1 = dynamic_cast(tv1)) == 0 || - (atv2 = dynamic_cast(tv2)) == 0) { - return FALSE; + view_routes.push_back (ViewRoute (tv, route)); } - ra = &atv1->route(); - rb = &atv2->route(); + list::iterator trailing; + list::iterator leading; + + if (up) { + + trailing = view_routes.begin(); + leading = view_routes.begin(); + + ++leading; + + while (leading != view_routes.end()) { + if (selection->selected (leading->first)) { + view_routes.insert (trailing, ViewRoute (leading->first, leading->second)); + leading = view_routes.erase (leading); + } else { + ++leading; + ++trailing; + } + } - /* use of ">" forces the correct sort order */ + } else { - return ra->order_key ("editor") > rb->order_key ("editor"); -} + /* if we could use reverse_iterator in list::insert, this code + would be a beautiful reflection of the code above. but we can't + and so it looks like a bit of a mess. + */ + + trailing = view_routes.end(); + leading = view_routes.end(); + --leading; if (leading == view_routes.begin()) { return; } + --leading; + --trailing; + + while (1) { + + if (selection->selected (leading->first)) { + list::iterator tmp; + + /* need to insert *after* trailing, not *before* it, + which is what insert (iter, val) normally does. + */ + + tmp = trailing; + tmp++; + + view_routes.insert (tmp, ViewRoute (leading->first, leading->second)); + + /* can't use iter = cont.erase (iter); form here, because + we need iter to move backwards. + */ + + tmp = leading; + --tmp; + + bool done = false; + + if (leading == view_routes.begin()) { + /* the one we've just inserted somewhere else + was the first in the list. erase this copy, + and then break, because we're done. + */ + done = true; + } + + view_routes.erase (leading); + + if (done) { + break; + } + + leading = tmp; + + } else { + if (leading == view_routes.begin()) { + break; + } + --leading; + --trailing; + } + }; + } + + for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) { + neworder.push_back (leading->second->order_key (_order_key)); + } + + route_display_model->reorder (neworder); + + session->sync_order_keys (_order_key); +}