summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <carl@carlh.net>2009-01-20 14:46:00 +0000
committerCarl Hetherington <carl@carlh.net>2009-01-20 14:46:00 +0000
commit61db2175eb8b8fffd0c1796ace78ac33c9e1adf0 (patch)
tree6fdc23e7e0161ce54642b0bd44dc8e0a33f05efe
parentef038c1a84ecd541a540d5a5baa677d7663e535c (diff)
New matrix-based editor for connections and bundles, based on thorwil's design.
Add Bundle Manager dialog. git-svn-id: svn://localhost/ardour2/branches/3.0@4415 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--gtk2_ardour/SConscript8
-rw-r--r--gtk2_ardour/ardour.menus.in1
-rw-r--r--gtk2_ardour/bundle_manager.cc148
-rw-r--r--gtk2_ardour/bundle_manager.h54
-rw-r--r--gtk2_ardour/editor.cc12
-rw-r--r--gtk2_ardour/editor.h3
-rw-r--r--gtk2_ardour/editor_actions.cc1
-rw-r--r--gtk2_ardour/io_selector.cc250
-rw-r--r--gtk2_ardour/io_selector.h48
-rw-r--r--gtk2_ardour/matrix.cc511
-rw-r--r--gtk2_ardour/matrix.h113
-rw-r--r--gtk2_ardour/option_editor.cc8
-rw-r--r--gtk2_ardour/port_group.cc159
-rw-r--r--gtk2_ardour/port_group.h44
-rw-r--r--gtk2_ardour/port_matrix.cc284
-rw-r--r--gtk2_ardour/port_matrix.h129
-rw-r--r--gtk2_ardour/port_matrix_body.cc269
-rw-r--r--gtk2_ardour/port_matrix_body.h94
-rw-r--r--gtk2_ardour/port_matrix_column_labels.cc199
-rw-r--r--gtk2_ardour/port_matrix_column_labels.h49
-rw-r--r--gtk2_ardour/port_matrix_component.cc107
-rw-r--r--gtk2_ardour/port_matrix_component.h136
-rw-r--r--gtk2_ardour/port_matrix_grid.cc195
-rw-r--r--gtk2_ardour/port_matrix_grid.h53
-rw-r--r--gtk2_ardour/port_matrix_row_labels.cc240
-rw-r--r--gtk2_ardour/port_matrix_row_labels.h57
-rw-r--r--gtk2_ardour/route_params_ui.cc4
-rw-r--r--libs/ardour/ardour/bundle.h39
-rw-r--r--libs/ardour/bundle.cc103
-rw-r--r--libs/ardour/io.cc11
-rw-r--r--libs/ardour/session.cc17
-rw-r--r--libs/ardour/user_bundle.cc10
32 files changed, 2160 insertions, 1196 deletions
diff --git a/gtk2_ardour/SConscript b/gtk2_ardour/SConscript
index c6fb356cd9..d42edb1919 100644
--- a/gtk2_ardour/SConscript
+++ b/gtk2_ardour/SConscript
@@ -196,7 +196,6 @@ lineset.cc
location_ui.cc
main.cc
marker.cc
-matrix.cc
midi_channel_selector.cc
midi_port_dialog.cc
midi_region_view.cc
@@ -216,8 +215,13 @@ piano_roll_header.cc
playlist_selector.cc
plugin_selector.cc
plugin_ui.cc
-port_matrix.cc
port_group.cc
+port_matrix.cc
+port_matrix_body.cc
+port_matrix_column_labels.cc
+port_matrix_component.cc
+port_matrix_grid.cc
+port_matrix_row_labels.cc
processor_box.cc
prompter.cc
public_editor.cc
diff --git a/gtk2_ardour/ardour.menus.in b/gtk2_ardour/ardour.menus.in
index c6688e92a2..dbddc2d93c 100644
--- a/gtk2_ardour/ardour.menus.in
+++ b/gtk2_ardour/ardour.menus.in
@@ -423,6 +423,7 @@
<menuitem action='ToggleThemeManager'/>
<menuitem action='ToggleBigClock'/>
<menuitem action='toggle-rhythm-ferret'/>
+ <menuitem action='toggle-bundle-manager'/>
<separator/>
</menu>
<menu name='Options' action='Options'>
diff --git a/gtk2_ardour/bundle_manager.cc b/gtk2_ardour/bundle_manager.cc
index e4e848557e..1b493348ae 100644
--- a/gtk2_ardour/bundle_manager.cc
+++ b/gtk2_ardour/bundle_manager.cc
@@ -38,71 +38,79 @@ BundleEditorMatrix::BundleEditorMatrix (
PortGroupList::Mask (PortGroupList::SYSTEM | PortGroupList::OTHER)
)
{
- _bundle = boost::dynamic_pointer_cast<ARDOUR::UserBundle> (bundle);
- assert (_bundle != 0);
+ _our_bundle = bundle;
}
void
-BundleEditorMatrix::set_state (int r, std::string const & p, bool s, uint32_t keymod)
+BundleEditorMatrix::set_state (
+ boost::shared_ptr<ARDOUR::Bundle> ab,
+ uint32_t ac,
+ boost::shared_ptr<ARDOUR::Bundle> bb,
+ uint32_t bc,
+ bool s,
+ uint32_t k
+ )
{
- if (s) {
- _bundle->add_port_to_channel (r, p);
- } else {
- _bundle->remove_port_from_channel (r, p);
+ ARDOUR::Bundle::PortList const& pl = bb->channel_ports (bc);
+ for (ARDOUR::Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
+ if (s) {
+ ab->add_port_to_channel (ac, *i);
+ } else {
+ ab->remove_port_from_channel (ac, *i);
+ }
}
}
bool
-BundleEditorMatrix::get_state (int r, std::string const & p) const
+BundleEditorMatrix::get_state (
+ boost::shared_ptr<ARDOUR::Bundle> ab,
+ uint32_t ac,
+ boost::shared_ptr<ARDOUR::Bundle> bb,
+ uint32_t bc
+ ) const
{
- return _bundle->port_attached_to_channel (r, p);
-}
+ ARDOUR::Bundle::PortList const& pl = bb->channel_ports (bc);
+ for (ARDOUR::Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
+ if (!ab->port_attached_to_channel (ac, *i)) {
+ return false;
+ }
+ }
-uint32_t
-BundleEditorMatrix::n_rows () const
-{
- return _bundle->nchannels ();
+ return true;
}
-uint32_t
-BundleEditorMatrix::maximum_rows () const
+void
+BundleEditorMatrix::add_channel (boost::shared_ptr<ARDOUR::Bundle> b)
{
- /* 65536 channels in a bundle ought to be enough for anyone (TM) */
- return 65536;
-}
+ NameChannelDialog d;
+ d.set_position (Gtk::WIN_POS_MOUSE);
-uint32_t
-BundleEditorMatrix::minimum_rows () const
-{
- return 0;
-}
+ if (d.run () != Gtk::RESPONSE_ACCEPT) {
+ return;
+ }
-std::string
-BundleEditorMatrix::row_name (int r) const
-{
- std::stringstream s;
- s << r + 1; // 1-based counting
- return s.str();
+ _our_bundle->add_channel (d.get_name());
+ setup ();
}
void
-BundleEditorMatrix::add_row ()
+BundleEditorMatrix::remove_channel (boost::shared_ptr<ARDOUR::Bundle> b, uint32_t c)
{
- _bundle->add_channel ();
+ _our_bundle->remove_channel (c);
setup ();
}
void
-BundleEditorMatrix::remove_row (int r)
+BundleEditorMatrix::rename_channel (boost::shared_ptr<ARDOUR::Bundle> b, uint32_t c)
{
- _bundle->remove_channel (r);
- setup ();
-}
+ NameChannelDialog d (b, c);
+ d.set_position (Gtk::WIN_POS_MOUSE);
-std::string
-BundleEditorMatrix::row_descriptor () const
-{
- return _("channel");
+ if (d.run () != Gtk::RESPONSE_ACCEPT) {
+ return;
+ }
+
+ b->set_channel_name (c, d.get_name ());
}
BundleEditor::BundleEditor (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::UserBundle> bundle, bool add)
@@ -111,21 +119,21 @@ BundleEditor::BundleEditor (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::
Gtk::Table* t = new Gtk::Table (3, 2);
t->set_spacings (4);
+ /* Bundle name */
Gtk::Alignment* a = new Gtk::Alignment (1, 0.5, 0, 1);
a->add (*Gtk::manage (new Gtk::Label (_("Name:"))));
t->attach (*Gtk::manage (a), 0, 1, 0, 1, Gtk::FILL, Gtk::FILL);
t->attach (_name, 1, 2, 0, 1);
-
_name.set_text (_bundle->name ());
_name.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::name_changed));
+ /* Direction (input or output) */
a = new Gtk::Alignment (1, 0.5, 0, 1);
a->add (*Gtk::manage (new Gtk::Label (_("Direction:"))));
t->attach (*Gtk::manage (a), 0, 1, 1, 2, Gtk::FILL, Gtk::FILL);
a = new Gtk::Alignment (0, 0.5, 0, 1);
a->add (_input_or_output);
t->attach (*Gtk::manage (a), 1, 2, 1, 2);
-
_input_or_output.append_text (_("Input"));
_input_or_output.append_text (_("Output"));
@@ -137,6 +145,7 @@ BundleEditor::BundleEditor (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::
_input_or_output.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::input_or_output_changed));
+ /* Type (audio or MIDI) */
a = new Gtk::Alignment (1, 0.5, 0, 1);
a->add (*Gtk::manage (new Gtk::Label (_("Type:"))));
t->attach (*Gtk::manage (a), 0, 1, 2, 3, Gtk::FILL, Gtk::FILL);
@@ -159,11 +168,16 @@ BundleEditor::BundleEditor (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::
_type.signal_changed().connect (sigc::mem_fun (*this, &BundleEditor::type_changed));
get_vbox()->pack_start (*Gtk::manage (t), false, false);
-
get_vbox()->pack_start (_matrix);
-
get_vbox()->set_spacing (4);
+ /* Add Channel button */
+ Gtk::Button* add_channel_button = Gtk::manage (new Gtk::Button (_("Add Channel")));
+ add_channel_button->set_name ("IOSelectorButton");
+ add_channel_button->set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::ADD, Gtk::ICON_SIZE_BUTTON)));
+ get_action_area()->pack_start (*add_channel_button, false, false);
+ add_channel_button->signal_clicked().connect (sigc::bind (sigc::mem_fun (_matrix, &BundleEditorMatrix::add_channel), boost::shared_ptr<ARDOUR::Bundle> ()));
+
if (add) {
add_button (Gtk::Stock::CANCEL, 1);
add_button (Gtk::Stock::ADD, 0);
@@ -269,7 +283,7 @@ BundleManager::new_clicked ()
boost::shared_ptr<ARDOUR::UserBundle> b (new ARDOUR::UserBundle (""));
/* Start off with a single channel */
- b->add_channel ();
+ b->add_channel ("");
BundleEditor e (_session, b, true);
if (e.run () == 0) {
@@ -333,3 +347,47 @@ BundleManager::bundle_name_changed (boost::shared_ptr<ARDOUR::UserBundle> b)
}
}
+
+NameChannelDialog::NameChannelDialog ()
+ : ArdourDialog (_("Add channel")),
+ _adding (true)
+{
+ setup ();
+}
+
+NameChannelDialog::NameChannelDialog (boost::shared_ptr<ARDOUR::Bundle> b, uint32_t c)
+ : ArdourDialog (_("Rename channel")),
+ _bundle (b),
+ _channel (c),
+ _adding (false)
+{
+ _name.set_text (b->channel_name (c));
+
+ setup ();
+}
+
+void
+NameChannelDialog::setup ()
+{
+ Gtk::HBox* box = Gtk::manage (new Gtk::HBox ());
+
+ box->pack_start (*Gtk::manage (new Gtk::Label (_("Name"))));
+ box->pack_start (_name);
+
+ get_vbox ()->pack_end (*box);
+ box->show_all ();
+
+ add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+ if (_adding) {
+ add_button (Gtk::Stock::ADD, Gtk::RESPONSE_ACCEPT);
+ } else {
+ add_button (Gtk::Stock::APPLY, Gtk::RESPONSE_ACCEPT);
+ }
+ set_default_response (Gtk::RESPONSE_ACCEPT);
+}
+
+std::string
+NameChannelDialog::get_name () const
+{
+ return _name.get_text ();
+}
diff --git a/gtk2_ardour/bundle_manager.h b/gtk2_ardour/bundle_manager.h
index 097328b602..18b0b29e92 100644
--- a/gtk2_ardour/bundle_manager.h
+++ b/gtk2_ardour/bundle_manager.h
@@ -22,6 +22,7 @@
#include <gtkmm/treeview.h>
#include <gtkmm/liststore.h>
+#include <gtkmm/entry.h>
#include "ardour_dialog.h"
#include "port_matrix.h"
@@ -35,19 +36,28 @@ class BundleEditorMatrix : public PortMatrix
public:
BundleEditorMatrix (ARDOUR::Session &, boost::shared_ptr<ARDOUR::Bundle>);
- void set_state (int, std::string const &, bool, uint32_t);
- bool get_state (int, std::string const &) const;
- uint32_t n_rows () const;
- uint32_t maximum_rows () const;
- uint32_t minimum_rows () const;
- std::string row_name (int) const;
- void add_row ();
- void remove_row (int);
- std::string row_descriptor () const;
-
- private:
-
- boost::shared_ptr<ARDOUR::UserBundle> _bundle;
+ void set_state (
+ boost::shared_ptr<ARDOUR::Bundle> ab,
+ uint32_t ac,
+ boost::shared_ptr<ARDOUR::Bundle> bb,
+ uint32_t bc,
+ bool s,
+ uint32_t k
+ );
+
+ bool get_state (
+ boost::shared_ptr<ARDOUR::Bundle> ab,
+ uint32_t ac,
+ boost::shared_ptr<ARDOUR::Bundle> bb,
+ uint32_t bc
+ ) const;
+
+ void add_channel (boost::shared_ptr<ARDOUR::Bundle>);
+ void remove_channel (boost::shared_ptr<ARDOUR::Bundle>, uint32_t);
+ bool can_rename_channels () const {
+ return true;
+ }
+ void rename_channel (boost::shared_ptr<ARDOUR::Bundle>, uint32_t);
};
class BundleEditor : public ArdourDialog
@@ -104,4 +114,22 @@ class BundleManager : public ArdourDialog
Gtk::Button delete_button;
};
+class NameChannelDialog : public ArdourDialog
+{
+public:
+ NameChannelDialog ();
+ NameChannelDialog (boost::shared_ptr<ARDOUR::Bundle>, uint32_t);
+
+ std::string get_name () const;
+
+private:
+
+ void setup ();
+
+ boost::shared_ptr<ARDOUR::Bundle> _bundle;
+ uint32_t _channel;
+ Gtk::Entry _name;
+ bool _adding;
+};
+
#endif
diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc
index 3eba17a06e..08be372b14 100644
--- a/gtk2_ardour/editor.cc
+++ b/gtk2_ardour/editor.cc
@@ -87,6 +87,7 @@
#include "actions.h"
#include "tempo_lines.h"
#include "analysis_window.h"
+#include "bundle_manager.h"
#include "i18n.h"
@@ -347,6 +348,7 @@ Editor::Editor ()
select_new_marker = false;
zoomed_to_region = false;
rhythm_ferret = 0;
+ _bundle_manager = 0;
allow_vertical_scroll = false;
no_save_visual = false;
need_resize_line = false;
@@ -5128,6 +5130,16 @@ Editor::show_rhythm_ferret ()
}
void
+Editor::show_bundle_manager ()
+{
+ if (_bundle_manager == 0) {
+ _bundle_manager = new BundleManager (*session);
+ }
+
+ _bundle_manager->show ();
+}
+
+void
Editor::first_idle ()
{
MessageDialog* dialog = 0;
diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h
index 622d288213..87c2a1deb9 100644
--- a/gtk2_ardour/editor.h
+++ b/gtk2_ardour/editor.h
@@ -110,6 +110,7 @@ class ControlPoint;
class SoundFileOmega;
class RhythmFerret;
class AnalysisWindow;
+class BundleManager;
/* <CMT Additions> */
class ImageFrameView;
@@ -394,6 +395,7 @@ class Editor : public PublicEditor
void toggle_meter_updating();
void show_rhythm_ferret();
+ void show_bundle_manager ();
void goto_visual_state (uint32_t);
void save_visual_state (uint32_t);
@@ -2347,6 +2349,7 @@ public:
void snap_to_internal (nframes64_t& first, int32_t direction = 0, bool for_mark = false);
RhythmFerret* rhythm_ferret;
+ BundleManager* _bundle_manager;
void fit_tracks ();
void set_track_height (uint32_t h);
diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc
index 0e27aabaef..5c973034c4 100644
--- a/gtk2_ardour/editor_actions.cc
+++ b/gtk2_ardour/editor_actions.cc
@@ -563,6 +563,7 @@ Editor::register_actions ()
ActionManager::region_selection_sensitive_actions.push_back (act);
act = ActionManager::register_action (editor_actions, "toggle-rhythm-ferret", _("Rhythm Ferret"), mem_fun(*this, &Editor::show_rhythm_ferret));
ActionManager::session_sensitive_actions.push_back (act);
+ act = ActionManager::register_action (editor_actions, "toggle-bundle-manager", _("Bundle Manager"), mem_fun (*this, &Editor::show_bundle_manager));
act = ActionManager::register_action (editor_actions, "tab-to-transient-forwards", _("Move Forward to Transient"), bind (mem_fun(*this, &Editor::tab_to_transient), true));
ActionManager::session_sensitive_actions.push_back (act);
diff --git a/gtk2_ardour/io_selector.cc b/gtk2_ardour/io_selector.cc
index 0e40aa6ad3..06274df95e 100644
--- a/gtk2_ardour/io_selector.cc
+++ b/gtk2_ardour/io_selector.cc
@@ -30,6 +30,7 @@
#include "ardour/audio_track.h"
#include "ardour/midi_track.h"
#include "ardour/data_type.h"
+#include "ardour/bundle.h"
#include "io_selector.h"
#include "utils.h"
@@ -44,80 +45,130 @@ IOSelector::IOSelector (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::IO>
PortGroupList::Mask (PortGroupList::BUSS |
PortGroupList::SYSTEM |
PortGroupList::OTHER))
+ , _session (session)
, _io (io)
{
- list<string> our_ports;
-
/* Listen for ports changing on the IO */
- if (_offer_inputs) {
- _io->output_changed.connect (mem_fun(*this, &IOSelector::ports_changed));
+ _io->PortCountChanged.connect (sigc::hide (mem_fun (*this, &IOSelector::ports_changed)));
+
+ setup ();
+}
+void
+IOSelector::setup ()
+{
+ _our_bundle = boost::shared_ptr<ARDOUR::Bundle> (new ARDOUR::Bundle);
+ _our_bundle->set_name (_io->name());
+
+ if (offering_input ()) {
const PortSet& ps (_io->outputs());
+ int j = 0;
for (PortSet::const_iterator i = ps.begin(); i != ps.end(); ++i) {
- our_ports.push_back (i->name());
+ char buf[32];
+ snprintf (buf, sizeof(buf), _("out %d"), j + 1);
+ _our_bundle->add_channel (buf);
+ _our_bundle->add_port_to_channel (j, i->name());
+ ++j;
}
-
+
} else {
- _io->input_changed.connect (mem_fun(*this, &IOSelector::ports_changed));
-
+
const PortSet& ps (_io->inputs());
+ int j = 0;
for (PortSet::const_iterator i = ps.begin(); i != ps.end(); ++i) {
- our_ports.push_back (i->name());
+ char buf[32];
+ snprintf (buf, sizeof(buf), _("in %d"), j + 1);
+ _our_bundle->add_channel (buf);
+ _our_bundle->add_port_to_channel (j, i->name());
+ ++j;
}
}
-
- set_ports (our_ports);
- setup ();
+ PortMatrix::setup ();
}
void
-IOSelector::ports_changed (ARDOUR::IOChange change, void *src)
+IOSelector::ports_changed ()
{
- ENSURE_GUI_THREAD (bind (mem_fun (*this, &IOSelector::ports_changed), change, src));
+ ENSURE_GUI_THREAD (mem_fun (*this, &IOSelector::ports_changed));
setup ();
}
void
-IOSelector::set_state (int r, std::string const & p, bool s, uint32_t keymod)
+IOSelector::set_state (
+ boost::shared_ptr<ARDOUR::Bundle> ab,
+ uint32_t ac,
+ boost::shared_ptr<ARDOUR::Bundle> bb,
+ uint32_t bc,
+ bool s,
+ uint32_t k
+ )
{
- if (s) {
- if (!_offer_inputs) {
- _io->connect_input (_io->input(r), p, 0);
- } else {
- _io->connect_output (_io->output(r), p, 0);
- }
- } else {
- if (!_offer_inputs) {
- _io->disconnect_input (_io->input(r), p, 0);
- } else {
- _io->disconnect_output (_io->output(r), p, 0);
+ ARDOUR::Bundle::PortList const& our_ports = ab->channel_ports (ac);
+ ARDOUR::Bundle::PortList const& other_ports = bb->channel_ports (bc);
+
+ for (ARDOUR::Bundle::PortList::const_iterator i = our_ports.begin(); i != our_ports.end(); ++i) {
+ for (ARDOUR::Bundle::PortList::const_iterator j = other_ports.begin(); j != other_ports.end(); ++j) {
+
+ Port* f = _session.engine().get_port_by_name (*i);
+ if (!f) {
+ return;
+ }
+
+ if (s) {
+ if (!offering_input()) {
+ _io->connect_input (f, *j, 0);
+ } else {
+ _io->connect_output (f, *j, 0);
+ }
+ } else {
+ if (!offering_input()) {
+ _io->disconnect_input (f, *j, 0);
+ } else {
+ _io->disconnect_output (f, *j, 0);
+ }
+ }
}
}
}
bool
-IOSelector::get_state (int r, std::string const & p) const
+IOSelector::get_state (
+ boost::shared_ptr<ARDOUR::Bundle> ab,
+ uint32_t ac,
+ boost::shared_ptr<ARDOUR::Bundle> bb,
+ uint32_t bc
+ ) const
{
- vector<string> connections;
+ ARDOUR::Bundle::PortList const& our_ports = ab->channel_ports (ac);
+ ARDOUR::Bundle::PortList const& other_ports = bb->channel_ports (bc);
- if (_offer_inputs) {
- _io->output(r)->get_connections (connections);
- } else {
- _io->input(r)->get_connections (connections);
+ for (ARDOUR::Bundle::PortList::const_iterator i = our_ports.begin(); i != our_ports.end(); ++i) {
+ for (ARDOUR::Bundle::PortList::const_iterator j = other_ports.begin(); j != other_ports.end(); ++j) {
+
+ Port* f = _session.engine().get_port_by_name (*i);
+ if (!f) {
+ return false;
+ }
+
+ if (!f->connected_to (*j)) {
+ /* if any one thing is not connected, all bets are off */
+ return false;
+ }
+ }
}
- return (std::find (connections.begin (), connections.end (), p) != connections.end ());
+ return true;
}
uint32_t
IOSelector::n_rows () const
{
- if (!_offer_inputs) {
+ if (!offering_input()) {
return _io->inputs().num_ports (_io->default_type());
} else {
return _io->outputs().num_ports (_io->default_type());
@@ -127,7 +178,7 @@ IOSelector::n_rows () const
uint32_t
IOSelector::maximum_rows () const
{
- if (!_offer_inputs) {
+ if (!offering_input()) {
return _io->input_maximum ().get (_io->default_type());
} else {
return _io->output_maximum ().get (_io->default_type());
@@ -138,39 +189,22 @@ IOSelector::maximum_rows () const
uint32_t
IOSelector::minimum_rows () const
{
- if (!_offer_inputs) {
+ if (!offering_input()) {
return _io->input_minimum ().get (_io->default_type());
} else {
return _io->output_minimum ().get (_io->default_type());
}
}
-std::string
-IOSelector::row_name (int r) const
-{
- string n;
- string::size_type pos;
-
- if (!_offer_inputs) {
- n = _io->input(r)->name();
- } else {
- n = _io->output(r)->name();
- }
-
- if ((pos = n.find ('/')) != string::npos) {
- return n.substr (pos+1);
- } else {
- return n;
- }
-}
-
void
-IOSelector::add_row ()
+IOSelector::add_channel (boost::shared_ptr<ARDOUR::Bundle> b)
{
+ /* we ignore the bundle parameter, as we know what it is that we're adding to */
+
// The IO selector only works for single typed IOs
const ARDOUR::DataType t = _io->default_type ();
- if (!_offer_inputs) {
+ if (!offering_input()) {
try {
_io->add_input_port ("", this);
@@ -195,24 +229,20 @@ IOSelector::add_row ()
}
void
-IOSelector::remove_row (int r)
+IOSelector::remove_channel (boost::shared_ptr<ARDOUR::Bundle> b, uint32_t c)
{
- // The IO selector only works for single typed IOs
- const ARDOUR::DataType t = _io->default_type ();
+ Port* f = _session.engine().get_port_by_name (b->channel_ports(c)[0]);
+ if (!f) {
+ return;
+ }
- if (!_offer_inputs) {
- _io->remove_input_port (_io->input (r), this);
+ if (offering_input()) {
+ _io->remove_output_port (f, this);
} else {
- _io->remove_output_port (_io->output (r), this);
+ _io->remove_input_port (f, this);
}
}
-std::string
-IOSelector::row_descriptor () const
-{
- return _("port");
-}
-
IOSelectorWindow::IOSelectorWindow (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::IO> io, bool for_input, bool can_cancel)
: ArdourDialog ("I/O selector")
, _selector (session, io, !for_input)
@@ -223,30 +253,34 @@ IOSelectorWindow::IOSelectorWindow (ARDOUR::Session& session, boost::shared_ptr<
, rescan_button (_("Rescan"))
{
+ /* XXX: what's this for? */
add_events (Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK);
+
set_name ("IOSelectorWindow2");
+ /* Disconnect All button */
disconnect_button.set_name ("IOSelectorButton");
disconnect_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::DISCONNECT, Gtk::ICON_SIZE_BUTTON)));
+ disconnect_button.signal_clicked().connect (sigc::mem_fun (_selector, &IOSelector::disassociate_all));
get_action_area()->pack_start (disconnect_button, false, false);
+ /* Add Port button */
if (_selector.maximum_rows() > _selector.n_rows()) {
add_button.set_name ("IOSelectorButton");
add_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::ADD, Gtk::ICON_SIZE_BUTTON)));
get_action_area()->pack_start (add_button, false, false);
- add_button.signal_clicked().connect (sigc::mem_fun (_selector, &IOSelector::add_row));
+ add_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (_selector, &IOSelector::add_channel), boost::shared_ptr<Bundle> ()));
}
- if (!for_input) {
- io->output_changed.connect (mem_fun(*this, &IOSelectorWindow::ports_changed));
- } else {
- io->input_changed.connect (mem_fun(*this, &IOSelectorWindow::ports_changed));
- }
-
- rescan_button.set_name ("IOSelectorButton");
+ /* Rescan button */
+ rescan_button.set_name ("IOSelectorButton");
rescan_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::REFRESH, Gtk::ICON_SIZE_BUTTON)));
+ rescan_button.signal_clicked().connect (sigc::mem_fun (_selector, &IOSelector::setup));
get_action_area()->pack_start (rescan_button, false, false);
+ io->PortCountChanged.connect (sigc::hide (mem_fun (*this, &IOSelectorWindow::ports_changed)));
+
+ /* Cancel button */
if (can_cancel) {
cancel_button.set_name ("IOSelectorButton");
cancel_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::CANCEL, Gtk::ICON_SIZE_BUTTON)));
@@ -254,37 +288,32 @@ IOSelectorWindow::IOSelectorWindow (ARDOUR::Session& session, boost::shared_ptr<
} else {
cancel_button.hide();
}
-
+ cancel_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::cancel));
+
+ /* OK button */
ok_button.set_name ("IOSelectorButton");
if (!can_cancel) {
ok_button.set_image (*Gtk::manage (new Gtk::Image (Gtk::Stock::CLOSE, Gtk::ICON_SIZE_BUTTON)));
}
+ ok_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::accept));
get_action_area()->pack_start (ok_button, false, false);
get_vbox()->set_spacing (8);
- get_vbox()->pack_start (_selector, true, true);
- suggestion.set_alignment (0.5, 0.5);
- suggestion_box.pack_start (suggestion, true, true);
- get_vbox()->pack_start (suggestion_box, false, false);
-
- ok_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::accept));
- cancel_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::cancel));
- rescan_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::rescan));
+ /* XXX: do we still need the ScrolledWindow? */
+ Gtk::ScrolledWindow* sel_scroll = Gtk::manage (new Gtk::ScrolledWindow);
+ sel_scroll->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_NEVER);
+ sel_scroll->add (_selector);
+ get_vbox()->pack_start (*sel_scroll, true, true);
set_position (Gtk::WIN_POS_MOUSE);
io_name_changed (this);
- ports_changed (IOChange (0), this);
- leave_scroller ((GdkEventCrossing*) 0);
+ ports_changed ();
show_all ();
signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), this));
-
- _selector.scrolled_window().add_events (Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
- _selector.scrolled_window().signal_enter_notify_event().connect (mem_fun (*this, &IOSelectorWindow::enter_scroller), false);
- _selector.scrolled_window().signal_leave_notify_event().connect (mem_fun (*this, &IOSelectorWindow::leave_scroller), false);
}
IOSelectorWindow::~IOSelectorWindow()
@@ -292,24 +321,8 @@ IOSelectorWindow::~IOSelectorWindow()
}
-bool
-IOSelectorWindow::enter_scroller (GdkEventCrossing* ignored)
-{
- cerr << "IN\n";
- suggestion.set_text (_("Click to connect. Ctrl-click to disconnect. Shift-click for cross-connect"));
- return false;
-}
-
-bool
-IOSelectorWindow::leave_scroller (GdkEventCrossing* ignored)
-{
- cerr << "OUT, ev = " << ignored << "\n";
- suggestion.set_text (_("Right-click on individual port names for per-port operations"));
- return false;
-}
-
void
-IOSelectorWindow::ports_changed (ARDOUR::IOChange change, void *src)
+IOSelectorWindow::ports_changed ()
{
if (_selector.maximum_rows() > _selector.n_rows()) {
add_button.set_sensitive (true);
@@ -319,12 +332,6 @@ IOSelectorWindow::ports_changed (ARDOUR::IOChange change, void *src)
}
void
-IOSelectorWindow::rescan ()
-{
- _selector.setup ();
-}
-
-void
IOSelectorWindow::cancel ()
{
_selector.Finished (IOSelector::Cancelled);
@@ -365,10 +372,8 @@ PortInsertUI::PortInsertUI (ARDOUR::Session& sess, boost::shared_ptr<ARDOUR::Por
: input_selector (sess, pi->io(), true),
output_selector (sess, pi->io(), false)
{
- hbox.pack_start (output_selector, true, true);
- hbox.pack_start (input_selector, true, true);
-
- pack_start (hbox);
+ pack_start (output_selector, true, true);
+ pack_start (input_selector, true, true);
}
void
@@ -420,7 +425,6 @@ PortInsertWindow::PortInsertWindow (ARDOUR::Session& sess, boost::shared_ptr<ARD
ok_button.signal_clicked().connect (mem_fun (*this, &PortInsertWindow::accept));
cancel_button.signal_clicked().connect (mem_fun (*this, &PortInsertWindow::cancel));
- rescan_button.signal_clicked().connect (mem_fun (*this, &PortInsertWindow::rescan));
signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), reinterpret_cast<Window *> (this)));
@@ -445,12 +449,6 @@ PortInsertWindow::on_map ()
void
-PortInsertWindow::rescan ()
-{
- _portinsertui.redisplay ();
-}
-
-void
PortInsertWindow::cancel ()
{
_portinsertui.finished (IOSelector::Cancelled);
diff --git a/gtk2_ardour/io_selector.h b/gtk2_ardour/io_selector.h
index 57c6e6db86..fb12de36ba 100644
--- a/gtk2_ardour/io_selector.h
+++ b/gtk2_ardour/io_selector.h
@@ -23,25 +23,47 @@
#include "ardour_dialog.h"
#include "port_matrix.h"
+namespace ARDOUR {
+ class PortInsert;
+}
+
class IOSelector : public PortMatrix {
public:
IOSelector (ARDOUR::Session&, boost::shared_ptr<ARDOUR::IO>, bool);
- void set_state (int, std::string const &, bool, uint32_t);
- bool get_state (int, std::string const &) const;
+ void set_state (
+ boost::shared_ptr<ARDOUR::Bundle>,
+ uint32_t,
+ boost::shared_ptr<ARDOUR::Bundle>,
+ uint32_t,
+ bool,
+ uint32_t
+ );
+
+ bool get_state (
+ boost::shared_ptr<ARDOUR::Bundle>,
+ uint32_t,
+ boost::shared_ptr<ARDOUR::Bundle>,
+ uint32_t
+ ) const;
+
+ void add_channel (boost::shared_ptr<ARDOUR::Bundle>);
+ void remove_channel (boost::shared_ptr<ARDOUR::Bundle>, uint32_t);
+ bool can_rename_channels () const {
+ return false;
+ }
+
uint32_t n_rows () const;
uint32_t maximum_rows () const;
uint32_t minimum_rows () const;
- std::string row_name (int) const;
- void add_row ();
- void remove_row (int);
- std::string row_descriptor () const;
- boost::shared_ptr<ARDOUR::IO> const io() { return _io; }
+ boost::shared_ptr<ARDOUR::IO> const io () { return _io; }
+ void setup ();
private:
+ ARDOUR::Session& _session;
boost::shared_ptr<ARDOUR::IO> _io;
- void ports_changed (ARDOUR::IOChange, void*);
+ void ports_changed ();
};
class IOSelectorWindow : public ArdourDialog
@@ -66,17 +88,11 @@ class IOSelectorWindow : public ArdourDialog
Gtk::Button cancel_button;
Gtk::Button rescan_button;
- Gtk::HBox suggestion_box;
- Gtk::Label suggestion;
-
- void rescan ();
void cancel ();
void accept ();
- void ports_changed (ARDOUR::IOChange change, void *src);
+ void ports_changed ();
void io_name_changed (void *src);
- bool enter_scroller (GdkEventCrossing*);
- bool leave_scroller (GdkEventCrossing*);
};
@@ -89,7 +105,6 @@ class PortInsertUI : public Gtk::VBox
void finished (IOSelector::Result);
private:
- Gtk::HBox hbox;
IOSelector input_selector;
IOSelector output_selector;
};
@@ -111,7 +126,6 @@ class PortInsertWindow : public ArdourDialog
Gtk::Button rescan_button;
Gtk::Frame button_frame;
- void rescan ();
void cancel ();
void accept ();
diff --git a/gtk2_ardour/matrix.cc b/gtk2_ardour/matrix.cc
deleted file mode 100644
index b67081711a..0000000000
--- a/gtk2_ardour/matrix.cc
+++ /dev/null
@@ -1,511 +0,0 @@
-#include <gtkmm.h>
-#include <cairo/cairo.h>
-#include <stdlib.h>
-#include <iostream>
-#include <algorithm>
-#include <stdint.h>
-#include <cmath>
-#include <map>
-#include <vector>
-
-#include "matrix.h"
-#include "port_matrix.h"
-
-using namespace std;
-using namespace Gtk;
-using namespace ARDOUR;
-
-Matrix::Matrix (PortMatrix* p) : _port_matrix (p)
-{
- alloc_width = 0;
- alloc_height = 0;
- line_width = 0;
- line_height = 0;
- labels_y_shift = 0;
- labels_x_shift = 0;
- arc_radius = 0;
- xstep = 0;
- ystep = 0;
- pixmap = 0;
- drawn = false;
- angle_radians = M_PI / 4.0;
- motion_x = -1;
- motion_y = -1;
-
- border = 10;
-
- add_events (Gdk::POINTER_MOTION_MASK|Gdk::LEAVE_NOTIFY_MASK);
-}
-
-void
-Matrix::set_ports (const list<string>& ports)
-{
- ours = ports;
- reset_size ();
-}
-
-void
-Matrix::add_group (PortGroup& pg)
-{
- for (vector<string>::const_iterator s = pg.ports.begin(); s != pg.ports.end(); ++s) {
- others.push_back (OtherPort (*s, pg));
- }
-
- if (pg.visible) {
- reset_size ();
- }
-}
-
-
-void
-Matrix::clear ()
-{
- others.clear ();
- reset_size ();
-}
-
-void
-Matrix::remove_group (PortGroup& pg)
-{
- for (list<OtherPort>::iterator o = others.begin(); o != others.end(); ) {
- if (&(*o).group() == &pg) {
- o = others.erase (o);
- } else {
- ++o;
- }
- }
-
- if (pg.visible) {
- reset_size ();
- }
-}
-
-void
-Matrix::hide_group (PortGroup& pg)
-{
- reset_size();
-}
-
-void
-Matrix::show_group (PortGroup& pg)
-{
- reset_size ();
-}
-
-void
-Matrix::setup_nodes ()
-{
- for (vector<MatrixNode*>::iterator p = nodes.begin(); p != nodes.end(); ++p) {
- delete *p;
- }
-
- nodes.clear ();
-
- nodes.assign (ours.size() * get_visible_others (), 0);
-
- int n, x, y;
- list<string>::iterator m;
- list<OtherPort>::iterator s;
-
- for (n = 0, y = 0, m = ours.begin(); m != ours.end(); ++m, ++y) {
- for (x = 0, s = others.begin(); s != others.end(); ++s) {
- if (s->visible ()) {
- bool const c = _port_matrix->get_state (y, s->name());
- nodes[n] = new MatrixNode (*m, *s, c, x, y);
- n++;
- x++;
- }
- }
- }
-}
-
-
-void
-Matrix::other_name_size_information (double* rotated_width, double* rotated_height, double* typical_height) const
-{
- double w = 0;
- double h = 0;
-
- GdkPixmap* pm = gdk_pixmap_new (NULL, 1, 1, 24);
- gdk_drawable_set_colormap (pm, gdk_colormap_get_system());
- cairo_t* cr = gdk_cairo_create (pm);
-
- for (list<OtherPort>::const_iterator s = others.begin(); s != others.end(); ++s) {
- if (s->visible()) {
-
- cairo_text_extents_t extents;
- cairo_text_extents (cr, s->short_name().c_str(), &extents);
-
- if (extents.width > w) {
- w = extents.width;
- h = extents.height;
- }
- }
- }
-
- cairo_destroy (cr);
- gdk_pixmap_unref (pm);
-
- /* transform */
-
- *rotated_width = fabs (w * cos (angle_radians) + h * sin (angle_radians));
- *rotated_height = fabs (w * sin (angle_radians) + h * cos (angle_radians));
- *typical_height = h;
-}
-
-
-std::pair<int, int>
-Matrix::ideal_size () const
-{
- double rw;
- double rh;
- double th;
-
- other_name_size_information (&rw, &rh, &th);
-
- double const ideal_xstep = th * 2;
- double const ideal_ystep = 16;
-
- uint32_t const visible_others = get_visible_others ();
-
- return std::make_pair (
- int (rw + (2 * border) + ideal_xstep * visible_others),
- int (rh + (2 * border) + ideal_ystep * ours.size ())
- );
-}
-
-
-void
-Matrix::reset_size ()
-{
- double rw;
- double rh;
- double th;
-
- other_name_size_information (&rw, &rh, &th);
-
- /* y shift is the largest transformed text height plus a bit for luck */
- labels_y_shift = int (ceil (rh) + 10);
- /* x shift is the width of the leftmost label */
- labels_x_shift = int (ceil (rw));
-
- uint32_t const visible_others = get_visible_others ();
-
- if (!visible_others) {
- xstep = 1;
- ystep = 1;
- line_width = 1;
- line_height = 1;
- arc_radius = 3;
- return;
- }
-
- if (ours.size () > 1) {
-
- xstep = (alloc_width - labels_x_shift - (2 * border)) / visible_others;
- line_width = xstep * (visible_others - 1);
-
- ystep = (alloc_height - labels_y_shift - (2 * border)) / (ours.size() - 1);
- line_height = ystep * (ours.size() - 1);
-
- } else {
-
- /* we have <= 1 of our ports, so steps don't matter */
-
- xstep = 20;
- ystep = 20;
-
- line_height = (ours.size() - 1) * ystep;
- line_width = visible_others * xstep;
- }
-
- int half_step = min (ystep / 2, xstep / 2);
- if (half_step > 3) {
- arc_radius = half_step - 5;
- } else {
- arc_radius = 3;
- }
-
- arc_radius = min (arc_radius, 10);
-
-
- setup_nodes ();
-
- // cerr << "Based on ours = " << ours.size() << " others = " << others.size()
- // << " dimens = "
- // << " xstep " << xstep << endl
- // << " ystep " << ystep << endl
- // << " line_width " << line_width << endl
- // << " line_height " << line_height << endl
- // << " border " << border << endl
- // << " arc_radius " << arc_radius << endl
- // << " labels_x_shift " << labels_x_shift << endl
- // << " labels_y_shift " << labels_y_shift << endl;
-}
-
-bool
-Matrix::on_motion_notify_event (GdkEventMotion* ev)
-{
- motion_x = ev->x;
- motion_y = ev->y;
- queue_draw ();
- return false;
-}
-
-bool
-Matrix::on_leave_notify_event (GdkEventCrossing *ev)
-{
- motion_x = -1;
- motion_y = -1;
- queue_draw ();
- return false;
-}
-
-void
-Matrix::on_size_request (Requisition* req)
-{
- std::pair<int, int> const is = ideal_size ();
- req->width = is.first;
- req->height = is.second;
-}
-
-MatrixNode*
-Matrix::get_node (int32_t x, int32_t y)
-{
- int const half_xstep = xstep / 2;
- int const half_ystep = ystep / 2;
-
- x -= labels_x_shift + border;
- if (x < -half_xstep) {
- return 0;
- }
-
- y -= labels_y_shift + border;
- if (y < -half_ystep) {
- return 0;
- }
-
- x = (x + half_xstep) / xstep;
- y = (y + half_ystep) / ystep;
-
- x = y * get_visible_others () + x;
-
- if (x >= int32_t (nodes.size())) {
- return 0;
- }
-
- return nodes[x];
-}
-
-bool
-Matrix::on_button_press_event (GdkEventButton* ev)
-{
- MatrixNode* node;
-
- if ((node = get_node (ev->x, ev->y)) != 0) {
- node->set_connected (!node->connected());
- _port_matrix->set_state (node->y (), node->their_name (), node->connected (), 0);
- drawn = false;
- queue_draw();
- return true;
- }
-
- return false;
-}
-
-void
-Matrix::alloc_pixmap ()
-{
- if (pixmap) {
- gdk_pixmap_unref (pixmap);
- }
-
- pixmap = gdk_pixmap_new (get_window()->gobj(),
- alloc_width,
- alloc_height,
- -1);
-
- drawn = false;
-}
-
-void
-Matrix::on_size_allocate (Allocation& alloc)
-{
- EventBox::on_size_allocate (alloc);
-
- alloc_width = alloc.get_width();
- alloc_height = alloc.get_height();
-
- if (is_realized()) {
- alloc_pixmap ();
- reset_size ();
-#ifdef MATRIX_USE_BACKING_PIXMAP
- redraw (pixmap, 0, 0, alloc_width, alloc_height);
-#endif
- }
-}
-
-void
-Matrix::on_realize ()
-{
- EventBox::on_realize ();
- alloc_pixmap ();
-}
-
-void
-Matrix::redraw (GdkDrawable* drawable, GdkRectangle* rect)
-{
- list<string>::iterator o;
- list<OtherPort>::iterator t;
- int x, y;
-
- cairo_t* cr = gdk_cairo_create (drawable);
-
- cairo_set_source_rgb (cr, 0.83, 0.83, 0.83);
- cairo_rectangle (cr, rect->x, rect->y, rect->width, rect->height);
- cairo_fill (cr);
-
- cairo_set_line_width (cr, 0.5);
-
- int32_t const top_shift = labels_y_shift + border;
- int32_t const left_shift = labels_x_shift + border;
-
- /* horizontal grid lines and side labels */
-
- for (y = top_shift, o = ours.begin(); o != ours.end(); ++o, y += ystep) {
-
- cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
- cairo_move_to (cr, left_shift, y);
- cairo_line_to (cr, left_shift+line_width, y);
- cairo_stroke (cr);
-#if 0
-
- cairo_text_extents_t extents;
- cairo_text_extents (cr, (*o).c_str(),&extents);
- cairo_move_to (cr, border, y+extents.height/2);
- cairo_show_text (cr, (*o).c_str());
-#endif
-
- }
-
- /* vertical grid lines and rotated labels*/
-
- for (x = left_shift, t = others.begin(); t != others.end(); ++t, x += xstep) {
-
- cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
- cairo_move_to (cr, x, top_shift);
- cairo_line_to (cr, x, top_shift+line_height);
- cairo_stroke (cr);
-
- cairo_move_to (cr, x-left_shift+12, border);
- cairo_set_source_rgb (cr, 0, 0, 1.0);
-
- cairo_save (cr);
- cairo_rotate (cr, angle_radians);
- cairo_show_text (cr, t->short_name().c_str());
- cairo_restore (cr);
-
- }
-
- /* nodes */
-
- for (vector<MatrixNode*>::iterator n = nodes.begin(); n != nodes.end(); ++n) {
-
- x = (*n)->x() * xstep;
- y = (*n)->y() * ystep;
-
- cairo_new_path (cr);
-
- if (arc_radius) {
- cairo_arc (cr, left_shift+x, top_shift+y, arc_radius, 0, 2.0 * M_PI);
- if ((*n)->connected()) {
- cairo_set_source_rgba (cr, 1.0, 0, 0, 1.0);
- cairo_fill (cr);
- } else {
- cairo_set_source_rgba (cr, 1.0, 0, 0, 0.7);
- cairo_stroke (cr);
- }
- }
- }
-
- /* motion indicators */
-
- if (motion_x >= left_shift && motion_y >= top_shift) {
-
- int col_left = left_shift + ((motion_x + (xstep / 2) + - left_shift) / xstep) * xstep;
- int row_top = top_shift + ((motion_y + (ystep / 2) - top_shift) / ystep) * ystep;
-
- cairo_set_line_width (cr, 5);
- cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.3);
-
- /* horizontal (row) */
-
- cairo_line_to (cr, left_shift, row_top);
- cairo_line_to (cr, left_shift + line_width, row_top);
- cairo_stroke (cr);
-
- /* vertical (col) */
-
- cairo_move_to (cr, col_left, top_shift);
- cairo_line_to (cr, col_left, top_shift + line_height);
- cairo_stroke (cr);
- }
-
- cairo_destroy (cr);
-
-#ifdef MATRIX_USE_BACKING_PIXMAP
- drawn = true;
-#endif
-}
-
-bool
-Matrix::on_expose_event (GdkEventExpose* event)
-{
-#ifdef MATRIX_USE_BACKING_PIXMAP
- if (!drawn) {
- redraw (pixmap, 0, 0, alloc_width, alloc_height);
- }
-
- gdk_draw_drawable (get_window()->gobj(),
- get_style()->get_fg_gc (STATE_NORMAL)->gobj(),
- pixmap,
- event->area.x,
- event->area.y,
- event->area.x,
- event->area.y,
- event->area.width,
- event->area.height);
-#else
- redraw (get_window()->gobj(), &event->area);
-#endif
-
-
-
- return true;
-}
-
-uint32_t
-Matrix::get_visible_others () const
-{
- uint32_t v = 0;
-
- for (list<OtherPort>::const_iterator s = others.begin(); s != others.end(); ++s) {
- if (s->visible()) {
- ++v;
- }
- }
-
- return v;
-}
-
-MatrixNode::MatrixNode (std::string a, OtherPort o, bool c, int32_t x, int32_t y)
- : _name (a), them (o), _connected (c), _x(x), _y(y)
-{
-
-}
-
-std::string
-OtherPort::name () const
-{
- return _group.prefix + _short_name;
-}
diff --git a/gtk2_ardour/matrix.h b/gtk2_ardour/matrix.h
deleted file mode 100644
index a02f2fb397..0000000000
--- a/gtk2_ardour/matrix.h
+++ /dev/null
@@ -1,113 +0,0 @@
-#ifndef __gtk_ardour_matrix_h__
-#define __gtk_ardour_matrix_h__
-
-#include <list>
-#include <vector>
-#include <string>
-#include <stdint.h>
-
-#include <gtkmm/eventbox.h>
-#include <gtkmm/widget.h>
-
-#include "port_group.h"
-
-/// One of the other ports that we're connecting ours to
-class OtherPort {
-public:
- OtherPort (const std::string& n, PortGroup& g)
- : _short_name (n), _group (g) {}
-
- std::string name () const;
- std::string short_name () const { return _short_name; }
- PortGroup& group() const { return _group; }
- bool visible() const { return _group.visible; }
-
-public:
- std::string _short_name;
- PortGroup& _group;
-};
-
-/// A node on the matrix
-class MatrixNode {
- public:
- MatrixNode (std::string, OtherPort, bool, int32_t, int32_t);
- ~MatrixNode() {}
-
- PortGroup& get_group() const { return them.group(); }
-
- std::string our_name() const { return _name; }
- std::string their_name() const { return them.name(); }
-
- bool connected() const { return _connected; }
- void set_connected (bool yn) { _connected = yn; }
- int32_t x() const { return _x; }
- int32_t y() const { return _y; }
-
- private:
- std::string _name;
- OtherPort them;
- bool _connected;
- int32_t _x;
- int32_t _y;
-};
-
-class Matrix : public Gtk::EventBox
-{
- public:
- Matrix (PortMatrix*);
-
- void set_ports (const std::list<std::string>&);
- void add_group (PortGroup&);
- void remove_group (PortGroup&);
- void hide_group (PortGroup&);
- void show_group (PortGroup&);
- void clear ();
-
- int row_spacing () const { return xstep; }
-
- protected:
- bool on_button_press_event (GdkEventButton* ev);
- bool on_expose_event (GdkEventExpose* ev);
- void on_size_allocate (Gtk::Allocation&);
- void on_size_request (Gtk::Requisition*);
- void on_realize ();
- bool on_motion_notify_event (GdkEventMotion*);
- bool on_leave_notify_event (GdkEventCrossing*);
-
- MatrixNode* get_node (int32_t x, int32_t y);
-
-private:
- PortMatrix* _port_matrix; ///< the PortMatrix that we're working for
- int height;
- int width;
- int alloc_width;
- int alloc_height;
- bool drawn;
- int labels_y_shift;
- int labels_x_shift;
- float angle_radians;
- int border;
- int ystep;
- int xstep;
- uint32_t line_height;
- uint32_t line_width;
- int arc_radius;
- int32_t motion_x;
- int32_t motion_y;
-
- std::list<std::string> ours;
- std::list<OtherPort> others;
- std::vector<MatrixNode*> nodes;
-
- void reset_size ();
- void redraw (GdkDrawable*, GdkRectangle*);
- void alloc_pixmap ();
- void setup_nodes ();
- uint32_t get_visible_others () const;
- void other_name_size_information (double *, double *, double *) const;
- std::pair<int, int> ideal_size () const;
-
- GdkPixmap* pixmap;
-};
-
-#endif /* __gtk_ardour_matrix_h__ */
diff --git a/gtk2_ardour/option_editor.cc b/gtk2_ardour/option_editor.cc
index 12f82ccbfd..935197a0ca 100644
--- a/gtk2_ardour/option_editor.cc
+++ b/gtk2_ardour/option_editor.cc
@@ -1120,11 +1120,11 @@ OptionEditor::setup_click_editor ()
click_path_entry.set_sensitive (true);
click_emphasis_path_entry.set_sensitive (true);
- click_io_selector = new IOSelector (*session, session->click_io(), false);
+ click_io_selector = new IOSelector (*session, session->click_io(), true);
click_gpm = new GainMeter (*session);
click_gpm->set_io (session->click_io());
- click_hpacker.pack_start (*click_io_selector, false, false);
+ click_hpacker.pack_start (*click_io_selector, true, true);
click_hpacker.pack_start (*click_gpm, false, false);
click_packer.show_all ();
@@ -1163,11 +1163,11 @@ OptionEditor::setup_auditioner_editor ()
void
OptionEditor::connect_audition_editor ()
{
- auditioner_io_selector = new IOSelector (*session, session->the_auditioner(), false);
+ auditioner_io_selector = new IOSelector (*session, session->the_auditioner(), true);
auditioner_gpm = new GainMeter (*session);
auditioner_gpm->set_io (session->the_auditioner());
- audition_hpacker.pack_start (*auditioner_io_selector, false, false);
+ audition_hpacker.pack_start (*auditioner_io_selector, true, true);
audition_hpacker.pack_start (*auditioner_gpm, false, false);
auditioner_io_selector->show_all ();
diff --git a/gtk2_ardour/port_group.cc b/gtk2_ardour/port_group.cc
index 3de45eee73..4157348d8e 100644
--- a/gtk2_ardour/port_group.cc
+++ b/gtk2_ardour/port_group.cc
@@ -18,28 +18,42 @@
*/
#include "port_group.h"
+#include "port_matrix.h"
#include "i18n.h"
#include "ardour/session.h"
#include "ardour/audio_track.h"
#include "ardour/midi_track.h"
#include "ardour/audioengine.h"
+#include "ardour/bundle.h"
#include <boost/shared_ptr.hpp>
#include <cstring>
using namespace std;
using namespace Gtk;
+/** Add a bundle to a group.
+ * @param b Bundle.
+ */
+void
+PortGroup::add_bundle (boost::shared_ptr<ARDOUR::Bundle> b)
+{
+ bundles.push_back (b);
+}
+
/** Add a port to a group.
- * @param p Port name, with or without prefix.
+ * @param p Port.
*/
void
-PortGroup::add (std::string const & p)
+PortGroup::add_port (std::string const &p)
{
- if (prefix.empty() == false && p.substr (0, prefix.length()) == prefix) {
- ports.push_back (p.substr (prefix.length()));
- } else {
- ports.push_back (p);
- }
+ ports.push_back (p);
+}
+
+void
+PortGroup::clear ()
+{
+ bundles.clear ();
+ ports.clear ();
}
/** PortGroupUI constructor.
@@ -47,14 +61,14 @@ PortGroup::add (std::string const & p)
* @Param g PortGroup to represent.
*/
-PortGroupUI::PortGroupUI (PortMatrix& m, PortGroup& g)
+PortGroupUI::PortGroupUI (PortMatrix* m, PortGroup* g)
: _port_matrix (m)
, _port_group (g)
- , _ignore_check_button_toggle (false)
- , _visibility_checkbutton (g.name)
+ , _visibility_checkbutton (g->name)
{
- _port_group.visible = true;
- _ignore_check_button_toggle = false;
+ _port_group->visible = true;
+ setup_visibility_checkbutton ();
+
_visibility_checkbutton.signal_toggled().connect (sigc::mem_fun (*this, &PortGroupUI::visibility_checkbutton_toggled));
}
@@ -62,66 +76,49 @@ PortGroupUI::PortGroupUI (PortMatrix& m, PortGroup& g)
void
PortGroupUI::visibility_checkbutton_toggled ()
{
- _port_group.visible = _visibility_checkbutton.get_active ();
+ _port_group->visible = _visibility_checkbutton.get_active ();
+ setup_visibility_checkbutton ();
+ _port_matrix->setup ();
}
-/** @return Checkbutton used to toggle visibility */
-Widget&
-PortGroupUI::get_visibility_checkbutton ()
-{
- return _visibility_checkbutton;
-}
-
-
-/** Handle a toggle of a port check button */
+/** Set up the visibility checkbutton according to PortGroup::visible */
void
-PortGroupUI::port_checkbutton_toggled (CheckButton* b, int r, int c)
+PortGroupUI::setup_visibility_checkbutton ()
{
- if (_ignore_check_button_toggle == false) {
- // _port_matrix.hide_group (_port_group);
- }
-}
-
-/** Set up visibility of the port group according to PortGroup::visible */
-void
-PortGroupUI::setup_visibility ()
-{
- if (_visibility_checkbutton.get_active () != _port_group.visible) {
- _visibility_checkbutton.set_active (_port_group.visible);
+ if (_visibility_checkbutton.get_active () != _port_group->visible) {
+ _visibility_checkbutton.set_active (_port_group->visible);
}
}
/** PortGroupList constructor.
- * @param session Session to get ports from.
- * @param type Type of ports to offer (audio or MIDI)
- * @param offer_inputs true to offer output ports, otherwise false.
+ * @param session Session to get bundles from.
+ * @param type Type of bundles to offer (audio or MIDI)
+ * @param offer_inputs true to offer output bundles, otherwise false.
* @param mask Mask of groups to make visible by default.
*/
PortGroupList::PortGroupList (ARDOUR::Session & session, ARDOUR::DataType type, bool offer_inputs, Mask mask)
: _session (session), _type (type), _offer_inputs (offer_inputs),
- _buss (_("Bus"), "ardour:", mask & BUSS),
- _track (_("Track"), "ardour:", mask & TRACK),
- _system (_("System"), "system:", mask & SYSTEM),
- _other (_("Other"), "", mask & OTHER)
+ _buss (_("Bus"), mask & BUSS),
+ _track (_("Track"), mask & TRACK),
+ _system (_("System"), mask & SYSTEM),
+ _other (_("Other"), mask & OTHER)
{
refresh ();
}
-/** Find or re-find all our ports and set up our lists */
+/** Find or re-find all our bundles and set up our lists */
void
PortGroupList::refresh ()
{
clear ();
-
- _buss.ports.clear ();
- _track.ports.clear ();
- _system.ports.clear ();
- _other.ports.clear ();
- /* Find the ports provided by ardour; we can't derive their type just from their
- names, so we'll have to be more devious.
- */
+ _buss.clear ();
+ _track.clear ();
+ _system.clear ();
+ _other.clear ();
+
+ /* Find the bundles for routes */
boost::shared_ptr<ARDOUR::Session::RouteList> routes = _session.get_routes ();
@@ -148,14 +145,12 @@ PortGroupList::refresh ()
}
if (g) {
- ARDOUR::PortSet const & p = _offer_inputs ? ((*i)->inputs()) : ((*i)->outputs());
- for (uint32_t j = 0; j < p.num_ports(); ++j) {
- g->add (p.port(j)->name ());
- }
-
- std::sort (g->ports.begin(), g->ports.end());
+ g->add_bundle (_offer_inputs ? (*i)->bundle_for_inputs() : (*i)->bundle_for_outputs ());
}
}
+
+ /* Bundles created by the session */
+ _session.foreach_bundle (sigc::mem_fun (*this, &PortGroupList::maybe_add_session_bundle));
/* XXX: inserts, sends, plugin inserts? */
@@ -163,9 +158,9 @@ PortGroupList::refresh ()
finding all the ports that we can connect to.
*/
- const char **ports = _session.engine().get_ports ("", _type.to_jack_type(), _offer_inputs ?
- JackPortIsInput : JackPortIsOutput);
- if (ports) {
+ const char **ports = _session.engine().get_ports ("", _type.to_jack_type(), _offer_inputs ?
+ JackPortIsInput : JackPortIsOutput);
+ if (ports) {
int n = 0;
string client_matching_string;
@@ -178,11 +173,11 @@ PortGroupList::refresh ()
if (p.substr(0, strlen ("system:")) == "system:") {
/* system: prefix */
- _system.add (p);
+ _system.add_port (p);
} else {
if (p.substr(0, client_matching_string.length()) != client_matching_string) {
/* other (non-ardour) prefix */
- _other.add (p);
+ _other.add_port (p);
}
}
@@ -198,41 +193,6 @@ PortGroupList::refresh ()
push_back (&_other);
}
-int
-PortGroupList::n_visible_ports () const
-{
- int n = 0;
-
- for (const_iterator i = begin(); i != end(); ++i) {
- if ((*i)->visible) {
- n += (*i)->ports.size();
- }
- }
-
- return n;
-}
-
-std::string
-PortGroupList::get_port_by_index (int n, bool with_prefix) const
-{
- /* XXX: slightly inefficient algorithm */
-
- for (const_iterator i = begin(); i != end(); ++i) {
- for (std::vector<std::string>::const_iterator j = (*i)->ports.begin(); j != (*i)->ports.end(); ++j) {
- if (n == 0) {
- if (with_prefix) {
- return (*i)->prefix + *j;
- } else {
- return *j;
- }
- }
- --n;
- }
- }
-
- return "";
-}
-
void
PortGroupList::set_type (ARDOUR::DataType t)
{
@@ -245,3 +205,10 @@ PortGroupList::set_offer_inputs (bool i)
_offer_inputs = i;
}
+void
+PortGroupList::maybe_add_session_bundle (boost::shared_ptr<ARDOUR::Bundle> b)
+{
+ if (b->ports_are_inputs () == _offer_inputs) {
+ _system.bundles.push_back (b);
+ }
+}
diff --git a/gtk2_ardour/port_group.h b/gtk2_ardour/port_group.h
index 9a38bfc39a..0641d231ef 100644
--- a/gtk2_ardour/port_group.h
+++ b/gtk2_ardour/port_group.h
@@ -22,37 +22,39 @@
#include <vector>
#include <string>
-
#include <gtkmm/widget.h>
#include <gtkmm/checkbutton.h>
-
+#include <boost/shared_ptr.hpp>
#include <ardour/data_type.h>
namespace ARDOUR {
class Session;
- class IO;
- class PortInsert;
+ class Bundle;
}
class PortMatrix;
-/// A list of port names, grouped by some aspect of their type e.g. busses, tracks, system
+/** A list of bundles and ports, grouped by some aspect of their
+ * type e.g. busses, tracks, system. Each group has 0 or more bundles
+ * and 0 or more ports, where the ports are not in the bundles.
+ */
class PortGroup
{
public:
/** PortGroup constructor.
* @param n Name.
- * @param p Port name prefix (including trailing :)
* @param v true if group should be visible in the UI, otherwise false.
*/
- PortGroup (std::string const & n, std::string const & p, bool v)
- : name (n), prefix (p), visible (v) {}
+ PortGroup (std::string const & n, bool v)
+ : name (n), visible (v) {}
- void add (std::string const & p);
+ void add_bundle (boost::shared_ptr<ARDOUR::Bundle>);
+ void add_port (std::string const &);
+ void clear ();
std::string name; ///< name for the group
- std::string prefix; ///< prefix e.g. "ardour:"
- std::vector<std::string> ports; ///< port names
+ std::vector<boost::shared_ptr<ARDOUR::Bundle> > bundles;
+ std::vector<std::string> ports;
bool visible; ///< true if the group is visible in the UI
};
@@ -60,20 +62,18 @@ class PortGroup
class PortGroupUI
{
public:
- PortGroupUI (PortMatrix&, PortGroup&);
+ PortGroupUI (PortMatrix*, PortGroup*);
- Gtk::Widget& get_visibility_checkbutton ();
- PortGroup& port_group () { return _port_group; }
- void setup_visibility ();
+ Gtk::Widget& visibility_checkbutton () {
+ return _visibility_checkbutton;
+ }
private:
- void port_checkbutton_toggled (Gtk::CheckButton*, int, int);
- bool port_checkbutton_release (GdkEventButton* ev, Gtk::CheckButton* b, int r, int c);
void visibility_checkbutton_toggled ();
+ void setup_visibility_checkbutton ();
- PortMatrix& _port_matrix; ///< the PortMatrix that we are working for
- PortGroup& _port_group; ///< the PortGroup that we are representing
- bool _ignore_check_button_toggle;
+ PortMatrix* _port_matrix; ///< the PortMatrix that we are working for
+ PortGroup* _port_group; ///< the PortGroup that we are representing
Gtk::CheckButton _visibility_checkbutton;
};
@@ -91,12 +91,12 @@ class PortGroupList : public std::list<PortGroup*>
PortGroupList (ARDOUR::Session &, ARDOUR::DataType, bool, Mask);
void refresh ();
- int n_visible_ports () const;
- std::string get_port_by_index (int, bool with_prefix = true) const;
void set_type (ARDOUR::DataType);
void set_offer_inputs (bool);
private:
+ void maybe_add_session_bundle (boost::shared_ptr<ARDOUR::Bundle>);
+
ARDOUR::Session& _session;
ARDOUR::DataType _type;
bool _offer_inputs;
diff --git a/gtk2_ardour/port_matrix.cc b/gtk2_ardour/port_matrix.cc
index e04dd3b252..1e9227a525 100644
--- a/gtk2_ardour/port_matrix.cc
+++ b/gtk2_ardour/port_matrix.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2002-2007 Paul Davis
+ Copyright (C) 2002-2009 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,175 +17,205 @@
*/
+#include <iostream>
+#include <gtkmm/scrolledwindow.h>
+#include <gtkmm/adjustment.h>
#include <gtkmm/label.h>
-#include <gtkmm/enums.h>
-#include <gtkmm/menu.h>
-#include <gtkmm/menu_elems.h>
-#include <gtkmm/menuitem.h>
-#include <gtkmm/menushell.h>
-#include <glibmm/objectbase.h>
-#include <gtkmm2ext/doi.h>
-#include "ardour/data_type.h"
-#include "i18n.h"
+#include "ardour/bundle.h"
#include "port_matrix.h"
+#include "i18n.h"
-using namespace Gtk;
-
+/** PortMatrix constructor.
+ * @param session Our session.
+ * @param type Port type that we are handling.
+ * @param offer_inputs true to offer inputs, otherwise false.
+ * @param mask Mask of port groups to offer.
+ */
PortMatrix::PortMatrix (ARDOUR::Session& session, ARDOUR::DataType type, bool offer_inputs, PortGroupList::Mask mask)
- : _offer_inputs (offer_inputs), _port_group_list (session, type, offer_inputs, mask), _type (type), matrix (this)
+ : _offer_inputs (offer_inputs),
+ _port_group_list (session, type, offer_inputs, mask),
+ _type (type),
+ _body (this)
{
- _side_vbox_pad = 0;
-
- _visibility_checkbutton_box.pack_start (*(manage (new Label (_("Connections displayed: ")))), false, false, 10);
- pack_start (_visibility_checkbutton_box, false, false);
-
- _scrolled_window.set_policy (POLICY_ALWAYS, POLICY_AUTOMATIC);
- _scrolled_window.set_shadow_type (SHADOW_NONE);
+ /* checkbuttons for visibility of groups */
+ Gtk::HBox* visibility_buttons = Gtk::manage (new Gtk::HBox);
- _scrolled_window.add (matrix);
+ visibility_buttons->pack_start (*Gtk::manage (new Gtk::Label (_("Show:"))), Gtk::PACK_SHRINK);
+
+ for (std::list<PortGroup*>::iterator i = _port_group_list.begin(); i != _port_group_list.end(); ++i) {
+ _port_group_uis.push_back (new PortGroupUI (this, *i));
+ }
- if (offer_inputs) {
- _overall_hbox.pack_start (_side_vbox, false, false, 6);
- _overall_hbox.pack_start (_scrolled_window, true, true);
- } else {
- _overall_hbox.pack_start (_scrolled_window, true, true, 6);
- _overall_hbox.pack_start (_side_vbox, false, false);
+ for (std::list<PortGroupUI*>::iterator i = _port_group_uis.begin(); i != _port_group_uis.end(); ++i) {
+ visibility_buttons->pack_start ((*i)->visibility_checkbutton(), Gtk::PACK_SHRINK);
}
- pack_start (_overall_hbox);
-}
+ pack_start (*visibility_buttons, Gtk::PACK_SHRINK);
+ pack_start (_hscroll, Gtk::PACK_SHRINK);
+ Gtk::HBox* hbox = Gtk::manage (new Gtk::HBox);
+ hbox->pack_start (_body);
+ hbox->pack_start (_vscroll, Gtk::PACK_SHRINK);
+ pack_start (*hbox);
-PortMatrix::~PortMatrix ()
-{
- clear ();
-}
+ _hscroll.signal_value_changed().connect (sigc::mem_fun (*this, &PortMatrix::hscroll_changed));
+ _vscroll.signal_value_changed().connect (sigc::mem_fun (*this, &PortMatrix::vscroll_changed));
+ setup_scrollbars ();
-void
-PortMatrix::set_ports (const std::list<std::string>& ports)
-{
- matrix.set_ports (ports);
+ /* XXX hard-coded initial size suggestion */
+ set_size_request (400, 200);
+ show_all ();
}
-/** Clear out the things that change when the number of source or destination ports changes */
-void
-PortMatrix::clear ()
+PortMatrix::~PortMatrix ()
{
- /* remove lurking, invisible label and padding */
-
- _side_vbox.children().clear ();
-
- delete _side_vbox_pad;
- _side_vbox_pad = 0;
-
- for (std::vector<PortGroupUI*>::iterator i = _port_group_ui.begin(); i != _port_group_ui.end(); ++i) {
- _visibility_checkbutton_box.remove ((*i)->get_visibility_checkbutton());
+ for (std::list<PortGroupUI*>::iterator i = _port_group_uis.begin(); i != _port_group_uis.end(); ++i) {
delete *i;
}
-
- _port_group_ui.clear ();
}
-/** Set up the dialogue */
void
PortMatrix::setup ()
{
- /* sort out the ports that we'll offer to connect to */
_port_group_list.refresh ();
-
- clear ();
- _side_vbox_pad = new Label (""); /* unmanaged, explicitly deleted */
-
- _side_vbox.pack_start (*_side_vbox_pad, false, false);
- _side_vbox.pack_start (*manage (new Label ("")));
-
- matrix.clear ();
-
- /* Matrix and visibility checkbuttons */
- for (PortGroupList::iterator i = _port_group_list.begin(); i != _port_group_list.end(); ++i) {
-
- PortGroupUI* t = new PortGroupUI (*this, **i);
-
- _port_group_ui.push_back (t);
-
- matrix.add_group (**i);
-
- _visibility_checkbutton_box.pack_start (t->get_visibility_checkbutton(), false, false);
-
- CheckButton* chk = dynamic_cast<CheckButton*>(&t->get_visibility_checkbutton());
-
- if (chk) {
- chk->signal_toggled().connect (sigc::mem_fun (*this, &PortMatrix::reset_visibility));
+ std::vector<boost::shared_ptr<ARDOUR::Bundle> > column;
+ std::vector<boost::shared_ptr<ARDOUR::Bundle> > row;
+
+ for (PortGroupList::iterator i = _port_group_list.begin (); i != _port_group_list.end (); ++i) {
+ if ((*i)->visible) {
+
+ std::copy ((*i)->bundles.begin(), (*i)->bundles.end(), std::back_inserter (column));
+
+ /* make a bundle for the ports, if there are any */
+ if (!(*i)->ports.empty()) {
+
+ boost::shared_ptr<ARDOUR::Bundle> b (new ARDOUR::Bundle ("", _type, !_offer_inputs));
+
+ std::string const pre = common_prefix ((*i)->ports);
+ if (!pre.empty()) {
+ b->set_name (pre.substr (0, pre.length() - 1));
+ }
+
+ for (uint32_t j = 0; j < (*i)->ports.size(); ++j) {
+ std::string const p = (*i)->ports[j];
+ b->add_channel (p.substr (pre.length()));
+ b->set_port (j, p);
+ }
+
+ column.push_back (b);
+ }
}
}
- show_all ();
+ row.push_back (_our_bundle);
- reset_visibility ();
+ _body.setup (row, column);
+ setup_scrollbars ();
+ queue_draw ();
}
void
-PortMatrix::reset_visibility ()
+PortMatrix::set_offer_inputs (bool s)
{
- for (std::vector<PortGroupUI*>::iterator i = _port_group_ui.begin(); i != _port_group_ui.end(); ++i) {
+ _offer_inputs = s;
+ _port_group_list.set_offer_inputs (s);
+ setup ();
+}
- (*i)->setup_visibility ();
-
- if ((*i)->port_group().visible) {
- matrix.show_group ((*i)->port_group());
- } else {
- matrix.hide_group ((*i)->port_group());
- }
- }
+void
+PortMatrix::set_type (ARDOUR::DataType t)
+{
+ _type = t;
+ _port_group_list.set_type (t);
+ setup ();
}
+void
+PortMatrix::hscroll_changed ()
+{
+ _body.set_xoffset (_hscroll.get_adjustment()->get_value());
+}
-/** Handle a button press on a row label */
-bool
-PortMatrix::row_label_button_pressed (GdkEventButton* e, int r)
+void
+PortMatrix::vscroll_changed ()
{
- if (e->type != GDK_BUTTON_PRESS || e->button != 3) {
- return false;
- }
+ _body.set_yoffset (_vscroll.get_adjustment()->get_value());
+}
- Menu* menu = manage (new Menu);
- Menu_Helpers::MenuList& items = menu->items ();
- menu->set_name ("ArdourContextMenu");
+void
+PortMatrix::setup_scrollbars ()
+{
+ Gtk::Adjustment* a = _hscroll.get_adjustment ();
+ a->set_lower (0);
+ a->set_upper (_body.full_scroll_width());
+ a->set_page_size (_body.alloc_scroll_width());
+ a->set_step_increment (32);
+ a->set_page_increment (128);
+
+ a = _vscroll.get_adjustment ();
+ a->set_lower (0);
+ a->set_upper (_body.full_scroll_height());
+ a->set_page_size (_body.alloc_scroll_height());
+ a->set_step_increment (32);
+ a->set_page_increment (128);
+}
- bool const can_add = maximum_rows () > n_rows ();
- bool const can_remove = minimum_rows () < n_rows ();
- std::string const name = row_name (r);
+std::string
+PortMatrix::common_prefix (std::vector<std::string> const & p) const
+{
+ /* common prefix before '/' ? */
+ if (p[0].find_first_of ("/") != std::string::npos) {
+ std::string const fp = p[0].substr (0, (p[0].find_first_of ("/") + 1));
+ uint32_t j = 1;
+ while (j < p.size()) {
+ if (p[j].substr (0, fp.length()) != fp) {
+ break;
+ }
+ ++j;
+ }
+
+ if (j == p.size()) {
+ return fp;
+ }
+ }
- items.push_back (
- Menu_Helpers::MenuElem (string_compose(_("Add %1"), row_descriptor()), sigc::mem_fun (*this, &PortMatrix::add_row))
- );
-
- items.back().set_sensitive (can_add);
-
- items.push_back (
- Menu_Helpers::MenuElem (string_compose(_("Remove %1 \"%2\""), row_descriptor(), name), sigc::bind (sigc::mem_fun (*this, &PortMatrix::remove_row), r))
- );
-
- items.back().set_sensitive (can_remove);
+ /* or before ':' ? */
+ if (p[0].find_first_of (":") != std::string::npos) {
+ std::string const fp = p[0].substr (0, (p[0].find_first_of (":") + 1));
+ uint32_t j = 1;
+ while (j < p.size()) {
+ if (p[j].substr (0, fp.length()) != fp) {
+ break;
+ }
+ ++j;
+ }
+
+ if (j == p.size()) {
+ return fp;
+ }
+ }
- menu->popup (e->button, e->time);
-
- return true;
+ return "";
}
void
-PortMatrix::set_type (ARDOUR::DataType t)
+PortMatrix::disassociate_all ()
{
- _type = t;
- _port_group_list.set_type (t);
- setup ();
-}
+ for (PortGroupList::iterator i = _port_group_list.begin(); i != _port_group_list.end(); ++i) {
+
+ for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::iterator j = (*i)->bundles.begin(); j != (*i)->bundles.end(); ++j) {
-void
-PortMatrix::set_offer_inputs (bool i)
-{
- _offer_inputs = i;
- _port_group_list.set_offer_inputs (i);
- setup ();
-}
+ for (uint32_t k = 0; k < (*j)->nchannels(); ++k) {
+
+ for (uint32_t l = 0; l < _our_bundle->nchannels(); ++l) {
+ set_state (
+ _our_bundle, l, *j, k, false, 0
+ );
+ }
+ }
+ }
+ }
+
+ _body.repaint_grid ();
+}
diff --git a/gtk2_ardour/port_matrix.h b/gtk2_ardour/port_matrix.h
index 27f295b89d..37c05553f1 100644
--- a/gtk2_ardour/port_matrix.h
+++ b/gtk2_ardour/port_matrix.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2002-2007 Paul Davis
+ Copyright (C) 2002-2009 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,32 +17,43 @@
*/
-#ifndef __ardour_ui_port_matrix_h__
-#define __ardour_ui_port_matrix_h__
+#ifndef __gtk_ardour_port_matrix_h__
+#define __gtk_ardour_port_matrix_h__
+#include <list>
#include <gtkmm/box.h>
-#include <gtkmm/checkbutton.h>
-#include <gtkmm/table.h>
-#include <gtkmm/frame.h>
-#include <gtkmm/eventbox.h>
-#include <gtkmm/scrolledwindow.h>
-
-#include "ardour_dialog.h"
+#include <gtkmm/scrollbar.h>
+#include <boost/shared_ptr.hpp>
+#include "port_matrix_body.h"
#include "port_group.h"
-#include "matrix.h"
+
+/** The `port matrix' UI. This is a widget which lets the user alter
+ * associations between one set of ports and another. e.g. to connect
+ * things together.
+ *
+ * The columns are labelled with various ports from around Ardour and the
+ * system.
+ *
+ * It is made up of a body, PortMatrixBody, which is rendered using cairo,
+ * and some scrollbars. All of this is arranged inside the VBox that we
+ * inherit from.
+ */
namespace ARDOUR {
- class Session;
- class IO;
- class PortInsert;
+ class Bundle;
}
-class PortMatrix : public Gtk::VBox {
- public:
+class PortMatrix : public Gtk::VBox
+{
+public:
PortMatrix (ARDOUR::Session&, ARDOUR::DataType, bool, PortGroupList::Mask);
~PortMatrix ();
- void setup ();
+ virtual void setup ();
+ void set_offer_inputs (bool);
+ void set_type (ARDOUR::DataType);
+ bool offering_input () const { return _offer_inputs; }
+ void disassociate_all ();
enum Result {
Cancelled,
@@ -51,55 +62,63 @@ class PortMatrix : public Gtk::VBox {
sigc::signal<void, Result> Finished;
- void set_type (ARDOUR::DataType);
- void set_offer_inputs (bool);
- bool offering_input() const { return _offer_inputs; }
-
- /** @param r Our row index.
- * @param p Other port.
+ /** @param ab Our bundle.
+ * @param ac Channel on our bundle.
+ * @param bb Other bundle.
+ * @arapm bc Channel on other bundle.
* @param s New state.
* @param k XXX
*/
- virtual void set_state (int r, std::string const & p, bool s, uint32_t k) = 0;
-
- /** @param r Our row index.
- * @param p Other port.
+ virtual void set_state (
+ boost::shared_ptr<ARDOUR::Bundle> ab,
+ uint32_t ac,
+ boost::shared_ptr<ARDOUR::Bundle> bb,
+ uint32_t bc,
+ bool s,
+ uint32_t k
+ ) = 0;
+
+ /** @param ab Our bundle.
+ * @param ac Channel on our bundle.
+ * @param bb Other bundle.
+ * @arapm bc Channel on other bundle.
* @return true if r is connected to p, otherwise false.
*/
- virtual bool get_state (int r, std::string const &p) const = 0;
+ virtual bool get_state (
+ boost::shared_ptr<ARDOUR::Bundle> ab,
+ uint32_t ac,
+ boost::shared_ptr<ARDOUR::Bundle> bb,
+ uint32_t bc
+ ) const = 0;
+
+ virtual void add_channel (boost::shared_ptr<ARDOUR::Bundle>) = 0;
+ virtual void remove_channel (boost::shared_ptr<ARDOUR::Bundle>, uint32_t) = 0;
+ virtual bool can_rename_channels () const = 0;
+ virtual void rename_channel (boost::shared_ptr<ARDOUR::Bundle>, uint32_t) {}
- virtual uint32_t n_rows () const = 0;
- virtual uint32_t maximum_rows () const = 0;
- virtual uint32_t minimum_rows () const = 0;
- virtual std::string row_name (int) const = 0;
- virtual void add_row () = 0;
- virtual void remove_row (int) = 0;
- virtual std::string row_descriptor () const = 0;
-
- Gtk::Widget& scrolled_window() { return _scrolled_window; }
+ void setup_scrollbars ();
- protected:
+protected:
+ /// our bundle
+ boost::shared_ptr<ARDOUR::Bundle> _our_bundle;
+
+private:
+ void hscroll_changed ();
+ void vscroll_changed ();
+ std::string common_prefix (std::vector<std::string> const &) const;
+
+ /// true to offer inputs, otherwise false
bool _offer_inputs;
- void set_ports (const std::list<std::string>&);
-
- private:
+ /// list of port groups
PortGroupList _port_group_list;
+ /// port type that we are working with
ARDOUR::DataType _type;
- Matrix matrix;
- std::vector<PortGroupUI*> _port_group_ui;
- std::vector<Gtk::EventBox*> _row_labels;
- Gtk::VBox* _row_labels_vbox;
- Gtk::HBox _overall_hbox;
- Gtk::VBox _side_vbox;
- Gtk::HBox _port_group_hbox;
- Gtk::ScrolledWindow _scrolled_window;
- Gtk::Label* _side_vbox_pad;
- Gtk::HBox _visibility_checkbutton_box;
-
- void clear ();
- bool row_label_button_pressed (GdkEventButton*, int);
- void reset_visibility ();
+
+ PortMatrixBody _body;
+ Gtk::HScrollbar _hscroll;
+ Gtk::VScrollbar _vscroll;
+ std::list<PortGroupUI*> _port_group_uis;
};
#endif
diff --git a/gtk2_ardour/port_matrix_body.cc b/gtk2_ardour/port_matrix_body.cc
new file mode 100644
index 0000000000..d30dca5e85
--- /dev/null
+++ b/gtk2_ardour/port_matrix_body.cc
@@ -0,0 +1,269 @@
+/*
+ Copyright (C) 2002-2009 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.
+
+*/
+
+#include <iostream>
+#include "ardour/bundle.h"
+#include "port_matrix_body.h"
+#include "port_matrix.h"
+
+PortMatrixBody::PortMatrixBody (PortMatrix* p)
+ : _port_matrix (p),
+ _column_labels (this),
+ _row_labels (p, this),
+ _grid (p, this),
+ _alloc_width (0),
+ _alloc_height (0),
+ _alloc_xdiv (0),
+ _alloc_ydiv (0),
+ _xoffset (0),
+ _yoffset (0)
+{
+
+}
+
+
+bool
+PortMatrixBody::on_expose_event (GdkEventExpose* event)
+{
+ Gdk::Rectangle const exposure (
+ event->area.x, event->area.y, event->area.width, event->area.height
+ );
+
+ Gdk::Rectangle const col (0, 0, _alloc_width, _alloc_ydiv);
+ Gdk::Rectangle const row (_alloc_xdiv, _alloc_ydiv, _alloc_width - _alloc_xdiv, _alloc_height - _alloc_ydiv);
+ Gdk::Rectangle const grid (0, _alloc_ydiv, _alloc_xdiv, _alloc_height - _alloc_ydiv);
+
+ bool intersects;
+ Gdk::Rectangle r = exposure;
+ r.intersect (col, intersects);
+
+ if (intersects) {
+ gdk_draw_drawable (
+ get_window()->gobj(),
+ get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
+ _column_labels.get_pixmap (get_window()->gobj()),
+ r.get_x() + _xoffset,
+ r.get_y(),
+ r.get_x(),
+ r.get_y(),
+ r.get_width(),
+ r.get_height()
+ );
+ }
+
+ r = exposure;
+ r.intersect (row, intersects);
+
+ if (intersects) {
+ gdk_draw_drawable (
+ get_window()->gobj(),
+ get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
+ _row_labels.get_pixmap (get_window()->gobj()),
+ r.get_x() - _alloc_xdiv,
+ r.get_y() + _yoffset - _alloc_ydiv,
+ r.get_x(),
+ r.get_y(),
+ r.get_width(),
+ r.get_height()
+ );
+ }
+
+ r = exposure;
+ r.intersect (grid, intersects);
+
+ if (intersects) {
+ gdk_draw_drawable (
+ get_window()->gobj(),
+ get_style()->get_fg_gc (Gtk::STATE_NORMAL)->gobj(),
+ _grid.get_pixmap (get_window()->gobj()),
+ r.get_x() + _xoffset,
+ r.get_y() + _yoffset - _alloc_ydiv,
+ r.get_x(),
+ r.get_y(),
+ r.get_width(),
+ r.get_height()
+ );
+ }
+
+ return true;
+}
+
+void
+PortMatrixBody::on_size_request (Gtk::Requisition *req)
+{
+ std::pair<int, int> const col = _column_labels.dimensions ();
+ std::pair<int, int> const row = _row_labels.dimensions ();
+ std::pair<int, int> const grid = _grid.dimensions ();
+
+ req->width = std::max (col.first, grid.first + row.first);
+ req->height = col.second + grid.second;
+}
+
+void
+PortMatrixBody::on_size_allocate (Gtk::Allocation& alloc)
+{
+ Gtk::EventBox::on_size_allocate (alloc);
+ set_allocation (alloc);
+
+ _alloc_width = alloc.get_width ();
+ _alloc_height = alloc.get_height ();
+
+ compute_divs ();
+ _port_matrix->setup_scrollbars ();
+}
+
+void
+PortMatrixBody::compute_divs ()
+{
+ std::pair<uint32_t, uint32_t> const col = _column_labels.dimensions ();
+ if (_alloc_height > col.second) {
+ /* allocated height is enough for the column labels */
+ _alloc_ydiv = col.second;
+ } else {
+ /* not enough space for the column labels */
+ _alloc_ydiv = _alloc_height;
+ }
+
+ std::pair<uint32_t, uint32_t> const grid = _grid.dimensions ();
+ std::pair<uint32_t, uint32_t> const row = _row_labels.dimensions ();
+
+ if (_alloc_width > (grid.first + row.first)) {
+ /* allocated width is larger than we need, so
+ put the x division at the extent of the grid */
+ _alloc_xdiv = grid.first;
+ } else if (_alloc_width > row.first) {
+ /* allocated width is large enough for the row labels
+ but not for the whole grid, so display the whole
+ row label section and cut part of the grid off */
+ _alloc_xdiv = _alloc_width - row.first;
+ } else {
+ /* allocated width isn't even enough for the row labels */
+ _alloc_xdiv = 0;
+ }
+}
+
+void
+PortMatrixBody::setup (
+ std::vector<boost::shared_ptr<ARDOUR::Bundle> > const & row,
+ std::vector<boost::shared_ptr<ARDOUR::Bundle> > const & column
+ )
+{
+ for (std::list<sigc::connection>::iterator i = _bundle_connections.begin(); i != _bundle_connections.end(); ++i) {
+ i->disconnect ();
+ }
+
+ _bundle_connections.clear ();
+
+ _row_bundles = row;
+ _column_bundles = column;
+
+ for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::iterator i = _row_bundles.begin(); i != _row_bundles.end(); ++i) {
+
+ _bundle_connections.push_back (
+ (*i)->NameChanged.connect (sigc::mem_fun (*this, &PortMatrixBody::repaint_row_labels))
+ );
+
+ }
+
+ for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::iterator i = _column_bundles.begin(); i != _column_bundles.end(); ++i) {
+ _bundle_connections.push_back (
+ (*i)->NameChanged.connect (sigc::mem_fun (*this, &PortMatrixBody::repaint_column_labels))
+ );
+ }
+
+ _column_labels.setup ();
+ _row_labels.setup ();
+ _grid.setup ();
+
+ compute_divs ();
+}
+
+uint32_t
+PortMatrixBody::full_scroll_width ()
+{
+ return _grid.dimensions().first;
+
+}
+
+uint32_t
+PortMatrixBody::alloc_scroll_width ()
+{
+ return _alloc_xdiv;
+}
+
+uint32_t
+PortMatrixBody::full_scroll_height ()
+{
+ return _grid.dimensions().second;
+}
+
+uint32_t
+PortMatrixBody::alloc_scroll_height ()
+{
+ return _alloc_height - _alloc_ydiv;
+}
+
+void
+PortMatrixBody::set_xoffset (uint32_t xo)
+{
+ _xoffset = xo;
+ queue_draw ();
+}
+
+void
+PortMatrixBody::set_yoffset (uint32_t yo)
+{
+ _yoffset = yo;
+ queue_draw ();
+}
+
+bool
+PortMatrixBody::on_button_press_event (GdkEventButton* ev)
+{
+ if (ev->x < _alloc_xdiv && ev->y > _alloc_ydiv) {
+ _grid.button_press (ev->x + _xoffset, ev->y + _yoffset - _alloc_ydiv, ev->button);
+ } else if (ev->x > _alloc_xdiv && ev->y > _alloc_ydiv) {
+ _row_labels.button_press (ev->x - _alloc_xdiv, ev->y + _yoffset - _alloc_ydiv, ev->button, ev->time);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void
+PortMatrixBody::repaint_grid ()
+{
+ _grid.require_render ();
+ queue_draw ();
+}
+
+void
+PortMatrixBody::repaint_column_labels ()
+{
+ _column_labels.require_render ();
+ queue_draw ();
+}
+
+void
+PortMatrixBody::repaint_row_labels ()
+{
+ _row_labels.require_render ();
+ queue_draw ();
+}
diff --git a/gtk2_ardour/port_matrix_body.h b/gtk2_ardour/port_matrix_body.h
new file mode 100644
index 0000000000..503bb3ab62
--- /dev/null
+++ b/gtk2_ardour/port_matrix_body.h
@@ -0,0 +1,94 @@
+/*
+ Copyright (C) 2002-2009 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 __gtk_ardour_port_matrix_body_h__
+#define __gtk_ardour_port_matrix_body_h__
+
+#include "port_matrix_column_labels.h"
+#include "port_matrix_row_labels.h"
+#include "port_matrix_grid.h"
+
+class PortMatrix;
+
+/** The main body of the port matrix. It is made up of three parts:
+ * column labels, grid and row labels, each drawn using cairo.
+ * This class handles the arrangement of these parts.
+ */
+class PortMatrixBody : public Gtk::EventBox
+{
+public:
+ PortMatrixBody (PortMatrix *);
+
+ /** @return bundles to offer for columns */
+ std::vector<boost::shared_ptr<ARDOUR::Bundle> > const & column_bundles () {
+ return _column_bundles;
+ }
+
+ /** @return bundles to offer for rows */
+ std::vector<boost::shared_ptr<ARDOUR::Bundle> > const & row_bundles () {
+ return _row_bundles;
+ }
+
+ void setup (
+ std::vector<boost::shared_ptr<ARDOUR::Bundle> > const &,
+ std::vector<boost::shared_ptr<ARDOUR::Bundle> > const &
+ );
+
+ uint32_t full_scroll_width ();
+ uint32_t alloc_scroll_width ();
+ uint32_t full_scroll_height ();
+ uint32_t alloc_scroll_height ();
+
+ void set_xoffset (uint32_t);
+ void set_yoffset (uint32_t);
+
+ void repaint_grid ();
+
+protected:
+ bool on_expose_event (GdkEventExpose *);
+ void on_size_request (Gtk::Requisition *);
+ void on_size_allocate (Gtk::Allocation &);
+ bool on_button_press_event (GdkEventButton *);
+
+private:
+ void compute_divs ();
+ void repaint_column_labels ();
+ void repaint_row_labels ();
+
+ PortMatrix* _port_matrix;
+ PortMatrixColumnLabels _column_labels;
+ PortMatrixRowLabels _row_labels;
+ PortMatrixGrid _grid;
+
+ uint32_t _alloc_width; ///< allocated width
+ uint32_t _alloc_height; ///< allocated height
+ uint32_t _alloc_xdiv; ///< position of the division between grid and row labels
+ uint32_t _alloc_ydiv; ///< position of the division between column labels and grid
+ uint32_t _xoffset;
+ uint32_t _yoffset;
+
+ /// bundles to offer for columns
+ std::vector<boost::shared_ptr<ARDOUR::Bundle> > _column_bundles;
+ /// bundles to offer for rows
+ std::vector<boost::shared_ptr<ARDOUR::Bundle> > _row_bundles;
+
+ std::list<sigc::connection> _bundle_connections;
+};
+
+#endif
diff --git a/gtk2_ardour/port_matrix_column_labels.cc b/gtk2_ardour/port_matrix_column_labels.cc
new file mode 100644
index 0000000000..343d225b55
--- /dev/null
+++ b/gtk2_ardour/port_matrix_column_labels.cc
@@ -0,0 +1,199 @@
+/*
+ Copyright (C) 2002-2009 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.
+
+*/
+
+#include <iostream>
+#include "ardour/bundle.h"
+#include "port_matrix_column_labels.h"
+#include "port_matrix.h"
+
+PortMatrixColumnLabels::PortMatrixColumnLabels (PortMatrixBody* b)
+ : PortMatrixComponent (b)
+{
+
+}
+
+void
+PortMatrixColumnLabels::compute_dimensions ()
+{
+ GdkPixmap* pm = gdk_pixmap_new (NULL, 1, 1, 24);
+ gdk_drawable_set_colormap (pm, gdk_colormap_get_system());
+ cairo_t* cr = gdk_cairo_create (pm);
+
+ /* width of the longest bundle name */
+ _longest_bundle_name = 0;
+ /* width of the longest channel name */
+ _longest_channel_name = 0;
+ /* height of highest bit of text */
+ _highest_text = 0;
+
+ for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->column_bundles().begin (); i != _body->column_bundles().end(); ++i) {
+
+ cairo_text_extents_t ext;
+ cairo_text_extents (cr, (*i)->name().c_str(), &ext);
+ if (ext.width > _longest_bundle_name) {
+ _longest_bundle_name = ext.width;
+ }
+ if (ext.height > _highest_text) {
+ _highest_text = ext.height;
+ }
+
+ for (uint32_t j = 0; j < (*i)->nchannels (); ++j) {
+
+ cairo_text_extents (
+ cr,
+ (*i)->channel_name (j).c_str(),
+ &ext
+ );
+
+ if (ext.width > _longest_channel_name) {
+ _longest_channel_name = ext.width;
+ }
+ if (ext.height > _highest_text) {
+ _highest_text = ext.height;
+ }
+ }
+ }
+
+ cairo_destroy (cr);
+ gdk_pixmap_unref (pm);
+
+ /* width and height of the whole thing */
+
+ _width = 0;
+ for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->column_bundles().begin (); i != _body->column_bundles().end(); ++i) {
+ _width += (*i)->nchannels() * column_width();
+ }
+
+ _height =
+ (_longest_bundle_name + _longest_channel_name + 4 * name_pad()) * sin (angle())
+ + _highest_text * cos (angle());
+
+ _width += _height / tan (angle ());
+}
+
+uint32_t
+PortMatrixColumnLabels::basic_text_x_pos (int c) const
+{
+ return column_width() / 2 +
+ _highest_text / (2 * sin (angle ()));
+}
+
+void
+PortMatrixColumnLabels::render (cairo_t* cr)
+{
+ /* BACKGROUND */
+
+ set_source_rgb (cr, background_colour());
+ cairo_rectangle (cr, 0, 0, _width, _height);
+ cairo_fill (cr);
+
+ /* BUNDLE PARALLELOGRAM-TYPE-THING AND NAME */
+
+ uint32_t x = 0;
+ for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->column_bundles().begin (); i != _body->column_bundles().end(); ++i) {
+
+ Gdk::Color colour = get_a_bundle_colour (i - _body->column_bundles().begin ());
+ set_source_rgb (cr, colour);
+
+ uint32_t const w = (*i)->nchannels() * column_width();
+
+ uint32_t x_ = x;
+ uint32_t y_ = _height;
+
+ cairo_move_to (cr, x_, y_);
+ x_ += w;
+ cairo_line_to (cr, x_, y_);
+ x_ += _height / tan (angle ());
+ y_ -= _height;
+ cairo_line_to (cr, x_, y_);
+ x_ -= w;
+ cairo_line_to (cr, x_, y_);
+ cairo_line_to (cr, x, _height);
+ cairo_fill_preserve (cr);
+ set_source_rgb (cr, background_colour());
+ cairo_set_line_width (cr, label_border_width());
+ cairo_stroke (cr);
+
+ set_source_rgb (cr, text_colour());
+
+ uint32_t const rl = 3 * name_pad() + _longest_channel_name;
+
+ cairo_move_to (
+ cr,
+ x + basic_text_x_pos (0) + rl * cos (angle()),
+ _height - rl * sin (angle())
+ );
+
+ cairo_save (cr);
+ cairo_rotate (cr, -angle());
+ cairo_show_text (cr, (*i)->name().c_str());
+ cairo_restore (cr);
+
+ x += (*i)->nchannels () * column_width();
+ }
+
+
+ /* PORT NAMES */
+
+ x = 0;
+ for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->column_bundles().begin(); i != _body->column_bundles().end(); ++i) {
+
+ for (uint32_t j = 0; j < (*i)->nchannels(); ++j) {
+
+ uint32_t const p = _longest_channel_name + (2 * name_pad());
+ uint32_t const w = column_width();
+
+ uint32_t x_ = x;
+ uint32_t y_ = _height;
+ cairo_move_to (cr, x_, y_);
+ x_ += w;
+ cairo_line_to (cr, x_, y_);
+ x_ += p * cos (angle());
+ y_ -= p * sin (angle());
+ cairo_line_to (cr, x_, y_);
+ x_ -= column_width() * pow (sin (angle()), 2);
+ y_ -= column_width() * sin (angle()) * cos (angle());
+ cairo_line_to (cr, x_, y_);
+ cairo_line_to (cr, x, _height);
+
+ Gdk::Color colour = get_a_bundle_colour (i - _body->column_bundles().begin());
+ set_source_rgb (cr, colour);
+ cairo_fill_preserve (cr);
+ set_source_rgb (cr, background_colour());
+ cairo_set_line_width (cr, label_border_width());
+ cairo_stroke (cr);
+
+ set_source_rgb (cr, text_colour());
+ cairo_move_to (cr, x + basic_text_x_pos(j), _height - name_pad() * sin (angle()));
+
+ cairo_save (cr);
+ cairo_rotate (cr, -angle());
+
+ cairo_show_text (
+ cr,
+ (*i)->channel_name(j).c_str()
+ );
+
+ cairo_restore (cr);
+
+ x += column_width();
+ }
+ }
+}
+
diff --git a/gtk2_ardour/port_matrix_column_labels.h b/gtk2_ardour/port_matrix_column_labels.h
new file mode 100644
index 0000000000..3c9ff41838
--- /dev/null
+++ b/gtk2_ardour/port_matrix_column_labels.h
@@ -0,0 +1,49 @@
+/*
+ Copyright (C) 2002-2009 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 __port_matrix_column_labels_h__
+#define __port_matrix_column_labels_h__
+
+#include <boost/shared_ptr.hpp>
+#include "port_matrix_component.h"
+
+class PortMatrixBody;
+
+namespace ARDOUR {
+ class Bundle;
+}
+
+/** The column labels part of the port matrix */
+class PortMatrixColumnLabels : public PortMatrixComponent
+{
+public:
+ PortMatrixColumnLabels (PortMatrixBody *);
+
+private:
+ void render (cairo_t *);
+ void compute_dimensions ();
+ uint32_t basic_text_x_pos (int) const;
+
+ std::vector<boost::shared_ptr<ARDOUR::Bundle> > _bundles;
+ uint32_t _longest_bundle_name;
+ uint32_t _longest_channel_name;
+ uint32_t _highest_text;
+};
+
+#endif
diff --git a/gtk2_ardour/port_matrix_component.cc b/gtk2_ardour/port_matrix_component.cc
new file mode 100644
index 0000000000..e2d1e07027
--- /dev/null
+++ b/gtk2_ardour/port_matrix_component.cc
@@ -0,0 +1,107 @@
+/*
+ Copyright (C) 2002-2009 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.
+
+*/
+
+#include <iostream>
+#include "port_matrix_component.h"
+
+/** Constructor.
+ * @param p Port matrix that we're in.
+ */
+PortMatrixComponent::PortMatrixComponent (PortMatrixBody* b)
+ : _body (b),
+ _pixmap (0),
+ _render_required (true),
+ _dimension_computation_required (true)
+{
+
+}
+
+/** Destructor */
+PortMatrixComponent::~PortMatrixComponent ()
+{
+ if (_pixmap) {
+ gdk_pixmap_unref (_pixmap);
+ }
+}
+
+void
+PortMatrixComponent::setup ()
+{
+ _dimension_computation_required = true;
+ _render_required = true;
+}
+
+GdkPixmap *
+PortMatrixComponent::get_pixmap (GdkDrawable *drawable)
+{
+ if (_render_required) {
+
+ if (_dimension_computation_required) {
+ compute_dimensions ();
+ _dimension_computation_required = false;
+ }
+
+ /* we may be zero width or height; if so, just
+ use the smallest allowable pixmap */
+ if (_width == 0) {
+ _width = 1;
+ }
+ if (_height == 0) {
+ _height = 1;
+ }
+
+ /* make a pixmap of the right size */
+ if (_pixmap) {
+ gdk_pixmap_unref (_pixmap);
+ }
+ _pixmap = gdk_pixmap_new (drawable, _width, _height, -1);
+
+ /* render */
+ cairo_t* cr = gdk_cairo_create (_pixmap);
+ render (cr);
+ cairo_destroy (cr);
+
+ _render_required = false;
+ }
+
+ return _pixmap;
+}
+
+void
+PortMatrixComponent::set_source_rgb (cairo_t *cr, Gdk::Color const & c)
+{
+ cairo_set_source_rgb (cr, c.get_red_p(), c.get_green_p(), c.get_blue_p());
+}
+
+void
+PortMatrixComponent::set_source_rgba (cairo_t *cr, Gdk::Color const & c, double a)
+{
+ cairo_set_source_rgba (cr, c.get_red_p(), c.get_green_p(), c.get_blue_p(), a);
+}
+
+std::pair<uint32_t, uint32_t>
+PortMatrixComponent::dimensions ()
+{
+ if (_dimension_computation_required) {
+ compute_dimensions ();
+ _dimension_computation_required = false;
+ }
+
+ return std::make_pair (_width, _height);
+}
diff --git a/gtk2_ardour/port_matrix_component.h b/gtk2_ardour/port_matrix_component.h
new file mode 100644
index 0000000000..a041c807e8
--- /dev/null
+++ b/gtk2_ardour/port_matrix_component.h
@@ -0,0 +1,136 @@
+/*
+ Copyright (C) 2002-2009 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 __gtk_ardour_port_matrix_component_h__
+#define __gtk_ardour_port_matrix_component_h__
+
+#include <gtkmm/eventbox.h>
+
+class PortMatrixBody;
+
+/** One component of the PortMatrix. This is a cairo-rendered
+ * Pixmap.
+ */
+class PortMatrixComponent
+{
+public:
+ PortMatrixComponent (PortMatrixBody *);
+ virtual ~PortMatrixComponent ();
+
+ void setup ();
+ GdkPixmap* get_pixmap (GdkDrawable *);
+ std::pair<uint32_t, uint32_t> dimensions ();
+ void require_render () {
+ _render_required = true;
+ }
+
+ /** @return width of columns in the grid */
+ static uint32_t column_width () {
+ return 32;
+ }
+
+ /** @return height of rows in the grid */
+ static uint32_t row_height () {
+ return 32;
+ }
+
+protected:
+
+ /** @return width of borders drawn around labels */
+ static uint32_t label_border_width () {
+ return 1;
+ }
+
+ /** @return padding between a name and the nearest line */
+ static uint32_t name_pad () {
+ return 8;
+ }
+
+ /** @return width of thin lines in the grid */
+ static uint32_t thin_grid_line_width () {
+ return 1;
+ }
+
+ /** @return width of thick lines in the grid */
+ static uint32_t thick_grid_line_width () {
+ return 2;
+ }
+
+ /** @return space around the connection indicator */
+ static uint32_t connection_indicator_pad () {
+ return 8;
+ }
+
+ /** @return angle of column labels, in radians */
+ static double angle () {
+ return M_PI / 4;
+ }
+
+ /* XXX I guess these colours should come from a theme, or something */
+
+ /* @return background colour */
+ static Gdk::Color background_colour () {
+ return Gdk::Color ("#000000");
+ }
+
+ /* @return text colour */
+ static Gdk::Color text_colour () {
+ return Gdk::Color ("#ffffff");
+ }
+
+ /* @return grid line colour */
+ static Gdk::Color grid_colour () {
+ return Gdk::Color ("#333333");
+ }
+
+ /* @return colour of association blobs */
+ static Gdk::Color association_colour () {
+ return Gdk::Color ("#00ff00");
+ }
+
+ /* XXX */
+ static Gdk::Color get_a_bundle_colour (int x) {
+ if ((x % 2) == 0) {
+ return Gdk::Color ("#547027");
+ } else {
+ return Gdk::Color ("#3552a6");
+ }
+ }
+
+ void set_source_rgb (cairo_t *, Gdk::Color const &);
+ void set_source_rgba (cairo_t *, Gdk::Color const &, double);
+
+ /** Render the complete component to a cairo context. */
+ virtual void render (cairo_t *) = 0;
+ /** Compute any required dimensions. This must set up
+ * _width and _height.
+ */
+ virtual void compute_dimensions () = 0;
+
+ PortMatrixBody* _body; ///< the PortMatrixBody that we're in
+ uint32_t _width; ///< full width of the contents
+ uint32_t _height; ///< full height of the contents
+
+private:
+ GdkPixmap* _pixmap; ///< pixmap
+ bool _render_required; ///< true if the rendered pixmap is out of date
+ bool _dimension_computation_required; ///< true if the dimensions are out of date
+};
+
+#endif
diff --git a/gtk2_ardour/port_matrix_grid.cc b/gtk2_ardour/port_matrix_grid.cc
new file mode 100644
index 0000000000..461e9f5f72
--- /dev/null
+++ b/gtk2_ardour/port_matrix_grid.cc
@@ -0,0 +1,195 @@
+/*
+ Copyright (C) 2002-2009 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.
+
+*/
+
+#include <iostream>
+#include <cairo/cairo.h>
+#include "ardour/bundle.h"
+#include "port_matrix_grid.h"
+#include "port_matrix.h"
+
+PortMatrixGrid::PortMatrixGrid (PortMatrix* p, PortMatrixBody* b)
+ : PortMatrixComponent (b),
+ _port_matrix (p)
+{
+
+}
+
+void
+PortMatrixGrid::compute_dimensions ()
+{
+ _width = 0;
+ for (uint32_t i = 0; i < _body->column_bundles().size(); ++i) {
+ _width += _body->column_bundles()[i]->nchannels() * column_width();
+ }
+
+ _height = 0;
+ for (uint32_t i = 0; i < _body->row_bundles().size(); ++i) {
+ _height += _body->row_bundles()[i]->nchannels() * row_height();
+ }
+}
+
+
+void
+PortMatrixGrid::render (cairo_t* cr)
+{
+ /* BACKGROUND */
+
+ set_source_rgb (cr, background_colour());
+ cairo_rectangle (cr, 0, 0, _width, _height);
+ cairo_fill (cr);
+
+ /* VERTICAL GRID LINES */
+
+ set_source_rgb (cr, grid_colour());
+ uint32_t x = 0;
+ for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::size_type i = 0; i < _body->column_bundles().size(); ++i) {
+
+ cairo_set_line_width (cr, thin_grid_line_width());
+ for (uint32_t j = 1; j < _body->column_bundles()[i]->nchannels(); ++j) {
+ x += column_width();
+ cairo_move_to (cr, x, 0);
+ cairo_line_to (cr, x, _height);
+ cairo_stroke (cr);
+ }
+
+ if (i < (_body->column_bundles().size() - 1)) {
+ x += column_width();
+ cairo_set_line_width (cr, thick_grid_line_width());
+ cairo_move_to (cr, x, 0);
+ cairo_line_to (cr, x, _height);
+ cairo_stroke (cr);
+ }
+ }
+
+ uint32_t grid_width = x + column_width();
+
+ /* HORIZONTAL GRID LINES */
+
+ uint32_t y = 0;
+ for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::size_type i = 0; i < _body->row_bundles().size(); ++i) {
+
+ cairo_set_line_width (cr, thin_grid_line_width());
+ for (uint32_t j = 1; j < _body->row_bundles()[i]->nchannels(); ++j) {
+ y += row_height();
+ cairo_move_to (cr, 0, y);
+ cairo_line_to (cr, grid_width, y);
+ cairo_stroke (cr);
+ }
+
+ if (i < (_body->row_bundles().size() - 1)) {
+ y += row_height();
+ cairo_set_line_width (cr, thick_grid_line_width());
+ cairo_move_to (cr, 0, y);
+ cairo_line_to (cr, grid_width, y);
+ cairo_stroke (cr);
+ }
+ }
+
+ /* ASSOCIATION INDICATORS */
+
+ uint32_t bx = 0;
+ uint32_t by = 0;
+
+ for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->column_bundles().begin(); i < _body->column_bundles().end(); ++i) {
+ by = 0;
+
+ for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator j = _body->row_bundles().begin(); j < _body->row_bundles().end(); ++j) {
+
+ x = bx;
+ for (uint32_t k = 0; k < (*i)->nchannels (); k++) {
+
+ y = by;
+ for (uint32_t l = 0; l < (*j)->nchannels (); ++l) {
+
+ if (_port_matrix->get_state (*j, l, *i, k)) {
+
+ set_source_rgba (cr, association_colour(), 0.5);
+ cairo_arc (
+ cr,
+ x + column_width() / 2,
+ y + column_width() / 2,
+ (column_width() - (2 * connection_indicator_pad())) / 2,
+ 0,
+ 2 * M_PI
+ );
+
+ cairo_fill (cr);
+
+ }
+ y += row_height();
+ }
+ x += column_width();
+ }
+
+ by += (*j)->nchannels () * row_height();
+ }
+
+ bx += (*i)->nchannels () * column_width();
+ }
+}
+
+
+void
+PortMatrixGrid::button_press (double x, double y, int b)
+{
+ uint32_t grid_column = x / column_width ();
+ uint32_t grid_row = y / row_height ();
+
+ boost::shared_ptr<ARDOUR::Bundle> our_bundle;
+ uint32_t our_channel = 0;
+ boost::shared_ptr<ARDOUR::Bundle> other_bundle;
+ uint32_t other_channel = 0;
+
+ for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->row_bundles().begin(); i != _body->row_bundles().end(); ++i) {
+ if (grid_row < (*i)->nchannels ()) {
+ our_bundle = *i;
+ our_channel = grid_row;
+ break;
+ } else {
+ grid_row -= (*i)->nchannels ();
+ }
+ }
+
+ for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->column_bundles().begin(); i != _body->column_bundles().end(); ++i) {
+ if (grid_column < (*i)->nchannels ()) {
+ other_bundle = *i;
+ other_channel = grid_column;
+ break;
+ } else {
+ grid_column -= (*i)->nchannels ();
+ }
+ }
+
+ if (our_bundle && other_bundle) {
+
+ bool const s = _port_matrix->get_state (
+ our_bundle, our_channel, other_bundle, other_channel
+ );
+
+ _port_matrix->set_state (
+ our_bundle, our_channel, other_bundle, other_channel,
+ !s, 0
+ );
+
+ require_render ();
+ _body->queue_draw ();
+ }
+}
+
+
diff --git a/gtk2_ardour/port_matrix_grid.h b/gtk2_ardour/port_matrix_grid.h
new file mode 100644
index 0000000000..298d33c0b5
--- /dev/null
+++ b/gtk2_ardour/port_matrix_grid.h
@@ -0,0 +1,53 @@
+/*
+ Copyright (C) 2002-2009 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 __gtk_ardour_port_matrix_grid_h__
+#define __gtk_ardour_port_matrix_grid_h__
+
+#include <string>
+#include <vector>
+#include <boost/shared_ptr.hpp>
+#include "port_matrix_component.h"
+
+class PortMatrix;
+class PortMatrixBody;
+
+namespace ARDOUR {
+ class Bundle;
+}
+
+/// The grid part of the port matrix
+class PortMatrixGrid : public PortMatrixComponent
+{
+public:
+ PortMatrixGrid (PortMatrix *, PortMatrixBody *);
+
+ void button_press (double, double, int);
+
+private:
+ void compute_dimensions ();
+ void render (cairo_t *);
+
+ std::vector<boost::shared_ptr<ARDOUR::Bundle> > _column_bundles;
+ std::vector<boost::shared_ptr<ARDOUR::Bundle> > _row_bundles;
+
+ PortMatrix* _port_matrix;
+};
+
+#endif
diff --git a/gtk2_ardour/port_matrix_row_labels.cc b/gtk2_ardour/port_matrix_row_labels.cc
new file mode 100644
index 0000000000..18e479942e
--- /dev/null
+++ b/gtk2_ardour/port_matrix_row_labels.cc
@@ -0,0 +1,240 @@
+/*
+ Copyright (C) 2002-2009 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.
+
+*/
+
+#include <iostream>
+#include <boost/weak_ptr.hpp>
+#include <gtkmm/menu.h>
+#include <gtkmm/menushell.h>
+#include <gtkmm/menu_elems.h>
+#include <cairo/cairo.h>
+#include "ardour/bundle.h"
+#include "port_matrix_row_labels.h"
+#include "port_matrix.h"
+#include "i18n.h"
+
+PortMatrixRowLabels::PortMatrixRowLabels (PortMatrix* p, PortMatrixBody* b)
+ : PortMatrixComponent (b), _port_matrix (p), _menu (0)
+{
+
+}
+
+PortMatrixRowLabels::~PortMatrixRowLabels ()
+{
+ delete _menu;
+}
+
+void
+PortMatrixRowLabels::compute_dimensions ()
+{
+ GdkPixmap* pm = gdk_pixmap_new (NULL, 1, 1, 24);
+ gdk_drawable_set_colormap (pm, gdk_colormap_get_system());
+ cairo_t* cr = gdk_cairo_create (pm);
+
+ _longest_port_name = 0;
+ for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->row_bundles().begin(); i != _body->row_bundles().end(); ++i) {
+ for (uint32_t j = 0; j < (*i)->nchannels(); ++j) {
+ cairo_text_extents_t ext;
+ cairo_text_extents (cr, (*i)->channel_name(j).c_str(), &ext);
+ if (ext.width > _longest_port_name) {
+ _longest_port_name = ext.width;
+ }
+ }
+ }
+
+ _longest_bundle_name = 0;
+ for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->row_bundles().begin(); i != _body->row_bundles().end(); ++i) {
+ cairo_text_extents_t ext;
+ cairo_text_extents (cr, (*i)->name().c_str(), &ext);
+ if (ext.width > _longest_bundle_name) {
+ _longest_bundle_name = ext.width;
+ }
+ }
+
+ cairo_destroy (cr);
+ gdk_pixmap_unref (pm);
+
+ _height = 0;
+ for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->row_bundles().begin(); i != _body->row_bundles().end(); ++i) {
+ _height += (*i)->nchannels() * row_height();
+ }
+
+ _width = _longest_port_name +
+ name_pad() * 4 +
+ _longest_bundle_name + name_pad() * 2;
+}
+
+
+void
+PortMatrixRowLabels::render (cairo_t* cr)
+{
+ /* BACKGROUND */
+
+ set_source_rgb (cr, background_colour());
+ cairo_rectangle (cr, 0, 0, _width, _height);
+ cairo_fill (cr);
+
+ /* SIDE BUNDLE NAMES */
+
+ uint32_t x = _longest_port_name + name_pad() * 3;
+
+ uint32_t y = 0;
+ for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->row_bundles().begin(); i != _body->row_bundles().end(); ++i) {
+
+ Gdk::Color const colour = get_a_bundle_colour (i - _body->row_bundles().begin ());
+ set_source_rgb (cr, colour);
+ cairo_rectangle (
+ cr,
+ 0,
+ y,
+ _longest_port_name + name_pad() * 4 + _longest_bundle_name + name_pad() * 2,
+ row_height() * (*i)->nchannels()
+ );
+ cairo_fill_preserve (cr);
+ set_source_rgb (cr, background_colour());
+ cairo_set_line_width (cr, label_border_width ());
+ cairo_stroke (cr);
+
+ uint32_t off = 0;
+ if ((*i)->nchannels () > 0) {
+ /* use the extent of our first channel name so that the bundle name is vertically aligned with it */
+ cairo_text_extents_t ext;
+ cairo_text_extents (cr, (*i)->channel_name(0).c_str(), &ext);
+ off = (row_height() - ext.height) / 2;
+ } else {
+ off = row_height() / 2;
+ }
+
+ set_source_rgb (cr, text_colour());
+ cairo_move_to (cr, x, y + name_pad() + off);
+ cairo_show_text (cr, (*i)->name().c_str());
+
+ y += row_height() * (*i)->nchannels ();
+ }
+
+
+ /* SIDE PORT NAMES */
+
+ y = 0;
+ for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->row_bundles().begin(); i != _body->row_bundles().end(); ++i) {
+ for (uint32_t j = 0; j < (*i)->nchannels(); ++j) {
+
+ Gdk::Color const colour = get_a_bundle_colour (i - _body->row_bundles().begin ());
+ set_source_rgb (cr, colour);
+ cairo_rectangle (
+ cr,
+ 0,
+ y,
+ _longest_port_name + (name_pad() * 2),
+ row_height()
+ );
+ cairo_fill_preserve (cr);
+ set_source_rgb (cr, background_colour());
+ cairo_set_line_width (cr, label_border_width ());
+ cairo_stroke (cr);
+
+ cairo_text_extents_t ext;
+ cairo_text_extents (cr, (*i)->channel_name(j).c_str(), &ext);
+ uint32_t const off = (row_height() - ext.height) / 2;
+
+ set_source_rgb (cr, text_colour());
+ cairo_move_to (cr, name_pad(), y + name_pad() + off);
+ cairo_show_text (cr, (*i)->channel_name(j).c_str());
+
+ y += row_height();
+ }
+ }
+}
+
+void
+PortMatrixRowLabels::button_press (double x, double y, int b, uint32_t t)
+{
+ if (b == 3 && x < (_longest_port_name + name_pad() * 2) ) {
+
+ delete _menu;
+
+ _menu = new Gtk::Menu;
+ _menu->set_name ("ArdourContextMenu");
+
+ Gtk::Menu_Helpers::MenuList& items = _menu->items ();
+
+
+ uint32_t row = y / row_height ();
+
+ boost::shared_ptr<ARDOUR::Bundle> bundle;
+ uint32_t channel;
+
+ for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::const_iterator i = _body->row_bundles().begin(); i != _body->row_bundles().end(); ++i) {
+ if (row < (*i)->nchannels ()) {
+ bundle = *i;
+ channel = row;
+ break;
+ } else {
+ row -= (*i)->nchannels ();
+ }
+ }
+
+ if (bundle) {
+ char buf [64];
+
+ if (_port_matrix->can_rename_channels ()) {
+ snprintf (buf, sizeof (buf), _("Rename '%s'..."), bundle->channel_name (channel).c_str());
+ items.push_back (
+ Gtk::Menu_Helpers::MenuElem (
+ buf,
+ sigc::bind (sigc::mem_fun (*this, &PortMatrixRowLabels::rename_channel_proxy), bundle, channel)
+ )
+ );
+ }
+
+ snprintf (buf, sizeof (buf), _("Remove '%s'"), bundle->channel_name (channel).c_str());
+ items.push_back (
+ Gtk::Menu_Helpers::MenuElem (
+ buf,
+ sigc::bind (sigc::mem_fun (*this, &PortMatrixRowLabels::remove_channel_proxy), bundle, channel)
+ )
+ );
+
+ _menu->popup (1, t);
+ }
+ }
+}
+
+
+void
+PortMatrixRowLabels::remove_channel_proxy (boost::weak_ptr<ARDOUR::Bundle> b, uint32_t c)
+{
+ boost::shared_ptr<ARDOUR::Bundle> sb = b.lock ();
+ if (!sb) {
+ return;
+ }
+
+ _port_matrix->remove_channel (sb, c);
+
+}
+
+void
+PortMatrixRowLabels::rename_channel_proxy (boost::weak_ptr<ARDOUR::Bundle> b, uint32_t c)
+{
+ boost::shared_ptr<ARDOUR::Bundle> sb = b.lock ();
+ if (!sb) {
+ return;
+ }
+
+ _port_matrix->rename_channel (sb, c);
+}
diff --git a/gtk2_ardour/port_matrix_row_labels.h b/gtk2_ardour/port_matrix_row_labels.h
new file mode 100644
index 0000000000..74af1092c2
--- /dev/null
+++ b/gtk2_ardour/port_matrix_row_labels.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (C) 2002-2009 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 __port_matrix_row_labels_h__
+#define __port_matrix_row_labels_h__
+
+#include <boost/shared_ptr.hpp>
+#include "port_matrix_component.h"
+
+class PortMatrix;
+class PortMatrixBody;
+
+namespace ARDOUR {
+ class Bundle;
+}
+
+namespace Gtk {
+ class Menu;
+}
+
+class PortMatrixRowLabels : public PortMatrixComponent
+{
+public:
+ PortMatrixRowLabels (PortMatrix *, PortMatrixBody *);
+ ~PortMatrixRowLabels ();
+
+ void button_press (double, double, int, uint32_t);
+
+private:
+ void render (cairo_t *);
+ void compute_dimensions ();
+ void remove_channel_proxy (boost::weak_ptr<ARDOUR::Bundle>, uint32_t);
+ void rename_channel_proxy (boost::weak_ptr<ARDOUR::Bundle>, uint32_t);
+
+ PortMatrix* _port_matrix;
+ uint32_t _longest_port_name;
+ uint32_t _longest_bundle_name;
+ Gtk::Menu* _menu;
+};
+
+#endif
diff --git a/gtk2_ardour/route_params_ui.cc b/gtk2_ardour/route_params_ui.cc
index 670635fb4d..13807a1521 100644
--- a/gtk2_ardour/route_params_ui.cc
+++ b/gtk2_ardour/route_params_ui.cc
@@ -320,13 +320,13 @@ RouteParams_UI::setup_io_frames()
cleanup_io_frames();
// input
- _input_iosel = new IOSelector (*session, _route, true);
+ _input_iosel = new IOSelector (*session, _route, false);
_input_iosel->setup ();
input_frame.add (*_input_iosel);
input_frame.show_all();
// output
- _output_iosel = new IOSelector (*session, _route, false);
+ _output_iosel = new IOSelector (*session, _route, true);
_output_iosel->setup ();
output_frame.add (*_output_iosel);
output_frame.show_all();
diff --git a/libs/ardour/ardour/bundle.h b/libs/ardour/ardour/bundle.h
index 1b029dc2b4..8b1af39e75 100644
--- a/libs/ardour/ardour/bundle.h
+++ b/libs/ardour/ardour/bundle.h
@@ -21,17 +21,21 @@
#define __ardour_bundle_h__
#include <string>
+#include <vector>
+#include <glibmm/thread.h>
#include <sigc++/signal.h>
#include "ardour/data_type.h"
namespace ARDOUR {
/** A set of `channels', each of which is associated with 0 or more ports.
+ * Each channel has a name which can be anything useful.
* Intended for grouping things like, for example, a buss' outputs.
* `Channel' is a rather overloaded term but I can't think of a better
* one right now.
*/
-class Bundle : public sigc::trackable {
+class Bundle : public sigc::trackable
+{
public:
/// List of ports associated with a channel. We can't use a
@@ -39,6 +43,17 @@ class Bundle : public sigc::trackable {
/// (ie those without a Port object)
typedef std::vector<std::string> PortList;
+ struct Channel {
+ Channel (std::string n) : name (n) {}
+
+ bool operator== (Channel const &o) const {
+ return name == o.name && ports == o.ports;
+ }
+
+ std::string name;
+ PortList ports;
+ };
+
/** Construct an audio bundle.
* @param i true if ports are inputs, otherwise false.
*/
@@ -50,6 +65,13 @@ class Bundle : public sigc::trackable {
*/
Bundle (std::string const & n, bool i = true) : _name (n), _type (DataType::AUDIO), _ports_are_inputs (i) {}
+ /** Construct a bundle.
+ * @param n Name.
+ * @param t Type.
+ * @param i true if ports are inputs, otherwise false.
+ */
+ Bundle (std::string const & n, DataType t, bool i = true) : _name (n), _type (t), _ports_are_inputs (i) {}
+
virtual ~Bundle() {}
/** @return Number of channels that this Bundle has */
@@ -60,13 +82,16 @@ class Bundle : public sigc::trackable {
*/
PortList const & channel_ports (uint32_t) const;
- void add_channel ();
+ void add_channel (std::string const &);
+ std::string channel_name (uint32_t) const;
+ void set_channel_name (uint32_t, std::string const &);
void add_port_to_channel (uint32_t, std::string);
void set_port (uint32_t, std::string);
void remove_port_from_channel (uint32_t, std::string);
- void set_nchannels (uint32_t);
bool port_attached_to_channel (uint32_t, std::string);
+ bool uses_port (std::string) const;
void remove_channel (uint32_t);
+ void remove_channels ();
/** Set the name.
* @param n New name.
@@ -94,7 +119,7 @@ class Bundle : public sigc::trackable {
bool operator== (Bundle const &) const;
- /** Emitted when the name changes */
+ /** Emitted when the bundle name or a channel name has changed */
sigc::signal<void> NameChanged;
/** The number of channels has changed */
sigc::signal<void> ConfigurationChanged;
@@ -103,10 +128,10 @@ class Bundle : public sigc::trackable {
protected:
- /// mutex for _ports;
+ /// mutex for _channel_ports and _channel_names
/// XXX: is this necessary?
- mutable Glib::Mutex _ports_mutex;
- std::vector<PortList> _ports;
+ mutable Glib::Mutex _channel_mutex;
+ std::vector<Channel> _channel;
private:
int set_channels (std::string const &);
diff --git a/libs/ardour/bundle.cc b/libs/ardour/bundle.cc
index bdad9d364d..379a3d4c2b 100644
--- a/libs/ardour/bundle.cc
+++ b/libs/ardour/bundle.cc
@@ -32,8 +32,8 @@ using namespace PBD;
uint32_t
Bundle::nchannels () const
{
- Glib::Mutex::Lock lm (_ports_mutex);
- return _ports.size ();
+ Glib::Mutex::Lock lm (_channel_mutex);
+ return _channel.size ();
}
Bundle::PortList const &
@@ -41,8 +41,8 @@ Bundle::channel_ports (uint32_t c) const
{
assert (c < nchannels());
- Glib::Mutex::Lock lm (_ports_mutex);
- return _ports[c];
+ Glib::Mutex::Lock lm (_channel_mutex);
+ return _channel[c].ports;
}
/** Add an association between one of our channels and a port.
@@ -55,8 +55,8 @@ Bundle::add_port_to_channel (uint32_t ch, string portname)
assert (ch < nchannels());
{
- Glib::Mutex::Lock lm (_ports_mutex);
- _ports[ch].push_back (portname);
+ Glib::Mutex::Lock lm (_channel_mutex);
+ _channel[ch].ports.push_back (portname);
}
PortsChanged (ch); /* EMIT SIGNAL */
@@ -74,8 +74,8 @@ Bundle::remove_port_from_channel (uint32_t ch, string portname)
bool changed = false;
{
- Glib::Mutex::Lock lm (_ports_mutex);
- PortList& pl = _ports[ch];
+ Glib::Mutex::Lock lm (_channel_mutex);
+ PortList& pl = _channel[ch].ports;
PortList::iterator i = find (pl.begin(), pl.end(), portname);
if (i != pl.end()) {
@@ -95,48 +95,31 @@ Bundle::remove_port_from_channel (uint32_t ch, string portname)
bool
Bundle::operator== (const Bundle& other) const
{
- return other._ports == _ports;
+ return other._channel == _channel;
}
-/** Set the number of channels.
- * @param n New number of channels.
- */
-
-void
-Bundle::set_nchannels (uint32_t n)
-{
- {
- Glib::Mutex::Lock lm (_ports_mutex);
- _ports.clear ();
- for (uint32_t i = 0; i < n; ++i) {
- _ports.push_back (PortList());
- }
- }
-
- ConfigurationChanged (); /* EMIT SIGNAL */
-}
-
void
Bundle::set_port (uint32_t ch, string portname)
{
assert (ch < nchannels());
{
- Glib::Mutex::Lock lm (_ports_mutex);
- _ports[ch].clear ();
- _ports[ch].push_back (portname);
+ Glib::Mutex::Lock lm (_channel_mutex);
+ _channel[ch].ports.clear ();
+ _channel[ch].ports.push_back (portname);
}
PortsChanged (ch); /* EMIT SIGNAL */
}
+/** @param n Channel name */
void
-Bundle::add_channel ()
+Bundle::add_channel (std::string const & n)
{
{
- Glib::Mutex::Lock lm (_ports_mutex);
- _ports.push_back (PortList ());
+ Glib::Mutex::Lock lm (_channel_mutex);
+ _channel.push_back (Channel (n));
}
ConfigurationChanged (); /* EMIT SIGNAL */
@@ -147,8 +130,8 @@ Bundle::port_attached_to_channel (uint32_t ch, std::string portname)
{
assert (ch < nchannels());
- Glib::Mutex::Lock lm (_ports_mutex);
- return (std::find (_ports[ch].begin (), _ports[ch].end (), portname) != _ports[ch].end ());
+ Glib::Mutex::Lock lm (_channel_mutex);
+ return (std::find (_channel[ch].ports.begin (), _channel[ch].ports.end (), portname) != _channel[ch].ports.end ());
}
void
@@ -156,6 +139,52 @@ Bundle::remove_channel (uint32_t ch)
{
assert (ch < nchannels ());
- Glib::Mutex::Lock lm (_ports_mutex);
- _ports.erase (_ports.begin () + ch);
+ Glib::Mutex::Lock lm (_channel_mutex);
+ _channel.erase (_channel.begin () + ch);
+}
+
+void
+Bundle::remove_channels ()
+{
+ Glib::Mutex::Lock lm (_channel_mutex);
+
+ _channel.clear ();
+}
+
+bool
+Bundle::uses_port (std::string p) const
+{
+ Glib::Mutex::Lock lm (_channel_mutex);
+
+ for (std::vector<Channel>::const_iterator i = _channel.begin(); i != _channel.end(); ++i) {
+ for (PortList::const_iterator j = i->ports.begin(); j != i->ports.end(); ++j) {
+ if (*j == p) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+std::string
+Bundle::channel_name (uint32_t ch) const
+{
+ assert (ch < nchannels());
+
+ Glib::Mutex::Lock lm (_channel_mutex);
+ return _channel[ch].name;
+}
+
+void
+Bundle::set_channel_name (uint32_t ch, std::string const & n)
+{
+ assert (ch < nchannels());
+
+ {
+ Glib::Mutex::Lock lm (_channel_mutex);
+ _channel[ch].name = n;
+ }
+
+ NameChanged (); /* EMIT SIGNAL */
}
diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc
index ed1064f0e8..2b8f12680f 100644
--- a/libs/ardour/io.cc
+++ b/libs/ardour/io.cc
@@ -593,7 +593,7 @@ IO::remove_output_port (Port* port, void* src)
PortCountChanged (n_outputs()); /* EMIT SIGNAL */
}
- if (change == ConnectionsChanged) {
+ if (change == ConfigurationChanged) {
setup_bundles_for_inputs_and_outputs ();
}
@@ -2592,19 +2592,24 @@ IO::setup_bundles_for_inputs_and_outputs ()
{
char buf[32];
+ _bundle_for_inputs->remove_channels ();
+ _bundle_for_outputs->remove_channels ();
+
snprintf(buf, sizeof (buf), _("%s in"), _name.c_str());
_bundle_for_inputs->set_name (buf);
uint32_t const ni = inputs().num_ports();
- _bundle_for_inputs->set_nchannels (ni);
for (uint32_t i = 0; i < ni; ++i) {
+ snprintf (buf, sizeof(buf), _("in %d"), (i + 1));
+ _bundle_for_inputs->add_channel (buf);
_bundle_for_inputs->set_port (i, inputs().port(i)->name());
}
snprintf(buf, sizeof (buf), _("%s out"), _name.c_str());
_bundle_for_outputs->set_name (buf);
uint32_t const no = outputs().num_ports();
- _bundle_for_outputs->set_nchannels (no);
for (uint32_t i = 0; i < no; ++i) {
+ snprintf (buf, sizeof(buf), _("out %d"), (i + 1));
+ _bundle_for_outputs->add_channel (buf);
_bundle_for_outputs->set_port (i, outputs().port(i)->name());
}
}
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index c020509924..2b4d264bbb 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -598,7 +598,7 @@ Session::when_engine_running ()
snprintf (buf, sizeof (buf), _("out %" PRIu32), np+1);
shared_ptr<Bundle> c (new Bundle (buf, true));
- c->set_nchannels (1);
+ c->add_channel (_("mono"));
c->set_port (0, _engine.get_nth_physical_output (DataType::AUDIO, np));
add_bundle (c);
@@ -609,7 +609,7 @@ Session::when_engine_running ()
snprintf (buf, sizeof (buf), _("in %" PRIu32), np+1);
shared_ptr<Bundle> c (new Bundle (buf, false));
- c->set_nchannels (1);
+ c->add_channel (_("mono"));
c->set_port (0, _engine.get_nth_physical_input (DataType::AUDIO, np));
add_bundle (c);
@@ -622,8 +622,9 @@ Session::when_engine_running ()
snprintf (buf, sizeof (buf), _("out %" PRIu32 "+%" PRIu32), np+1, np+2);
shared_ptr<Bundle> c (new Bundle (buf, true));
- c->set_nchannels (2);
+ c->add_channel (_("left"));
c->set_port (0, _engine.get_nth_physical_output (DataType::AUDIO, np));
+ c->add_channel (_("right"));
c->set_port (1, _engine.get_nth_physical_output (DataType::AUDIO, np + 1));
add_bundle (c);
@@ -634,8 +635,9 @@ Session::when_engine_running ()
snprintf (buf, sizeof (buf), _("in %" PRIu32 "+%" PRIu32), np+1, np+2);
shared_ptr<Bundle> c (new Bundle (buf, false));
- c->set_nchannels (2);
+ c->add_channel (_("left"));
c->set_port (0, _engine.get_nth_physical_input (DataType::AUDIO, np));
+ c->add_channel (_("right"));
c->set_port (1, _engine.get_nth_physical_input (DataType::AUDIO, np + 1));
add_bundle (c);
@@ -2003,13 +2005,6 @@ Session::add_routes (RouteList& new_routes, bool save)
if ((*x)->is_control()) {
_control_out = (*x);
}
-
- /* only busses get automatic bundles formed */
-
- if (!boost::dynamic_pointer_cast<Track> (*x)) {
- add_bundle ((*x)->bundle_for_inputs());
- add_bundle ((*x)->bundle_for_outputs());
- }
}
if (_control_out && IO::connecting_legal) {
diff --git a/libs/ardour/user_bundle.cc b/libs/ardour/user_bundle.cc
index d53bf8b155..2dee0af01e 100644
--- a/libs/ardour/user_bundle.cc
+++ b/libs/ardour/user_bundle.cc
@@ -45,7 +45,7 @@ ARDOUR::UserBundle::set_state (XMLNode const & node)
return -1;
}
- add_channel ();
+ add_channel ("XXX");
XMLNodeList const ports = (*i)->children ();
@@ -83,13 +83,13 @@ ARDOUR::UserBundle::get_state ()
node->add_property ("name", name ());
{
- Glib::Mutex::Lock lm (_ports_mutex);
+ Glib::Mutex::Lock lm (_channel_mutex);
- for (std::vector<PortList>::iterator i = _ports.begin(); i != _ports.end(); ++i) {
-
+ for (std::vector<Channel>::iterator i = _channel.begin(); i != _channel.end(); ++i) {
XMLNode* c = new XMLNode ("Channel");
+ c->add_property ("name", i->name);
- for (PortList::iterator j = i->begin(); j != i->end(); ++j) {
+ for (PortList::iterator j = i->ports.begin(); j != i->ports.end(); ++j) {
XMLNode* p = new XMLNode ("Port");
p->add_property ("name", *j);
c->add_child_nocopy (*p);