merge changes to libmidi++ API from 2.0-ongoing
[ardour.git] / gtk2_ardour / option_editor.cc
index ad34e8ed0b38449ad117cff0686e1e7c7e4365d4..93cccfcbf35d6003db1ea79c377be7d15fdb249d 100644 (file)
@@ -26,6 +26,8 @@
 #include <ardour/sndfilesource.h>
 #include <ardour/crossfade.h>
 #include <midi++/manager.h>
+#include <midi++/factory.h>
+#include <midi++/port_request.h>
 #include <gtkmm2ext/stop_signal.h>
 #include <gtkmm2ext/utils.h>
 #include <gtkmm2ext/window_title.h>
@@ -40,6 +42,7 @@
 #include "utils.h"
 #include "editing.h"
 #include "option_editor.h"
+#include "midi_port_dialog.h"
 
 #include "i18n.h"
 
@@ -75,8 +78,10 @@ OptionEditor::OptionEditor (ARDOUR_UI& uip, PublicEditor& ed, Mixer_UI& mixui)
 
          /* MIDI */
 
-         mmc_device_id_adjustment (0.0, 0.0, (double) 0x7f, 1.0, 16.0),
-         mmc_device_id_spinner (mmc_device_id_adjustment),
+         mmc_receive_device_id_adjustment (0.0, 0.0, (double) 0x7f, 1.0, 16.0),
+         mmc_receive_device_id_spinner (mmc_receive_device_id_adjustment),
+         mmc_send_device_id_adjustment (0.0, 0.0, (double) 0x7f, 1.0, 16.0),
+         mmc_send_device_id_spinner (mmc_send_device_id_adjustment),
 
          /* Click */
 
@@ -363,46 +368,131 @@ OptionEditor::smpte_offset_chosen()
        }
 }
 
-
 void
 OptionEditor::setup_midi_options ()
 {
        HBox* hbox;
+       Label* label;
+
+       midi_port_table.set_row_spacings (6);
+       midi_port_table.set_col_spacings (10);
+
+       redisplay_midi_ports ();
+
+       mmc_receive_device_id_adjustment.signal_value_changed().connect (mem_fun (*this, &OptionEditor::mmc_receive_device_id_adjusted));
+       mmc_send_device_id_adjustment.signal_value_changed().connect (mem_fun (*this, &OptionEditor::mmc_send_device_id_adjusted));
+
+       hbox = manage (new HBox);
+       hbox->set_border_width (6);
+       hbox->pack_start (midi_port_table, true, false);
+
+       midi_packer.pack_start (*hbox, false, false);
+       midi_packer.pack_start (add_midi_port_button, false, false);
+
+       hbox = manage (new HBox);
+       hbox->set_border_width (6);
+       hbox->set_spacing (6);
+       label = (manage (new Label (_("Inbound MMC Device ID")))); 
+       hbox->pack_start (mmc_receive_device_id_spinner, false, false);
+       hbox->pack_start (*label, false, false);
+       midi_packer.pack_start (*hbox, false, false);
+
+       hbox = manage (new HBox);
+       hbox->set_border_width (6);
+       hbox->set_spacing (6);
+       label = (manage (new Label (_("Outbound MMC Device ID")))); 
+       hbox->pack_start (mmc_send_device_id_spinner, false, false);
+       hbox->pack_start (*label, false, false);
+       midi_packer.pack_start (*hbox, false, false);
+
+       add_midi_port_button.signal_clicked().connect (mem_fun (*this, &OptionEditor::add_midi_port));
+}
+
+void
+OptionEditor::redisplay_midi_ports ()
+{
        MIDI::Manager::PortMap::const_iterator i;
        const MIDI::Manager::PortMap& ports = MIDI::Manager::instance()->get_midi_ports();
        int n;
-       ToggleButton* tb;
-       RadioButton* rb;
 
-       Gtk::Table* table = manage (new Table (ports.size() + 4, 10));
+       /* remove all existing widgets */
 
-       table->set_row_spacings (6);
-       table->set_col_spacings (10);
+       // XXX broken in gtkmm 2.10
+       // midi_port_table.clear ();
 
-       table->attach (*(manage (new Label (_("Port")))), 0, 1, 0, 1);
-       table->attach (*(manage (new Label (_("Offline")))), 1, 2, 0, 1);
-       table->attach (*(manage (new Label (_("Trace\nInput")))), 2, 3, 0, 1);
-       table->attach (*(manage (new Label (_("Trace\nOutput")))), 3, 4, 0, 1);
-       table->attach (*(manage (new Label (_("MTC")))), 4, 5, 0, 1);
-       table->attach (*(manage (new Label (_("MMC")))), 6, 7, 0, 1);
-       table->attach (*(manage (new Label (_("MIDI Parameter\nControl")))), 8, 9, 0, 1);
+       for (vector<Widget*>::iterator w = midi_port_table_widgets.begin(); w != midi_port_table_widgets.end(); ++w) {
+               midi_port_table.remove (**w);
+       }
 
-       table->attach (*(manage (new HSeparator())), 0, 9, 1, 2);
-       table->attach (*(manage (new VSeparator())), 5, 6, 0, 8);
-       table->attach (*(manage (new VSeparator())), 7, 8, 0, 8);
-       
-       table->attach (*(manage (new Label (_("MMC Device ID")))), 9, 10, 0, 1);
-       table->attach (mmc_device_id_spinner, 9, 10, 1, 2);
-       
-       mmc_device_id_adjustment.signal_value_changed().connect (mem_fun (*this, &OptionEditor::mmc_device_id_adjusted));
+       midi_port_table_widgets.clear ();
 
-       for (n = 0, i = ports.begin(); i != ports.end(); ++n, ++i) {
+       midi_port_table.resize (ports.size() + 4, 11);
+
+       Gtk::Label* label;
 
-               pair<MIDI::Port*,vector<RadioButton*> > newpair;
+       label = (manage (new Label (_("Port")))); 
+       label->show ();
+       midi_port_table_widgets.push_back (label);
+       midi_port_table.attach (*label, 0, 1, 0, 1);
+       label = (manage (new Label (_("Offline")))); 
+       label->show ();
+       midi_port_table_widgets.push_back (label);
+       midi_port_table.attach (*label, 1, 2, 0, 1);
+       label = (manage (new Label (_("Trace\nInput")))); 
+       label->show ();
+       midi_port_table_widgets.push_back (label);
+       midi_port_table.attach (*label, 2, 3, 0, 1);
+       label = (manage (new Label (_("Trace\nOutput")))); 
+       label->show ();
+       midi_port_table_widgets.push_back (label);
+       midi_port_table.attach (*label, 3, 4, 0, 1);
+       label = (manage (new Label (_("MTC")))); 
+       label->show ();
+       midi_port_table_widgets.push_back (label);
+       midi_port_table.attach (*label, 4, 5, 0, 1);
+       label = (manage (new Label (_("MMC")))); 
+       label->show ();
+       midi_port_table_widgets.push_back (label);
+       midi_port_table.attach (*label, 6, 7, 0, 1);
+       label = (manage (new Label (_("MIDI Parameter\nControl")))); 
+       label->show ();
+       midi_port_table_widgets.push_back (label);
+       midi_port_table.attach (*label, 8, 9, 0, 1);
+
+       Gtk::HSeparator* hsep = (manage (new HSeparator())); 
+       hsep->show ();
+       midi_port_table_widgets.push_back (hsep);
+       midi_port_table.attach (*hsep, 0, 9, 1, 2);
+       Gtk::VSeparator* vsep = (manage (new VSeparator())); 
+       vsep->show ();
+       midi_port_table_widgets.push_back (vsep);
+       midi_port_table.attach (*vsep, 5, 6, 0, 8);
+       vsep = (manage (new VSeparator())); 
+       vsep->show ();
+       midi_port_table_widgets.push_back (vsep);
+       midi_port_table.attach (*vsep, 7, 8, 0, 8);
+       
+       for (n = 0, i = ports.begin(); i != ports.end(); ++n, ++i) {
 
-               newpair.first = i->second;
+               ToggleButton* tb;
+               RadioButton* rb;
+               Button* bb;
 
-               table->attach (*(manage (new Label (i->first))), 0, 1, n+2, n+3,FILL|EXPAND, FILL );
+               /* the remove button. create early so we can pass it to various callbacks */
+               
+               bb = manage (new Button (Stock::REMOVE));
+               bb->set_name ("OptionEditorToggleButton");
+               bb->show ();
+               midi_port_table_widgets.push_back (bb);
+               midi_port_table.attach (*bb, 9, 10, n+2, n+3, FILL|EXPAND, FILL);
+               bb->signal_clicked().connect (bind (mem_fun(*this, &OptionEditor::remove_midi_port), i->second));
+               bb->set_sensitive (port_removable (i->second));
+
+               label = (manage (new Label (i->first))); 
+               label->show ();
+               midi_port_table_widgets.push_back (label);
+               midi_port_table.attach (*label, 0, 1, n+2, n+3,FILL|EXPAND, FILL );
+               
                tb = manage (new ToggleButton (_("online")));
                tb->set_name ("OptionEditorToggleButton");
 
@@ -416,25 +506,32 @@ OptionEditor::setup_midi_options ()
                        set_size_request_to_display_given_text (*tb, _("online"), 15, 12);
                }
 
-               tb->set_active (!(*i).second->input()->offline());
-               tb->signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::port_online_toggled), (*i).second, tb));
-               (*i).second->input()->OfflineStatusChanged.connect (bind (mem_fun(*this, &OptionEditor::map_port_online), (*i).second, tb));
-               table->attach (*tb, 1, 2, n+2, n+3, FILL|EXPAND, FILL);
+               if (i->second->input()) {
+                       tb->set_active (!i->second->input()->offline());
+                       tb->signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::port_online_toggled), i->second, tb));
+                       i->second->input()->OfflineStatusChanged.connect (bind (mem_fun(*this, &OptionEditor::map_port_online), (*i).second, tb));
+               }
+               tb->show ();
+               midi_port_table_widgets.push_back (tb);
+               midi_port_table.attach (*tb, 1, 2, n+2, n+3, FILL|EXPAND, FILL);
 
                tb = manage (new ToggleButton ());
                tb->set_name ("OptionEditorToggleButton");
                tb->signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::port_trace_in_toggled), (*i).second, tb));
                tb->set_size_request (10, 10);
-               table->attach (*tb, 2, 3, n+2, n+3, FILL|EXPAND, FILL);
+               tb->show ();
+               midi_port_table_widgets.push_back (tb);
+               midi_port_table.attach (*tb, 2, 3, n+2, n+3, FILL|EXPAND, FILL);
 
                tb = manage (new ToggleButton ());
                tb->set_name ("OptionEditorToggleButton");
                tb->signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::port_trace_out_toggled), (*i).second, tb));
                tb->set_size_request (10, 10);
-               table->attach (*tb, 3, 4, n+2, n+3, FILL|EXPAND, FILL);
+               tb->show ();
+               midi_port_table_widgets.push_back (tb);
+               midi_port_table.attach (*tb, 3, 4, n+2, n+3, FILL|EXPAND, FILL);
 
                rb = manage (new RadioButton ());
-               newpair.second.push_back (rb);
                rb->set_name ("OptionEditorToggleButton");
                if (n == 0) {
                        mtc_button_group = rb->get_group();
@@ -442,99 +539,154 @@ OptionEditor::setup_midi_options ()
                        rb->set_group (mtc_button_group);
 
                }
-               table->attach (*rb, 4, 5, n+2, n+3, FILL|EXPAND, FILL);
-               rb->signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::mtc_port_chosen), (*i).second, rb));
+               rb->show ();
+               midi_port_table_widgets.push_back (rb);
+               midi_port_table.attach (*rb, 4, 5, n+2, n+3, FILL|EXPAND, FILL);
+               rb->signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::mtc_port_chosen), (*i).second, rb, bb));
 
-               if (Config->get_mtc_port_name() == i->first) {
+               if (session && i->second == session->mtc_port()) {
                        rb->set_active (true);
                }
                
                rb = manage (new RadioButton ());
-               newpair.second.push_back (rb);
                rb->set_name ("OptionEditorToggleButton");
                if (n == 0) {
                        mmc_button_group = rb->get_group();
                } else {
                        rb->set_group (mmc_button_group);
                }
-               table->attach (*rb, 6, 7, n+2, n+3, FILL|EXPAND, FILL);
-               rb->signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::mmc_port_chosen), (*i).second, rb));
+               rb->show ();
+               midi_port_table_widgets.push_back (rb);
+               midi_port_table.attach (*rb, 6, 7, n+2, n+3, FILL|EXPAND, FILL);
+               rb->signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::mmc_port_chosen), (*i).second, rb, bb));
 
-               if (Config->get_mmc_port_name() == i->first) {
+               if (session && i->second == session->mmc_port()) {
                        rb->set_active (true);
                }
 
                rb = manage (new RadioButton ());
-               newpair.second.push_back (rb);
                rb->set_name ("OptionEditorToggleButton");
                if (n == 0) {
                        midi_button_group = rb->get_group();
                } else {
                        rb->set_group (midi_button_group);
                }
-               table->attach (*rb, 8, 9, n+2, n+3, FILL|EXPAND, FILL);
-               rb->signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::midi_port_chosen), (*i).second, rb));
+               rb->show ();
+               midi_port_table_widgets.push_back (rb);
+               midi_port_table.attach (*rb, 8, 9, n+2, n+3, FILL|EXPAND, FILL);
+               rb->signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::midi_port_chosen), (*i).second, rb, bb));
 
-               if (Config->get_midi_port_name() == i->first) {
+               if (session && i->second == session->midi_port()) {
                        rb->set_active (true);
                }
-               
-               port_toggle_buttons.insert (newpair);
+
        }
 
-       table->show_all ();
+       midi_port_table.show();
+}
 
-       hbox = manage (new HBox);
-       hbox->set_border_width (6);
-       hbox->pack_start (*table, true, false);
-       midi_packer.pack_start (*hbox, false, false);
+void
+OptionEditor::remove_midi_port (MIDI::Port* port)
+{
+       MIDI::Manager::instance()->remove_port (port);
+       redisplay_midi_ports ();
+}
+
+void
+OptionEditor::add_midi_port ()
+{
+       MidiPortDialog dialog;
+
+       dialog.set_position (WIN_POS_MOUSE);
+       dialog.set_transient_for (*this);
+
+       dialog.show ();
+
+       int ret = dialog.run ();
+
+       switch (ret) {
+       case RESPONSE_ACCEPT:
+               break;
+       default:
+               return;
+               break;
+       }
+
+       Glib::ustring mode = dialog.port_mode_combo.get_active_text();
+       std::string smod;
+
+       if (mode == _("input")) {
+               smod = X_("input");
+       } else if (mode == (_("output"))) {
+               smod = X_("output");
+       } else {
+               smod = "duplex";
+       }
+
+       MIDI::PortRequest req (X_("ardour"),
+                              dialog.port_name.get_text(),
+                              smod,
+                              MIDI::PortFactory::default_port_type());
+
+       if (MIDI::Manager::instance()->add_port (req) != 0) {
+               redisplay_midi_ports ();
+       }
+}
+
+bool
+OptionEditor::port_removable (MIDI::Port *port)
+{
+       if (!session) {
+               return true;
+       }
+
+       if (port == session->mtc_port() ||
+           port == session->mmc_port() ||
+           port == session->midi_port()) {
+               return false;
+       }
+       return true;
 }
 
 void
-OptionEditor::mtc_port_chosen (MIDI::Port *port, Gtk::RadioButton* rb) 
+OptionEditor::mtc_port_chosen (MIDI::Port *port, Gtk::RadioButton* rb, Gtk::Button* bb
 {
        if (session) {
                if (rb->get_active()) {
-                       if (port) {
-                               session->set_mtc_port (port->name());
-                               Config->set_mtc_port_name (port->name());
-                       } else {
-                               session->set_mtc_port ("");
-                       }
-                       rb->set_active (true);
+                       session->set_mtc_port (port->name());
+                       Config->set_mtc_port_name (port->name());
+               } else {
+                       session->set_mtc_port ("");
                }
+               bb->set_sensitive (port_removable (port));
        }
 }
 
 void
-OptionEditor::mmc_port_chosen (MIDI::Port* port, Gtk::RadioButton* rb)
+OptionEditor::mmc_port_chosen (MIDI::Port* port, Gtk::RadioButton* rb, Gtk::Button* bb)
 {
        if (session) {
                if (rb->get_active()) {
-                       if (port) {
-                               session->set_mmc_port (port->name());
-                               Config->set_mtc_port_name (port->name());
-                       } else {
-                               session->set_mmc_port ("");
-                       }
-                       rb->set_active (true);
+                       session->set_mmc_port (port->name());
+                       Config->set_mtc_port_name (port->name());
+               } else {
+                       session->set_mmc_port ("");
                }
+               bb->set_sensitive (port_removable (port));
        }
 }
 
 void
-OptionEditor::midi_port_chosen (MIDI::Port* port, Gtk::RadioButton* rb)
+OptionEditor::midi_port_chosen (MIDI::Port* port, Gtk::RadioButton* rb, Gtk::Button* bb)
 {
        if (session) {
                if (rb->get_active()) {
-                       if (port) {
-                               session->set_midi_port (port->name());
-                               Config->set_midi_port_name (port->name());
-                       } else {
-                               session->set_midi_port ("");
-                       }
-                       rb->set_active (true);
+                       session->set_midi_port (port->name());
+                       Config->set_midi_port_name (port->name());
+               } else {
+                       session->set_midi_port ("");
                }
+               bb->set_sensitive (port_removable (port));
        }
 }
 
@@ -565,12 +717,22 @@ OptionEditor::map_port_online (MIDI::Port* port, ToggleButton* tb)
 }
 
 void
-OptionEditor::mmc_device_id_adjusted ()
+OptionEditor::mmc_receive_device_id_adjusted ()
+{
+       uint8_t id = (uint8_t) mmc_receive_device_id_spinner.get_value();
+
+       if (id != Config->get_mmc_receive_device_id()) {
+               Config->set_mmc_receive_device_id (id);
+       }
+}
+
+void
+OptionEditor::mmc_send_device_id_adjusted ()
 {
-       uint8_t id = (uint8_t) mmc_device_id_spinner.get_value();
+       uint8_t id = (uint8_t) mmc_send_device_id_spinner.get_value();
 
-       if (id != Config->get_mmc_device_id()) {
-               Config->set_mmc_device_id (id);
+       if (id != Config->get_mmc_send_device_id()) {
+               Config->set_mmc_send_device_id (id);
        }
 }