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:
parent
149f6795bb
commit
682e152aaf
|
@ -94,77 +94,73 @@ FaderPort::FaderPort (Session& s)
|
|||
/* 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);
|
||||
|
||||
buttons.insert (std::make_pair (Mute, ButtonInfo (*this, _("Mute"), Mute, 21)));
|
||||
buttons.insert (std::make_pair (Solo, ButtonInfo (*this, _("Solo"), Solo, 22)));
|
||||
buttons.insert (std::make_pair (Rec, ButtonInfo (*this, _("Rec"), Rec, 23)));
|
||||
buttons.insert (std::make_pair (Left, ButtonInfo (*this, _("Left"), Left, 20)));
|
||||
buttons.insert (std::make_pair (Bank, ButtonInfo (*this, _("Bank"), Bank, 19)));
|
||||
buttons.insert (std::make_pair (Right, ButtonInfo (*this, _("Right"), Right, 18)));
|
||||
buttons.insert (std::make_pair (Output, ButtonInfo (*this, _("Output"), Output, 17)));
|
||||
buttons.insert (std::make_pair (FP_Read, ButtonInfo (*this, _("Read"), FP_Read, 13)));
|
||||
buttons.insert (std::make_pair (FP_Write, ButtonInfo (*this, _("Write"), FP_Write, 14)));
|
||||
buttons.insert (std::make_pair (FP_Touch, ButtonInfo (*this, _("Touch"), FP_Touch, 15)));
|
||||
buttons.insert (std::make_pair (FP_Off, ButtonInfo (*this, _("Off"), FP_Off, 16)));
|
||||
buttons.insert (std::make_pair (Mix, ButtonInfo (*this, _("Mix"), Mix, 12)));
|
||||
buttons.insert (std::make_pair (Proj, ButtonInfo (*this, _("Proj"), Proj, 11)));
|
||||
buttons.insert (std::make_pair (Trns, ButtonInfo (*this, _("Trns"), Trns, 10)));
|
||||
buttons.insert (std::make_pair (Undo, ButtonInfo (*this, _("Undo"), Undo, 9)));
|
||||
buttons.insert (std::make_pair (Shift, ButtonInfo (*this, _("Shift"), Shift, 5)));
|
||||
buttons.insert (std::make_pair (Punch, ButtonInfo (*this, _("Punch"), Punch, 6)));
|
||||
buttons.insert (std::make_pair (User, ButtonInfo (*this, _("User"), User, 7)));
|
||||
buttons.insert (std::make_pair (Loop, ButtonInfo (*this, _("Loop"), Loop, 8)));
|
||||
buttons.insert (std::make_pair (Rewind, ButtonInfo (*this, _("Rewind"), Rewind, 4)));
|
||||
buttons.insert (std::make_pair (Ffwd, ButtonInfo (*this, _("Ffwd"), Ffwd, 3)));
|
||||
buttons.insert (std::make_pair (Stop, ButtonInfo (*this, _("Stop"), Stop, 2)));
|
||||
buttons.insert (std::make_pair (Play, ButtonInfo (*this, _("Play"), Play, 1)));
|
||||
buttons.insert (std::make_pair (RecEnable, ButtonInfo (*this, _("RecEnable"), RecEnable, 0)));
|
||||
buttons.insert (std::make_pair (FaderTouch, ButtonInfo (*this, _("Fader (touch)"), FaderTouch, -1)));
|
||||
buttons.insert (std::make_pair (Mute, Button (*this, _("Mute"), Mute, 21)));
|
||||
buttons.insert (std::make_pair (Solo, Button (*this, _("Solo"), Solo, 22)));
|
||||
buttons.insert (std::make_pair (Rec, Button (*this, _("Rec"), Rec, 23)));
|
||||
buttons.insert (std::make_pair (Left, Button (*this, _("Left"), Left, 20)));
|
||||
buttons.insert (std::make_pair (Bank, Button (*this, _("Bank"), Bank, 19)));
|
||||
buttons.insert (std::make_pair (Right, Button (*this, _("Right"), Right, 18)));
|
||||
buttons.insert (std::make_pair (Output, Button (*this, _("Output"), Output, 17)));
|
||||
buttons.insert (std::make_pair (FP_Read, Button (*this, _("Read"), FP_Read, 13)));
|
||||
buttons.insert (std::make_pair (FP_Write, Button (*this, _("Write"), FP_Write, 14)));
|
||||
buttons.insert (std::make_pair (FP_Touch, Button (*this, _("Touch"), FP_Touch, 15)));
|
||||
buttons.insert (std::make_pair (FP_Off, Button (*this, _("Off"), FP_Off, 16)));
|
||||
buttons.insert (std::make_pair (Mix, Button (*this, _("Mix"), Mix, 12)));
|
||||
buttons.insert (std::make_pair (Proj, Button (*this, _("Proj"), Proj, 11)));
|
||||
buttons.insert (std::make_pair (Trns, Button (*this, _("Trns"), Trns, 10)));
|
||||
buttons.insert (std::make_pair (Undo, Button (*this, _("Undo"), Undo, 9)));
|
||||
buttons.insert (std::make_pair (Shift, Button (*this, _("Shift"), Shift, 5)));
|
||||
buttons.insert (std::make_pair (Punch, Button (*this, _("Punch"), Punch, 6)));
|
||||
buttons.insert (std::make_pair (User, Button (*this, _("User"), User, 7)));
|
||||
buttons.insert (std::make_pair (Loop, Button (*this, _("Loop"), Loop, 8)));
|
||||
buttons.insert (std::make_pair (Rewind, Button (*this, _("Rewind"), Rewind, 4)));
|
||||
buttons.insert (std::make_pair (Ffwd, Button (*this, _("Ffwd"), Ffwd, 3)));
|
||||
buttons.insert (std::make_pair (Stop, Button (*this, _("Stop"), Stop, 2)));
|
||||
buttons.insert (std::make_pair (Play, Button (*this, _("Play"), Play, 1)));
|
||||
buttons.insert (std::make_pair (RecEnable, Button (*this, _("RecEnable"), RecEnable, 0)));
|
||||
buttons.insert (std::make_pair (FaderTouch, Button (*this, _("Fader (touch)"), FaderTouch, -1)));
|
||||
|
||||
button_info (Mix).set_action ( string("Common/toggle-editor-mixer"), true);
|
||||
button_info (Proj).set_action ( string("Common/toggle-meterbridge"), true);
|
||||
button_info (Trns).set_action ( string("Window/toggle-locations"), true);
|
||||
get_button (Left).set_action ( boost::bind (&FaderPort::left, this), true);
|
||||
get_button (Right).set_action ( boost::bind (&FaderPort::right, this), true);
|
||||
|
||||
button_info (Left).set_action ( boost::bind (&FaderPort::left, this), true);
|
||||
button_info (Right).set_action ( boost::bind (&FaderPort::right, this), true);
|
||||
get_button (Undo).set_action (boost::bind (&FaderPort::undo, 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);
|
||||
button_info (Undo).set_action (boost::bind (&FaderPort::redo, this), true, ShiftDown);
|
||||
button_info (Undo).set_flash (true);
|
||||
get_button (FP_Read).set_action (boost::bind (&FaderPort::read, this), true);
|
||||
get_button (FP_Write).set_action (boost::bind (&FaderPort::write, this), 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);
|
||||
button_info (FP_Write).set_action (boost::bind (&FaderPort::write, 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);
|
||||
get_button (Play).set_action (boost::bind (&BasicUI::transport_play, this, true), true);
|
||||
get_button (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
|
||||
the default action (since StopDown will be set when looking for the
|
||||
action to invoke.
|
||||
*/
|
||||
button_info (Stop).set_action (boost::bind (&BasicUI::transport_stop, this), true, StopDown);
|
||||
button_info (Ffwd).set_action (boost::bind (&BasicUI::ffwd, this), true);
|
||||
get_button (Stop).set_action (boost::bind (&BasicUI::transport_stop, this), true, StopDown);
|
||||
get_button (Ffwd).set_action (boost::bind (&BasicUI::ffwd, this), true);
|
||||
|
||||
/* See comments about Stop above .. */
|
||||
button_info (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));
|
||||
button_info (Rewind).set_action (boost::bind (&BasicUI::goto_start, this), true, ButtonState (RewindDown|ShiftDown));
|
||||
get_button (Rewind).set_action (boost::bind (&BasicUI::rewind, this), true, RewindDown);
|
||||
get_button (Rewind).set_action (boost::bind (&BasicUI::goto_zero, this), true, ButtonState (RewindDown|StopDown));
|
||||
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);
|
||||
button_info (Ffwd).set_action (boost::bind (&BasicUI::goto_end, this), true, ShiftDown);
|
||||
get_button (Ffwd).set_action (boost::bind (&BasicUI::ffwd, this), true);
|
||||
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);
|
||||
button_info (Loop).set_action (boost::bind (&BasicUI::add_marker, this, string()), true, ShiftDown);
|
||||
get_button (Loop).set_action (boost::bind (&BasicUI::loop_toggle, this), true);
|
||||
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);
|
||||
button_info (User).set_action (boost::bind (&BasicUI::next_marker, this), true, ShiftDown);
|
||||
get_button (Punch).set_action (boost::bind (&BasicUI::prev_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);
|
||||
button_info (Solo).set_action (boost::bind (&FaderPort::solo, this), true);
|
||||
button_info (Rec).set_action (boost::bind (&FaderPort::rec_enable, this), true);
|
||||
get_button (Mute).set_action (boost::bind (&FaderPort::mute, this), true);
|
||||
get_button (Solo).set_action (boost::bind (&FaderPort::solo, 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);
|
||||
button_info (Output).set_action (boost::bind (&FaderPort::use_monitor, this), true, ShiftDown);
|
||||
get_button (Output).set_action (boost::bind (&FaderPort::use_master, this), true);
|
||||
get_button (Output).set_action (boost::bind (&FaderPort::use_monitor, this), true, ShiftDown);
|
||||
}
|
||||
|
||||
FaderPort::~FaderPort ()
|
||||
|
@ -190,8 +186,8 @@ FaderPort::start_midi_handling ()
|
|||
{
|
||||
/* handle device inquiry response */
|
||||
_input_port->parser()->sysex.connect_same_thread (midi_connections, boost::bind (&FaderPort::sysex_handler, this, _1, _2, _3));
|
||||
/* handle switches */
|
||||
_input_port->parser()->poly_pressure.connect_same_thread (midi_connections, boost::bind (&FaderPort::switch_handler, this, _1, _2));
|
||||
/* handle buttons */
|
||||
_input_port->parser()->poly_pressure.connect_same_thread (midi_connections, boost::bind (&FaderPort::button_handler, this, _1, _2));
|
||||
/* handle encoder */
|
||||
_input_port->parser()->pitchbend.connect_same_thread (midi_connections, boost::bind (&FaderPort::encoder_handler, this, _1, _2));
|
||||
/* handle fader */
|
||||
|
@ -263,18 +259,21 @@ FaderPort::all_lights_out ()
|
|||
}
|
||||
}
|
||||
|
||||
FaderPort::ButtonInfo&
|
||||
FaderPort::button_info (ButtonID id) const
|
||||
FaderPort::Button&
|
||||
FaderPort::get_button (ButtonID id) const
|
||||
{
|
||||
ButtonMap::const_iterator b = buttons.find (id);
|
||||
assert (b != buttons.end());
|
||||
return const_cast<ButtonInfo&>(b->second);
|
||||
return const_cast<Button&>(b->second);
|
||||
}
|
||||
|
||||
void
|
||||
FaderPort::switch_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
|
||||
FaderPort::button_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
|
||||
{
|
||||
ButtonID id (ButtonID (tb->controller_number));
|
||||
Button& button (get_button (id));
|
||||
|
||||
button.do_timing (tb->value ? true : false);
|
||||
|
||||
switch (id) {
|
||||
case Shift:
|
||||
|
@ -307,13 +306,11 @@ FaderPort::switch_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
|
|||
break;
|
||||
}
|
||||
|
||||
ButtonInfo& bi (button_info (id));
|
||||
|
||||
if (bi.uses_flash()) {
|
||||
bi.set_led_state (_output_port, (int)tb->value);
|
||||
if (button.uses_flash()) {
|
||||
button.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
|
||||
|
@ -489,7 +486,7 @@ FaderPort::blink ()
|
|||
blink_state = !blink_state;
|
||||
|
||||
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;
|
||||
|
@ -517,15 +514,15 @@ FaderPort::notify_record_state_changed ()
|
|||
{
|
||||
switch (session->record_status()) {
|
||||
case Session::Disabled:
|
||||
button_info (RecEnable).set_led_state (_output_port, false);
|
||||
get_button (RecEnable).set_led_state (_output_port, false);
|
||||
blinkers.remove (RecEnable);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
case Session::Recording:
|
||||
button_info (RecEnable).set_led_state (_output_port, true);
|
||||
get_button (RecEnable).set_led_state (_output_port, true);
|
||||
blinkers.remove (RecEnable);
|
||||
break;
|
||||
}
|
||||
|
@ -534,11 +531,11 @@ FaderPort::notify_record_state_changed ()
|
|||
void
|
||||
FaderPort::notify_transport_state_changed ()
|
||||
{
|
||||
button_info (Loop).set_led_state (_output_port, session->get_play_loop());
|
||||
button_info (Play).set_led_state (_output_port, session->transport_speed() == 1.0);
|
||||
button_info (Stop).set_led_state (_output_port, session->transport_stopped ());
|
||||
button_info (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 (Loop).set_led_state (_output_port, session->get_play_loop());
|
||||
get_button (Play).set_led_state (_output_port, session->transport_speed() == 1.0);
|
||||
get_button (Stop).set_led_state (_output_port, session->transport_stopped ());
|
||||
get_button (Rewind).set_led_state (_output_port, session->transport_speed() < 0.0);
|
||||
get_button (Ffwd).set_led_state (_output_port, session->transport_speed() > 1.0);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -588,6 +585,17 @@ FaderPort::get_state ()
|
|||
child->add_child_nocopy (boost::shared_ptr<ARDOUR::Port>(_output_port)->get_state());
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -646,6 +669,8 @@ FaderPort::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1,
|
|||
return false;
|
||||
}
|
||||
|
||||
cerr << "Connection state = " << hex << connection_state << dec << endl;
|
||||
|
||||
if ((connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) {
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
ConnectionChange (); /* emit signal for our GUI */
|
||||
|
||||
return true; /* connection status changed */
|
||||
}
|
||||
|
||||
void
|
||||
FaderPort::connected ()
|
||||
{
|
||||
std::cerr << "faderport connected\n";
|
||||
std::cerr << "faderport connected or disconnected\n";
|
||||
|
||||
start_midi_handling ();
|
||||
|
||||
|
@ -686,68 +713,91 @@ FaderPort::connected ()
|
|||
}
|
||||
|
||||
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:
|
||||
if (press) {
|
||||
ToDoMap::iterator x = on_press.find (bs);
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (!x->second.action_name.empty()) {
|
||||
fp.access_action (x->second.action_name);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case InternalFunction:
|
||||
if (press) {
|
||||
ToDoMap::iterator x = on_press.find (bs);
|
||||
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 ();
|
||||
}
|
||||
}
|
||||
if (x->second.function) {
|
||||
x->second.function ();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
type = NamedAction;
|
||||
todo.type = NamedAction;
|
||||
|
||||
if (when_pressed) {
|
||||
todo.action_name = name;
|
||||
on_press[bs] = todo;
|
||||
if (name.empty()) {
|
||||
on_press.erase (bs);
|
||||
} else {
|
||||
todo.action_name = name;
|
||||
on_press[bs] = todo;
|
||||
}
|
||||
} else {
|
||||
todo.action_name = name;
|
||||
on_release[bs] = todo;
|
||||
if (name.empty()) {
|
||||
on_release.erase (bs);
|
||||
} else {
|
||||
todo.action_name = name;
|
||||
on_release[bs] = todo;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
type = InternalFunction;
|
||||
todo.type = InternalFunction;
|
||||
|
||||
if (when_pressed) {
|
||||
todo.function = f;
|
||||
|
@ -759,7 +809,7 @@ FaderPort::ButtonInfo::set_action (boost::function<void()> f, bool when_pressed,
|
|||
}
|
||||
|
||||
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)) {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
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) {
|
||||
_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) {
|
||||
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) {
|
||||
blinkers.push_back (Mute);
|
||||
} else {
|
||||
|
@ -864,19 +995,19 @@ FaderPort::map_cut ()
|
|||
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
|
||||
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
|
||||
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
|
||||
|
@ -884,9 +1015,9 @@ FaderPort::map_recenable ()
|
|||
{
|
||||
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (_current_route);
|
||||
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 {
|
||||
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 ()
|
||||
{
|
||||
if (!_current_route) {
|
||||
button_info (Mute).set_led_state (_output_port, false);
|
||||
button_info (Solo).set_led_state (_output_port, false);
|
||||
button_info (Rec).set_led_state (_output_port, false);
|
||||
get_button (Mute).set_led_state (_output_port, false);
|
||||
get_button (Solo).set_led_state (_output_port, false);
|
||||
get_button (Rec).set_led_state (_output_port, false);
|
||||
blinkers.remove (Mute);
|
||||
blinkers.remove (Solo);
|
||||
} else {
|
||||
|
@ -974,5 +1105,5 @@ FaderPort::input_port()
|
|||
void
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -151,6 +151,8 @@ class FaderPort : public ARDOUR::ControlProtocol, public AbstractUI<FaderPortReq
|
|||
RewindDown = 0x2,
|
||||
StopDown = 0x4,
|
||||
UserDown = 0x8,
|
||||
LongishPress = 0x10,
|
||||
LongPress = 0x20
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
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 fader_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb);
|
||||
|
||||
ButtonState button_state;
|
||||
|
||||
friend class ButtonInfo;
|
||||
friend class Button;
|
||||
|
||||
class ButtonInfo {
|
||||
class Button {
|
||||
public:
|
||||
|
||||
enum ActionType {
|
||||
|
@ -206,14 +208,15 @@ class FaderPort : public ARDOUR::ControlProtocol, public AbstractUI<FaderPortReq
|
|||
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)
|
||||
, name (str)
|
||||
, id (i)
|
||||
, out (o)
|
||||
, type (NamedAction)
|
||||
, led_on (false)
|
||||
, flash (false)
|
||||
, pressed_at (0)
|
||||
, long_press (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);
|
||||
bool uses_flash () const { return flash; }
|
||||
void set_flash (bool yn) { flash = yn; }
|
||||
void do_timing (bool press);
|
||||
|
||||
XMLNode& get_state () const;
|
||||
int set_state (XMLNode const&);
|
||||
|
||||
private:
|
||||
FaderPort& fp;
|
||||
std::string name;
|
||||
ButtonID id;
|
||||
int out;
|
||||
ActionType type;
|
||||
bool led_on;
|
||||
bool flash;
|
||||
ARDOUR::microseconds_t pressed_at;
|
||||
int long_press;
|
||||
|
||||
/* could be a union if boost::function didn't require a
|
||||
* constructor
|
||||
*/
|
||||
struct ToDo {
|
||||
ActionType type;
|
||||
/* could be a union if boost::function didn't require a
|
||||
* constructor
|
||||
*/
|
||||
std::string action_name;
|
||||
boost::function<void()> function;
|
||||
};
|
||||
|
@ -245,10 +254,10 @@ class FaderPort : public ARDOUR::ControlProtocol, public AbstractUI<FaderPortReq
|
|||
ToDoMap on_release;
|
||||
};
|
||||
|
||||
typedef std::map<ButtonID,ButtonInfo> ButtonMap;
|
||||
typedef std::map<ButtonID,Button> ButtonMap;
|
||||
|
||||
ButtonMap buttons;
|
||||
ButtonInfo& button_info (ButtonID) const;
|
||||
Button& get_button (ButtonID) const;
|
||||
|
||||
void all_lights_out ();
|
||||
void close ();
|
||||
|
|
|
@ -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
|
||||
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/box.h>
|
||||
#include <gtkmm/combobox.h>
|
||||
#include <gtkmm/liststore.h>
|
||||
#include <gtkmm/label.h>
|
||||
#include <gtkmm/spinbutton.h>
|
||||
#include <gtkmm/table.h>
|
||||
#include <gtkmm/treestore.h>
|
||||
|
||||
namespace Gtk {
|
||||
class CellRendererCombo;
|
||||
}
|
||||
#include <gtkmm/liststore.h>
|
||||
|
||||
#include "pbd/unwind.h"
|
||||
#include "pbd/strsplit.h"
|
||||
|
@ -47,68 +32,10 @@ namespace Gtk {
|
|||
#include "ardour/audioengine.h"
|
||||
|
||||
#include "faderport.h"
|
||||
#include "gui.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 ARDOUR;
|
||||
using namespace ArdourSurface;
|
||||
|
@ -136,7 +63,7 @@ FaderPort::tear_down_gui ()
|
|||
delete w;
|
||||
}
|
||||
}
|
||||
delete (FPGUI*) gui;
|
||||
delete static_cast<FPGUI*> (gui);
|
||||
gui = 0;
|
||||
}
|
||||
|
||||
|
@ -151,6 +78,7 @@ FaderPort::build_gui ()
|
|||
FPGUI::FPGUI (FaderPort& p)
|
||||
: fp (p)
|
||||
, table (2, 5)
|
||||
, action_table (4, 5)
|
||||
, ignore_active_change (false)
|
||||
{
|
||||
set_border_width (12);
|
||||
|
@ -164,65 +92,138 @@ FPGUI::FPGUI (FaderPort& p)
|
|||
Gtk::Alignment* align;
|
||||
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);
|
||||
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));
|
||||
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);
|
||||
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);
|
||||
row++;
|
||||
|
||||
l = manage (new Gtk::Label (_("Receives MIDI via:")));
|
||||
l = manage (new Gtk::Label (_("Receives MIDI from:")));
|
||||
l->set_alignment (1.0, 0.5);
|
||||
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);
|
||||
row++;
|
||||
|
||||
build_mix_action_combo (mix_combo);
|
||||
build_proj_action_combo (proj_combo);
|
||||
build_trns_action_combo (trns_combo);
|
||||
build_mix_action_combo (mix_combo[0], FaderPort::ButtonState(0));
|
||||
build_mix_action_combo (mix_combo[1], FaderPort::ShiftDown);
|
||||
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);
|
||||
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->set (0.0, 0.5);
|
||||
align->add (mix_combo);
|
||||
table.attach (*align, 1, 2, row, 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->add (mix_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);
|
||||
table.attach (*align, 1, 2, row, 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->add (mix_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);
|
||||
table.attach (*align, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions (0));
|
||||
align->add (mix_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 (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++;
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
@ -240,18 +241,18 @@ FPGUI::connection_handler ()
|
|||
|
||||
PBD::Unwinder<bool> ici (ignore_active_change, true);
|
||||
|
||||
update_port_combos ();
|
||||
}
|
||||
|
||||
void
|
||||
FPGUI::update_port_combos ()
|
||||
{
|
||||
vector<string> midi_inputs;
|
||||
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::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> output = build_midi_port_list (midi_outputs, false);
|
||||
bool input_found = false;
|
||||
|
@ -411,7 +412,16 @@ FPGUI::build_available_action_menu ()
|
|||
}
|
||||
|
||||
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));
|
||||
TreeIter rowp;
|
||||
|
@ -419,29 +429,51 @@ FPGUI::build_mix_action_combo (Gtk::ComboBox& cb)
|
|||
|
||||
rowp = model->append();
|
||||
row = *(rowp);
|
||||
row[action_columns.name] = _("Toggle Editor & Mixer Windows");
|
||||
row[action_columns.path] = X_("Common/toggle-editor-mixer");
|
||||
row[action_columns.name] = _("Disabled");
|
||||
row[action_columns.path] = string();
|
||||
|
||||
rowp = model->append();
|
||||
row = *(rowp);
|
||||
row[action_columns.name] = _("Show/Hide Editor mixer strip");
|
||||
row[action_columns.path] = X_("Editor/show-editor-mixer");
|
||||
for (vector<pair<string,string> >::const_iterator i = actions.begin(); i != actions.end(); ++i) {
|
||||
rowp = model->append();
|
||||
row = *(rowp);
|
||||
row[action_columns.name] = i->first;
|
||||
row[action_columns.path] = i->second;
|
||||
}
|
||||
|
||||
cb.set_model (model);
|
||||
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
|
||||
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
|
||||
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>
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
106
libs/surfaces/faderport/gui.h
Normal file
106
libs/surfaces/faderport/gui.h
Normal 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__ */
|
|
@ -171,14 +171,14 @@ FaderPort::use_master ()
|
|||
if (_current_route == r) {
|
||||
r = pre_master_route.lock();
|
||||
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);
|
||||
} else {
|
||||
if (_current_route != session->master_out() && _current_route != session->monitor_out()) {
|
||||
pre_master_route = boost::weak_ptr<Route> (_current_route);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -193,14 +193,14 @@ FaderPort::use_monitor ()
|
|||
if (_current_route == r) {
|
||||
r = pre_monitor_route.lock();
|
||||
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);
|
||||
} else {
|
||||
if (_current_route != session->master_out() && _current_route != session->monitor_out()) {
|
||||
pre_monitor_route = boost::weak_ptr<Route> (_current_route);
|
||||
}
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue
Block a user