restore/extend/simplify ControlProtocol API to allow tracking of selection

This commit is contained in:
Paul Davis 2016-07-06 13:36:55 -04:00
parent eed3ea5047
commit 2047ee527c
6 changed files with 93 additions and 75 deletions

View file

@ -49,8 +49,20 @@ PBD::Signal0<void> ControlProtocol::VerticalZoomOutSelected;
PBD::Signal0<void> ControlProtocol::StepTracksDown; PBD::Signal0<void> ControlProtocol::StepTracksDown;
PBD::Signal0<void> ControlProtocol::StepTracksUp; PBD::Signal0<void> ControlProtocol::StepTracksUp;
PBD::Signal1<void,boost::shared_ptr<ARDOUR::Stripable> > ControlProtocol::AddStripableToSelection;
PBD::Signal1<void,boost::shared_ptr<ARDOUR::Stripable> > ControlProtocol::SetStripableSelection;
PBD::Signal1<void,boost::shared_ptr<ARDOUR::Stripable> > ControlProtocol::ToggleStripableSelection;
PBD::Signal1<void,boost::shared_ptr<ARDOUR::Stripable> > ControlProtocol::RemoveStripableFromSelection;
PBD::Signal0<void> ControlProtocol::ClearStripableSelection;
PBD::Signal1<void,StripableNotificationListPtr> ControlProtocol::StripableSelectionChanged; PBD::Signal1<void,StripableNotificationListPtr> ControlProtocol::StripableSelectionChanged;
Glib::Threads::Mutex ControlProtocol::first_selected_mutex;
boost::weak_ptr<Stripable> ControlProtocol::_first_selected_stripable;
StripableNotificationList ControlProtocol::_last_selected;
bool ControlProtocol::selection_connected = false;
PBD::ScopedConnection ControlProtocol::selection_connection;
const std::string ControlProtocol::state_node_name ("Protocol"); const std::string ControlProtocol::state_node_name ("Protocol");
ControlProtocol::ControlProtocol (Session& s, string str) ControlProtocol::ControlProtocol (Session& s, string str)
@ -58,6 +70,12 @@ ControlProtocol::ControlProtocol (Session& s, string str)
, _name (str) , _name (str)
, _active (false) , _active (false)
{ {
if (!selection_connected) {
/* this is all static, connect it only once (and early), for all ControlProtocols */
StripableSelectionChanged.connect_same_thread (selection_connection, boost::bind (&ControlProtocol::stripable_selection_changed, _1));
selection_connected = true;
}
} }
ControlProtocol::~ControlProtocol () ControlProtocol::~ControlProtocol ()
@ -324,3 +342,35 @@ ControlProtocol::set_state (XMLNode const & node, int /* version */)
return 0; return 0;
} }
boost::shared_ptr<Stripable>
ControlProtocol::first_selected_stripable ()
{
Glib::Threads::Mutex::Lock lm (first_selected_mutex);
return _first_selected_stripable.lock();
}
void
ControlProtocol::set_first_selected_stripable (boost::shared_ptr<Stripable> s)
{
Glib::Threads::Mutex::Lock lm (first_selected_mutex);
_first_selected_stripable = s;
}
void
ControlProtocol::stripable_selection_changed (StripableNotificationListPtr sp)
{
_last_selected = *sp;
{
Glib::Threads::Mutex::Lock lm (first_selected_mutex);
if (!_last_selected.empty()) {
_first_selected_stripable = _last_selected.front().lock();
} else {
_first_selected_stripable = boost::weak_ptr<Stripable>();
}
}
cerr << "CP: selection now " << _last_selected.size() << endl;
}

View file

@ -39,6 +39,7 @@ namespace ARDOUR {
class Route; class Route;
class Session; class Session;
class Bundle; class Bundle;
class Stripable;
class LIBCONTROLCP_API ControlProtocol : public PBD::Stateful, public PBD::ScopedConnectionList, public BasicUI class LIBCONTROLCP_API ControlProtocol : public PBD::Stateful, public PBD::ScopedConnectionList, public BasicUI
{ {
@ -78,6 +79,12 @@ class LIBCONTROLCP_API ControlProtocol : public PBD::Stateful, public PBD::Scope
static PBD::Signal0<void> StepTracksDown; static PBD::Signal0<void> StepTracksDown;
static PBD::Signal0<void> StepTracksUp; static PBD::Signal0<void> StepTracksUp;
static PBD::Signal1<void,boost::shared_ptr<ARDOUR::Stripable> > AddStripableToSelection;
static PBD::Signal1<void,boost::shared_ptr<ARDOUR::Stripable> > SetStripableSelection;
static PBD::Signal1<void,boost::shared_ptr<ARDOUR::Stripable> > ToggleStripableSelection;
static PBD::Signal1<void,boost::shared_ptr<ARDOUR::Stripable> > RemoveStripableFromSelection;
static PBD::Signal0<void> ClearStripableSelection;
/* signals that one UI (e.g. the GUI) can emit to get all other UI's to /* signals that one UI (e.g. the GUI) can emit to get all other UI's to
respond. Typically this will always be GUI->"others" - the GUI pays respond. Typically this will always be GUI->"others" - the GUI pays
no attention to these signals. no attention to these signals.
@ -85,6 +92,9 @@ class LIBCONTROLCP_API ControlProtocol : public PBD::Stateful, public PBD::Scope
static PBD::Signal1<void,StripableNotificationListPtr> StripableSelectionChanged; static PBD::Signal1<void,StripableNotificationListPtr> StripableSelectionChanged;
static boost::shared_ptr<ARDOUR::Stripable> first_selected_stripable ();
static void set_first_selected_stripable (boost::shared_ptr<ARDOUR::Stripable>);
/* the model here is as follows: /* the model here is as follows:
we imagine most control surfaces being able to control we imagine most control surfaces being able to control
@ -132,6 +142,7 @@ class LIBCONTROLCP_API ControlProtocol : public PBD::Stateful, public PBD::Scope
int set_state (XMLNode const &, int version); int set_state (XMLNode const &, int version);
static const std::string state_node_name; static const std::string state_node_name;
static StripableNotificationList const & last_selected() { return _last_selected; }
protected: protected:
std::vector<boost::shared_ptr<ARDOUR::Route> > route_table; std::vector<boost::shared_ptr<ARDOUR::Route> > route_table;
@ -143,6 +154,14 @@ class LIBCONTROLCP_API ControlProtocol : public PBD::Stateful, public PBD::Scope
private: private:
LIBCONTROLCP_LOCAL ControlProtocol (const ControlProtocol&); /* noncopyable */ LIBCONTROLCP_LOCAL ControlProtocol (const ControlProtocol&); /* noncopyable */
bool _active; bool _active;
static Glib::Threads::Mutex first_selected_mutex;
static boost::weak_ptr<ARDOUR::Stripable> _first_selected_stripable;
static StripableNotificationList _last_selected;
static void stripable_selection_changed (StripableNotificationListPtr);
static bool selection_connected;
static PBD::ScopedConnection selection_connection;
}; };
extern "C" { extern "C" {

View file

@ -167,7 +167,8 @@ MIDIFunction::execute ()
if (!_argument.empty()) { if (!_argument.empty()) {
uint32_t rid; uint32_t rid;
sscanf (_argument.c_str(), "%d", &rid); sscanf (_argument.c_str(), "%d", &rid);
_ui->toggle_selection (rid, ARDOUR::PresentationInfo::Flag (ARDOUR::PresentationInfo::Route|ARDOUR::PresentationInfo::VCA)); // XX fix me ... need to get stripable, not RID
//_ui->toggle_selection (rid, ARDOUR::PresentationInfo::Flag (ARDOUR::PresentationInfo::Route|ARDOUR::PresentationInfo::VCA));
DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Function: SetRouteSelection = %1\n", rid)); DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Function: SetRouteSelection = %1\n", rid));
} }
break; break;

View file

@ -289,12 +289,12 @@ MackieControlProtocol::get_sorted_stripables()
switch (_view_mode) { switch (_view_mode) {
case Mixer: case Mixer:
if (!is_hidden (s)) { if (!s->presentation_info().hidden()) {
sorted.push_back (s); sorted.push_back (s);
} }
break; break;
case AudioTracks: case AudioTracks:
if (is_audio_track(s) && !is_hidden(s)) { if (is_audio_track(s) && !s->presentation_info().hidden()) {
sorted.push_back (s); sorted.push_back (s);
} }
break; break;
@ -306,13 +306,13 @@ MackieControlProtocol::get_sorted_stripables()
} }
#endif #endif
} else { } else {
if (!is_track(s) && !is_hidden(s)) { if (!is_track(s) && !s->presentation_info().hidden()) {
sorted.push_back (s); sorted.push_back (s);
} }
} }
break; break;
case MidiTracks: case MidiTracks:
if (is_midi_track(s) && !is_hidden(s)) { if (is_midi_track(s) && !s->presentation_info().hidden()) {
sorted.push_back (s); sorted.push_back (s);
} }
break; break;
@ -320,22 +320,22 @@ MackieControlProtocol::get_sorted_stripables()
break; break;
case Auxes: // in ardour, for now aux and buss are same. for mixbus, "Busses" are mixbuses, "Auxes" are ardour buses case Auxes: // in ardour, for now aux and buss are same. for mixbus, "Busses" are mixbuses, "Auxes" are ardour buses
#ifdef MIXBUS #ifdef MIXBUS
if (!s->mixbus() && !is_track() && !is_hidden(s)) if (!s->mixbus() && !is_track() && !s->presentation_info().hidden())
#else #else
if (!is_track(s) && !is_hidden(s)) if (!is_track(s) && !s->presentation_info().hidden())
#endif #endif
{ {
sorted.push_back (s); sorted.push_back (s);
} }
break; break;
case Hidden: // Show all the tracks we have hidden case Hidden: // Show all the tracks we have hidden
if (is_hidden(s)) { if (s->presentation_info().hidden()) {
// maybe separate groups // maybe separate groups
sorted.push_back (s); sorted.push_back (s);
} }
break; break;
case Selected: // For example: a group (this is USER) case Selected: // For example: a group (this is USER)
if (selected(s) && !is_hidden(s)) { if (s->presentation_info().selected() && !s->presentation_info().hidden()) {
sorted.push_back (s); sorted.push_back (s);
} }
break; break;
@ -2039,23 +2039,19 @@ MackieControlProtocol::select_range ()
return; return;
} }
if (stripables.size() == 1 && _last_selected_stripables.size() == 1 && stripables.front()->presentation_info().selected()) { if (stripables.size() == 1 && ControlProtocol::last_selected().size() == 1 && stripables.front()->presentation_info().selected()) {
/* cancel selection for one and only selected stripable */ /* cancel selection for one and only selected stripable */
session->toggle_stripable_selection (stripables.front()); ToggleStripableSelection (stripables.front());
} else { } else {
for (StripableList::iterator s = stripables.begin(); s != stripables.end(); ++s) { for (StripableList::iterator s = stripables.begin(); s != stripables.end(); ++s) {
if (main_modifier_state() == MODIFIER_CONTROL) { if (main_modifier_state() == MODIFIER_SHIFT) {
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("toggle selection of %1 (%2)\n", (*s)->name(), (*s)->presentation_info().order())); ToggleStripableSelection (*s);
session->toggle_stripable_selection (*s);
} else { } else {
if (s == stripables.begin()) { if (s == stripables.begin()) {
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("set selection of %1 (%2)\n", (*s)->name(), (*s)->presentation_info().order())); SetStripableSelection (*s);
session->set_stripable_selection (*s); } else {
} else { AddStripableToSelection (*s);
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("add to selection %1 (%2)\n", (*s)->name(), (*s)->presentation_info().order()));
session->add_stripable_selection (*s);
} }
} }
} }
@ -2351,27 +2347,6 @@ MackieControlProtocol::is_midi_track (boost::shared_ptr<Stripable> r) const
return boost::dynamic_pointer_cast<MidiTrack>(r) != 0; return boost::dynamic_pointer_cast<MidiTrack>(r) != 0;
} }
bool
MackieControlProtocol::selected (boost::shared_ptr<Stripable> r) const
{
for (Selection::const_iterator i = _last_selected_stripables.begin(); i != _last_selected_stripables.end(); ++i) {
boost::shared_ptr<ARDOUR::Stripable> rt = (*i).lock();
if (rt == r) {
return true;
}
}
return false;
}
bool
MackieControlProtocol::is_hidden (boost::shared_ptr<Stripable> r) const
{
if (!r) {
return false;
}
return (r->presentation_info().flags() & PresentationInfo::Hidden);
}
bool bool
MackieControlProtocol::is_mapped (boost::shared_ptr<Stripable> r) const MackieControlProtocol::is_mapped (boost::shared_ptr<Stripable> r) const
{ {
@ -2391,14 +2366,6 @@ MackieControlProtocol::update_selected (boost::shared_ptr<Stripable> s, bool bec
{ {
if (became_selected) { if (became_selected) {
if (selected (s)) {
/* already selected .. mmmm */
cerr << "stripable " << s->name() << " already marked as selected\n";
return;
}
_last_selected_stripables.push_back (boost::weak_ptr<Stripable> (s));
check_fader_automation_state (); check_fader_automation_state ();
/* It is possible that first_selected_route() may return null if we /* It is possible that first_selected_route() may return null if we
@ -2412,33 +2379,19 @@ MackieControlProtocol::update_selected (boost::shared_ptr<Stripable> s, bool bec
set_subview_mode (None, boost::shared_ptr<Stripable>()); set_subview_mode (None, boost::shared_ptr<Stripable>());
} }
} else {
for (Selection::iterator i = _last_selected_stripables.begin(); i != _last_selected_stripables.end(); ++i) {
boost::shared_ptr<ARDOUR::Stripable> ss = (*i).lock();
if (ss == s) {
_last_selected_stripables.erase (i);
break;
}
}
} }
} }
boost::shared_ptr<Stripable> boost::shared_ptr<Stripable>
MackieControlProtocol::first_selected_stripable () const MackieControlProtocol::first_selected_stripable () const
{ {
if (_last_selected_stripables.empty()) { boost::shared_ptr<Stripable> s = ControlProtocol::first_selected_stripable();
return boost::shared_ptr<Stripable>();
}
boost::shared_ptr<Stripable> r = (*(_last_selected_stripables.begin())).lock(); if (s) {
if (r) {
/* check it is on one of our surfaces */ /* check it is on one of our surfaces */
if (is_mapped (r)) { if (is_mapped (s)) {
return r; return s;
} }
/* stripable is not mapped. thus, the currently selected stripable is /* stripable is not mapped. thus, the currently selected stripable is
@ -2446,10 +2399,10 @@ MackieControlProtocol::first_selected_stripable () const
* no currently selected stripable. * no currently selected stripable.
*/ */
r.reset (); s.reset ();
} }
return r; /* may be null */ return s; /* may be null */
} }
boost::shared_ptr<Stripable> boost::shared_ptr<Stripable>

View file

@ -138,8 +138,6 @@ class MackieControlProtocol
bool is_track (boost::shared_ptr<ARDOUR::Stripable>) const; bool is_track (boost::shared_ptr<ARDOUR::Stripable>) const;
bool is_audio_track (boost::shared_ptr<ARDOUR::Stripable>) const; bool is_audio_track (boost::shared_ptr<ARDOUR::Stripable>) const;
bool is_midi_track (boost::shared_ptr<ARDOUR::Stripable>) const; bool is_midi_track (boost::shared_ptr<ARDOUR::Stripable>) const;
bool selected (boost::shared_ptr<ARDOUR::Stripable>) const;
bool is_hidden (boost::shared_ptr<ARDOUR::Stripable>) const;
bool is_mapped (boost::shared_ptr<ARDOUR::Stripable>) const; bool is_mapped (boost::shared_ptr<ARDOUR::Stripable>) const;
boost::shared_ptr<ARDOUR::Stripable> first_selected_stripable () const; boost::shared_ptr<ARDOUR::Stripable> first_selected_stripable () const;
void update_selected (boost::shared_ptr<ARDOUR::Stripable>, bool selected); void update_selected (boost::shared_ptr<ARDOUR::Stripable>, bool selected);
@ -335,8 +333,6 @@ class MackieControlProtocol
bool needs_ipmidi_restart; bool needs_ipmidi_restart;
bool _metering_active; bool _metering_active;
bool _initialized; bool _initialized;
typedef std::vector<boost::weak_ptr<ARDOUR::Stripable> > Selection;
Selection _last_selected_stripables;
XMLNode* configuration_state; XMLNode* configuration_state;
int state_version; int state_version;
int _last_bank[9]; int _last_bank[9];

View file

@ -2600,9 +2600,8 @@ OSC::route_plugin_parameter_print (int ssid, int piid, int par, lo_message msg)
void void
OSC::gui_selection_changed () OSC::gui_selection_changed ()
{ {
boost::shared_ptr<Stripable> strip; boost::shared_ptr<Stripable> strip = ControlProtocol::first_selected_stripable();
strip = boost::dynamic_pointer_cast<Stripable>(session->get_editor_mixer().lock());
if (strip) { if (strip) {
_select = strip; _select = strip;
for (uint32_t it = 0; it < _surface.size(); ++it) { for (uint32_t it = 0; it < _surface.size(); ++it) {