X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor_route_list.cc;h=00b4a3656d400327a2f6f1b03e8a8701bfa2f9f8;hb=73a6b8ef25bb90ad6c66b25b17da5962a38291d2;hp=4bc105935423f30a59dbdc643d449ad54be98374;hpb=085056ae03387e08d868f01c97e482fa6e5c468d;p=ardour.git diff --git a/gtk2_ardour/editor_route_list.cc b/gtk2_ardour/editor_route_list.cc index 4bc1059354..00b4a3656d 100644 --- a/gtk2_ardour/editor_route_list.cc +++ b/gtk2_ardour/editor_route_list.cc @@ -17,6 +17,8 @@ */ +#include +#include #include #include #include @@ -31,21 +33,23 @@ #include "gui_thread.h" #include "actions.h" -#include +#include "pbd/unknown_type.h" -#include +#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; +const char* _order_key = N_("editor"); void -Editor::handle_new_route (Session::RouteList& routes) +Editor::handle_new_route (RouteList& routes) { ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_new_route), routes)); @@ -54,11 +58,10 @@ Editor::handle_new_route (Session::RouteList& routes) TreeModel::Row parent; TreeModel::Row row; - ignore_route_list_reorder = true; - ignore_route_order_sync = true; + route_redisplay_does_not_sync_order_keys = true; no_route_list_redisplay = true; - for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) { + for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) { boost::shared_ptr route = (*x); if (route->is_hidden()) { @@ -116,22 +119,19 @@ Editor::handle_new_route (Session::RouteList& routes) if ((rtv = dynamic_cast (tv)) != 0) { /* added a new fresh one at the end */ - if (rtv->route()->order_key(N_("editor")) == -1) { - rtv->route()->set_order_key (N_("editor"), route_display_model->children().size()-1); + 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; - tv->set_old_order_key (route_display_model->children().size() - 1); 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; - ignore_route_order_sync = false; no_route_list_redisplay = false; redisplay_route_list (); @@ -139,14 +139,16 @@ Editor::handle_new_route (Session::RouteList& routes) 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 (const string & what, void *src) { ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_gui_changes), what, src)); - + if (what == "track_height") { /* Optional :make tracks change height while it happens, instead of on first-idle @@ -168,35 +170,54 @@ Editor::remove_route (TimeAxisView *tv) TrackViewList::iterator i; TreeModel::Children rows = route_display_model->children(); TreeModel::Children::iterator ri; + boost::shared_ptr route; + TimeAxisView* next_tv; if (tv == entered_track) { entered_track = 0; } - /* Decrement old order keys for tracks `above' the one that is being removed */ - for (ri = rows.begin(); ri != rows.end(); ++ri) { - TimeAxisView* v = (*ri)[route_display_columns.tv]; - if (v->old_order_key() > tv->old_order_key()) { - v->set_old_order_key (v->old_order_key() - 1); - } - } + /* 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; } } + route_redisplay_does_not_sync_order_keys = false; + if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) { - track_views.erase (i); + + 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) { - /* since the editor mixer goes away when you remove a route, set the - * button to inactive and untick the menu option - */ + 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"); + ActionManager::uncheck_toggleaction ("/Editor/show-editor-mixer"); + } + } } void @@ -276,13 +297,13 @@ Editor::route_list_reordered (const TreeModel::Path& path,const TreeModel::itera void -Editor::sync_order_keys () +Editor::sync_order_keys (const char *src) { vector neworder; TreeModel::Children rows = route_display_model->children(); TreeModel::Children::iterator ri; - if (ignore_route_order_sync || !session || (session->state_of_the_state() & Session::Loading) || rows.empty()) { + if ((strcmp (src, _order_key) == 0) || !session || (session->state_of_the_state() & Session::Loading) || rows.empty()) { return; } @@ -290,15 +311,27 @@ Editor::sync_order_keys () neworder.push_back (0); } - for (ri = rows.begin(); ri != rows.end(); ++ri) { - TimeAxisView* tv = (*ri)[route_display_columns.tv]; + 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]; - neworder[route->order_key (X_("editor"))] = tv->old_order_key (); + + int old_key = order; + int new_key = route->order_key (_order_key); + + neworder[new_key] = old_key; + + if (new_key != old_key) { + changed = true; + } } - ignore_route_list_reorder = true; - route_display_model->reorder (neworder); - ignore_route_list_reorder = false; + if (changed) { + route_redisplay_does_not_reset_order_keys = true; + route_display_model->reorder (neworder); + route_redisplay_does_not_reset_order_keys = false; + } } void @@ -307,36 +340,33 @@ Editor::redisplay_route_list () TreeModel::Children rows = route_display_model->children(); TreeModel::Children::iterator i; uint32_t position; - uint32_t order; int n; if (no_route_list_redisplay) { return; } - for (n = 0, order = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) { + for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) { TimeAxisView *tv = (*i)[route_display_columns.tv]; - RouteTimeAxisView* rt; + boost::shared_ptr route = (*i)[route_display_columns.route]; if (tv == 0) { // just a "title" row continue; } - if (!ignore_route_list_reorder) { + if (!route_redisplay_does_not_reset_order_keys) { /* this reorder is caused by user action, so reassign sort order keys to tracks. */ - if ((rt = dynamic_cast (tv)) != 0) { - rt->route()->set_order_key (N_("editor"), order); - ++order; - } + route->set_order_key (_order_key, n); } 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); @@ -350,6 +380,13 @@ Editor::redisplay_route_list () } + /* 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. + */ + + Glib::signal_idle().connect (mem_fun (*this, &Editor::sync_track_view_list_and_route_list)); + 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()) { @@ -360,12 +397,25 @@ Editor::redisplay_route_list () vertical_adjustment.set_value (full_canvas_height - canvas_height); } - if (Config->get_sync_all_route_ordering() && !ignore_route_list_reorder) { - ignore_route_order_sync = true; - Route::SyncOrderKeys (); // EMIT SIGNAL - ignore_route_order_sync = false; + if (!route_redisplay_does_not_reset_order_keys && !route_redisplay_does_not_sync_order_keys) { + session->sync_order_keys (_order_key); } +} +bool +Editor::sync_track_view_list_and_route_list () +{ + TreeModel::Children rows = route_display_model->children(); + TreeModel::Children::iterator i; + + track_views.clear (); + + for (i = rows.begin(); i != rows.end(); ++i) { + TimeAxisView *tv = (*i)[route_display_columns.tv]; + track_views.push_back (tv); + } + + return false; // do not call again (until needed) } void @@ -577,15 +627,15 @@ Editor::route_list_selection_filter (const Glib::RefPtr& model, const struct EditorOrderRouteSorter { bool operator() (boost::shared_ptr a, boost::shared_ptr b) { /* use of ">" forces the correct sort order */ - return a->order_key ("editor") < b->order_key ("editor"); + return a->order_key (_order_key) < b->order_key (_order_key); } }; void Editor::initial_route_list_display () { - boost::shared_ptr routes = session->get_routes(); - Session::RouteList r (*routes); + boost::shared_ptr routes = session->get_routes(); + RouteList r (*routes); EditorOrderRouteSorter sorter; r.sort (sorter); @@ -604,20 +654,26 @@ Editor::initial_route_list_display () void Editor::track_list_reorder (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter, int* new_order) { + route_redisplay_does_not_sync_order_keys = true; session->set_remote_control_ids(); redisplay_route_list (); + route_redisplay_does_not_sync_order_keys = false; } 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; } 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 (); @@ -630,14 +686,10 @@ Editor::route_list_display_drag_data_received (const RefPtr& c const SelectionData& data, guint info, guint time) { - cerr << "RouteLD::dddr target = " << data.get_target() << endl; - if (data.get_target() == "GTK_TREE_MODEL_ROW") { - cerr << "Delete drag data drop to treeview\n"; route_list_display.on_drag_data_received (context, x, y, data, info, time); return; } - cerr << "some other kind of drag\n"; context->drag_finish (true, false, time); } @@ -664,3 +716,115 @@ Editor::foreach_time_axis_view (sigc::slot theslot) theslot (**i); } } + +void +Editor::move_selected_tracks (bool up) +{ + if (selection->tracks.empty()) { + return; + } + + typedef std::pair > ViewRoute; + std::list view_routes; + std::vector neworder; + TreeModel::Children rows = route_display_model->children(); + TreeModel::Children::iterator ri; + + for (ri = rows.begin(); ri != rows.end(); ++ri) { + TimeAxisView* tv = (*ri)[route_display_columns.tv]; + boost::shared_ptr route = (*ri)[route_display_columns.route]; + + view_routes.push_back (ViewRoute (tv, 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; + } + } + + } else { + + /* 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); +}