faderport: some code cleanups, add timing for button presses, add new comboboxes to GUI to allow more button programming, save button state

This commit is contained in:
Paul Davis 2015-11-30 12:51:18 -05:00
parent 149f6795bb
commit 682e152aaf
5 changed files with 547 additions and 280 deletions

View file

@ -94,77 +94,73 @@ FaderPort::FaderPort (Session& s)
/* Catch port connections and disconnections */ /* Catch port connections and disconnections */
ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR, boost::bind (&FaderPort::connection_handler, this, _1, _2, _3, _4, _5), this); ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR, boost::bind (&FaderPort::connection_handler, this, _1, _2, _3, _4, _5), this);
buttons.insert (std::make_pair (Mute, ButtonInfo (*this, _("Mute"), Mute, 21))); buttons.insert (std::make_pair (Mute, Button (*this, _("Mute"), Mute, 21)));
buttons.insert (std::make_pair (Solo, ButtonInfo (*this, _("Solo"), Solo, 22))); buttons.insert (std::make_pair (Solo, Button (*this, _("Solo"), Solo, 22)));
buttons.insert (std::make_pair (Rec, ButtonInfo (*this, _("Rec"), Rec, 23))); buttons.insert (std::make_pair (Rec, Button (*this, _("Rec"), Rec, 23)));
buttons.insert (std::make_pair (Left, ButtonInfo (*this, _("Left"), Left, 20))); buttons.insert (std::make_pair (Left, Button (*this, _("Left"), Left, 20)));
buttons.insert (std::make_pair (Bank, ButtonInfo (*this, _("Bank"), Bank, 19))); buttons.insert (std::make_pair (Bank, Button (*this, _("Bank"), Bank, 19)));
buttons.insert (std::make_pair (Right, ButtonInfo (*this, _("Right"), Right, 18))); buttons.insert (std::make_pair (Right, Button (*this, _("Right"), Right, 18)));
buttons.insert (std::make_pair (Output, ButtonInfo (*this, _("Output"), Output, 17))); buttons.insert (std::make_pair (Output, Button (*this, _("Output"), Output, 17)));
buttons.insert (std::make_pair (FP_Read, ButtonInfo (*this, _("Read"), FP_Read, 13))); buttons.insert (std::make_pair (FP_Read, Button (*this, _("Read"), FP_Read, 13)));
buttons.insert (std::make_pair (FP_Write, ButtonInfo (*this, _("Write"), FP_Write, 14))); buttons.insert (std::make_pair (FP_Write, Button (*this, _("Write"), FP_Write, 14)));
buttons.insert (std::make_pair (FP_Touch, ButtonInfo (*this, _("Touch"), FP_Touch, 15))); buttons.insert (std::make_pair (FP_Touch, Button (*this, _("Touch"), FP_Touch, 15)));
buttons.insert (std::make_pair (FP_Off, ButtonInfo (*this, _("Off"), FP_Off, 16))); buttons.insert (std::make_pair (FP_Off, Button (*this, _("Off"), FP_Off, 16)));
buttons.insert (std::make_pair (Mix, ButtonInfo (*this, _("Mix"), Mix, 12))); buttons.insert (std::make_pair (Mix, Button (*this, _("Mix"), Mix, 12)));
buttons.insert (std::make_pair (Proj, ButtonInfo (*this, _("Proj"), Proj, 11))); buttons.insert (std::make_pair (Proj, Button (*this, _("Proj"), Proj, 11)));
buttons.insert (std::make_pair (Trns, ButtonInfo (*this, _("Trns"), Trns, 10))); buttons.insert (std::make_pair (Trns, Button (*this, _("Trns"), Trns, 10)));
buttons.insert (std::make_pair (Undo, ButtonInfo (*this, _("Undo"), Undo, 9))); buttons.insert (std::make_pair (Undo, Button (*this, _("Undo"), Undo, 9)));
buttons.insert (std::make_pair (Shift, ButtonInfo (*this, _("Shift"), Shift, 5))); buttons.insert (std::make_pair (Shift, Button (*this, _("Shift"), Shift, 5)));
buttons.insert (std::make_pair (Punch, ButtonInfo (*this, _("Punch"), Punch, 6))); buttons.insert (std::make_pair (Punch, Button (*this, _("Punch"), Punch, 6)));
buttons.insert (std::make_pair (User, ButtonInfo (*this, _("User"), User, 7))); buttons.insert (std::make_pair (User, Button (*this, _("User"), User, 7)));
buttons.insert (std::make_pair (Loop, ButtonInfo (*this, _("Loop"), Loop, 8))); buttons.insert (std::make_pair (Loop, Button (*this, _("Loop"), Loop, 8)));
buttons.insert (std::make_pair (Rewind, ButtonInfo (*this, _("Rewind"), Rewind, 4))); buttons.insert (std::make_pair (Rewind, Button (*this, _("Rewind"), Rewind, 4)));
buttons.insert (std::make_pair (Ffwd, ButtonInfo (*this, _("Ffwd"), Ffwd, 3))); buttons.insert (std::make_pair (Ffwd, Button (*this, _("Ffwd"), Ffwd, 3)));
buttons.insert (std::make_pair (Stop, ButtonInfo (*this, _("Stop"), Stop, 2))); buttons.insert (std::make_pair (Stop, Button (*this, _("Stop"), Stop, 2)));
buttons.insert (std::make_pair (Play, ButtonInfo (*this, _("Play"), Play, 1))); buttons.insert (std::make_pair (Play, Button (*this, _("Play"), Play, 1)));
buttons.insert (std::make_pair (RecEnable, ButtonInfo (*this, _("RecEnable"), RecEnable, 0))); buttons.insert (std::make_pair (RecEnable, Button (*this, _("RecEnable"), RecEnable, 0)));
buttons.insert (std::make_pair (FaderTouch, ButtonInfo (*this, _("Fader (touch)"), FaderTouch, -1))); buttons.insert (std::make_pair (FaderTouch, Button (*this, _("Fader (touch)"), FaderTouch, -1)));
button_info (Mix).set_action ( string("Common/toggle-editor-mixer"), true); get_button (Left).set_action ( boost::bind (&FaderPort::left, this), true);
button_info (Proj).set_action ( string("Common/toggle-meterbridge"), true); get_button (Right).set_action ( boost::bind (&FaderPort::right, this), true);
button_info (Trns).set_action ( string("Window/toggle-locations"), true);
button_info (Left).set_action ( boost::bind (&FaderPort::left, this), true); get_button (Undo).set_action (boost::bind (&FaderPort::undo, this), true);
button_info (Right).set_action ( boost::bind (&FaderPort::right, this), true); get_button (Undo).set_action (boost::bind (&FaderPort::redo, this), true, ShiftDown);
get_button (Undo).set_flash (true);
button_info (Undo).set_action (boost::bind (&FaderPort::undo, this), true); get_button (FP_Read).set_action (boost::bind (&FaderPort::read, this), true);
button_info (Undo).set_action (boost::bind (&FaderPort::redo, this), true, ShiftDown); get_button (FP_Write).set_action (boost::bind (&FaderPort::write, this), true);
button_info (Undo).set_flash (true); get_button (FP_Touch).set_action (boost::bind (&FaderPort::touch, this), true);
get_button (FP_Off).set_action (boost::bind (&FaderPort::off, this), true);
button_info (FP_Read).set_action (boost::bind (&FaderPort::read, this), true); get_button (Play).set_action (boost::bind (&BasicUI::transport_play, this, true), true);
button_info (FP_Write).set_action (boost::bind (&FaderPort::write, this), true); get_button (RecEnable).set_action (boost::bind (&BasicUI::rec_enable_toggle, this), true);
button_info (FP_Touch).set_action (boost::bind (&FaderPort::touch, this), true);
button_info (FP_Off).set_action (boost::bind (&FaderPort::off, this), true);
button_info (Play).set_action (boost::bind (&BasicUI::transport_play, this, true), true);
button_info (RecEnable).set_action (boost::bind (&BasicUI::rec_enable_toggle, this), true);
/* Stop is a modifier, so we have to use its own button state to get /* Stop is a modifier, so we have to use its own button state to get
the default action (since StopDown will be set when looking for the the default action (since StopDown will be set when looking for the
action to invoke. action to invoke.
*/ */
button_info (Stop).set_action (boost::bind (&BasicUI::transport_stop, this), true, StopDown); get_button (Stop).set_action (boost::bind (&BasicUI::transport_stop, this), true, StopDown);
button_info (Ffwd).set_action (boost::bind (&BasicUI::ffwd, this), true); get_button (Ffwd).set_action (boost::bind (&BasicUI::ffwd, this), true);
/* See comments about Stop above .. */ /* See comments about Stop above .. */
button_info (Rewind).set_action (boost::bind (&BasicUI::rewind, this), true, RewindDown); get_button (Rewind).set_action (boost::bind (&BasicUI::rewind, this), true, RewindDown);
button_info (Rewind).set_action (boost::bind (&BasicUI::goto_zero, this), true, ButtonState (RewindDown|StopDown)); get_button (Rewind).set_action (boost::bind (&BasicUI::goto_zero, this), true, ButtonState (RewindDown|StopDown));
button_info (Rewind).set_action (boost::bind (&BasicUI::goto_start, this), true, ButtonState (RewindDown|ShiftDown)); get_button (Rewind).set_action (boost::bind (&BasicUI::goto_start, this), true, ButtonState (RewindDown|ShiftDown));
button_info (Ffwd).set_action (boost::bind (&BasicUI::ffwd, this), true); get_button (Ffwd).set_action (boost::bind (&BasicUI::ffwd, this), true);
button_info (Ffwd).set_action (boost::bind (&BasicUI::goto_end, this), true, ShiftDown); get_button (Ffwd).set_action (boost::bind (&BasicUI::goto_end, this), true, ShiftDown);
button_info (Loop).set_action (boost::bind (&BasicUI::loop_toggle, this), true); get_button (Loop).set_action (boost::bind (&BasicUI::loop_toggle, this), true);
button_info (Loop).set_action (boost::bind (&BasicUI::add_marker, this, string()), true, ShiftDown); get_button (Loop).set_action (boost::bind (&BasicUI::add_marker, this, string()), true, ShiftDown);
button_info (Punch).set_action (boost::bind (&BasicUI::prev_marker, this), true, ShiftDown); get_button (Punch).set_action (boost::bind (&BasicUI::prev_marker, this), true, ShiftDown);
button_info (User).set_action (boost::bind (&BasicUI::next_marker, this), true, ShiftDown); get_button (User).set_action (boost::bind (&BasicUI::next_marker, this), true, ShiftDown);
button_info (Mute).set_action (boost::bind (&FaderPort::mute, this), true); get_button (Mute).set_action (boost::bind (&FaderPort::mute, this), true);
button_info (Solo).set_action (boost::bind (&FaderPort::solo, this), true); get_button (Solo).set_action (boost::bind (&FaderPort::solo, this), true);
button_info (Rec).set_action (boost::bind (&FaderPort::rec_enable, this), true); get_button (Rec).set_action (boost::bind (&FaderPort::rec_enable, this), true);
button_info (Output).set_action (boost::bind (&FaderPort::use_master, this), true); get_button (Output).set_action (boost::bind (&FaderPort::use_master, this), true);
button_info (Output).set_action (boost::bind (&FaderPort::use_monitor, this), true, ShiftDown); get_button (Output).set_action (boost::bind (&FaderPort::use_monitor, this), true, ShiftDown);
} }
FaderPort::~FaderPort () FaderPort::~FaderPort ()
@ -190,8 +186,8 @@ FaderPort::start_midi_handling ()
{ {
/* handle device inquiry response */ /* handle device inquiry response */
_input_port->parser()->sysex.connect_same_thread (midi_connections, boost::bind (&FaderPort::sysex_handler, this, _1, _2, _3)); _input_port->parser()->sysex.connect_same_thread (midi_connections, boost::bind (&FaderPort::sysex_handler, this, _1, _2, _3));
/* handle switches */ /* handle buttons */
_input_port->parser()->poly_pressure.connect_same_thread (midi_connections, boost::bind (&FaderPort::switch_handler, this, _1, _2)); _input_port->parser()->poly_pressure.connect_same_thread (midi_connections, boost::bind (&FaderPort::button_handler, this, _1, _2));
/* handle encoder */ /* handle encoder */
_input_port->parser()->pitchbend.connect_same_thread (midi_connections, boost::bind (&FaderPort::encoder_handler, this, _1, _2)); _input_port->parser()->pitchbend.connect_same_thread (midi_connections, boost::bind (&FaderPort::encoder_handler, this, _1, _2));
/* handle fader */ /* handle fader */
@ -263,18 +259,21 @@ FaderPort::all_lights_out ()
} }
} }
FaderPort::ButtonInfo& FaderPort::Button&
FaderPort::button_info (ButtonID id) const FaderPort::get_button (ButtonID id) const
{ {
ButtonMap::const_iterator b = buttons.find (id); ButtonMap::const_iterator b = buttons.find (id);
assert (b != buttons.end()); assert (b != buttons.end());
return const_cast<ButtonInfo&>(b->second); return const_cast<Button&>(b->second);
} }
void void
FaderPort::switch_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb) FaderPort::button_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
{ {
ButtonID id (ButtonID (tb->controller_number)); ButtonID id (ButtonID (tb->controller_number));
Button& button (get_button (id));
button.do_timing (tb->value ? true : false);
switch (id) { switch (id) {
case Shift: case Shift:
@ -307,13 +306,11 @@ FaderPort::switch_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
break; break;
} }
ButtonInfo& bi (button_info (id)); if (button.uses_flash()) {
button.set_led_state (_output_port, (int)tb->value);
if (bi.uses_flash()) {
bi.set_led_state (_output_port, (int)tb->value);
} }
bi.invoke (button_state, tb->value ? true : false); button.invoke (button_state, tb->value ? true : false);
} }
void void
@ -489,7 +486,7 @@ FaderPort::blink ()
blink_state = !blink_state; blink_state = !blink_state;
for (Blinkers::iterator b = blinkers.begin(); b != blinkers.end(); b++) { for (Blinkers::iterator b = blinkers.begin(); b != blinkers.end(); b++) {
button_info(*b).set_led_state (_output_port, blink_state); get_button(*b).set_led_state (_output_port, blink_state);
} }
return true; return true;
@ -517,15 +514,15 @@ FaderPort::notify_record_state_changed ()
{ {
switch (session->record_status()) { switch (session->record_status()) {
case Session::Disabled: case Session::Disabled:
button_info (RecEnable).set_led_state (_output_port, false); get_button (RecEnable).set_led_state (_output_port, false);
blinkers.remove (RecEnable); blinkers.remove (RecEnable);
break; break;
case Session::Enabled: case Session::Enabled:
button_info (RecEnable).set_led_state (_output_port, true); get_button (RecEnable).set_led_state (_output_port, true);
blinkers.push_back (RecEnable); blinkers.push_back (RecEnable);
break; break;
case Session::Recording: case Session::Recording:
button_info (RecEnable).set_led_state (_output_port, true); get_button (RecEnable).set_led_state (_output_port, true);
blinkers.remove (RecEnable); blinkers.remove (RecEnable);
break; break;
} }
@ -534,11 +531,11 @@ FaderPort::notify_record_state_changed ()
void void
FaderPort::notify_transport_state_changed () FaderPort::notify_transport_state_changed ()
{ {
button_info (Loop).set_led_state (_output_port, session->get_play_loop()); get_button (Loop).set_led_state (_output_port, session->get_play_loop());
button_info (Play).set_led_state (_output_port, session->transport_speed() == 1.0); get_button (Play).set_led_state (_output_port, session->transport_speed() == 1.0);
button_info (Stop).set_led_state (_output_port, session->transport_stopped ()); get_button (Stop).set_led_state (_output_port, session->transport_stopped ());
button_info (Rewind).set_led_state (_output_port, session->transport_speed() < 0.0); get_button (Rewind).set_led_state (_output_port, session->transport_speed() < 0.0);
button_info (Ffwd).set_led_state (_output_port, session->transport_speed() > 1.0); get_button (Ffwd).set_led_state (_output_port, session->transport_speed() > 1.0);
} }
void void
@ -588,6 +585,17 @@ FaderPort::get_state ()
child->add_child_nocopy (boost::shared_ptr<ARDOUR::Port>(_output_port)->get_state()); child->add_child_nocopy (boost::shared_ptr<ARDOUR::Port>(_output_port)->get_state());
node.add_child_nocopy (*child); node.add_child_nocopy (*child);
/* Save action state for Mix, Proj, Trns and User buttons, since these
* are user controlled. We can only save named-action operations, since
* internal functions are just pointers to functions and hard to
* serialize without enumerating them all somewhere.
*/
node.add_child_nocopy (get_button (Mix).get_state());
node.add_child_nocopy (get_button (Proj).get_state());
node.add_child_nocopy (get_button (Trns).get_state());
node.add_child_nocopy (get_button (User).get_state());
return node; return node;
} }
@ -616,6 +624,21 @@ FaderPort::set_state (const XMLNode& node, int version)
} }
} }
for (XMLNodeList::const_iterator n = node.children().begin(); n != node.children().end(); ++n) {
if ((*n)->name() == X_("Button")) {
XMLProperty const * prop = (*n)->property (X_("id"));
if (!prop) {
continue;
}
int xid = atoi (prop->value());
ButtonMap::iterator b = buttons.find (ButtonID (xid));
if (b == buttons.end()) {
continue;
}
b->second.set_state (**n);
}
}
return 0; return 0;
} }
@ -646,6 +669,8 @@ FaderPort::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1,
return false; return false;
} }
cerr << "Connection state = " << hex << connection_state << dec << endl;
if ((connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) { if ((connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) {
/* XXX this is a horrible hack. Without a short sleep here, /* XXX this is a horrible hack. Without a short sleep here,
@ -661,13 +686,15 @@ FaderPort::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1,
_device_active = false; _device_active = false;
} }
ConnectionChange (); /* emit signal for our GUI */
return true; /* connection status changed */ return true; /* connection status changed */
} }
void void
FaderPort::connected () FaderPort::connected ()
{ {
std::cerr << "faderport connected\n"; std::cerr << "faderport connected or disconnected\n";
start_midi_handling (); start_midi_handling ();
@ -686,68 +713,91 @@ FaderPort::connected ()
} }
void void
FaderPort::ButtonInfo::invoke (FaderPort::ButtonState bs, bool press) FaderPort::Button::invoke (FaderPort::ButtonState bs, bool press)
{ {
switch (type) { if (!press) {
if (long_press == 1) {
bs = FaderPort::ButtonState (bs | LongishPress);
} else if (long_press == 2) {
bs = FaderPort::ButtonState (bs | LongPress);
}
}
ToDoMap::iterator x;
if (press) {
if ((x = on_press.find (bs)) == on_press.end()) {
return;
}
} else {
if ((x = on_press.find (bs)) == on_release.end()) {
return;
}
}
switch (x->second.type) {
case NamedAction: case NamedAction:
if (press) { if (!x->second.action_name.empty()) {
ToDoMap::iterator x = on_press.find (bs); fp.access_action (x->second.action_name);
if (x != on_press.end()) {
if (!x->second.action_name.empty()) {
fp.access_action (x->second.action_name);
}
}
} else {
ToDoMap::iterator x = on_release.find (bs);
if (x != on_release.end()) {
if (!x->second.action_name.empty()) {
fp.access_action (x->second.action_name);
}
}
} }
break; break;
case InternalFunction: case InternalFunction:
if (press) { if (x->second.function) {
ToDoMap::iterator x = on_press.find (bs); x->second.function ();
if (x != on_press.end()) {
if (x->second.function) {
x->second.function ();
}
}
} else {
ToDoMap::iterator x = on_release.find (bs);
if (x != on_release.end()) {
if (x->second.function) {
x->second.function ();
}
}
} }
break;
} }
} }
void void
FaderPort::ButtonInfo::set_action (string const& name, bool when_pressed, FaderPort::ButtonState bs) FaderPort::Button::do_timing (bool press)
{
if (press) {
pressed_at = get_microseconds ();
long_press = 0;
} else {
if (pressed_at > 0) {
const ARDOUR::microseconds_t delta = ARDOUR::get_microseconds () - pressed_at;
if (delta < 500000) {
long_press = 0;
} else if (delta < 1000000) {
long_press = 1;
} else {
long_press = 2;
}
pressed_at = 0;
}
}
}
void
FaderPort::Button::set_action (string const& name, bool when_pressed, FaderPort::ButtonState bs)
{ {
ToDo todo; ToDo todo;
type = NamedAction; todo.type = NamedAction;
if (when_pressed) { if (when_pressed) {
todo.action_name = name; if (name.empty()) {
on_press[bs] = todo; on_press.erase (bs);
} else {
todo.action_name = name;
on_press[bs] = todo;
}
} else { } else {
todo.action_name = name; if (name.empty()) {
on_release[bs] = todo; on_release.erase (bs);
} else {
todo.action_name = name;
on_release[bs] = todo;
}
} }
} }
void void
FaderPort::ButtonInfo::set_action (boost::function<void()> f, bool when_pressed, FaderPort::ButtonState bs) FaderPort::Button::set_action (boost::function<void()> f, bool when_pressed, FaderPort::ButtonState bs)
{ {
ToDo todo; ToDo todo;
type = InternalFunction; todo.type = InternalFunction;
if (when_pressed) { if (when_pressed) {
todo.function = f; todo.function = f;
@ -759,7 +809,7 @@ FaderPort::ButtonInfo::set_action (boost::function<void()> f, bool when_pressed,
} }
void void
FaderPort::ButtonInfo::set_led_state (boost::shared_ptr<MIDI::Port> port, int onoff, bool force) FaderPort::Button::set_led_state (boost::shared_ptr<MIDI::Port> port, int onoff, bool force)
{ {
if (!force && (led_on == (bool) onoff)) { if (!force && (led_on == (bool) onoff)) {
/* nothing to do */ /* nothing to do */
@ -779,6 +829,87 @@ FaderPort::ButtonInfo::set_led_state (boost::shared_ptr<MIDI::Port> port, int on
led_on = (onoff ? true : false); led_on = (onoff ? true : false);
} }
int
FaderPort::Button::set_state (XMLNode const& node)
{
const XMLProperty* prop = node.property ("id");
if (!prop) {
return -1;
}
int xid = atoi (prop->value());
if (xid != id) {
return -1;
}
typedef pair<string,FaderPort::ButtonState> state_pair_t;
vector<state_pair_t> state_pairs;
state_pairs.push_back (make_pair (string ("plain"), ButtonState (0)));
state_pairs.push_back (make_pair (string ("shift"), ShiftDown));
state_pairs.push_back (make_pair (string ("longish"), LongishPress));
state_pairs.push_back (make_pair (string ("long"), LongPress));
on_press.clear ();
on_release.clear ();
for (vector<state_pair_t>::const_iterator sp = state_pairs.begin(); sp != state_pairs.end(); ++sp) {
string propname;
propname = sp->first + X_("-press");
if ((prop = node.property (propname)) == 0) {
continue;
}
set_action (prop->value(), true, sp->second);
propname = sp->first + X_("-release");
if ((prop = node.property (propname)) == 0) {
continue;
}
set_action (prop->value(), false, sp->second);
}
return 0;
}
XMLNode&
FaderPort::Button::get_state () const
{
XMLNode* node = new XMLNode (X_("Button"));
char buf[16];
snprintf (buf, sizeof (buf), "%d", id);
node->add_property (X_("id"), buf);
ToDoMap::const_iterator x;
ToDo null;
null.type = NamedAction;
typedef pair<string,FaderPort::ButtonState> state_pair_t;
vector<state_pair_t> state_pairs;
state_pairs.push_back (make_pair (string ("plain"), ButtonState (0)));
state_pairs.push_back (make_pair (string ("shift"), ShiftDown));
state_pairs.push_back (make_pair (string ("longish"), LongishPress));
state_pairs.push_back (make_pair (string ("long"), LongPress));
for (vector<state_pair_t>::const_iterator sp = state_pairs.begin(); sp != state_pairs.end(); ++sp) {
if ((x = on_press.find (sp->second)) != on_press.end()) {
if (x->second.type == NamedAction) {
node->add_property (string (sp->first + X_("-press")).c_str(), x->second.action_name);
}
}
if ((x = on_release.find (sp->second)) != on_release.end()) {
if (x->second.type == NamedAction) {
node->add_property (string (sp->first + X_("-release")).c_str(), x->second.action_name);
}
}
}
return *node;
}
void void
FaderPort::gui_track_selection_changed (RouteNotificationListPtr routes) FaderPort::gui_track_selection_changed (RouteNotificationListPtr routes)
{ {
@ -813,7 +944,7 @@ FaderPort::set_current_route (boost::shared_ptr<Route> r)
/* turn this off. It will be turned on back on in use_master() or /* turn this off. It will be turned on back on in use_master() or
use_monitor() as appropriate. use_monitor() as appropriate.
*/ */
button_info(Output).set_led_state (_output_port, false); get_button(Output).set_led_state (_output_port, false);
if (_current_route) { if (_current_route) {
_current_route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort::drop_current_route, this), this); _current_route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort::drop_current_route, this), this);
@ -850,7 +981,7 @@ FaderPort::map_cut ()
if (mp) { if (mp) {
bool yn = mp->cut_all (); bool yn = mp->cut_all ();
button_info (Mute).set_led_state (_output_port, yn); get_button (Mute).set_led_state (_output_port, yn);
if (yn) { if (yn) {
blinkers.push_back (Mute); blinkers.push_back (Mute);
} else { } else {
@ -864,19 +995,19 @@ FaderPort::map_cut ()
void void
FaderPort::map_mute (void*) FaderPort::map_mute (void*)
{ {
button_info (Mute).set_led_state (_output_port, _current_route->muted()); get_button (Mute).set_led_state (_output_port, _current_route->muted());
} }
void void
FaderPort::map_solo (bool, void*, bool) FaderPort::map_solo (bool, void*, bool)
{ {
button_info (Solo).set_led_state (_output_port, _current_route->soloed() || _current_route->listening_via_monitor()); get_button (Solo).set_led_state (_output_port, _current_route->soloed() || _current_route->listening_via_monitor());
} }
void void
FaderPort::map_listen (void*, bool) FaderPort::map_listen (void*, bool)
{ {
button_info (Solo).set_led_state (_output_port, _current_route->listening_via_monitor()); get_button (Solo).set_led_state (_output_port, _current_route->listening_via_monitor());
} }
void void
@ -884,9 +1015,9 @@ FaderPort::map_recenable ()
{ {
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (_current_route); boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (_current_route);
if (t) { if (t) {
button_info (Rec).set_led_state (_output_port, t->record_enabled()); get_button (Rec).set_led_state (_output_port, t->record_enabled());
} else { } else {
button_info (Rec).set_led_state (_output_port, false); get_button (Rec).set_led_state (_output_port, false);
} }
} }
@ -944,9 +1075,9 @@ void
FaderPort::map_route_state () FaderPort::map_route_state ()
{ {
if (!_current_route) { if (!_current_route) {
button_info (Mute).set_led_state (_output_port, false); get_button (Mute).set_led_state (_output_port, false);
button_info (Solo).set_led_state (_output_port, false); get_button (Solo).set_led_state (_output_port, false);
button_info (Rec).set_led_state (_output_port, false); get_button (Rec).set_led_state (_output_port, false);
blinkers.remove (Mute); blinkers.remove (Mute);
blinkers.remove (Solo); blinkers.remove (Solo);
} else { } else {
@ -974,5 +1105,5 @@ FaderPort::input_port()
void void
FaderPort::set_action (ButtonID id, std::string const& action_name, bool on_press, ButtonState bs) FaderPort::set_action (ButtonID id, std::string const& action_name, bool on_press, ButtonState bs)
{ {
button_info(id).set_action (action_name, on_press, bs); get_button(id).set_action (action_name, on_press, bs);
} }

View file

@ -151,6 +151,8 @@ class FaderPort : public ARDOUR::ControlProtocol, public AbstractUI<FaderPortReq
RewindDown = 0x2, RewindDown = 0x2,
StopDown = 0x4, StopDown = 0x4,
UserDown = 0x8, UserDown = 0x8,
LongishPress = 0x10,
LongPress = 0x20
}; };
void set_action (ButtonID, std::string const& action_name, bool on_press, FaderPort::ButtonState = ButtonState (0)); void set_action (ButtonID, std::string const& action_name, bool on_press, FaderPort::ButtonState = ButtonState (0));
@ -190,15 +192,15 @@ class FaderPort : public ARDOUR::ControlProtocol, public AbstractUI<FaderPortReq
int last_encoder_delta, last_last_encoder_delta; int last_encoder_delta, last_last_encoder_delta;
void sysex_handler (MIDI::Parser &p, MIDI::byte *, size_t); void sysex_handler (MIDI::Parser &p, MIDI::byte *, size_t);
void switch_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb); void button_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb);
void encoder_handler (MIDI::Parser &, MIDI::pitchbend_t pb); void encoder_handler (MIDI::Parser &, MIDI::pitchbend_t pb);
void fader_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb); void fader_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb);
ButtonState button_state; ButtonState button_state;
friend class ButtonInfo; friend class Button;
class ButtonInfo { class Button {
public: public:
enum ActionType { enum ActionType {
@ -206,14 +208,15 @@ class FaderPort : public ARDOUR::ControlProtocol, public AbstractUI<FaderPortReq
InternalFunction, InternalFunction,
}; };
ButtonInfo (FaderPort& f, std::string const& str, ButtonID i, int o) Button (FaderPort& f, std::string const& str, ButtonID i, int o)
: fp (f) : fp (f)
, name (str) , name (str)
, id (i) , id (i)
, out (o) , out (o)
, type (NamedAction)
, led_on (false) , led_on (false)
, flash (false) , flash (false)
, pressed_at (0)
, long_press (0)
{} {}
void set_action (std::string const& action_name, bool on_press, FaderPort::ButtonState = ButtonState (0)); void set_action (std::string const& action_name, bool on_press, FaderPort::ButtonState = ButtonState (0));
@ -222,20 +225,26 @@ class FaderPort : public ARDOUR::ControlProtocol, public AbstractUI<FaderPortReq
void invoke (ButtonState bs, bool press); void invoke (ButtonState bs, bool press);
bool uses_flash () const { return flash; } bool uses_flash () const { return flash; }
void set_flash (bool yn) { flash = yn; } void set_flash (bool yn) { flash = yn; }
void do_timing (bool press);
XMLNode& get_state () const;
int set_state (XMLNode const&);
private: private:
FaderPort& fp; FaderPort& fp;
std::string name; std::string name;
ButtonID id; ButtonID id;
int out; int out;
ActionType type;
bool led_on; bool led_on;
bool flash; bool flash;
ARDOUR::microseconds_t pressed_at;
int long_press;
/* could be a union if boost::function didn't require a
* constructor
*/
struct ToDo { struct ToDo {
ActionType type;
/* could be a union if boost::function didn't require a
* constructor
*/
std::string action_name; std::string action_name;
boost::function<void()> function; boost::function<void()> function;
}; };
@ -245,10 +254,10 @@ class FaderPort : public ARDOUR::ControlProtocol, public AbstractUI<FaderPortReq
ToDoMap on_release; ToDoMap on_release;
}; };
typedef std::map<ButtonID,ButtonInfo> ButtonMap; typedef std::map<ButtonID,Button> ButtonMap;
ButtonMap buttons; ButtonMap buttons;
ButtonInfo& button_info (ButtonID) const; Button& get_button (ButtonID) const;
void all_lights_out (); void all_lights_out ();
void close (); void close ();

View file

@ -1,5 +1,5 @@
/* /*
Copyright (C) 2009-2012 Paul Davis Copyright (C) 2015 Paul Davis
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -17,24 +17,9 @@
*/ */
#include <iostream>
#include <list>
#include <vector>
#include <string>
#include <gtkmm/adjustment.h>
#include <gtkmm/alignment.h> #include <gtkmm/alignment.h>
#include <gtkmm/box.h>
#include <gtkmm/combobox.h>
#include <gtkmm/liststore.h>
#include <gtkmm/label.h> #include <gtkmm/label.h>
#include <gtkmm/spinbutton.h> #include <gtkmm/liststore.h>
#include <gtkmm/table.h>
#include <gtkmm/treestore.h>
namespace Gtk {
class CellRendererCombo;
}
#include "pbd/unwind.h" #include "pbd/unwind.h"
#include "pbd/strsplit.h" #include "pbd/strsplit.h"
@ -47,68 +32,10 @@ namespace Gtk {
#include "ardour/audioengine.h" #include "ardour/audioengine.h"
#include "faderport.h" #include "faderport.h"
#include "gui.h"
#include "i18n.h" #include "i18n.h"
namespace ArdourSurface {
class FPGUI : public Gtk::VBox
{
public:
FPGUI (FaderPort&);
~FPGUI ();
private:
FaderPort& fp;
Gtk::Table table;
Gtk::ComboBox input_combo;
Gtk::ComboBox output_combo;
Gtk::ComboBox mix_combo;
Gtk::ComboBox proj_combo;
Gtk::ComboBox trns_combo;
void update_port_combos (std::vector<std::string> const&, std::vector<std::string> const&);
PBD::ScopedConnection connection_change_connection;
void connection_handler ();
struct MidiPortColumns : public Gtk::TreeModel::ColumnRecord {
MidiPortColumns() {
add (short_name);
add (full_name);
}
Gtk::TreeModelColumn<std::string> short_name;
Gtk::TreeModelColumn<std::string> full_name;
};
MidiPortColumns midi_port_columns;
bool ignore_active_change;
Glib::RefPtr<Gtk::ListStore> build_midi_port_list (std::vector<std::string> const & ports, bool for_input);
void active_port_changed (Gtk::ComboBox*,bool for_input);
struct ActionColumns : public Gtk::TreeModel::ColumnRecord {
ActionColumns() {
add (name);
add (path);
}
Gtk::TreeModelColumn<std::string> name;
Gtk::TreeModelColumn<std::string> path;
};
ActionColumns action_columns;
Glib::RefPtr<Gtk::TreeStore> available_action_model;
std::map<std::string,std::string> action_map; // map from action names to paths
void build_mix_action_combo (Gtk::ComboBox&);
void build_proj_action_combo (Gtk::ComboBox&);
void build_trns_action_combo (Gtk::ComboBox&);
void build_available_action_menu ();
void action_changed (Gtk::ComboBox*, FaderPort::ButtonID);
};
}
using namespace PBD; using namespace PBD;
using namespace ARDOUR; using namespace ARDOUR;
using namespace ArdourSurface; using namespace ArdourSurface;
@ -136,7 +63,7 @@ FaderPort::tear_down_gui ()
delete w; delete w;
} }
} }
delete (FPGUI*) gui; delete static_cast<FPGUI*> (gui);
gui = 0; gui = 0;
} }
@ -151,6 +78,7 @@ FaderPort::build_gui ()
FPGUI::FPGUI (FaderPort& p) FPGUI::FPGUI (FaderPort& p)
: fp (p) : fp (p)
, table (2, 5) , table (2, 5)
, action_table (4, 5)
, ignore_active_change (false) , ignore_active_change (false)
{ {
set_border_width (12); set_border_width (12);
@ -164,65 +92,138 @@ FPGUI::FPGUI (FaderPort& p)
Gtk::Alignment* align; Gtk::Alignment* align;
int row = 0; int row = 0;
vector<string> midi_inputs;
vector<string> midi_outputs;
ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsOutput|ARDOUR::IsPhysical), midi_inputs);
ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsInput|ARDOUR::IsPhysical), midi_outputs);
update_port_combos (midi_inputs, midi_outputs);
input_combo.pack_start (midi_port_columns.short_name); input_combo.pack_start (midi_port_columns.short_name);
output_combo.pack_start (midi_port_columns.short_name); output_combo.pack_start (midi_port_columns.short_name);
input_combo.signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &FPGUI::active_port_changed), &input_combo, true)); input_combo.signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &FPGUI::active_port_changed), &input_combo, true));
output_combo.signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &FPGUI::active_port_changed), &output_combo, false)); output_combo.signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &FPGUI::active_port_changed), &output_combo, false));
l = manage (new Gtk::Label (_("Sends MIDI via:"))); l = manage (new Gtk::Label (_("Sends MIDI to:")));
l->set_alignment (1.0, 0.5); l->set_alignment (1.0, 0.5);
table.attach (*l, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0)); table.attach (*l, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
table.attach (input_combo, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0); table.attach (input_combo, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
row++; row++;
l = manage (new Gtk::Label (_("Receives MIDI via:"))); l = manage (new Gtk::Label (_("Receives MIDI from:")));
l->set_alignment (1.0, 0.5); l->set_alignment (1.0, 0.5);
table.attach (*l, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0)); table.attach (*l, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
table.attach (output_combo, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0); table.attach (output_combo, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
row++; row++;
build_mix_action_combo (mix_combo); build_mix_action_combo (mix_combo[0], FaderPort::ButtonState(0));
build_proj_action_combo (proj_combo); build_mix_action_combo (mix_combo[1], FaderPort::ShiftDown);
build_trns_action_combo (trns_combo); build_mix_action_combo (mix_combo[2], FaderPort::LongishPress);
build_mix_action_combo (mix_combo[3], FaderPort::LongPress);
l = manage (new Gtk::Label (_("Mix Button"))); build_proj_action_combo (proj_combo[0], FaderPort::ButtonState(0));
build_proj_action_combo (proj_combo[1], FaderPort::ShiftDown);
build_proj_action_combo (proj_combo[2], FaderPort::LongishPress);
build_proj_action_combo (proj_combo[3], FaderPort::LongPress);
build_trns_action_combo (trns_combo[0], FaderPort::ButtonState(0));
build_trns_action_combo (trns_combo[1], FaderPort::ShiftDown);
build_trns_action_combo (trns_combo[2], FaderPort::LongishPress);
build_trns_action_combo (trns_combo[3], FaderPort::LongPress);
action_table.set_row_spacings (4);
action_table.set_col_spacings (6);
action_table.set_border_width (12);
action_table.set_homogeneous (false);
int action_row = 0;
l = manage (new Gtk::Label (_("Button")));
l->set_alignment (1.0, 0.5); l->set_alignment (1.0, 0.5);
table.attach (*l, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions (0)); action_table.attach (*l, 0, 1, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
l = manage (new Gtk::Label (_("Press")));
l->set_alignment (1.0, 0.5);
action_table.attach (*l, 1, 2, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
l = manage (new Gtk::Label (_("Shift")));
l->set_alignment (1.0, 0.5);
action_table.attach (*l, 2, 3, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
l = manage (new Gtk::Label (_("Medium")));
l->set_alignment (1.0, 0.5);
action_table.attach (*l, 3, 4, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
l = manage (new Gtk::Label (_("Long")));
l->set_alignment (1.0, 0.5);
action_table.attach (*l, 4, 5, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
action_row++;
l = manage (new Gtk::Label (_("Mix")));
l->set_alignment (1.0, 0.5);
action_table.attach (*l, 0, 1, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment); align = manage (new Alignment);
align->set (0.0, 0.5); align->set (0.0, 0.5);
align->add (mix_combo); align->add (mix_combo[0]);
table.attach (*align, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions (0)); action_table.attach (*align, 1, 2, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
row++;
l = manage (new Gtk::Label (_("Proj Button")));
l->set_alignment (1.0, 0.5);
table.attach (*l, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment); align = manage (new Alignment);
align->set (0.0, 0.5); align->set (0.0, 0.5);
align->add (proj_combo); align->add (mix_combo[1]);
table.attach (*align, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions (0)); action_table.attach (*align, 2, 3, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
row++;
l = manage (new Gtk::Label (_("Trns Button")));
l->set_alignment (1.0, 0.5);
table.attach (*l, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment); align = manage (new Alignment);
align->set (0.0, 0.5); align->set (0.0, 0.5);
align->add (trns_combo); align->add (mix_combo[2]);
table.attach (*align, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions (0)); action_table.attach (*align, 3, 4, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (mix_combo[3]);
action_table.attach (*align, 4, 5, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
action_row++;
l = manage (new Gtk::Label (_("Proj")));
l->set_alignment (1.0, 0.5);
action_table.attach (*l, 0, 1, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (proj_combo[0]);
action_table.attach (*align, 1, 2, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (proj_combo[1]);
action_table.attach (*align, 2, 3, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (proj_combo[2]);
action_table.attach (*align, 3, 4, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (proj_combo[3]);
action_table.attach (*align, 4, 5, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
action_row++;
l = manage (new Gtk::Label (_("Trns")));
l->set_alignment (1.0, 0.5);
action_table.attach (*l, 0, 1, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (trns_combo[0]);
action_table.attach (*align, 1, 2, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (trns_combo[1]);
action_table.attach (*align, 2, 3, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (trns_combo[2]);
action_table.attach (*align, 3, 4, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
align = manage (new Alignment);
align->set (0.0, 0.5);
align->add (trns_combo[3]);
action_table.attach (*align, 4, 5, action_row, action_row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
action_row++;
table.attach (action_table, 0, 5, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
row++; row++;
pack_start (table, false, false); pack_start (table, false, false);
/* update the port connection combos */
update_port_combos ();
/* catch future changes to connection state */
fp.ConnectionChange.connect (connection_change_connection, invalidator (*this), boost::bind (&FPGUI::connection_handler, this), gui_context()); fp.ConnectionChange.connect (connection_change_connection, invalidator (*this), boost::bind (&FPGUI::connection_handler, this), gui_context());
} }
@ -240,18 +241,18 @@ FPGUI::connection_handler ()
PBD::Unwinder<bool> ici (ignore_active_change, true); PBD::Unwinder<bool> ici (ignore_active_change, true);
update_port_combos ();
}
void
FPGUI::update_port_combos ()
{
vector<string> midi_inputs; vector<string> midi_inputs;
vector<string> midi_outputs; vector<string> midi_outputs;
ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsOutput|ARDOUR::IsTerminal), midi_inputs); ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsOutput|ARDOUR::IsTerminal), midi_inputs);
ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsInput|ARDOUR::IsTerminal), midi_outputs); ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsInput|ARDOUR::IsTerminal), midi_outputs);
update_port_combos (midi_inputs, midi_outputs);
}
void
FPGUI::update_port_combos (vector<string> const& midi_inputs, vector<string> const& midi_outputs)
{
Glib::RefPtr<Gtk::ListStore> input = build_midi_port_list (midi_inputs, true); Glib::RefPtr<Gtk::ListStore> input = build_midi_port_list (midi_inputs, true);
Glib::RefPtr<Gtk::ListStore> output = build_midi_port_list (midi_outputs, false); Glib::RefPtr<Gtk::ListStore> output = build_midi_port_list (midi_outputs, false);
bool input_found = false; bool input_found = false;
@ -411,7 +412,16 @@ FPGUI::build_available_action_menu ()
} }
void void
FPGUI::build_mix_action_combo (Gtk::ComboBox& cb) FPGUI::action_changed (Gtk::ComboBox* cb, FaderPort::ButtonID id)
{
TreeModel::const_iterator row = cb->get_active ();
string action_path = (*row)[action_columns.path];
fp.set_action (id, action_path, true);
}
void
FPGUI::build_action_combo (Gtk::ComboBox& cb, vector<pair<string,string> > const & actions, FaderPort::ButtonID id, FaderPort::ButtonState bs)
{ {
Glib::RefPtr<Gtk::ListStore> model (Gtk::ListStore::create (action_columns)); Glib::RefPtr<Gtk::ListStore> model (Gtk::ListStore::create (action_columns));
TreeIter rowp; TreeIter rowp;
@ -419,29 +429,51 @@ FPGUI::build_mix_action_combo (Gtk::ComboBox& cb)
rowp = model->append(); rowp = model->append();
row = *(rowp); row = *(rowp);
row[action_columns.name] = _("Toggle Editor & Mixer Windows"); row[action_columns.name] = _("Disabled");
row[action_columns.path] = X_("Common/toggle-editor-mixer"); row[action_columns.path] = string();
rowp = model->append(); for (vector<pair<string,string> >::const_iterator i = actions.begin(); i != actions.end(); ++i) {
row = *(rowp); rowp = model->append();
row[action_columns.name] = _("Show/Hide Editor mixer strip"); row = *(rowp);
row[action_columns.path] = X_("Editor/show-editor-mixer"); row[action_columns.name] = i->first;
row[action_columns.path] = i->second;
}
cb.set_model (model); cb.set_model (model);
cb.pack_start (action_columns.name); cb.pack_start (action_columns.name);
cb.signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &FPGUI::action_changed), &cb, FaderPort::Mix)); cb.signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &FPGUI::action_changed), &cb, id));
} }
void void
FPGUI::build_proj_action_combo (Gtk::ComboBox& cb) FPGUI::build_mix_action_combo (Gtk::ComboBox& cb, FaderPort::ButtonState bs)
{ {
vector<pair<string,string> > actions;
actions.push_back (make_pair (string (_("Toggle Editor & Mixer Windows")), string (X_("Common/toggle-editor-mixer"))));
actions.push_back (make_pair (string (_("Show/Hide Editor mixer strip")), string (X_("Editor/show-editor-mixer"))));
build_action_combo (cb, actions, FaderPort::Mix, bs);
} }
void
FPGUI::build_proj_action_combo (Gtk::ComboBox& cb, FaderPort::ButtonState bs)
{
vector<pair<string,string> > actions;
actions.push_back (make_pair (string("Toggle Meterbridge"), string(X_("Common/toggle-meterbridge"))));
build_action_combo (cb, actions, FaderPort::Proj, bs);
}
void void
FPGUI::build_trns_action_combo (Gtk::ComboBox& cb) FPGUI::build_trns_action_combo (Gtk::ComboBox& cb, FaderPort::ButtonState bs)
{ {
vector<pair<string,string> > actions;
actions.push_back (make_pair (string("Toggle Locations"), string(X_("Window/toggle-locations"))));
build_action_combo (cb, actions, FaderPort::Trns, bs);
} }
Glib::RefPtr<Gtk::ListStore> Glib::RefPtr<Gtk::ListStore>
@ -499,14 +531,3 @@ FPGUI::active_port_changed (Gtk::ComboBox* combo, bool for_input)
} }
} }
} }
void
FPGUI::action_changed (Gtk::ComboBox* cb, FaderPort::ButtonID id)
{
TreeModel::const_iterator row = cb->get_active ();
string action_path = (*row)[action_columns.path];
cerr << "Change " << id << " to " << action_path << endl;
fp.set_action (id, action_path, true);
}

View file

@ -0,0 +1,106 @@
/*
Copyright (C) 2015 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __ardour_faderport_gui_h__
#define __ardour_faderport_gui_h__
#include <vector>
#include <string>
#include <gtkmm/box.h>
#include <gtkmm/combobox.h>
#include <gtkmm/table.h>
#include <gtkmm/treestore.h>
namespace Gtk {
class CellRendererCombo;
class ListStore;
}
#include "faderport.h"
namespace ArdourSurface {
class FPGUI : public Gtk::VBox
{
public:
FPGUI (FaderPort&);
~FPGUI ();
private:
FaderPort& fp;
Gtk::Table table;
Gtk::Table action_table;
Gtk::ComboBox input_combo;
Gtk::ComboBox output_combo;
/* the mix, proj, trns and user buttons have no obvious semantics for
* ardour, mixbus etc., so we allow the user to define their
* functionality from a small, curated set of options.
*/
Gtk::ComboBox mix_combo[4];
Gtk::ComboBox proj_combo[4];
Gtk::ComboBox trns_combo[4];
Gtk::ComboBox user_combo[4];
void update_port_combos ();
PBD::ScopedConnection connection_change_connection;
void connection_handler ();
struct MidiPortColumns : public Gtk::TreeModel::ColumnRecord {
MidiPortColumns() {
add (short_name);
add (full_name);
}
Gtk::TreeModelColumn<std::string> short_name;
Gtk::TreeModelColumn<std::string> full_name;
};
MidiPortColumns midi_port_columns;
bool ignore_active_change;
Glib::RefPtr<Gtk::ListStore> build_midi_port_list (std::vector<std::string> const & ports, bool for_input);
void active_port_changed (Gtk::ComboBox*,bool for_input);
struct ActionColumns : public Gtk::TreeModel::ColumnRecord {
ActionColumns() {
add (name);
add (path);
}
Gtk::TreeModelColumn<std::string> name;
Gtk::TreeModelColumn<std::string> path;
};
ActionColumns action_columns;
Glib::RefPtr<Gtk::TreeStore> available_action_model;
std::map<std::string,std::string> action_map; // map from action names to paths
void build_action_combo (Gtk::ComboBox& cb, std::vector<std::pair<std::string,std::string> > const & actions, FaderPort::ButtonID, FaderPort::ButtonState);
void build_mix_action_combo (Gtk::ComboBox&, FaderPort::ButtonState);
void build_proj_action_combo (Gtk::ComboBox&, FaderPort::ButtonState);
void build_trns_action_combo (Gtk::ComboBox&, FaderPort::ButtonState);
void build_available_action_menu ();
void action_changed (Gtk::ComboBox*, FaderPort::ButtonID);
};
}
#endif /* __ardour_faderport_gui_h__ */

View file

@ -171,14 +171,14 @@ FaderPort::use_master ()
if (_current_route == r) { if (_current_route == r) {
r = pre_master_route.lock(); r = pre_master_route.lock();
set_current_route (r); set_current_route (r);
button_info(Output).set_led_state (_output_port, false); get_button(Output).set_led_state (_output_port, false);
blinkers.remove (Output); blinkers.remove (Output);
} else { } else {
if (_current_route != session->master_out() && _current_route != session->monitor_out()) { if (_current_route != session->master_out() && _current_route != session->monitor_out()) {
pre_master_route = boost::weak_ptr<Route> (_current_route); pre_master_route = boost::weak_ptr<Route> (_current_route);
} }
set_current_route (r); set_current_route (r);
button_info(Output).set_led_state (_output_port, true); get_button(Output).set_led_state (_output_port, true);
blinkers.remove (Output); blinkers.remove (Output);
} }
} }
@ -193,14 +193,14 @@ FaderPort::use_monitor ()
if (_current_route == r) { if (_current_route == r) {
r = pre_monitor_route.lock(); r = pre_monitor_route.lock();
set_current_route (r); set_current_route (r);
button_info(Output).set_led_state (_output_port, false); get_button(Output).set_led_state (_output_port, false);
blinkers.remove (Output); blinkers.remove (Output);
} else { } else {
if (_current_route != session->master_out() && _current_route != session->monitor_out()) { if (_current_route != session->master_out() && _current_route != session->monitor_out()) {
pre_monitor_route = boost::weak_ptr<Route> (_current_route); pre_monitor_route = boost::weak_ptr<Route> (_current_route);
} }
set_current_route (r); set_current_route (r);
button_info(Output).set_led_state (_output_port, true); get_button(Output).set_led_state (_output_port, true);
blinkers.push_back (Output); blinkers.push_back (Output);
} }
} else { } else {