+
+void
+jog_wheel_state_display (JogWheel::State state, SurfacePort & port)
+{
+ switch (state) {
+ case JogWheel::zoom:
+ port.write (builder.two_char_display ("Zm"));
+ break;
+ case JogWheel::scroll:
+ port.write (builder.two_char_display ("Sc"));
+ break;
+ case JogWheel::scrub:
+ port.write (builder.two_char_display ("Sb"));
+ break;
+ case JogWheel::shuttle:
+ port.write (builder.two_char_display ("Sh"));
+ break;
+ case JogWheel::speed:
+ port.write (builder.two_char_display ("Sp"));
+ break;
+ case JogWheel::select:
+ port.write (builder.two_char_display ("Se"));
+ break;
+ }
+}
+
+Mackie::LedState
+MackieControlProtocol::zoom_press (Mackie::Button &)
+{
+ _jog_wheel.zoom_state_toggle();
+ update_global_button ("scrub", _jog_wheel.jog_wheel_state() == JogWheel::scrub);
+ jog_wheel_state_display (_jog_wheel.jog_wheel_state(), mcu_port());
+ return _jog_wheel.jog_wheel_state() == JogWheel::zoom;
+}
+
+Mackie::LedState
+MackieControlProtocol::zoom_release (Mackie::Button &)
+{
+ return _jog_wheel.jog_wheel_state() == JogWheel::zoom;
+}
+
+Mackie::LedState
+MackieControlProtocol::scrub_press (Mackie::Button &)
+{
+ _jog_wheel.scrub_state_cycle();
+ update_global_button ("zoom", _jog_wheel.jog_wheel_state() == JogWheel::zoom);
+ jog_wheel_state_display (_jog_wheel.jog_wheel_state(), mcu_port());
+ return (
+ _jog_wheel.jog_wheel_state() == JogWheel::scrub
+ ||
+ _jog_wheel.jog_wheel_state() == JogWheel::shuttle
+ );
+}
+
+Mackie::LedState
+MackieControlProtocol::scrub_release (Mackie::Button &)
+{
+ return (
+ _jog_wheel.jog_wheel_state() == JogWheel::scrub
+ ||
+ _jog_wheel.jog_wheel_state() == JogWheel::shuttle
+ );
+}
+
+LedState
+MackieControlProtocol::drop_press (Button &)
+{
+ session->remove_last_capture();
+ return on;
+}
+
+LedState
+MackieControlProtocol::drop_release (Button &)
+{
+ return off;
+}
+
+LedState
+MackieControlProtocol::save_press (Button &)
+{
+ session->save_state ("");
+ return on;
+}
+
+LedState
+MackieControlProtocol::save_release (Button &)
+{
+ return off;
+}
+
+LedState
+MackieControlProtocol::timecode_beats_press (Button &)
+{
+ switch (_timecode_type) {
+ case ARDOUR::AnyTime::BBT:
+ _timecode_type = ARDOUR::AnyTime::Timecode;
+ break;
+ case ARDOUR::AnyTime::Timecode:
+ _timecode_type = ARDOUR::AnyTime::BBT;
+ break;
+ default:
+ ostringstream os;
+ os << "Unknown Anytime::Type " << _timecode_type;
+ throw runtime_error (os.str());
+ }
+ update_timecode_beats_led();
+ return on;
+}
+
+LedState
+MackieControlProtocol::timecode_beats_release (Button &)
+{
+ return off;
+}
+
+list<boost::shared_ptr<ARDOUR::Bundle> >
+MackieControlProtocol::bundles ()
+{
+ list<boost::shared_ptr<ARDOUR::Bundle> > b;
+ b.push_back (_input_bundle);
+ b.push_back (_output_bundle);
+ return b;
+}
+
+void
+MackieControlProtocol::port_connected_or_disconnected (string a, string b, bool connected)
+{
+ /* If something is connected to one of our output ports, send MIDI to update the surface
+ to whatever state it should have.
+ */
+
+ if (!connected) {
+ return;
+ }
+
+ MackiePorts::const_iterator i = _ports.begin();
+ while (i != _ports.end()) {
+
+ string const n = AudioEngine::instance()->make_port_name_non_relative ((*i)->output_port().name ());
+
+ if (a == n || b == n) {
+ break;
+ }
+
+ ++i;
+ }
+
+ if (i != _ports.end ()) {
+ update_surface ();
+ }
+}
+
+void
+MackieControlProtocol::do_request (MackieControlUIRequest* req)
+{
+ if (req->type == CallSlot) {
+
+ call_slot (MISSING_INVALIDATOR, req->the_slot);
+
+ } else if (req->type == Quit) {
+
+ stop ();
+ }
+}
+
+int
+MackieControlProtocol::stop ()
+{
+ BaseUI::quit ();
+
+ return 0;
+}
+
+/** Add a timeout so that a control's in_use flag will be reset some time in the future.
+ * @param in_use_control the control whose in_use flag to reset.
+ * @param touch_control a touch control to emit an event for, or 0.
+ */
+void
+MackieControlProtocol::add_in_use_timeout (SurfacePort& port, Control& in_use_control, Control* touch_control)
+{
+ Glib::RefPtr<Glib::TimeoutSource> timeout (Glib::TimeoutSource::create (250)); // milliseconds
+
+ in_use_control.in_use_connection.disconnect ();
+ in_use_control.in_use_connection = timeout->connect (
+ sigc::bind (sigc::mem_fun (*this, &MackieControlProtocol::control_in_use_timeout), &port, &in_use_control, touch_control));
+ in_use_control.in_use_touch_control = touch_control;
+
+ timeout->attach (main_loop()->get_context());
+
+ DEBUG_TRACE (DEBUG::MackieControl, string_compose ("timeout queued for port %1, control %2 touch control %3\n",
+ &port, &in_use_control, touch_control));}
+
+/** Handle timeouts to reset in_use for controls that can't
+ * do this by themselves (e.g. pots, and faders without touch support).
+ * @param in_use_control the control whose in_use flag to reset.
+ * @param touch_control a touch control to emit an event for, or 0.
+ */
+bool
+MackieControlProtocol::control_in_use_timeout (SurfacePort* port, Control* in_use_control, Control* touch_control)
+{
+ DEBUG_TRACE (DEBUG::MackieControl, string_compose ("timeout elapsed for port %1, control %2 touch control %3\n",
+ port, in_use_control, touch_control));
+
+ in_use_control->set_in_use (false);
+
+ if (touch_control) {
+ // empty control_state
+ ControlState control_state;
+ handle_control_event (*port, *touch_control, control_state);
+ }
+
+ // only call this method once from the timer
+ return false;
+}
+