+
+void
+Strip::lock_controls ()
+{
+ _controls_locked = true;
+}
+
+void
+Strip::unlock_controls ()
+{
+ _controls_locked = false;
+}
+
+void
+Strip::gui_selection_changed (const ARDOUR::StrongRouteNotificationList& rl)
+{
+ for (ARDOUR::StrongRouteNotificationList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
+ if ((*i) == _route) {
+ _surface->write (_select->set_state (on));
+ return;
+ }
+ }
+
+ _surface->write (_select->set_state (off));
+}
+
+string
+Strip::vpot_mode_string () const
+{
+ boost::shared_ptr<AutomationControl> ac = _vpot->control();
+
+ if (!ac) {
+ return string();
+ }
+
+ switch (ac->parameter().type()) {
+ case GainAutomation:
+ return "Fader";
+ case PanAzimuthAutomation:
+ return "Pan";
+ case PanWidthAutomation:
+ return "Width";
+ case PanElevationAutomation:
+ return "Elev";
+ case PanFrontBackAutomation:
+ return "F/Rear";
+ case PanLFEAutomation:
+ return "LFE";
+ }
+
+ return "???";
+}
+
+void
+Strip::flip_mode_changed (bool notify)
+{
+ if (!_route) {
+ return;
+ }
+
+ reset_saved_values ();
+
+ boost::shared_ptr<AutomationControl> fader_controllable = _fader->control ();
+ boost::shared_ptr<AutomationControl> vpot_controllable = _vpot->control ();
+
+ _fader->set_control (vpot_controllable);
+ _vpot->set_control (fader_controllable);
+
+ control_by_parameter[fader_controllable->parameter()] = _vpot;
+ control_by_parameter[vpot_controllable->parameter()] = _fader;
+
+ _surface->write (display (1, vpot_mode_string ()));
+
+ if (notify) {
+ notify_all ();
+ }
+}
+
+void
+Strip::queue_display_reset (uint32_t msecs)
+{
+ struct timeval now;
+ struct timeval delta;
+ struct timeval when;
+ gettimeofday (&now, 0);
+
+ delta.tv_sec = msecs/1000;
+ delta.tv_usec = (msecs - ((msecs/1000) * 1000)) * 1000;
+
+ timeradd (&now, &delta, &when);
+
+ _reset_display_at = (when.tv_sec * 1000000) + when.tv_usec;
+}
+
+void
+Strip::clear_display_reset ()
+{
+ _reset_display_at = 0;
+}
+
+void
+Strip::reset_display ()
+{
+ if (_route) {
+ _surface->write (display (1, vpot_mode_string()));
+ } else {
+ _surface->write (blank_display (1));
+ }
+
+ clear_display_reset ();
+}
+
+struct RouteCompareByName {
+ bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
+ return a->name().compare (b->name()) < 0;
+ }
+};
+
+void
+Strip::maybe_add_to_bundle_map (BundleMap& bm, boost::shared_ptr<Bundle> b, bool for_input, const ChanCount& channels)
+{
+ if (b->ports_are_outputs() == !for_input || b->nchannels() != channels) {
+ return;
+ }
+
+ bm[b->name()] = b;
+}
+
+void
+Strip::build_input_list (const ChanCount& channels)
+{
+ boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
+
+ input_bundles.clear ();
+
+ /* give user bundles first chance at being in the menu */
+
+ for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
+ if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
+ maybe_add_to_bundle_map (input_bundles, *i, true, channels);
+ }
+ }
+
+ for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
+ if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
+ maybe_add_to_bundle_map (input_bundles, *i, true, channels);
+ }
+ }
+
+ boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
+ RouteList copy = *routes;
+ copy.sort (RouteCompareByName ());
+
+ for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
+ maybe_add_to_bundle_map (input_bundles, (*i)->output()->bundle(), true, channels);
+ }
+
+}
+
+void
+Strip::build_output_list (const ChanCount& channels)
+{
+ boost::shared_ptr<ARDOUR::BundleList> b = _surface->mcp().get_session().bundles ();
+
+ output_bundles.clear ();
+
+ /* give user bundles first chance at being in the menu */
+
+ for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
+ if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
+ maybe_add_to_bundle_map (output_bundles, *i, false, channels);
+ }
+ }
+
+ for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
+ if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
+ maybe_add_to_bundle_map (output_bundles, *i, false, channels);
+ }
+ }
+
+ boost::shared_ptr<ARDOUR::RouteList> routes = _surface->mcp().get_session().get_routes ();
+ RouteList copy = *routes;
+ copy.sort (RouteCompareByName ());
+
+ for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
+ maybe_add_to_bundle_map (output_bundles, (*i)->input()->bundle(), false, channels);
+ }
+}
+
+void
+Strip::next_pot_mode ()
+{
+ vector<Evoral::Parameter>::iterator i;
+
+ if (_surface->mcp().flip_mode()) {
+ /* do not change vpot mode while in flipped mode */
+ DEBUG_TRACE (DEBUG::MackieControl, "not stepping pot mode - in flip mode\n");
+ _surface->write (display (1, "Flip"));
+ queue_display_reset (1000);
+ return;
+ }
+
+
+ boost::shared_ptr<AutomationControl> ac = _vpot->control();
+
+ if (!ac) {
+ return;
+ }
+
+ if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter())) {
+ return;
+ }
+
+ for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
+ if ((*i) == ac->parameter()) {
+ break;
+ }
+ }
+
+ /* move to the next mode in the list, or back to the start (which will
+ also happen if the current mode is not in the current pot mode list)
+ */
+
+ if (i != possible_pot_parameters.end()) {
+ ++i;
+ }
+
+ if (i == possible_pot_parameters.end()) {
+ i = possible_pot_parameters.begin();
+ }
+
+ set_vpot_parameter (*i);
+}
+
+void
+Strip::set_vpot_parameter (Evoral::Parameter p)
+{
+ boost::shared_ptr<Pannable> pannable;
+
+ DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to vpot mode %1\n", p));
+
+ reset_saved_values ();
+
+ switch (p.type()) {
+ case PanAzimuthAutomation:
+ pannable = _route->pannable ();
+ if (pannable) {
+ if (_surface->mcp().flip_mode()) {
+ /* gain to vpot, pan azi to fader */
+ _vpot->set_control (_route->gain_control());
+ control_by_parameter[GainAutomation] = _vpot;
+ if (pannable) {
+ _fader->set_control (pannable->pan_azimuth_control);
+ control_by_parameter[PanAzimuthAutomation] = _fader;
+ } else {
+ _fader->set_control (boost::shared_ptr<AutomationControl>());
+ control_by_parameter[PanAzimuthAutomation] = 0;
+ }
+ } else {
+ /* gain to fader, pan azi to vpot */
+ _fader->set_control (_route->gain_control());
+ control_by_parameter[GainAutomation] = _fader;
+ if (pannable) {
+ _vpot->set_control (pannable->pan_azimuth_control);
+ control_by_parameter[PanAzimuthAutomation] = _vpot;
+ } else {
+ _vpot->set_control (boost::shared_ptr<AutomationControl>());
+ control_by_parameter[PanAzimuthAutomation] = 0;
+ }
+ }
+ }
+ break;
+ case PanWidthAutomation:
+ pannable = _route->pannable ();
+ if (pannable) {
+ if (_surface->mcp().flip_mode()) {
+ /* gain to vpot, pan width to fader */
+ _vpot->set_control (_route->gain_control());
+ control_by_parameter[GainAutomation] = _vpot;
+ if (pannable) {
+ _fader->set_control (pannable->pan_width_control);
+ control_by_parameter[PanWidthAutomation] = _fader;
+ } else {
+ _fader->set_control (boost::shared_ptr<AutomationControl>());
+ control_by_parameter[PanWidthAutomation] = 0;
+ }
+ } else {
+ /* gain to fader, pan width to vpot */
+ _fader->set_control (_route->gain_control());
+ control_by_parameter[GainAutomation] = _fader;
+ if (pannable) {
+ _vpot->set_control (pannable->pan_width_control);
+ control_by_parameter[PanWidthAutomation] = _vpot;
+ } else {
+ _vpot->set_control (boost::shared_ptr<AutomationControl>());
+ control_by_parameter[PanWidthAutomation] = 0;
+ }
+ }
+ }
+ break;
+ case PanElevationAutomation:
+ break;
+ case PanFrontBackAutomation:
+ break;
+ case PanLFEAutomation:
+ break;
+ }
+
+ _surface->write (display (1, vpot_mode_string()));
+}
+
+void
+Strip::reset_saved_values ()
+{
+ _last_pan_azi_position_written = -1.0;
+ _last_pan_width_position_written = -1.0;
+ _last_gain_position_written = -1.0;
+
+}