ActionManager::load_menus (ARDOUR_COMMAND_LINE::menus_file);
- editor->track_mixer_selection ();
- mixer->track_editor_selection ();
-
/* catch up on parameters */
boost::function<void (std::string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
_summary = new EditorSummary (this);
selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
- selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
Selection& get_selection() const { return *selection; }
bool get_selection_extents (framepos_t &start, framepos_t &end) const; // the time extents of the current selection, whether Range, Region(s), Control Points, or Notes
Selection& get_cut_buffer() const { return *cut_buffer; }
- void track_mixer_selection ();
bool extend_selection_to_track (TimeAxisView&);
editor_mixer_strip_width = current_mixer_strip->get_width_enum ();
}
-void
-Editor::track_mixer_selection ()
-{
- Mixer_UI::instance()->selection().RoutesChanged.connect (sigc::mem_fun (*this, &Editor::follow_mixer_selection));
-}
-
-void
-Editor::follow_mixer_selection ()
-{
- if (_following_mixer_selection) {
- return;
- }
-
- _following_mixer_selection = true;
- selection->block_tracks_changed (true);
-
- AxisViewSelection& s (Mixer_UI::instance()->selection().axes);
-
- selection->clear_tracks ();
-
- for (AxisViewSelection::iterator i = s.begin(); i != s.end(); ++i) {
- TimeAxisView* tav = axis_view_from_stripable ((*i)->stripable());
- if (tav) {
- selection->add (tav);
- }
- }
-
- _following_mixer_selection = false;
- selection->block_tracks_changed (false);
- selection->TracksChanged (); /* EMIT SIGNAL */
-}
}
}
- Mixer_UI::instance()->selection().block_routes_changed (true);
- selection->block_tracks_changed (true);
{
+ PresentationInfo::ChangeSuspender cs;
DisplaySuspender ds;
+
boost::shared_ptr<RouteList> rl (new RouteList);
for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
rl->push_back (*x);
* destructors are called,
* diskstream drops references, save_state is called (again for every track)
*/
- selection->block_tracks_changed (false);
- Mixer_UI::instance()->selection().block_routes_changed (false);
- selection->TracksChanged (); /* EMIT SIGNAL */
}
void
EditorRoutes::EditorRoutes (Editor* e)
: EditorComponent (e)
, _ignore_reorder (false)
+ , _ignore_selection_change (false)
, _no_redisplay (false)
, _adding_routes (false)
, _route_deletion_in_progress (false)
}
_display.set_headers_visible (true);
- _display.get_selection()->set_mode (SELECTION_SINGLE);
+ _display.get_selection()->set_mode (SELECTION_MULTIPLE);
_display.get_selection()->set_select_function (sigc::mem_fun (*this, &EditorRoutes::selection_filter));
_display.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::selection_changed));
_display.set_reorderable (true);
_display.set_enable_search (false);
Route::PluginSetup.connect_same_thread (*this, boost::bind (&EditorRoutes::plugin_setup, this, _1, _2, _3));
- PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::sync_treeview_from_presentation_info, this), gui_context());
+ PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::presentation_info_changed, this, _1), gui_context());
}
bool
if (what_changed.contains (ARDOUR::Properties::hidden)) {
(*i)[_columns.visible] = !stripable->presentation_info().hidden();
- cerr << stripable->name() << " visibility changed, redisplay\n";
redisplay ();
}
}
void
-EditorRoutes::sync_treeview_from_presentation_info ()
+EditorRoutes::presentation_info_changed (PropertyChange const & what_changed)
+{
+ PropertyChange soh;
+ soh.add (Properties::selected);
+ soh.add (Properties::order);
+ soh.add (Properties::hidden);
+
+ if (what_changed.contains (soh)) {
+ sync_treeview_from_presentation_info (what_changed);
+ }
+}
+
+void
+EditorRoutes::sync_treeview_from_presentation_info (PropertyChange const & what_changed)
{
/* Some route order key(s) have been changed, make sure that
we update out tree/list model and GUI to reflect the change.
DEBUG_TRACE (DEBUG::OrderKeys, "editor sync model from presentation info.\n");
- vector<int> neworder;
+ PropertyChange hidden_or_order;
+ hidden_or_order.add (Properties::hidden);
+ hidden_or_order.add (Properties::order);
+
TreeModel::Children rows = _model->children();
- uint32_t old_order = 0;
- bool changed = false;
- if (rows.empty()) {
- return;
- }
+ if (what_changed.contains (hidden_or_order)) {
- OrderingKeys sorted;
- const size_t cmp_max = rows.size ();
+ vector<int> neworder;
+ uint32_t old_order = 0;
+ bool changed = false;
- for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
- boost::shared_ptr<Stripable> stripable = (*ri)[_columns.stripable];
- /* use global order */
- sorted.push_back (OrderKeys (old_order, stripable, cmp_max));
- }
+ if (rows.empty()) {
+ return;
+ }
+
+ OrderingKeys sorted;
+ const size_t cmp_max = rows.size ();
+
+ for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
+ boost::shared_ptr<Stripable> stripable = (*ri)[_columns.stripable];
+ /* use global order */
+ sorted.push_back (OrderKeys (old_order, stripable, cmp_max));
+ }
+
+ SortByNewDisplayOrder cmp;
- SortByNewDisplayOrder cmp;
+ sort (sorted.begin(), sorted.end(), cmp);
+ neworder.assign (sorted.size(), 0);
- sort (sorted.begin(), sorted.end(), cmp);
- neworder.assign (sorted.size(), 0);
+ uint32_t n = 0;
- uint32_t n = 0;
+ for (OrderingKeys::iterator sr = sorted.begin(); sr != sorted.end(); ++sr, ++n) {
- for (OrderingKeys::iterator sr = sorted.begin(); sr != sorted.end(); ++sr, ++n) {
+ neworder[n] = sr->old_display_order;
- neworder[n] = sr->old_display_order;
+ if (sr->old_display_order != n) {
+ changed = true;
+ }
+ }
- if (sr->old_display_order != n) {
- changed = true;
+ if (changed) {
+ Unwinder<bool> uw (_ignore_reorder, true);
+ /* prevent traverse_cells: assertion 'row_path != NULL'
+ * in case of DnD re-order: row-removed + row-inserted.
+ *
+ * The rows (stripables) are not actually removed from the model,
+ * but only from the display in the DnDTreeView.
+ * ->reorder() will fail to find the row_path.
+ * (re-order drag -> remove row -> rync PI from TV -> notify -> sync TV from PI -> crash)
+ */
+ _display.unset_model();
+ _model->reorder (neworder);
+ _display.set_model (_model);
}
}
- if (changed) {
- Unwinder<bool> uw (_ignore_reorder, true);
- /* prevent traverse_cells: assertion 'row_path != NULL'
- * in case of DnD re-order: row-removed + row-inserted.
- *
- * The rows (stripables) are not actually removed from the model,
- * but only from the display in the DnDTreeView.
- * ->reorder() will fail to find the row_path.
- * (re-order drag -> remove row -> rync PI from TV -> notify -> sync TV from PI -> crash)
- */
- _display.unset_model();
- _model->reorder (neworder);
- _display.set_model (_model);
+ if (what_changed.contains (Properties::selected)) {
+
+ TrackViewList tvl;
+ PBD::Unwinder<bool> uw (_ignore_selection_change, true);
+
+ /* step one: set the treeview model selection state */
+ for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri) {
+ boost::shared_ptr<Stripable> stripable = (*ri)[_columns.stripable];
+ if (stripable && stripable->presentation_info().selected()) {
+ TimeAxisView* tav = (*ri)[_columns.tv];
+ if (tav) {
+ tvl.push_back (tav);
+ }
+ _display.get_selection()->select (*ri);
+ } else {
+ _display.get_selection()->unselect (*ri);
+ }
+ }
+
+ /* step two: set the Selection (for stripables/routes) */
+
+ _editor->get_selection().set (tvl);
}
redisplay ();
void
EditorRoutes::selection_changed ()
{
+ if (_ignore_selection_change) {
+ return;
+ }
+
_editor->begin_reversible_selection_op (X_("Select Track from Route List"));
if (_display.get_selection()->count_selected_rows() > 0) {
TreeView::Selection::ListHandle_Path rows = _display.get_selection()->get_selected_rows ();
TrackViewList selected;
- _editor->get_selection().clear_regions ();
-
for (TreeView::Selection::ListHandle_Path::iterator i = rows.begin(); i != rows.end(); ++i) {
if ((iter = _model->get_iter (*i))) {
}
_editor->add_stripables (s);
- sync_treeview_from_presentation_info ();
+
+ sync_treeview_from_presentation_info (Properties::order);
}
void
void on_tv_solo_safe_toggled (std::string const &);
void build_menu ();
void show_menu ();
- void sync_treeview_from_presentation_info ();
+ void presentation_info_changed (PBD::PropertyChange const &);
+ void sync_treeview_from_presentation_info (PBD::PropertyChange const &);
void row_deleted (Gtk::TreeModel::Path const &);
void visible_changed (std::string const &);
void active_changed (std::string const &);
int _active_column;
bool _ignore_reorder;
+ bool _ignore_selection_change;
bool _no_redisplay;
bool _adding_routes;
bool _route_deletion_in_progress;
, ignore_reorder (false)
, _in_group_rebuild_or_clear (false)
, _route_deletion_in_progress (false)
- , _following_editor_selection (false)
, _maximised (false)
, _show_mixer_list (true)
, myactions (X_("mixer"))
load_bindings ();
_content.set_data ("ardour-bindings", bindings);
- PresentationInfo::Change.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::sync_treeview_from_presentation_info, this), gui_context());
+ PresentationInfo::Change.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::presentation_info_changed, this, _1), gui_context());
scroller.set_can_default (true);
// set_default (scroller);
select_none ();
}
-void
-Mixer_UI::track_editor_selection ()
-{
- PublicEditor::instance().get_selection().TracksChanged.connect (sigc::mem_fun (*this, &Mixer_UI::follow_editor_selection));
-}
-
Gtk::Window*
Mixer_UI::use_own_window (bool and_fill_it)
{
}
}
+void
+Mixer_UI::presentation_info_changed (PropertyChange const & what_changed)
+{
+ PropertyChange soh;
+ soh.add (Properties::selected);
+ soh.add (Properties::order);
+ soh.add (Properties::hidden);
+
+ if (what_changed.contains (soh)) {
+ sync_treeview_from_presentation_info (what_changed);
+ }
+}
+
void
Mixer_UI::sync_presentation_info_from_treeview ()
{
}
void
-Mixer_UI::sync_treeview_from_presentation_info ()
+Mixer_UI::sync_treeview_from_presentation_info (PropertyChange const & what_changed)
{
if (!_session || _session->deletion_in_progress()) {
return;
track_model->reorder (neworder);
}
- redisplay_track_list ();
-}
-
-void
-Mixer_UI::follow_editor_selection ()
-{
- if (_following_editor_selection) {
- return;
- }
-
- _following_editor_selection = true;
- _selection.block_routes_changed (true);
-
- TrackSelection& s (PublicEditor::instance().get_selection().tracks);
+ if (what_changed.contains (Properties::selected)) {
- _selection.clear_routes ();
+ PresentationInfo::ChangeSuspender cs;
- for (TrackViewList::iterator i = s.begin(); i != s.end(); ++i) {
- TimeAxisView* tav = dynamic_cast<TimeAxisView*> (*i);
- if (tav) {
- AxisView* axis = axis_by_stripable (tav->stripable());
- if (axis) {
- _selection.add (axis);
+ for (list<MixerStrip *>::const_iterator i = strips.begin(); i != strips.end(); ++i) {
+ boost::shared_ptr<Stripable> stripable = (*i)->stripable();
+ if (stripable && stripable->presentation_info().selected()) {
+ _selection.add (*i);
+ } else {
+ _selection.remove (*i);
}
}
}
- _following_editor_selection = false;
- _selection.block_routes_changed (false);
+ redisplay_track_list ();
}
add_stripables (sl);
}
- redisplay_track_list ();
- sync_treeview_from_presentation_info ();
+ sync_treeview_from_presentation_info (Properties::order);
}
void
void show_window ();
void set_session (ARDOUR::Session *);
- void track_editor_selection ();
PluginSelector* plugin_selector();
Width _strip_width;
+ void presentation_info_changed (PBD::PropertyChange const &);
+ void sync_treeview_from_presentation_info (PBD::PropertyChange const &);
void sync_presentation_info_from_treeview ();
- void sync_treeview_from_presentation_info ();
bool ignore_reorder;
friend class MixerGroupTabs;
- void follow_editor_selection ();
- bool _following_editor_selection;
-
void monitor_section_going_away ();
void monitor_section_attached ();
virtual Selection& get_selection () const = 0;
virtual bool get_selection_extents (framepos_t &start, framepos_t &end) const = 0;
virtual Selection& get_cut_buffer () const = 0;
- virtual void track_mixer_selection () = 0;
virtual bool extend_selection_to_track (TimeAxisView&) = 0;
virtual void play_selection () = 0;
virtual void play_with_preroll () = 0;
using namespace ARDOUR;
using namespace PBD;
-unsigned int RouteProcessorSelection::_no_route_change_signal = 0;
+
RouteProcessorSelection::RouteProcessorSelection()
{
}
void
RouteProcessorSelection::clear_routes ()
{
+ PresentationInfo::ChangeSuspender cs;
+
for (AxisViewSelection::iterator i = axes.begin(); i != axes.end(); ++i) {
(*i)->set_selected (false);
}
axes.clear ();
drop_connections ();
- if (0 == _no_route_change_signal) {
- RoutesChanged ();
- }
}
void
if (ms) {
ms->CatchDeletion.connect (*this, invalidator (*this), boost::bind (&RouteProcessorSelection::remove, this, _1), gui_context());
}
-
- if (0 == _no_route_change_signal) {
- RoutesChanged();
- }
}
}
if ((i = find (axes.begin(), axes.end(), r)) != axes.end()) {
(*i)->set_selected (false);
axes.erase (i);
- if (0 == _no_route_change_signal) {
- RoutesChanged ();
- }
}
}
{
return processors.empty () && axes.empty ();
}
-
-void
-RouteProcessorSelection::block_routes_changed (bool yn)
-{
- if (yn) {
- ++_no_route_change_signal;
- } else {
- assert (_no_route_change_signal > 0);
- --_no_route_change_signal;
- }
-}
RouteProcessorSelection& operator= (const RouteProcessorSelection& other);
sigc::signal<void> ProcessorsChanged;
- sigc::signal<void> RoutesChanged;
-
- void block_routes_changed (bool);
void clear ();
bool empty();
private:
void removed (AxisView*);
- static unsigned int _no_route_change_signal;
-
};
bool operator==(const RouteProcessorSelection& a, const RouteProcessorSelection& b);
: tracks (e)
, editor (e)
, next_time_id (0)
- , _no_tracks_changed (false)
{
clear ();
Selection::clear_tracks (bool with_signal)
{
if (!tracks.empty()) {
+ PresentationInfo::ChangeSuspender cs;
+
for (TrackViewList::iterator x = tracks.begin(); x != tracks.end(); ++x) {
(*x)->set_selected (false);
}
+
tracks.clear ();
- if (!_no_tracks_changed && with_signal) {
- TracksChanged();
- }
}
}
tracks.erase (i);
}
- if (!_no_tracks_changed) {
- TracksChanged();
- }
}
void
}
void
-Selection::add (const TrackViewList& track_list)
+Selection::add (TrackViewList const & track_list)
{
clear_objects(); //enforce object/range exclusivity
+ PresentationInfo::ChangeSuspender cs;
+
TrackViewList added = tracks.add (track_list);
if (!added.empty()) {
for (TrackViewList::iterator x = added.begin(); x != added.end(); ++x) {
(*x)->set_selected (true);
}
- if (!_no_tracks_changed) {
- TracksChanged ();
- }
}
}
if ((i = find (tracks.begin(), tracks.end(), track)) != tracks.end()) {
track->set_selected (false);
tracks.erase (i);
-
- if (!_no_tracks_changed) {
- TracksChanged();
- }
}
}
void
Selection::remove (const TrackViewList& track_list)
{
- bool changed = false;
-
for (TrackViewList::const_iterator i = track_list.begin(); i != track_list.end(); ++i) {
TrackViewList::iterator x = find (tracks.begin(), tracks.end(), *i);
if (x != tracks.end()) {
(*i)->set_selected (false);
tracks.erase (x);
- changed = true;
- }
- }
-
- if (changed) {
- if (!_no_tracks_changed) {
- TracksChanged();
}
}
}
Selection::set (TimeAxisView* track)
{
clear_objects (); //enforce object/range exclusivity
- clear_tracks (false);
+
+ PresentationInfo::ChangeSuspender cs;
+
+ if (!tracks.empty()) {
+
+ if (tracks.size() == 1 && tracks.front() == track) {
+ /* already single selection: nothing to do */
+ return;
+ }
+
+ for (TrackViewList::iterator x = tracks.begin(); x != tracks.end(); ++x) {
+ (*x)->set_selected (false);
+ }
+
+ tracks.clear ();
+ }
+
add (track);
}
Selection::set (const TrackViewList& track_list)
{
clear_objects(); //enforce object/range exclusivity
- clear_tracks (false);
+
+ PresentationInfo::ChangeSuspender cs;
+
+ if (!tracks.empty()) {
+
+ /* cannot use set<T>::operator== (set<T> const &) here, because
+ * apparently the ordering used within 2 sets is not
+ * necessarily the same.
+ */
+
+ if (tracks.size() == track_list.size()) {
+ bool missing = false;
+
+ for (TrackViewList::const_iterator x = track_list.begin(); x != track_list.end(); ++x) {
+ if (find (tracks.begin(), tracks.end(), *x) == tracks.end()) {
+ missing = true;
+ }
+ }
+
+ if (!missing) {
+ /* already same selection: nothing to do */
+ return;
+ }
+ }
+
+ /* argument is different from existing selection */
+
+ for (TrackViewList::iterator x = tracks.begin(); x != tracks.end(); ++x) {
+ (*x)->set_selected (false);
+ }
+
+ tracks.clear ();
+ }
+
add (track_list);
}
i = tmp;
}
}
-
-void
-Selection::block_tracks_changed (bool yn)
-{
- _no_tracks_changed = yn;
-}
// Selection& operator= (const Selection& other);
sigc::signal<void> RegionsChanged;
- sigc::signal<void> TracksChanged;
sigc::signal<void> TimeChanged;
sigc::signal<void> LinesChanged;
sigc::signal<void> PlaylistsChanged;
sigc::signal<void> MidiNotesChanged;
sigc::signal<void> MidiRegionsChanged;
- void block_tracks_changed (bool);
-
void clear ();
/** check if all selections are empty
private:
PublicEditor const * editor;
uint32_t next_time_id;
- bool _no_tracks_changed;
};
bool operator==(const Selection& a, const Selection& b);