PBD::Signal0<void> ControlProtocol::StepTracksDown;
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;
+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");
ControlProtocol::ControlProtocol (Session& s, string str)
, _name (str)
, _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 ()
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;
+}
class Route;
class Session;
class Bundle;
+class Stripable;
class LIBCONTROLCP_API ControlProtocol : public PBD::Stateful, public PBD::ScopedConnectionList, public BasicUI
{
static PBD::Signal0<void> StepTracksDown;
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
respond. Typically this will always be GUI->"others" - the GUI pays
no attention to these signals.
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:
we imagine most control surfaces being able to control
int set_state (XMLNode const &, int version);
static const std::string state_node_name;
+ static StripableNotificationList const & last_selected() { return _last_selected; }
protected:
std::vector<boost::shared_ptr<ARDOUR::Route> > route_table;
private:
LIBCONTROLCP_LOCAL ControlProtocol (const ControlProtocol&); /* noncopyable */
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" {
if (!_argument.empty()) {
uint32_t 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));
}
break;
switch (_view_mode) {
case Mixer:
- if (!is_hidden (s)) {
+ if (!s->presentation_info().hidden()) {
sorted.push_back (s);
}
break;
case AudioTracks:
- if (is_audio_track(s) && !is_hidden(s)) {
+ if (is_audio_track(s) && !s->presentation_info().hidden()) {
sorted.push_back (s);
}
break;
}
#endif
} else {
- if (!is_track(s) && !is_hidden(s)) {
+ if (!is_track(s) && !s->presentation_info().hidden()) {
sorted.push_back (s);
}
}
break;
case MidiTracks:
- if (is_midi_track(s) && !is_hidden(s)) {
+ if (is_midi_track(s) && !s->presentation_info().hidden()) {
sorted.push_back (s);
}
break;
break;
case Auxes: // in ardour, for now aux and buss are same. for mixbus, "Busses" are mixbuses, "Auxes" are ardour buses
#ifdef MIXBUS
- if (!s->mixbus() && !is_track() && !is_hidden(s))
+ if (!s->mixbus() && !is_track() && !s->presentation_info().hidden())
#else
- if (!is_track(s) && !is_hidden(s))
+ if (!is_track(s) && !s->presentation_info().hidden())
#endif
{
sorted.push_back (s);
}
break;
case Hidden: // Show all the tracks we have hidden
- if (is_hidden(s)) {
+ if (s->presentation_info().hidden()) {
// maybe separate groups
sorted.push_back (s);
}
break;
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);
}
break;
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 */
- session->toggle_stripable_selection (stripables.front());
+ ToggleStripableSelection (stripables.front());
} else {
-
for (StripableList::iterator s = stripables.begin(); s != stripables.end(); ++s) {
- if (main_modifier_state() == MODIFIER_CONTROL) {
- DEBUG_TRACE (DEBUG::MackieControl, string_compose ("toggle selection of %1 (%2)\n", (*s)->name(), (*s)->presentation_info().order()));
- session->toggle_stripable_selection (*s);
+ if (main_modifier_state() == MODIFIER_SHIFT) {
+ ToggleStripableSelection (*s);
} else {
if (s == stripables.begin()) {
- DEBUG_TRACE (DEBUG::MackieControl, string_compose ("set selection of %1 (%2)\n", (*s)->name(), (*s)->presentation_info().order()));
- session->set_stripable_selection (*s);
- } else {
- DEBUG_TRACE (DEBUG::MackieControl, string_compose ("add to selection %1 (%2)\n", (*s)->name(), (*s)->presentation_info().order()));
- session->add_stripable_selection (*s);
+ SetStripableSelection (*s);
+ } else {
+ AddStripableToSelection (*s);
}
}
}
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
MackieControlProtocol::is_mapped (boost::shared_ptr<Stripable> r) const
{
{
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 ();
/* It is possible that first_selected_route() may return null if we
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>
MackieControlProtocol::first_selected_stripable () const
{
- if (_last_selected_stripables.empty()) {
- return boost::shared_ptr<Stripable>();
- }
-
- boost::shared_ptr<Stripable> r = (*(_last_selected_stripables.begin())).lock();
+ boost::shared_ptr<Stripable> s = ControlProtocol::first_selected_stripable();
- if (r) {
+ if (s) {
/* check it is on one of our surfaces */
- if (is_mapped (r)) {
- return r;
+ if (is_mapped (s)) {
+ return s;
}
/* stripable is not mapped. thus, the currently selected stripable is
* no currently selected stripable.
*/
- r.reset ();
+ s.reset ();
}
- return r; /* may be null */
+ return s; /* may be null */
}
boost::shared_ptr<Stripable>
bool is_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 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;
boost::shared_ptr<ARDOUR::Stripable> first_selected_stripable () const;
void update_selected (boost::shared_ptr<ARDOUR::Stripable>, bool selected);
bool needs_ipmidi_restart;
bool _metering_active;
bool _initialized;
- typedef std::vector<boost::weak_ptr<ARDOUR::Stripable> > Selection;
- Selection _last_selected_stripables;
XMLNode* configuration_state;
int state_version;
int _last_bank[9];
void
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) {
_select = strip;
for (uint32_t it = 0; it < _surface.size(); ++it) {