diff options
author | Carl Hetherington <carl@carlh.net> | 2009-01-30 15:08:09 +0000 |
---|---|---|
committer | Carl Hetherington <carl@carlh.net> | 2009-01-30 15:08:09 +0000 |
commit | a384dab13095f3d909e52eff9e6170ae55416601 (patch) | |
tree | c8af98d36927095909f54d3e8e8819af4c98b184 | |
parent | 24aab941eb4d77e5bdf3933b11f8ce5659872b52 (diff) |
More port matrix re-working. Global matrix now has separate visibility buttons
for ins and outs. The matrix will now be arranged so that more ports are labelled
horizontally than vertically, to aid readability.
git-svn-id: svn://localhost/ardour2/branches/3.0@4467 d708f5d6-7413-0410-9779-e7cbd77b26cf
23 files changed, 830 insertions, 713 deletions
diff --git a/gtk2_ardour/bundle_manager.cc b/gtk2_ardour/bundle_manager.cc index 0f4bdb3c75..79bdd3e6f5 100644 --- a/gtk2_ardour/bundle_manager.cc +++ b/gtk2_ardour/bundle_manager.cc @@ -33,49 +33,40 @@ BundleEditorMatrix::BundleEditorMatrix ( ARDOUR::Session& session, boost::shared_ptr<ARDOUR::Bundle> bundle ) - : PortMatrix (session, bundle->type(), bundle->ports_are_inputs()) + : PortMatrix (session, bundle->type()), + _bundle (bundle) { - _port_group = new PortGroup ("", true); + _port_group = boost::shared_ptr<PortGroup> (new PortGroup ("")); _port_group->add_bundle (bundle); - _row_ports.push_back (_port_group); + _ports[OURS].add_group (_port_group); } -BundleEditorMatrix::~BundleEditorMatrix () +void +BundleEditorMatrix::setup () { - delete _port_group; + _ports[OTHER].gather (_session, _bundle->ports_are_inputs()); + PortMatrix::setup (); } void -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 - ) +BundleEditorMatrix::set_state (ARDOUR::BundleChannel c[2], bool s) { - ARDOUR::Bundle::PortList const& pl = bb->channel_ports (bc); + ARDOUR::Bundle::PortList const& pl = c[OTHER].bundle->channel_ports (c[OTHER].channel); for (ARDOUR::Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) { if (s) { - ab->add_port_to_channel (ac, *i); + c[OURS].bundle->add_port_to_channel (c[OURS].channel, *i); } else { - ab->remove_port_from_channel (ac, *i); + c[OURS].bundle->remove_port_from_channel (c[OURS].channel, *i); } } } PortMatrix::State -BundleEditorMatrix::get_state ( - boost::shared_ptr<ARDOUR::Bundle> ab, - uint32_t ac, - boost::shared_ptr<ARDOUR::Bundle> bb, - uint32_t bc - ) const +BundleEditorMatrix::get_state (ARDOUR::BundleChannel c[2]) const { - ARDOUR::Bundle::PortList const& pl = bb->channel_ports (bc); + ARDOUR::Bundle::PortList const& pl = c[OTHER].bundle->channel_ports (c[OTHER].channel); for (ARDOUR::Bundle::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) { - if (!ab->port_attached_to_channel (ac, *i)) { + if (!c[OURS].bundle->port_attached_to_channel (c[OURS].channel, *i)) { return NOT_ASSOCIATED; } } @@ -93,28 +84,28 @@ BundleEditorMatrix::add_channel (boost::shared_ptr<ARDOUR::Bundle> b) return; } - _port_group->only_bundle()->add_channel (d.get_name()); + _bundle->add_channel (d.get_name()); setup (); } void -BundleEditorMatrix::remove_channel (boost::shared_ptr<ARDOUR::Bundle> b, uint32_t c) +BundleEditorMatrix::remove_channel (ARDOUR::BundleChannel bc) { - _port_group->only_bundle()->remove_channel (c); + bc.bundle->remove_channel (bc.channel); setup (); } void -BundleEditorMatrix::rename_channel (boost::shared_ptr<ARDOUR::Bundle> b, uint32_t c) +BundleEditorMatrix::rename_channel (ARDOUR::BundleChannel bc) { - NameChannelDialog d (b, c); + NameChannelDialog d (bc.bundle, bc.channel); d.set_position (Gtk::WIN_POS_MOUSE); if (d.run () != Gtk::RESPONSE_ACCEPT) { return; } - b->set_channel_name (c, d.get_name ()); + bc.bundle->set_channel_name (bc.channel, d.get_name ()); } BundleEditor::BundleEditor (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::UserBundle> bundle, bool add) @@ -203,11 +194,11 @@ BundleEditor::input_or_output_changed () { if (_input_or_output.get_active_text() == _("Output")) { _bundle->set_ports_are_inputs (); - _matrix.set_offer_inputs (true); } else { _bundle->set_ports_are_outputs (); - _matrix.set_offer_inputs (false); } + + _matrix.setup (); } void diff --git a/gtk2_ardour/bundle_manager.h b/gtk2_ardour/bundle_manager.h index 8ab4279117..aa13967bff 100644 --- a/gtk2_ardour/bundle_manager.h +++ b/gtk2_ardour/bundle_manager.h @@ -35,33 +35,28 @@ class BundleEditorMatrix : public PortMatrix { public: BundleEditorMatrix (ARDOUR::Session &, boost::shared_ptr<ARDOUR::Bundle>); - ~BundleEditorMatrix (); - - 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 - ); - - State get_state ( - boost::shared_ptr<ARDOUR::Bundle> ab, - uint32_t ac, - boost::shared_ptr<ARDOUR::Bundle> bb, - uint32_t bc - ) const; + void set_state (ARDOUR::BundleChannel c[2], bool s); + State get_state (ARDOUR::BundleChannel c[2]) 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; + bool can_remove_channels (int d) const { + return d == OURS; + } + void remove_channel (ARDOUR::BundleChannel); + bool can_rename_channels (int d) const { + return d == OURS; } - void rename_channel (boost::shared_ptr<ARDOUR::Bundle>, uint32_t); + void rename_channel (ARDOUR::BundleChannel); + void setup (); private: - PortGroup* _port_group; + enum { + OTHER = 0, + OURS = 1 + }; + + boost::shared_ptr<PortGroup> _port_group; + boost::shared_ptr<ARDOUR::Bundle> _bundle; }; class BundleEditor : public ArdourDialog diff --git a/gtk2_ardour/global_port_matrix.cc b/gtk2_ardour/global_port_matrix.cc index 02a2862105..4cd6a78aea 100644 --- a/gtk2_ardour/global_port_matrix.cc +++ b/gtk2_ardour/global_port_matrix.cc @@ -25,45 +25,28 @@ #include "ardour/port.h" GlobalPortMatrix::GlobalPortMatrix (ARDOUR::Session& s, ARDOUR::DataType t) - : PortMatrix (s, t, true), - _session (s), - _our_port_group_list (t, false) + : PortMatrix (s, t) { setup (); - - _column_ports.VisibilityChanged.connect (sigc::mem_fun (*this, &GlobalPortMatrix::group_visibility_changed)); -} - -void -GlobalPortMatrix::group_visibility_changed () -{ - _row_ports.take_visibility_from (_column_ports); - setup (); } - void GlobalPortMatrix::setup () { - _row_ports.gather (_session); + _ports[IN].gather (_session, true); + _ports[OUT].gather (_session, false); + PortMatrix::setup (); } void -GlobalPortMatrix::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 - ) +GlobalPortMatrix::set_state (ARDOUR::BundleChannel c[2], bool s) { - ARDOUR::Bundle::PortList const& our_ports = ab->channel_ports (ac); - ARDOUR::Bundle::PortList const& other_ports = bb->channel_ports (bc); + ARDOUR::Bundle::PortList const & in_ports = c[IN].bundle->channel_ports (c[IN].channel); + ARDOUR::Bundle::PortList const & out_ports = c[OUT].bundle->channel_ports (c[OUT].channel); - 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) { + for (ARDOUR::Bundle::PortList::const_iterator i = in_ports.begin(); i != in_ports.end(); ++i) { + for (ARDOUR::Bundle::PortList::const_iterator j = out_ports.begin(); j != out_ports.end(); ++j) { ARDOUR::Port* p = _session.engine().get_port_by_name (*i); ARDOUR::Port* q = _session.engine().get_port_by_name (*j); @@ -78,7 +61,7 @@ GlobalPortMatrix::set_state ( if (s) { q->connect (*i); } else { - q->disconnect (*j); + q->disconnect (*i); } } @@ -89,18 +72,13 @@ GlobalPortMatrix::set_state ( PortMatrix::State -GlobalPortMatrix::get_state ( - boost::shared_ptr<ARDOUR::Bundle> ab, - uint32_t ac, - boost::shared_ptr<ARDOUR::Bundle> bb, - uint32_t bc - ) const +GlobalPortMatrix::get_state (ARDOUR::BundleChannel c[2]) const { - ARDOUR::Bundle::PortList const& our_ports = ab->channel_ports (ac); - ARDOUR::Bundle::PortList const& other_ports = bb->channel_ports (bc); + ARDOUR::Bundle::PortList const & in_ports = c[IN].bundle->channel_ports (c[IN].channel); + ARDOUR::Bundle::PortList const & out_ports = c[OUT].bundle->channel_ports (c[OUT].channel); - 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) { + for (ARDOUR::Bundle::PortList::const_iterator i = in_ports.begin(); i != in_ports.end(); ++i) { + for (ARDOUR::Bundle::PortList::const_iterator j = out_ports.begin(); j != out_ports.end(); ++j) { ARDOUR::Port* p = _session.engine().get_port_by_name (*i); ARDOUR::Port* q = _session.engine().get_port_by_name (*j); diff --git a/gtk2_ardour/global_port_matrix.h b/gtk2_ardour/global_port_matrix.h index 2eca9dee7f..fe7f56394e 100644 --- a/gtk2_ardour/global_port_matrix.h +++ b/gtk2_ardour/global_port_matrix.h @@ -31,34 +31,24 @@ public: void setup (); - void set_state ( - boost::shared_ptr<ARDOUR::Bundle>, - uint32_t, - boost::shared_ptr<ARDOUR::Bundle>, - uint32_t, - bool, - uint32_t - ); - - State get_state ( - boost::shared_ptr<ARDOUR::Bundle>, - uint32_t, - boost::shared_ptr<ARDOUR::Bundle>, - uint32_t - ) const; + void set_state (ARDOUR::BundleChannel c[2], bool); + State get_state (ARDOUR::BundleChannel c[2]) const; void add_channel (boost::shared_ptr<ARDOUR::Bundle>) {} - void remove_channel (boost::shared_ptr<ARDOUR::Bundle>, uint32_t) {} - bool can_rename_channels () const { + bool can_remove_channels (int d) const { + return false; + } + void remove_channel (ARDOUR::BundleChannel) {} + bool can_rename_channels (int d) const { return false; } private: - void group_visibility_changed (); - - ARDOUR::Session& _session; - PortGroupList _our_port_group_list; - + /* see PortMatrix: signal flow from 0 to 1 (out to in) */ + enum { + OUT = 0, + IN = 1, + }; }; diff --git a/gtk2_ardour/io_selector.cc b/gtk2_ardour/io_selector.cc index b472c8eb71..1f529cf3c5 100644 --- a/gtk2_ardour/io_selector.cc +++ b/gtk2_ardour/io_selector.cc @@ -41,33 +41,39 @@ using namespace ARDOUR; using namespace Gtk; -IOSelector::IOSelector (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::IO> io, bool offer_inputs) - : PortMatrix (session, io->default_type(), offer_inputs) - , _session (session) +IOSelector::IOSelector (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::IO> io, bool in) + : PortMatrix (session, io->default_type()) , _io (io) + , _find_inputs_for_io_outputs (in) { /* Listen for ports changing on the IO */ _io->PortCountChanged.connect (sigc::hide (mem_fun (*this, &IOSelector::ports_changed))); - _port_group = new PortGroup ("", true); - _row_ports.push_back (_port_group); + /* signal flow from 0 to 1 */ + if (_find_inputs_for_io_outputs) { + _other = 1; + _ours = 0; + } else { + _other = 0; + _ours = 1; + } + + _port_group = boost::shared_ptr<PortGroup> (new PortGroup ("")); + _ports[_ours].add_group (_port_group); setup (); } -IOSelector::~IOSelector () -{ - delete _port_group; -} - void IOSelector::setup () { + _ports[_other].gather (_session, _find_inputs_for_io_outputs); + _port_group->clear (); _port_group->add_bundle (boost::shared_ptr<ARDOUR::Bundle> (new ARDOUR::Bundle)); _port_group->only_bundle()->set_name (_io->name()); - if (offering_input ()) { + if (_find_inputs_for_io_outputs) { const PortSet& ps (_io->outputs()); int j = 0; @@ -106,17 +112,10 @@ IOSelector::ports_changed () } void -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 - ) +IOSelector::set_state (ARDOUR::BundleChannel c[2], bool s) { - ARDOUR::Bundle::PortList const& our_ports = ab->channel_ports (ac); - ARDOUR::Bundle::PortList const& other_ports = bb->channel_ports (bc); + ARDOUR::Bundle::PortList const & our_ports = c[_ours].bundle->channel_ports (c[_ours].channel); + ARDOUR::Bundle::PortList const & other_ports = c[_other].bundle->channel_ports (c[_other].channel); 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) { @@ -127,13 +126,13 @@ IOSelector::set_state ( } if (s) { - if (!offering_input()) { + if (!_find_inputs_for_io_outputs) { _io->connect_input (f, *j, 0); } else { _io->connect_output (f, *j, 0); } } else { - if (!offering_input()) { + if (!_find_inputs_for_io_outputs) { _io->disconnect_input (f, *j, 0); } else { _io->disconnect_output (f, *j, 0); @@ -144,15 +143,10 @@ IOSelector::set_state ( } PortMatrix::State -IOSelector::get_state ( - boost::shared_ptr<ARDOUR::Bundle> ab, - uint32_t ac, - boost::shared_ptr<ARDOUR::Bundle> bb, - uint32_t bc - ) const +IOSelector::get_state (ARDOUR::BundleChannel c[2]) const { - ARDOUR::Bundle::PortList const& our_ports = ab->channel_ports (ac); - ARDOUR::Bundle::PortList const& other_ports = bb->channel_ports (bc); + ARDOUR::Bundle::PortList const & our_ports = c[_ours].bundle->channel_ports (c[_ours].channel); + ARDOUR::Bundle::PortList const & other_ports = c[_other].bundle->channel_ports (c[_other].channel); 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) { @@ -174,9 +168,9 @@ IOSelector::get_state ( } uint32_t -IOSelector::n_rows () const +IOSelector::n_io_ports () const { - if (!offering_input()) { + if (!_find_inputs_for_io_outputs) { return _io->inputs().num_ports (_io->default_type()); } else { return _io->outputs().num_ports (_io->default_type()); @@ -184,9 +178,9 @@ IOSelector::n_rows () const } uint32_t -IOSelector::maximum_rows () const +IOSelector::maximum_io_ports () const { - if (!offering_input()) { + if (!_find_inputs_for_io_outputs) { return _io->input_maximum ().get (_io->default_type()); } else { return _io->output_maximum ().get (_io->default_type()); @@ -195,9 +189,9 @@ IOSelector::maximum_rows () const uint32_t -IOSelector::minimum_rows () const +IOSelector::minimum_io_ports () const { - if (!offering_input()) { + if (!_find_inputs_for_io_outputs) { return _io->input_minimum ().get (_io->default_type()); } else { return _io->output_minimum ().get (_io->default_type()); @@ -212,7 +206,7 @@ IOSelector::add_channel (boost::shared_ptr<ARDOUR::Bundle> b) // The IO selector only works for single typed IOs const ARDOUR::DataType t = _io->default_type (); - if (!offering_input()) { + if (!_find_inputs_for_io_outputs) { try { _io->add_input_port ("", this); @@ -237,14 +231,14 @@ IOSelector::add_channel (boost::shared_ptr<ARDOUR::Bundle> b) } void -IOSelector::remove_channel (boost::shared_ptr<ARDOUR::Bundle> b, uint32_t c) +IOSelector::remove_channel (ARDOUR::BundleChannel bc) { - Port* f = _session.engine().get_port_by_name (b->channel_ports(c)[0]); + Port* f = _session.engine().get_port_by_name (bc.bundle->channel_ports(bc.channel)[0]); if (!f) { return; } - if (offering_input()) { + if (_find_inputs_for_io_outputs) { _io->remove_output_port (f, this); } else { _io->remove_input_port (f, this); @@ -273,7 +267,7 @@ IOSelectorWindow::IOSelectorWindow (ARDOUR::Session& session, boost::shared_ptr< get_action_area()->pack_start (disconnect_button, false, false); /* Add Port button */ - if (_selector.maximum_rows() > _selector.n_rows()) { + if (_selector.maximum_io_ports() > _selector.n_io_ports()) { 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); @@ -323,7 +317,7 @@ IOSelectorWindow::IOSelectorWindow (ARDOUR::Session& session, boost::shared_ptr< void IOSelectorWindow::ports_changed () { - if (_selector.maximum_rows() > _selector.n_rows()) { + if (_selector.maximum_io_ports() > _selector.n_io_ports()) { add_button.set_sensitive (true); } else { add_button.set_sensitive (false); @@ -358,7 +352,7 @@ IOSelectorWindow::io_name_changed (void* src) string title; - if (!_selector.offering_input()) { + if (!_selector.find_inputs_for_io_outputs()) { title = string_compose(_("%1 input"), _selector.io()->name()); } else { title = string_compose(_("%1 output"), _selector.io()->name()); diff --git a/gtk2_ardour/io_selector.h b/gtk2_ardour/io_selector.h index 20bcb2ff27..fac7281cc0 100644 --- a/gtk2_ardour/io_selector.h +++ b/gtk2_ardour/io_selector.h @@ -27,43 +27,41 @@ namespace ARDOUR { class PortInsert; } -class IOSelector : public PortMatrix { +class IOSelector : public PortMatrix +{ public: IOSelector (ARDOUR::Session&, boost::shared_ptr<ARDOUR::IO>, bool); - ~IOSelector (); - - void set_state ( - boost::shared_ptr<ARDOUR::Bundle>, - uint32_t, - boost::shared_ptr<ARDOUR::Bundle>, - uint32_t, - bool, - uint32_t - ); - - State get_state ( - boost::shared_ptr<ARDOUR::Bundle>, - uint32_t, - boost::shared_ptr<ARDOUR::Bundle>, - uint32_t - ) const; + + void set_state (ARDOUR::BundleChannel c[2], bool); + State get_state (ARDOUR::BundleChannel c[2]) const; void add_channel (boost::shared_ptr<ARDOUR::Bundle>); - void remove_channel (boost::shared_ptr<ARDOUR::Bundle>, uint32_t); - bool can_rename_channels () const { + bool can_remove_channels (int d) const { + return d == _ours; + } + void remove_channel (ARDOUR::BundleChannel); + bool can_rename_channels (int d) const { return false; } - uint32_t n_rows () const; - uint32_t maximum_rows () const; - uint32_t minimum_rows () const; + uint32_t n_io_ports () const; + uint32_t maximum_io_ports () const; + uint32_t minimum_io_ports () const; boost::shared_ptr<ARDOUR::IO> const io () { return _io; } void setup (); + bool find_inputs_for_io_outputs () const { + return _find_inputs_for_io_outputs; + } + private: - ARDOUR::Session& _session; + + int _other; + int _ours; + boost::shared_ptr<ARDOUR::IO> _io; - PortGroup* _port_group; + boost::shared_ptr<PortGroup> _port_group; + bool _find_inputs_for_io_outputs; void ports_changed (); }; diff --git a/gtk2_ardour/mixer_strip.h b/gtk2_ardour/mixer_strip.h index a831a54117..45b650172b 100644 --- a/gtk2_ardour/mixer_strip.h +++ b/gtk2_ardour/mixer_strip.h @@ -49,7 +49,6 @@ #include <pbd/fastlog.h> #include "route_ui.h" -#include "io_selector.h" #include "gain_meter.h" #include "panner_ui.h" #include "enums.h" @@ -78,6 +77,7 @@ namespace Gtk { } class Mixer_UI; +class IOSelectorWindow; class MixerStrip : public RouteUI, public Gtk::EventBox { diff --git a/gtk2_ardour/port_group.cc b/gtk2_ardour/port_group.cc index e68c8364ec..4bf565a3e9 100644 --- a/gtk2_ardour/port_group.cc +++ b/gtk2_ardour/port_group.cc @@ -40,6 +40,8 @@ PortGroup::add_bundle (boost::shared_ptr<ARDOUR::Bundle> b) { assert (b.get()); _bundles.push_back (b); + + Modified (); } /** Add a port to a group. @@ -49,6 +51,8 @@ void PortGroup::add_port (std::string const &p) { ports.push_back (p); + + Modified (); } void @@ -56,6 +60,8 @@ PortGroup::clear () { _bundles.clear (); ports.clear (); + + Modified (); } bool @@ -82,62 +88,48 @@ PortGroup::only_bundle () assert (_bundles.size() == 1); return _bundles.front(); } - -/** PortGroupUI constructor. - * @param m PortMatrix to work for. - * @Param g PortGroup to represent. - */ -PortGroupUI::PortGroupUI (PortMatrix* m, PortGroup* g) - : _port_matrix (m) - , _port_group (g) - , _visibility_checkbutton (g->name) +uint32_t +PortGroup::total_ports () const { - _port_group->set_visible (true); - setup_visibility_checkbutton (); - - _visibility_checkbutton.signal_toggled().connect (sigc::mem_fun (*this, &PortGroupUI::visibility_checkbutton_toggled)); -} + uint32_t n = 0; + for (ARDOUR::BundleList::const_iterator i = _bundles.begin(); i != _bundles.end(); ++i) { + n += (*i)->nchannels (); + } -/** The visibility of a PortGroupUI has been toggled */ -void -PortGroupUI::visibility_checkbutton_toggled () -{ - _port_group->set_visible (_visibility_checkbutton.get_active ()); - setup_visibility_checkbutton (); - _port_matrix->setup (); -} + n += ports.size(); -/** Set up the visibility checkbutton according to PortGroup::visible */ -void -PortGroupUI::setup_visibility_checkbutton () -{ - if (_visibility_checkbutton.get_active () != _port_group->visible()) { - _visibility_checkbutton.set_active (_port_group->visible()); - } + return n; } + /** PortGroupList constructor. - * @param type Type of bundles to offer (audio or MIDI) - * @param offer_inputs true to offer output bundles, otherwise false. */ -PortGroupList::PortGroupList (ARDOUR::DataType type, bool offer_inputs) - : _type (type), _offer_inputs (offer_inputs), _bundles_dirty (true), - _buss (_("Bus"), true), - _track (_("Track"), true), - _system (_("System"), true), - _other (_("Other"), true) +PortGroupList::PortGroupList () + : _type (ARDOUR::DataType::AUDIO), _bundles_dirty (true) { } +void +PortGroupList::set_type (ARDOUR::DataType t) +{ + _type = t; + clear (); +} + /** Gather bundles from around the system and put them in this PortGroupList */ void -PortGroupList::gather (ARDOUR::Session& session) +PortGroupList::gather (ARDOUR::Session& session, bool inputs) { - clear_list (); + clear (); + + boost::shared_ptr<PortGroup> buss (new PortGroup (_("Buss"))); + boost::shared_ptr<PortGroup> track (new PortGroup (_("Track"))); + boost::shared_ptr<PortGroup> system (new PortGroup (_("System"))); + boost::shared_ptr<PortGroup> other (new PortGroup (_("Other"))); /* Find the bundles for routes. We take their bundles, copy them, and add ports from the route's processors */ @@ -148,7 +140,7 @@ PortGroupList::gather (ARDOUR::Session& session) /* Copy the appropriate bundle from the route */ boost::shared_ptr<ARDOUR::Bundle> bundle ( new ARDOUR::Bundle ( - _offer_inputs ? (*i)->bundle_for_inputs() : (*i)->bundle_for_outputs () + inputs ? (*i)->bundle_for_inputs() : (*i)->bundle_for_outputs () ) ); @@ -163,7 +155,7 @@ PortGroupList::gather (ARDOUR::Session& session) boost::shared_ptr<ARDOUR::IOProcessor> iop = boost::dynamic_pointer_cast<ARDOUR::IOProcessor> (p); if (iop) { - boost::shared_ptr<ARDOUR::Bundle> pb = _offer_inputs ? + boost::shared_ptr<ARDOUR::Bundle> pb = inputs ? iop->io()->bundle_for_inputs() : iop->io()->bundle_for_outputs(); bundle->add_channels_from_bundle (pb); } @@ -172,20 +164,20 @@ PortGroupList::gather (ARDOUR::Session& session) } /* Work out which group to put this bundle in */ - PortGroup* g = 0; + boost::shared_ptr<PortGroup> g; if (_type == ARDOUR::DataType::AUDIO) { if (boost::dynamic_pointer_cast<ARDOUR::AudioTrack> (*i)) { - g = &_track; + g = track; } else if (!boost::dynamic_pointer_cast<ARDOUR::MidiTrack>(*i)) { - g = &_buss; + g = buss; } } else if (_type == ARDOUR::DataType::MIDI) { if (boost::dynamic_pointer_cast<ARDOUR::MidiTrack> (*i)) { - g = &_track; + g = track; } /* No MIDI busses yet */ @@ -200,14 +192,14 @@ PortGroupList::gather (ARDOUR::Session& session) boost::shared_ptr<ARDOUR::BundleList> b = session.bundles (); for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) { - if ((*i)->ports_are_inputs() == _offer_inputs && (*i)->type() == _type) { - _system.add_bundle (*i); + if ((*i)->ports_are_inputs() == inputs && (*i)->type() == _type) { + system->add_bundle (*i); } } /* Now find all other ports that we haven't thought of yet */ - const char **ports = session.engine().get_ports ("", _type.to_jack_type(), _offer_inputs ? + const char **ports = session.engine().get_ports ("", _type.to_jack_type(), inputs ? JackPortIsInput : JackPortIsOutput); if (ports) { @@ -221,14 +213,14 @@ PortGroupList::gather (ARDOUR::Session& session) std::string const p = ports[n]; - if (!_system.has_port(p) && !_buss.has_port(p) && !_track.has_port(p) && !_other.has_port(p)) { + if (!system->has_port(p) && !buss->has_port(p) && !track->has_port(p) && !other->has_port(p)) { if (port_has_prefix (p, "system:") || port_has_prefix (p, "alsa_pcm") || port_has_prefix (p, "ardour:")) { - _system.add_port (p); + system->add_port (p); } else { - _other.add_port (p); + other->add_port (p); } } @@ -238,16 +230,10 @@ PortGroupList::gather (ARDOUR::Session& session) free (ports); } - push_back (&_system); - push_back (&_buss); - push_back (&_track); - push_back (&_other); - - for (iterator i = begin(); i != end(); ++i) { - _visibility_connections.push_back ( - (*i)->VisibilityChanged.connect (sigc::mem_fun (*this, &PortGroupList::visibility_changed)) - ); - } + add_group (system); + add_group (buss); + add_group (track); + add_group (other); _bundles_dirty = true; } @@ -260,25 +246,11 @@ PortGroupList::port_has_prefix (const std::string& n, const std::string& p) cons void -PortGroupList::set_type (ARDOUR::DataType t) -{ - _type = t; - _bundles_dirty = true; -} - -void -PortGroupList::set_offer_inputs (bool i) -{ - _offer_inputs = i; - _bundles_dirty = true; -} - -void PortGroupList::update_bundles () const { _bundles.clear (); - for (const_iterator i = begin (); i != end (); ++i) { + for (PortGroupList::List::const_iterator i = begin (); i != end (); ++i) { if ((*i)->visible()) { std::copy ((*i)->bundles().begin(), (*i)->bundles().end(), std::back_inserter (_bundles)); @@ -346,48 +318,46 @@ PortGroupList::common_prefix (std::vector<std::string> const & p) const } void -PortGroupList::visibility_changed () +PortGroupList::clear () { - VisibilityChanged (); + _groups.clear (); + _bundles_dirty = true; } -void -PortGroupList::take_visibility_from (PortGroupList const & o) +ARDOUR::BundleList const & +PortGroupList::bundles () const { - iterator i = begin (); - const_iterator j = o.begin (); - - while (i != end() && j != o.end()) { - (*i)->set_visible ((*j)->visible()); - ++i; - ++j; + if (_bundles_dirty) { + update_bundles (); } + + return _bundles; } -void -PortGroupList::clear_list () +uint32_t +PortGroupList::total_visible_ports () const { - clear (); - - _buss.clear (); - _track.clear (); - _system.clear (); - _other.clear (); - - for (std::vector<sigc::connection>::iterator i = _visibility_connections.begin(); i != _visibility_connections.end(); ++i) { - i->disconnect (); + uint32_t n = 0; + + for (PortGroupList::List::const_iterator i = begin(); i != end(); ++i) { + if ((*i)->visible()) { + n += (*i)->total_ports (); + } } - _visibility_connections.clear (); - _bundles_dirty = true; + return n; } -ARDOUR::BundleList const & -PortGroupList::bundles () const +void +PortGroupList::group_modified () { - if (_bundles_dirty) { - update_bundles (); - } + _bundles_dirty = true; +} - return _bundles; +void +PortGroupList::add_group (boost::shared_ptr<PortGroup> g) +{ + _groups.push_back (g); + g->Modified.connect (sigc::mem_fun (*this, &PortGroupList::group_modified)); + _bundles_dirty = true; } diff --git a/gtk2_ardour/port_group.h b/gtk2_ardour/port_group.h index d6008b61ba..c2961c4925 100644 --- a/gtk2_ardour/port_group.h +++ b/gtk2_ardour/port_group.h @@ -44,15 +44,15 @@ class PortGroup : public sigc::trackable public: /** PortGroup constructor. * @param n Name. - * @param v true if group should be visible in the UI, otherwise false. */ - PortGroup (std::string const & n, bool v) - : name (n), _visible (v) {} + PortGroup (std::string const & n) + : name (n), _visible (true) {} void add_bundle (boost::shared_ptr<ARDOUR::Bundle>); boost::shared_ptr<ARDOUR::Bundle> only_bundle (); void add_port (std::string const &); void clear (); + uint32_t total_ports () const; std::string name; ///< name for the group std::vector<std::string> ports; @@ -67,69 +67,56 @@ public: void set_visible (bool v) { _visible = v; - VisibilityChanged (); + Modified (); } bool has_port (std::string const &) const; - sigc::signal<void> VisibilityChanged; + sigc::signal<void> Modified; private: ARDOUR::BundleList _bundles; bool _visible; ///< true if the group is visible in the UI }; -/// The UI for a PortGroup -class PortGroupUI -{ - public: - PortGroupUI (PortMatrix*, PortGroup*); - - Gtk::Widget& visibility_checkbutton () { - return _visibility_checkbutton; - } - - private: - 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 - Gtk::CheckButton _visibility_checkbutton; -}; - /// A list of PortGroups -class PortGroupList : public std::list<PortGroup*>, public sigc::trackable +class PortGroupList { public: - PortGroupList (ARDOUR::DataType, bool); + PortGroupList (); - void gather (ARDOUR::Session &); + typedef std::vector<boost::shared_ptr<PortGroup> > List; + + void add_group (boost::shared_ptr<PortGroup>); void set_type (ARDOUR::DataType); + void gather (ARDOUR::Session &, bool); void set_offer_inputs (bool); ARDOUR::BundleList const & bundles () const; - void take_visibility_from (PortGroupList const &); - void clear_list (); + void clear (); + uint32_t total_visible_ports () const; + uint32_t size () const { + return _groups.size(); + } + + List::const_iterator begin () const { + return _groups.begin(); + } - sigc::signal<void> VisibilityChanged; + List::const_iterator end () const { + return _groups.end(); + } private: bool port_has_prefix (std::string const &, std::string const &) const; std::string common_prefix (std::vector<std::string> const &) const; - void visibility_changed (); void update_bundles () const; + void group_modified (); ARDOUR::DataType _type; bool _offer_inputs; mutable ARDOUR::BundleList _bundles; mutable bool _bundles_dirty; - - PortGroup _buss; - PortGroup _track; - PortGroup _system; - PortGroup _other; - - std::vector<sigc::connection> _visibility_connections; + List _groups; }; #endif /* __gtk_ardour_port_group_h__ */ diff --git a/gtk2_ardour/port_matrix.cc b/gtk2_ardour/port_matrix.cc index 55cd6a46b5..4607b840c1 100644 --- a/gtk2_ardour/port_matrix.cc +++ b/gtk2_ardour/port_matrix.cc @@ -21,6 +21,9 @@ #include <gtkmm/scrolledwindow.h> #include <gtkmm/adjustment.h> #include <gtkmm/label.h> +#include <gtkmm/menu.h> +#include <gtkmm/menushell.h> +#include <gtkmm/menu_elems.h> #include "ardour/bundle.h" #include "ardour/types.h" #include "ardour/session.h" @@ -31,59 +34,50 @@ /** PortMatrix constructor. * @param session Our session. * @param type Port type that we are handling. - * @param offer_inputs true to offer inputs, otherwise false. */ -PortMatrix::PortMatrix (ARDOUR::Session& session, ARDOUR::DataType type, bool offer_inputs) - : _row_ports (type, !offer_inputs), - _column_ports (type, offer_inputs), - _session (session), - _offer_inputs (offer_inputs), +PortMatrix::PortMatrix (ARDOUR::Session& session, ARDOUR::DataType type) + : _session (session), _type (type), - _body (this, offer_inputs ? PortMatrixBody::BOTTOM_AND_LEFT : PortMatrixBody::TOP_AND_RIGHT) + _body (this), + _menu (0), + _setup_once (false), + _arrangement (TOP_TO_RIGHT), + _row_index (0), + _column_index (1) { - setup (); - - /* checkbuttons for visibility of groups */ - Gtk::HBox* visibility_buttons = Gtk::manage (new Gtk::HBox); - - visibility_buttons->pack_start (*Gtk::manage (new Gtk::Label (_("Show:"))), Gtk::PACK_SHRINK); - - for (std::list<PortGroup*>::iterator i = _column_ports.begin(); i != _column_ports.end(); ++i) { - _port_group_uis.push_back (new PortGroupUI (this, *i)); - } - - 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); - } + _ports[0].set_type (type); + _ports[1].set_type (type); - 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); + _row_visibility_box.pack_start (_row_visibility_label, Gtk::PACK_SHRINK); + _column_visibility_box.pack_start (_column_visibility_label, Gtk::PACK_SHRINK); _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 (); + /* watch for routes being added or removed */ _session.RouteAdded.connect (sigc::hide (sigc::mem_fun (*this, &PortMatrix::routes_changed))); - routes_changed (); + + reconnect_to_routes (); - /* XXX hard-coded initial size suggestion */ - set_size_request (400, 200); show_all (); } PortMatrix::~PortMatrix () { - for (std::list<PortGroupUI*>::iterator i = _port_group_uis.begin(); i != _port_group_uis.end(); ++i) { + for (std::vector<Gtk::CheckButton*>::iterator i = _column_visibility_buttons.begin(); i != _column_visibility_buttons.end(); ++i) { + delete *i; + } + + for (std::vector<Gtk::CheckButton*>::iterator i = _row_visibility_buttons.begin(); i != _row_visibility_buttons.end(); ++i) { delete *i; } + + delete _menu; } +/** Disconnect from and reconnect to routes' signals that we need to watch for things that affect the matrix */ void -PortMatrix::routes_changed () +PortMatrix::reconnect_to_routes () { for (std::vector<sigc::connection>::iterator i = _route_connections.begin(); i != _route_connections.end(); ++i) { i->disconnect (); @@ -95,34 +89,120 @@ PortMatrix::routes_changed () (*i)->processors_changed.connect (sigc::mem_fun (*this, &PortMatrix::setup)) ); } +} +/** A route has been added to or removed from the session */ +void +PortMatrix::routes_changed () +{ + reconnect_to_routes (); setup (); } +/** Set up everything that changes about the matrix */ void PortMatrix::setup () { - _column_ports.gather (_session); - _body.setup (_row_ports, _column_ports); + select_arrangement (); + _body.setup (); setup_scrollbars (); queue_draw (); -} -void -PortMatrix::set_offer_inputs (bool s) -{ - _offer_inputs = s; - _column_ports.set_offer_inputs (s); - _row_ports.set_offer_inputs (!s); - setup (); + if (_setup_once) { + + /* we've set up before, so we need to clean up before re-setting-up */ + + for (std::vector<Gtk::CheckButton*>::iterator i = _column_visibility_buttons.begin(); i != _column_visibility_buttons.end(); ++i) { + _column_visibility_box.remove (**i); + delete *i; + } + + _column_visibility_buttons.clear (); + + for (std::vector<Gtk::CheckButton*>::iterator i = _row_visibility_buttons.begin(); i != _row_visibility_buttons.end(); ++i) { + _row_visibility_box.remove (**i); + delete *i; + } + + _row_visibility_buttons.clear (); + + _scroller_table.remove (_vscroll); + _scroller_table.remove (_body); + _scroller_table.remove (_hscroll); + + _main_hbox.remove (_scroller_table); + _main_hbox.remove (_row_visibility_box); + + remove (_column_visibility_box); + remove (_main_hbox); + } + + if (_column_index == 0) { + _column_visibility_label.set_text (_("Show Outputs")); + _row_visibility_label.set_text (_("Show Inputs")); + } else { + _column_visibility_label.set_text (_("Show Inputs")); + _row_visibility_label.set_text (_("Show Outputs")); + } + + /* only show visibility checkbuttons if there is more than one group */ + if (columns()->size() > 1) { + for (PortGroupList::List::const_iterator i = columns()->begin(); i != columns()->end(); ++i) { + Gtk::CheckButton* b = new Gtk::CheckButton ((*i)->name); + b->set_active ((*i)->visible()); + boost::weak_ptr<PortGroup> w (*i); + b->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &PortMatrix::visibility_toggled), w, b)); + _column_visibility_buttons.push_back (b); + _column_visibility_box.pack_start (*b, Gtk::PACK_SHRINK); + } + } + + if (rows()->size() > 1) { + for (PortGroupList::List::const_iterator i = rows()->begin(); i != rows()->end(); ++i) { + Gtk::CheckButton* b = new Gtk::CheckButton ((*i)->name); + b->set_active ((*i)->visible()); + boost::weak_ptr<PortGroup> w (*i); + b->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &PortMatrix::visibility_toggled), w, b)); + _row_visibility_buttons.push_back (b); + _row_visibility_box.pack_start (*b, Gtk::PACK_SHRINK); + } + } + + if (_arrangement == TOP_TO_RIGHT) { + + _scroller_table.attach (_hscroll, 0, 1, 0, 1, Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK); + _scroller_table.attach (_body, 0, 1, 1, 2); + _scroller_table.attach (_vscroll, 1, 2, 1, 2, Gtk::SHRINK); + + _main_hbox.pack_start (_scroller_table); + _main_hbox.pack_start (_row_visibility_box, Gtk::PACK_SHRINK); + + pack_start (_column_visibility_box, Gtk::PACK_SHRINK); + pack_start (_main_hbox); + + } else { + _scroller_table.attach (_vscroll, 0, 1, 0, 1, Gtk::SHRINK); + _scroller_table.attach (_body, 1, 2, 0, 1); + _scroller_table.attach (_hscroll, 1, 2, 1, 2, Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK); + + _main_hbox.pack_start (_row_visibility_box, Gtk::PACK_SHRINK); + _main_hbox.pack_start (_scroller_table); + + pack_start (_main_hbox); + pack_start (_column_visibility_box, Gtk::PACK_SHRINK); + } + + _setup_once = true; + + show_all (); } void PortMatrix::set_type (ARDOUR::DataType t) { _type = t; - _column_ports.set_type (t); - _row_ports.set_type (t); + _ports[0].set_type (_type); + _ports[1].set_type (_type); setup (); } @@ -156,23 +236,166 @@ PortMatrix::setup_scrollbars () a->set_page_increment (128); } +/** Disassociate all of our ports from each other */ void PortMatrix::disassociate_all () { - ARDOUR::BundleList c = _column_ports.bundles (); - ARDOUR::BundleList r = _row_ports.bundles (); + ARDOUR::BundleList a = _ports[0].bundles (); + ARDOUR::BundleList b = _ports[1].bundles (); - for (ARDOUR::BundleList::iterator i = c.begin(); i != c.end(); ++i) { + for (ARDOUR::BundleList::iterator i = a.begin(); i != a.end(); ++i) { for (uint32_t j = 0; j < (*i)->nchannels(); ++j) { - for (uint32_t k = 0; k < r.front()->nchannels(); ++k) { + for (ARDOUR::BundleList::iterator k = b.begin(); k != b.end(); ++k) { + for (uint32_t l = 0; l < (*k)->nchannels(); ++l) { + + ARDOUR::BundleChannel c[2] = { + ARDOUR::BundleChannel (*i, j), + ARDOUR::BundleChannel (*k, l) + }; + + set_state (c, false); - set_state ( - r.front(), k, *i, j, false, 0 - ); - + } } } } _body.rebuild_and_draw_grid (); } + +/* Decide how to arrange the components of the matrix */ +void +PortMatrix::select_arrangement () +{ + uint32_t const N[2] = { + _ports[0].total_visible_ports (), + _ports[1].total_visible_ports () + }; + + /* The list with the most ports goes on left or right, so that the most port + names are printed horizontally and hence more readable. However we also + maintain notional `signal flow' vaguely from left to right. Subclasses + should choose where to put ports based on signal flowing from _ports[0] + to _ports[1] */ + + if (N[0] > N[1]) { + + _row_index = 0; + _column_index = 1; + _arrangement = LEFT_TO_BOTTOM; + + } else { + + _row_index = 1; + _column_index = 0; + _arrangement = TOP_TO_RIGHT; + } +} + +/** @return columns list */ +PortGroupList const * +PortMatrix::columns () const +{ + return &_ports[_column_index]; +} + +/* @return rows list */ +PortGroupList const * +PortMatrix::rows () const +{ + return &_ports[_row_index]; +} + +/** A group visibility checkbutton has been toggled. + * @param w Group. + * @param b Button. + */ +void +PortMatrix::visibility_toggled (boost::weak_ptr<PortGroup> w, Gtk::CheckButton* b) +{ + boost::shared_ptr<PortGroup> g = w.lock (); + if (!g) { + return; + } + + g->set_visible (b->get_active()); + _body.setup (); + setup_scrollbars (); + queue_draw (); +} + +void +PortMatrix::popup_channel_context_menu (int dim, uint32_t N, uint32_t t) +{ + delete _menu; + + _menu = new Gtk::Menu; + _menu->set_name ("ArdourContextMenu"); + + Gtk::Menu_Helpers::MenuList& items = _menu->items (); + + ARDOUR::BundleChannel bc; + + ARDOUR::BundleList const r = _ports[dim].bundles(); + for (ARDOUR::BundleList::const_iterator i = r.begin(); i != r.end(); ++i) { + if (N < (*i)->nchannels ()) { + bc = ARDOUR::BundleChannel (*i, N); + break; + } else { + N -= (*i)->nchannels (); + } + } + + if (bc.bundle) { + char buf [64]; + + if (can_rename_channels (dim)) { + snprintf (buf, sizeof (buf), _("Rename '%s'..."), bc.bundle->channel_name (bc.channel).c_str()); + boost::weak_ptr<ARDOUR::Bundle> w (bc.bundle); + items.push_back ( + Gtk::Menu_Helpers::MenuElem ( + buf, + sigc::bind (sigc::mem_fun (*this, &PortMatrix::rename_channel_proxy), w, bc.channel) + ) + ); + } + + if (can_remove_channels (dim)) { + snprintf (buf, sizeof (buf), _("Remove '%s'"), bc.bundle->channel_name (bc.channel).c_str()); + boost::weak_ptr<ARDOUR::Bundle> w (bc.bundle); + items.push_back ( + Gtk::Menu_Helpers::MenuElem ( + buf, + sigc::bind (sigc::mem_fun (*this, &PortMatrix::remove_channel_proxy), w, bc.channel) + ) + ); + } + + _menu->popup (1, t); + } + +} + + +void +PortMatrix::remove_channel_proxy (boost::weak_ptr<ARDOUR::Bundle> b, uint32_t c) +{ + boost::shared_ptr<ARDOUR::Bundle> sb = b.lock (); + if (!sb) { + return; + } + + remove_channel (ARDOUR::BundleChannel (sb, c)); + +} + +void +PortMatrix::rename_channel_proxy (boost::weak_ptr<ARDOUR::Bundle> b, uint32_t c) +{ + boost::shared_ptr<ARDOUR::Bundle> sb = b.lock (); + if (!sb) { + return; + } + + rename_channel (ARDOUR::BundleChannel (sb, c)); +} diff --git a/gtk2_ardour/port_matrix.h b/gtk2_ardour/port_matrix.h index 425e3915c4..b93a288c50 100644 --- a/gtk2_ardour/port_matrix.h +++ b/gtk2_ardour/port_matrix.h @@ -23,6 +23,9 @@ #include <list> #include <gtkmm/box.h> #include <gtkmm/scrollbar.h> +#include <gtkmm/table.h> +#include <gtkmm/label.h> +#include <gtkmm/checkbutton.h> #include <boost/shared_ptr.hpp> #include "port_matrix_body.h" #include "port_group.h" @@ -31,12 +34,9 @@ * 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. + * and some scrollbars and other stuff. All of this is arranged inside the + * VBox that we inherit from. */ namespace ARDOUR { @@ -46,94 +46,116 @@ namespace ARDOUR { class PortMatrix : public Gtk::VBox { public: - PortMatrix (ARDOUR::Session&, ARDOUR::DataType, bool); + PortMatrix (ARDOUR::Session&, ARDOUR::DataType); ~PortMatrix (); - virtual void setup (); - void set_offer_inputs (bool); void set_type (ARDOUR::DataType); ARDOUR::DataType type () const { return _type; } - bool offering_input () const { - return _offer_inputs; - } - void disassociate_all (); + void setup_scrollbars (); + void popup_channel_context_menu (int, uint32_t, uint32_t); - enum Result { - Cancelled, - Accepted + enum Arrangement { + TOP_TO_RIGHT, ///< column labels on top, row labels to the right + LEFT_TO_BOTTOM ///< row labels to the left, column labels on the bottom }; - sigc::signal<void, Result> Finished; + /** @return Arrangement in use */ + Arrangement arrangement () const { + return _arrangement; + } - /** @param ab Our bundle. - * @param ac Channel on our bundle. - * @param bb Other bundle. - * @arapm bc Channel on other bundle. + PortGroupList const * columns () const; + + /** @return index into the _ports array for the list which is displayed as columns */ + int column_index () const { + return _column_index; + } + + PortGroupList const * rows () const; + + /** @return index into the _ports array for the list which is displayed as rows */ + int row_index () const { + return _row_index; + } + + virtual void setup (); + + /** @param c Channels; where c[0] is from _ports[0] and c[1] is from _ports[1]. * @param s New state. - * @param k XXX */ - 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; + virtual void set_state (ARDOUR::BundleChannel c[2], bool s) = 0; enum State { - ASSOCIATED, - NOT_ASSOCIATED, - UNKNOWN + ASSOCIATED, ///< the ports are associaed + NOT_ASSOCIATED, ///< the ports are not associated + UNKNOWN ///< we don't know anything about these two ports' relationship }; - /** @param ab Our bundle. - * @param ac Channel on our bundle. - * @param bb Other bundle. - * @arapm bc Channel on other bundle. + /** @param c Channels; where c[0] is from _ports[0] and c[1] is from _ports[1]. * @return state */ - virtual State get_state ( - boost::shared_ptr<ARDOUR::Bundle> ab, - uint32_t ac, - boost::shared_ptr<ARDOUR::Bundle> bb, - uint32_t bc - ) const = 0; + virtual State get_state (ARDOUR::BundleChannel c[2]) 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 bool can_remove_channels (int) const = 0; + virtual void remove_channel (ARDOUR::BundleChannel) = 0; + virtual bool can_rename_channels (int) const = 0; + virtual void rename_channel (ARDOUR::BundleChannel) {} - void setup_scrollbars (); + enum Result { + Cancelled, + Accepted + }; + + sigc::signal<void, Result> Finished; protected: - PortGroupList _row_ports; - PortGroupList _column_ports; + /** We have two port group lists. One will be presented on the rows of the matrix, + the other on the columns. The PortMatrix chooses the arrangement based on which has + more ports in it. Subclasses must fill these two lists with the port groups that they + wish to present. The PortMatrix will arrange its layout such that signal flow is vaguely + from left to right as you go from list 0 to list 1. Hence subclasses which deal with + inputs and outputs should put outputs in list 0 and inputs in list 1. */ + PortGroupList _ports[2]; + ARDOUR::Session& _session; private: void hscroll_changed (); void vscroll_changed (); void routes_changed (); + void reconnect_to_routes (); + void visibility_toggled (boost::weak_ptr<PortGroup>, Gtk::CheckButton *); + void select_arrangement (); + void remove_channel_proxy (boost::weak_ptr<ARDOUR::Bundle>, uint32_t); + void rename_channel_proxy (boost::weak_ptr<ARDOUR::Bundle>, uint32_t); - ARDOUR::Session& _session; - /// true to offer inputs, otherwise false - bool _offer_inputs; /// port type that we are working with ARDOUR::DataType _type; + std::vector<sigc::connection> _route_connections; PortMatrixBody _body; Gtk::HScrollbar _hscroll; Gtk::VScrollbar _vscroll; - std::list<PortGroupUI*> _port_group_uis; - std::vector<sigc::connection> _route_connections; + Gtk::HBox _main_hbox; + Gtk::HBox _column_visibility_box; + Gtk::Label _column_visibility_label; + std::vector<Gtk::CheckButton*> _column_visibility_buttons; + Gtk::VBox _row_visibility_box; + Gtk::Label _row_visibility_label; + std::vector<Gtk::CheckButton*> _row_visibility_buttons; + Gtk::Table _scroller_table; + Gtk::Menu* _menu; + bool _setup_once; + Arrangement _arrangement; + int _row_index; + int _column_index; }; #endif diff --git a/gtk2_ardour/port_matrix_body.cc b/gtk2_ardour/port_matrix_body.cc index d30fd58c6a..a16e893ee3 100644 --- a/gtk2_ardour/port_matrix_body.cc +++ b/gtk2_ardour/port_matrix_body.cc @@ -23,17 +23,14 @@ #include "port_matrix_body.h" #include "port_matrix.h" -PortMatrixBody::PortMatrixBody (PortMatrix* p, Arrangement a) - : _port_matrix (p), - _column_labels (this, a == TOP_AND_RIGHT ? PortMatrixColumnLabels::TOP : PortMatrixColumnLabels::BOTTOM), - _row_labels (p, this, a == BOTTOM_AND_LEFT ? PortMatrixRowLabels::LEFT : PortMatrixRowLabels::RIGHT), +PortMatrixBody::PortMatrixBody (PortMatrix* p) + : _matrix (p), + _column_labels (p, this), + _row_labels (p, this), _grid (p, this), - _arrangement (a), _xoffset (0), _yoffset (0), - _pointer_inside (false), - _column_ports (_port_matrix->type(), _port_matrix->offering_input()), - _row_ports (_port_matrix->type(), !_port_matrix->offering_input()) + _pointer_inside (false) { modify_bg (Gtk::STATE_NORMAL, Gdk::Color ("#00000")); add_events (Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK | Gdk::POINTER_MOTION_MASK); @@ -115,21 +112,23 @@ PortMatrixBody::on_size_request (Gtk::Requisition *req) 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; + /* don't ask for the maximum size of our contents, otherwise GTK won't + let the containing window shrink below this size */ + + req->width = std::min (512, std::max (col.first, grid.first + row.first)); + req->height = std::min (512, 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_rectangles (); - _port_matrix->setup_scrollbars (); + _matrix->setup_scrollbars (); } void @@ -144,7 +143,7 @@ PortMatrixBody::compute_rectangles () Gdk::Rectangle row_rect; Gdk::Rectangle grid_rect; - if (_arrangement == TOP_AND_RIGHT) { + if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) { /* build from top left */ @@ -187,7 +186,7 @@ PortMatrixBody::compute_rectangles () row_rect.set_width (_alloc_width - x); - } else if (_arrangement == BOTTOM_AND_LEFT) { + } else if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) { /* build from bottom right */ @@ -233,18 +232,18 @@ PortMatrixBody::compute_rectangles () } void -PortMatrixBody::setup (PortGroupList const& row, PortGroupList const& column) +PortMatrixBody::setup () { + /* Discard any old connections to bundles */ + for (std::list<sigc::connection>::iterator i = _bundle_connections.begin(); i != _bundle_connections.end(); ++i) { i->disconnect (); } - _bundle_connections.clear (); - - _row_ports = row; - _column_ports = column; - ARDOUR::BundleList r = _row_ports.bundles (); + /* Connect to bundles so that we find out when their names change */ + + ARDOUR::BundleList r = _matrix->rows()->bundles (); for (ARDOUR::BundleList::iterator i = r.begin(); i != r.end(); ++i) { _bundle_connections.push_back ( @@ -253,7 +252,7 @@ PortMatrixBody::setup (PortGroupList const& row, PortGroupList const& column) } - ARDOUR::BundleList c = _column_ports.bundles (); + ARDOUR::BundleList c = _matrix->columns()->bundles (); for (ARDOUR::BundleList::iterator i = c.begin(); i != c.end(); ++i) { _bundle_connections.push_back ( (*i)->NameChanged.connect (sigc::mem_fun (*this, &PortMatrixBody::rebuild_and_draw_column_labels)) @@ -264,6 +263,13 @@ PortMatrixBody::setup (PortGroupList const& row, PortGroupList const& column) _row_labels.setup (); _grid.setup (); + set_mouseover ( + PortMatrixNode ( + ARDOUR::BundleChannel (boost::shared_ptr<ARDOUR::Bundle> (), 0), + ARDOUR::BundleChannel (boost::shared_ptr<ARDOUR::Bundle> (), 0) + ) + ); + compute_rectangles (); } @@ -325,10 +331,13 @@ PortMatrixBody::on_button_press_event (GdkEventButton* ev) ev->button, ev->time ); - } else { - - return false; - + } else if (Gdk::Region (_column_labels.parent_rectangle()).point_in (ev->x, ev->y)) { + + _column_labels.button_press ( + _column_labels.parent_to_component_x (ev->x), + _column_labels.parent_to_component_y (ev->y), + ev->button, ev->time + ); } return true; diff --git a/gtk2_ardour/port_matrix_body.h b/gtk2_ardour/port_matrix_body.h index b1ec6e2ada..3692e05ec5 100644 --- a/gtk2_ardour/port_matrix_body.h +++ b/gtk2_ardour/port_matrix_body.h @@ -30,29 +30,13 @@ 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: - enum Arrangement { - TOP_AND_RIGHT, - BOTTOM_AND_LEFT - }; + PortMatrixBody (PortMatrix *); - PortMatrixBody (PortMatrix *, Arrangement); - - /** @return ports to offer for columns */ - PortGroupList const & column_ports () { - return _column_ports; - } - - /** @return ports to offer for rows */ - PortGroupList const & row_ports () { - return _row_ports; - } - - void setup (PortGroupList const &, PortGroupList const &); + void setup (); uint32_t full_scroll_width (); uint32_t alloc_scroll_width (); @@ -75,10 +59,6 @@ public: return _mouseover; } - Arrangement arrangement () const { - return _arrangement; - } - protected: bool on_expose_event (GdkEventExpose *); void on_size_request (Gtk::Requisition *); @@ -93,12 +73,11 @@ private: void rebuild_and_draw_row_labels (); void update_bundles (); - PortMatrix* _port_matrix; + PortMatrix* _matrix; PortMatrixColumnLabels _column_labels; PortMatrixRowLabels _row_labels; PortMatrixGrid _grid; - Arrangement _arrangement; uint32_t _alloc_width; ///< allocated width uint32_t _alloc_height; ///< allocated height Gdk::Rectangle _column_labels_rect; @@ -108,11 +87,6 @@ private: uint32_t _yoffset; bool _pointer_inside; - /// bundles to offer for columns - PortGroupList _column_ports; - /// bundles to offer for rows - PortGroupList _row_ports; - PortMatrixNode _mouseover; std::list<sigc::connection> _bundle_connections; diff --git a/gtk2_ardour/port_matrix_column_labels.cc b/gtk2_ardour/port_matrix_column_labels.cc index d99cb92d86..2a2fcf80d5 100644 --- a/gtk2_ardour/port_matrix_column_labels.cc +++ b/gtk2_ardour/port_matrix_column_labels.cc @@ -23,8 +23,8 @@ #include "port_matrix_column_labels.h" #include "port_matrix.h" -PortMatrixColumnLabels::PortMatrixColumnLabels (PortMatrixBody* b, Location l) - : PortMatrixComponent (b), _location (l) +PortMatrixColumnLabels::PortMatrixColumnLabels (PortMatrix* m, PortMatrixBody* b) + : PortMatrixComponent (m, b) { } @@ -45,7 +45,7 @@ PortMatrixColumnLabels::compute_dimensions () /* width of the whole thing */ _width = 0; - ARDOUR::BundleList const c = _body->column_ports().bundles(); + ARDOUR::BundleList const c = _matrix->columns()->bundles(); for (ARDOUR::BundleList::const_iterator i = c.begin (); i != c.end(); ++i) { cairo_text_extents_t ext; @@ -77,7 +77,7 @@ PortMatrixColumnLabels::compute_dimensions () } _highest_group_name = 0; - for (PortGroupList::const_iterator i = _body->column_ports().begin(); i != _body->column_ports().end(); ++i) { + for (PortGroupList::List::const_iterator i = _matrix->columns()->begin(); i != _matrix->columns()->end(); ++i) { if ((*i)->visible()) { cairo_text_extents_t ext; cairo_text_extents (cr, (*i)->name.c_str(), &ext); @@ -122,7 +122,7 @@ PortMatrixColumnLabels::render (cairo_t* cr) double x = 0; double y = 0; - if (_location == TOP) { + if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) { x = slanted_height() / tan (angle()); y = _highest_group_name + name_pad(); } else { @@ -131,7 +131,7 @@ PortMatrixColumnLabels::render (cairo_t* cr) } int g = 0; - for (PortGroupList::const_iterator i = _body->column_ports().begin(); i != _body->column_ports().end(); ++i) { + for (PortGroupList::List::const_iterator i = _matrix->columns()->begin(); i != _matrix->columns()->end(); ++i) { if (!(*i)->visible() || ((*i)->bundles().empty() && (*i)->ports.empty()) ) { continue; @@ -147,9 +147,9 @@ PortMatrixColumnLabels::render (cairo_t* cr) /* rectangle */ set_source_rgb (cr, get_a_group_colour (g)); double const rh = _highest_group_name + 2 * name_pad(); - if (_location == TOP) { + if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) { cairo_rectangle (cr, x, 0, w, rh); - } else if (_location == BOTTOM) { + } else { cairo_rectangle (cr, x, _height - rh, w, rh); } cairo_fill (cr); @@ -168,7 +168,7 @@ PortMatrixColumnLabels::render (cairo_t* cr) /* BUNDLE PARALLELOGRAM-TYPE-THING AND NAME */ x = 0; - ARDOUR::BundleList const c = _body->column_ports().bundles(); + ARDOUR::BundleList const c = _matrix->columns()->bundles(); for (ARDOUR::BundleList::const_iterator i = c.begin (); i != c.end(); ++i) { Gdk::Color colour = get_a_bundle_colour (i - c.begin ()); @@ -178,9 +178,9 @@ PortMatrixColumnLabels::render (cairo_t* cr) double x_ = x; - if (_location == TOP) { + if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) { y = _height; - } else if (_location == BOTTOM) { + } else { y = slanted_height(); } @@ -201,7 +201,7 @@ PortMatrixColumnLabels::render (cairo_t* cr) set_source_rgb (cr, text_colour()); - if (_location == TOP) { + if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) { double const rl = 3 * name_pad() + _longest_channel_name; cairo_move_to ( @@ -210,7 +210,7 @@ PortMatrixColumnLabels::render (cairo_t* cr) _height - rl * sin (angle()) ); - } else if (_location == BOTTOM) { + } else { cairo_move_to ( cr, @@ -235,7 +235,7 @@ PortMatrixColumnLabels::render (cairo_t* cr) for (uint32_t j = 0; j < (*i)->nchannels(); ++j) { - render_port_name (cr, get_a_bundle_colour (i - c.begin()), x, 0, PortMatrixBundleChannel (*i, j)); + render_port_name (cr, get_a_bundle_colour (i - c.begin()), x, 0, ARDOUR::BundleChannel (*i, j)); x += column_width(); } } @@ -286,44 +286,56 @@ PortMatrixColumnLabels::draw_extra (cairo_t* cr) } } -void -PortMatrixColumnLabels::render_port_name (cairo_t* cr, Gdk::Color colour, double xoff, double yoff, PortMatrixBundleChannel const &bc) +std::vector<std::pair<double, double> > +PortMatrixColumnLabels::port_name_shape (double xoff, double yoff) const { + std::vector<std::pair<double, double> > shape; + double const lc = _longest_channel_name + name_pad(); double const w = column_width(); - - if (_location == BOTTOM) { + + if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) { double x_ = xoff + slanted_height() / tan (angle()) + w; - double const ix = x_; double y_ = yoff; - cairo_move_to (cr, x_, y_); + shape.push_back (std::make_pair (x_, y_)); x_ -= w; - cairo_line_to (cr, x_, y_); + shape.push_back (std::make_pair (x_, y_)); x_ -= lc * cos (angle()); y_ += lc * sin (angle()); - cairo_line_to (cr, x_, y_); + shape.push_back (std::make_pair (x_, y_)); x_ += w * pow (sin (angle()), 2); y_ += w * sin (angle()) * cos (angle()); - cairo_line_to (cr, x_, y_); - cairo_line_to (cr, ix, yoff); + shape.push_back (std::make_pair (x_, y_)); - } else if (_location == TOP) { + } else { double x_ = xoff; double y_ = yoff + _height; - cairo_move_to (cr, x_, y_); + shape.push_back (std::make_pair (x_, y_)); x_ += w; - cairo_line_to (cr, x_, y_); + shape.push_back (std::make_pair (x_, y_)); x_ += lc * cos (angle()); y_ -= lc * sin (angle()); - cairo_line_to (cr, x_, y_); + shape.push_back (std::make_pair (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, xoff, yoff + _height); - + shape.push_back (std::make_pair (x_, y_)); } + + return shape; +} + +void +PortMatrixColumnLabels::render_port_name (cairo_t* cr, Gdk::Color colour, double xoff, double yoff, ARDOUR::BundleChannel const &bc) +{ + std::vector<std::pair<double, double> > const shape = port_name_shape (xoff, yoff); + + cairo_move_to (cr, shape[0].first, shape[0].second); + for (uint32_t i = 1; i < 4; ++i) { + cairo_line_to (cr, shape[i].first, shape[i].second); + } + cairo_line_to (cr, shape[0].first, shape[0].second); set_source_rgb (cr, colour); cairo_fill_preserve (cr); @@ -333,7 +345,7 @@ PortMatrixColumnLabels::render_port_name (cairo_t* cr, Gdk::Color colour, double set_source_rgb (cr, text_colour()); - if (_location == TOP) { + if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) { cairo_move_to ( cr, @@ -341,7 +353,7 @@ PortMatrixColumnLabels::render_port_name (cairo_t* cr, Gdk::Color colour, double yoff + _height - name_pad() * sin (angle()) ); - } else if (_location == BOTTOM) { + } else { double const rl = 3 * name_pad() + _longest_bundle_name; cairo_move_to ( @@ -363,9 +375,18 @@ PortMatrixColumnLabels::render_port_name (cairo_t* cr, Gdk::Color colour, double } double -PortMatrixColumnLabels::channel_x (PortMatrixBundleChannel const &bc) const +PortMatrixColumnLabels::channel_x (ARDOUR::BundleChannel const &bc) const { - return bc.nchannels (_body->column_ports().bundles()) * column_width(); + uint32_t n = 0; + + ARDOUR::BundleList::const_iterator i = _matrix->columns()->bundles().begin(); + while (i != _matrix->columns()->bundles().end() && *i != bc.bundle) { + n += (*i)->nchannels (); + ++i; + } + + n += bc.channel; + return n * column_width(); } void @@ -376,7 +397,7 @@ PortMatrixColumnLabels::queue_draw_for (PortMatrixNode const& n) double const x = channel_x (n.column); double const lc = _longest_channel_name + name_pad(); double const h = lc * sin (angle ()) + column_width() * sin (angle()) * cos (angle()); - if (_location == TOP) { + if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) { _body->queue_draw_area ( component_to_parent_x (x), @@ -385,7 +406,7 @@ PortMatrixColumnLabels::queue_draw_for (PortMatrixNode const& n) h ); - } else if (_location == BOTTOM) { + } else if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) { double const x_ = x + slanted_height() / tan (angle()) - lc * cos (angle()); @@ -401,3 +422,40 @@ PortMatrixColumnLabels::queue_draw_for (PortMatrixNode const& n) } } + +void +PortMatrixColumnLabels::button_press (double x, double y, int b, uint32_t t) +{ + if (b != 3) { + return; + } + + if (!_matrix->can_rename_channels (_matrix->column_index()) && + !_matrix->can_remove_channels (_matrix->column_index())) { + return; + } + + uint32_t N = _matrix->columns()->total_visible_ports (); + uint32_t i = 0; + for (; i < N; ++i) { + + std::vector<std::pair<double, double> > const shape = port_name_shape (i * column_width(), 0); + + uint32_t j = 0; + for (; j < 4; ++j) { + uint32_t k = (j + 1) % 4; + + double const P = (y - shape[j].second) * (shape[k].first - shape[j].first) - + (x - shape[j].first) * (shape[k].second - shape[j].second); + + if (P > 0) { + break; + } + } + + if (j == 4) { + _matrix->popup_channel_context_menu (_matrix->column_index(), i, t); + break; + } + } +} diff --git a/gtk2_ardour/port_matrix_column_labels.h b/gtk2_ardour/port_matrix_column_labels.h index 9021ec55e3..6ed87e9628 100644 --- a/gtk2_ardour/port_matrix_column_labels.h +++ b/gtk2_ardour/port_matrix_column_labels.h @@ -25,23 +25,19 @@ namespace ARDOUR { class Bundle; + class BundleChannel; } class PortMatrixNode; -class PortMatrixBundleChannel; /** The column labels part of the port matrix */ class PortMatrixColumnLabels : public PortMatrixComponent { public: + PortMatrixColumnLabels (PortMatrix *, PortMatrixBody *); - enum Location { - TOP, - BOTTOM - }; - - PortMatrixColumnLabels (PortMatrixBody *, Location); - + void button_press (double, double, int, uint32_t); + double component_to_parent_x (double x) const; double parent_to_component_x (double x) const; double component_to_parent_y (double y) const; @@ -53,9 +49,10 @@ private: void render (cairo_t *); void compute_dimensions (); double basic_text_x_pos (int) const; - void render_port_name (cairo_t *, Gdk::Color, double, double, PortMatrixBundleChannel const &); - double channel_x (PortMatrixBundleChannel const &) const; + void render_port_name (cairo_t *, Gdk::Color, double, double, ARDOUR::BundleChannel const &); + double channel_x (ARDOUR::BundleChannel const &) const; void queue_draw_for (PortMatrixNode const &); + std::vector<std::pair<double, double> > port_name_shape (double, double) const; double slanted_height () const { return _height - _highest_group_name - 2 * name_pad(); @@ -66,7 +63,6 @@ private: double _longest_channel_name; double _highest_text; double _highest_group_name; - Location _location; }; #endif diff --git a/gtk2_ardour/port_matrix_component.cc b/gtk2_ardour/port_matrix_component.cc index 74f989934e..02d754f5ce 100644 --- a/gtk2_ardour/port_matrix_component.cc +++ b/gtk2_ardour/port_matrix_component.cc @@ -23,8 +23,9 @@ /** Constructor. * @param p Port matrix that we're in. */ -PortMatrixComponent::PortMatrixComponent (PortMatrixBody* b) - : _body (b), +PortMatrixComponent::PortMatrixComponent (PortMatrix* m, PortMatrixBody* b) + : _matrix (m), + _body (b), _pixmap (0), _render_required (true), _dimension_computation_required (true) diff --git a/gtk2_ardour/port_matrix_component.h b/gtk2_ardour/port_matrix_component.h index 7531e44bdd..39ea6b3c0d 100644 --- a/gtk2_ardour/port_matrix_component.h +++ b/gtk2_ardour/port_matrix_component.h @@ -22,6 +22,7 @@ #include <gtkmm/eventbox.h> +class PortMatrix; class PortMatrixBody; class PortMatrixNode; @@ -31,7 +32,7 @@ class PortMatrixNode; class PortMatrixComponent { public: - PortMatrixComponent (PortMatrixBody *); + PortMatrixComponent (PortMatrix *, PortMatrixBody *); virtual ~PortMatrixComponent (); virtual double component_to_parent_x (double x) const = 0; @@ -174,6 +175,7 @@ protected: */ virtual void compute_dimensions () = 0; + PortMatrix* _matrix; PortMatrixBody* _body; ///< the PortMatrixBody that we're in uint32_t _width; ///< full width of the contents uint32_t _height; ///< full height of the contents diff --git a/gtk2_ardour/port_matrix_grid.cc b/gtk2_ardour/port_matrix_grid.cc index eae8823af8..7deab22b85 100644 --- a/gtk2_ardour/port_matrix_grid.cc +++ b/gtk2_ardour/port_matrix_grid.cc @@ -24,9 +24,8 @@ #include "port_matrix_grid.h" #include "port_matrix.h" -PortMatrixGrid::PortMatrixGrid (PortMatrix* p, PortMatrixBody* b) - : PortMatrixComponent (b), - _port_matrix (p) +PortMatrixGrid::PortMatrixGrid (PortMatrix* m, PortMatrixBody* b) + : PortMatrixComponent (m, b) { } @@ -35,13 +34,13 @@ void PortMatrixGrid::compute_dimensions () { _width = 0; - ARDOUR::BundleList const c = _body->column_ports().bundles(); + ARDOUR::BundleList const c = _matrix->columns()->bundles(); for (ARDOUR::BundleList::const_iterator i = c.begin(); i != c.end(); ++i) { _width += (*i)->nchannels() * column_width(); } _height = 0; - ARDOUR::BundleList const r = _body->row_ports().bundles(); + ARDOUR::BundleList const r = _matrix->rows()->bundles(); for (ARDOUR::BundleList::const_iterator i = r.begin(); i != r.end(); ++i) { _height += (*i)->nchannels() * row_height(); } @@ -61,7 +60,7 @@ PortMatrixGrid::render (cairo_t* cr) set_source_rgb (cr, grid_colour()); uint32_t x = 0; - ARDOUR::BundleList const c = _body->column_ports().bundles(); + ARDOUR::BundleList const c = _matrix->columns()->bundles(); for (ARDOUR::BundleList::size_type i = 0; i < c.size(); ++i) { cairo_set_line_width (cr, thin_grid_line_width()); @@ -86,7 +85,7 @@ PortMatrixGrid::render (cairo_t* cr) /* HORIZONTAL GRID LINES */ uint32_t y = 0; - ARDOUR::BundleList const r = _body->row_ports().bundles(); + ARDOUR::BundleList const r = _matrix->rows()->bundles(); for (ARDOUR::BundleList::size_type i = 0; i < r.size(); ++i) { cairo_set_line_width (cr, thin_grid_line_width()); @@ -121,8 +120,12 @@ PortMatrixGrid::render (cairo_t* cr) y = by; for (uint32_t l = 0; l < (*j)->nchannels (); ++l) { + + ARDOUR::BundleChannel c[2]; + c[_matrix->column_index()] = ARDOUR::BundleChannel (*i, k); + c[_matrix->row_index()] = ARDOUR::BundleChannel (*j, l); - PortMatrix::State const s = _port_matrix->get_state (*j, l, *i, k); + PortMatrix::State const s = _matrix->get_state (c); switch (s) { case PortMatrix::ASSOCIATED: @@ -172,32 +175,32 @@ PortMatrixNode PortMatrixGrid::position_to_node (double x, double y) const { return PortMatrixNode ( - position_to_channel (y, _body->row_ports().bundles(), row_height()), - position_to_channel (x, _body->column_ports().bundles(), column_width()) + position_to_channel (y, _matrix->rows()->bundles(), row_height()), + position_to_channel (x, _matrix->columns()->bundles(), column_width()) ); } -PortMatrixBundleChannel +ARDOUR::BundleChannel PortMatrixGrid::position_to_channel (double p, ARDOUR::BundleList const& bundles, double inc) const { uint32_t pos = p / inc; for (ARDOUR::BundleList::const_iterator i = bundles.begin(); i != bundles.end(); ++i) { if (pos < (*i)->nchannels()) { - return PortMatrixBundleChannel (*i, pos); + return ARDOUR::BundleChannel (*i, pos); } else { pos -= (*i)->nchannels(); } } - return PortMatrixBundleChannel (boost::shared_ptr<ARDOUR::Bundle> (), 0); + return ARDOUR::BundleChannel (boost::shared_ptr<ARDOUR::Bundle> (), 0); } double PortMatrixGrid::channel_position ( - PortMatrixBundleChannel bc, + ARDOUR::BundleChannel bc, ARDOUR::BundleList const& bundles, double inc) const { @@ -224,21 +227,22 @@ PortMatrixGrid::button_press (double x, double y, int b) PortMatrixNode const node = position_to_node (x, y); if (node.row.bundle && node.column.bundle) { - - PortMatrix::State const s = _port_matrix->get_state ( - node.row.bundle, node.row.channel, node.column.bundle, node.column.channel - ); + ARDOUR::BundleChannel c[2]; + c[_matrix->row_index()] = node.row; + c[_matrix->column_index()] = node.column; + + PortMatrix::State const s = _matrix->get_state (c); if (s == PortMatrix::ASSOCIATED || s == PortMatrix::NOT_ASSOCIATED) { bool const n = !(s == PortMatrix::ASSOCIATED); + + ARDOUR::BundleChannel c[2]; + c[_matrix->row_index()] = node.row; + c[_matrix->column_index()] = node.column; - _port_matrix->set_state ( - node.row.bundle, node.row.channel, - node.column.bundle, node.column.channel, - n, 0 - ); + _matrix->set_state (c, n); } require_render (); @@ -253,19 +257,19 @@ PortMatrixGrid::draw_extra (cairo_t* cr) cairo_set_line_width (cr, mouseover_line_width()); double const x = component_to_parent_x ( - channel_position (_body->mouseover().column, _body->column_ports().bundles(), column_width()) + column_width() / 2 + channel_position (_body->mouseover().column, _matrix->columns()->bundles(), column_width()) + column_width() / 2 ); double const y = component_to_parent_y ( - channel_position (_body->mouseover().row, _body->row_ports().bundles(), row_height()) + row_height() / 2 + channel_position (_body->mouseover().row, _matrix->rows()->bundles(), row_height()) + row_height() / 2 ); if (_body->mouseover().row.bundle) { cairo_move_to (cr, x, y); - if (_body->arrangement() == PortMatrixBody::BOTTOM_AND_LEFT) { + if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) { cairo_line_to (cr, component_to_parent_x (0), y); - } else if (_body->arrangement() == PortMatrixBody::TOP_AND_RIGHT) { + } else if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) { cairo_line_to (cr, _parent_rectangle.get_x() + _parent_rectangle.get_width(), y); } cairo_stroke (cr); @@ -274,9 +278,9 @@ PortMatrixGrid::draw_extra (cairo_t* cr) if (_body->mouseover().column.bundle) { cairo_move_to (cr, x, y); - if (_body->arrangement() == PortMatrixBody::BOTTOM_AND_LEFT) { + if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) { cairo_line_to (cr, x, _parent_rectangle.get_y() + _parent_rectangle.get_height()); - } else if (_body->arrangement() == PortMatrixBody::TOP_AND_RIGHT) { + } else if (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT) { cairo_line_to (cr, x, component_to_parent_y (0)); } cairo_stroke (cr); @@ -301,7 +305,7 @@ PortMatrixGrid::queue_draw_for (PortMatrixNode const &n) { if (n.row.bundle) { - double const y = channel_position (n.row, _body->row_ports().bundles(), row_height()); + double const y = channel_position (n.row, _matrix->rows()->bundles(), row_height()); _body->queue_draw_area ( _parent_rectangle.get_x(), component_to_parent_y (y), @@ -312,7 +316,7 @@ PortMatrixGrid::queue_draw_for (PortMatrixNode const &n) if (n.column.bundle) { - double const x = channel_position (n.column, _body->column_ports().bundles(), column_width()); + double const x = channel_position (n.column, _matrix->columns()->bundles(), column_width()); _body->queue_draw_area ( component_to_parent_x (x), diff --git a/gtk2_ardour/port_matrix_grid.h b/gtk2_ardour/port_matrix_grid.h index 945ba5a2e6..77a0a7eefc 100644 --- a/gtk2_ardour/port_matrix_grid.h +++ b/gtk2_ardour/port_matrix_grid.h @@ -34,7 +34,7 @@ namespace ARDOUR { class Bundle; } -/// The grid part of the port matrix +/** The grid part of the port matrix */ class PortMatrixGrid : public PortMatrixComponent { public: @@ -55,12 +55,10 @@ private: void compute_dimensions (); void render (cairo_t *); - double channel_position (PortMatrixBundleChannel, ARDOUR::BundleList const &, double) const; + double channel_position (ARDOUR::BundleChannel, ARDOUR::BundleList const &, double) const; PortMatrixNode position_to_node (double, double) const; - PortMatrixBundleChannel position_to_channel (double, ARDOUR::BundleList const &, double) const; + ARDOUR::BundleChannel position_to_channel (double, ARDOUR::BundleList const &, double) const; void queue_draw_for (PortMatrixNode const &); - - PortMatrix* _port_matrix; }; #endif diff --git a/gtk2_ardour/port_matrix_row_labels.cc b/gtk2_ardour/port_matrix_row_labels.cc index b938f22a21..0e48b5b6b2 100644 --- a/gtk2_ardour/port_matrix_row_labels.cc +++ b/gtk2_ardour/port_matrix_row_labels.cc @@ -19,26 +19,18 @@ #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, Location l) - : PortMatrixComponent (b), _port_matrix (p), _menu (0), _location (l) +PortMatrixRowLabels::PortMatrixRowLabels (PortMatrix* m, PortMatrixBody* b) + : PortMatrixComponent (m, b) { } -PortMatrixRowLabels::~PortMatrixRowLabels () -{ - delete _menu; -} - void PortMatrixRowLabels::compute_dimensions () { @@ -49,7 +41,7 @@ PortMatrixRowLabels::compute_dimensions () _longest_port_name = 0; _longest_bundle_name = 0; _height = 0; - ARDOUR::BundleList const r = _body->row_ports().bundles(); + ARDOUR::BundleList const r = _matrix->rows()->bundles(); for (ARDOUR::BundleList::const_iterator i = r.begin(); i != r.end(); ++i) { for (uint32_t j = 0; j < (*i)->nchannels(); ++j) { cairo_text_extents_t ext; @@ -69,7 +61,7 @@ PortMatrixRowLabels::compute_dimensions () } _highest_group_name = 0; - for (PortGroupList::const_iterator i = _body->row_ports().begin(); i != _body->row_ports().end(); ++i) { + for (PortGroupList::List::const_iterator i = _matrix->rows()->begin(); i != _matrix->rows()->end(); ++i) { if ((*i)->visible()) { cairo_text_extents_t ext; cairo_text_extents (cr, (*i)->name.c_str(), &ext); @@ -101,15 +93,15 @@ PortMatrixRowLabels::render (cairo_t* cr) /* PORT GROUP NAMES */ double x = 0; - if (_location == LEFT) { + if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) { x = 0; - } else if (_location == RIGHT) { + } else { x = _width - _highest_group_name - 2 * name_pad(); } double y = 0; int g = 0; - for (PortGroupList::const_iterator i = _body->row_ports().begin(); i != _body->row_ports().end(); ++i) { + for (PortGroupList::List::const_iterator i = _matrix->rows()->begin(); i != _matrix->rows()->end(); ++i) { if (!(*i)->visible() || ((*i)->bundles().empty() && (*i)->ports.empty()) ) { continue; @@ -146,14 +138,14 @@ PortMatrixRowLabels::render (cairo_t* cr) /* BUNDLE NAMES */ x = 0; - if (_location == LEFT) { + if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) { x = _highest_group_name + 2 * name_pad(); - } else if (_location == RIGHT) { + } else { x = _longest_port_name + name_pad() * 2; } y = 0; - ARDOUR::BundleList const r = _body->row_ports().bundles(); + ARDOUR::BundleList const r = _matrix->rows()->bundles(); for (ARDOUR::BundleList::const_iterator i = r.begin(); i != r.end(); ++i) { Gdk::Color const colour = get_a_bundle_colour (i - r.begin ()); @@ -187,7 +179,7 @@ PortMatrixRowLabels::render (cairo_t* cr) y = 0; for (ARDOUR::BundleList::const_iterator i = r.begin(); i != r.end(); ++i) { for (uint32_t j = 0; j < (*i)->nchannels(); ++j) { - render_port_name (cr, get_a_bundle_colour (i - r.begin()), 0, y, PortMatrixBundleChannel (*i, j)); + render_port_name (cr, get_a_bundle_colour (i - r.begin()), 0, y, ARDOUR::BundleChannel (*i, j)); y += row_height(); } } @@ -200,84 +192,20 @@ PortMatrixRowLabels::button_press (double x, double y, int b, uint32_t t) return; } - if ( (_location == LEFT && x > (_longest_bundle_name + name_pad() * 2)) || - (_location == RIGHT && 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 = 0; - - ARDOUR::BundleList const r = _body->row_ports().bundles(); - for (ARDOUR::BundleList::const_iterator i = r.begin(); i != r.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) { + if (!_matrix->can_rename_channels (_matrix->row_index()) && + !_matrix->can_remove_channels (_matrix->row_index())) { return; } - _port_matrix->remove_channel (sb, c); - -} + if ( (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM && x > (_longest_bundle_name + name_pad() * 2)) || + (_matrix->arrangement() == PortMatrix::TOP_TO_RIGHT && x < (_longest_port_name + name_pad() * 2)) + ) { -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; + _matrix->popup_channel_context_menu (_matrix->row_index(), y / row_height(), t); + } - - _port_matrix->rename_channel (sb, c); } - double PortMatrixRowLabels::component_to_parent_x (double x) const { @@ -305,9 +233,9 @@ PortMatrixRowLabels::parent_to_component_y (double y) const double PortMatrixRowLabels::port_name_x () const { - if (_location == LEFT) { + if (_matrix->arrangement() == PortMatrix::LEFT_TO_BOTTOM) { return _longest_bundle_name + _highest_group_name + name_pad() * 4; - } else if (_location == RIGHT) { + } else { return 0; } @@ -316,7 +244,7 @@ PortMatrixRowLabels::port_name_x () const void PortMatrixRowLabels::render_port_name ( - cairo_t* cr, Gdk::Color colour, double xoff, double yoff, PortMatrixBundleChannel const& bc + cairo_t* cr, Gdk::Color colour, double xoff, double yoff, ARDOUR::BundleChannel const& bc ) { set_source_rgb (cr, colour); @@ -336,9 +264,18 @@ PortMatrixRowLabels::render_port_name ( } double -PortMatrixRowLabels::channel_y (PortMatrixBundleChannel const& bc) const +PortMatrixRowLabels::channel_y (ARDOUR::BundleChannel const& bc) const { - return bc.nchannels (_body->row_ports().bundles()) * row_height(); + uint32_t n = 0; + + ARDOUR::BundleList::const_iterator i = _matrix->rows()->bundles().begin(); + while (i != _matrix->rows()->bundles().end() && *i != bc.bundle) { + n += (*i)->nchannels (); + ++i; + } + + n += bc.channel; + return n * row_height(); } void diff --git a/gtk2_ardour/port_matrix_row_labels.h b/gtk2_ardour/port_matrix_row_labels.h index ce77dc8294..85d59d139f 100644 --- a/gtk2_ardour/port_matrix_row_labels.h +++ b/gtk2_ardour/port_matrix_row_labels.h @@ -27,26 +27,21 @@ class PortMatrix; class PortMatrixBody; class PortMatrixNode; -class PortMatrixBundleChannel; namespace ARDOUR { class Bundle; + class BundleChannel; } namespace Gtk { class Menu; } +/** The row labels part of the port matrix */ class PortMatrixRowLabels : public PortMatrixComponent { public: - enum Location { - LEFT, - RIGHT - }; - - PortMatrixRowLabels (PortMatrix *, PortMatrixBody *, Location); - ~PortMatrixRowLabels (); + PortMatrixRowLabels (PortMatrix *, PortMatrixBody *); void button_press (double, double, int, uint32_t); @@ -62,17 +57,14 @@ private: 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); - void render_port_name (cairo_t *, Gdk::Color, double, double, PortMatrixBundleChannel const &); - double channel_y (PortMatrixBundleChannel const &) const; + void render_port_name (cairo_t *, Gdk::Color, double, double, ARDOUR::BundleChannel const &); + double channel_y (ARDOUR::BundleChannel const &) const; void queue_draw_for (PortMatrixNode const &); double port_name_x () const; - PortMatrix* _port_matrix; double _longest_port_name; double _longest_bundle_name; double _highest_group_name; - Gtk::Menu* _menu; - Location _location; }; #endif diff --git a/gtk2_ardour/port_matrix_types.h b/gtk2_ardour/port_matrix_types.h index 16fb440ace..2c80c24cce 100644 --- a/gtk2_ardour/port_matrix_types.h +++ b/gtk2_ardour/port_matrix_types.h @@ -22,36 +22,10 @@ #include "ardour/bundle.h" -struct PortMatrixBundleChannel { - PortMatrixBundleChannel () : channel (0) {} - PortMatrixBundleChannel (boost::shared_ptr<ARDOUR::Bundle> b, uint32_t c) - : bundle (b), channel (c) {} - - bool operator== (PortMatrixBundleChannel const& other) const { - return bundle == other.bundle && channel == other.channel; - } - bool operator!= (PortMatrixBundleChannel const& other) const { - return bundle != other.bundle || channel != other.channel; - } - - uint32_t nchannels (ARDOUR::BundleList const& bl) const { - uint32_t n = 0; - ARDOUR::BundleList::const_iterator i = bl.begin(); - while (i != bl.end() && *i != bundle) { - n += (*i)->nchannels (); - ++i; - } - n += channel; - return n; - } - - boost::shared_ptr<ARDOUR::Bundle> bundle; - uint32_t channel; -}; - -struct PortMatrixNode { +struct PortMatrixNode +{ PortMatrixNode () {} - PortMatrixNode (PortMatrixBundleChannel r, PortMatrixBundleChannel c) : row (r), column (c) {} + PortMatrixNode (ARDOUR::BundleChannel r, ARDOUR::BundleChannel c) : row (r), column (c) {} bool operator== (PortMatrixNode const& other) const { return row == other.row && column == other.column; @@ -60,8 +34,8 @@ struct PortMatrixNode { return row != other.row || column != other.column; } - PortMatrixBundleChannel row; - PortMatrixBundleChannel column; + ARDOUR::BundleChannel row; + ARDOUR::BundleChannel column; }; #endif diff --git a/libs/ardour/ardour/bundle.h b/libs/ardour/ardour/bundle.h index ac5928fc34..7e5cac6bf1 100644 --- a/libs/ardour/ardour/bundle.h +++ b/libs/ardour/ardour/bundle.h @@ -147,6 +147,30 @@ class Bundle : public sigc::trackable bool _ports_are_inputs; }; + + +struct BundleChannel +{ + BundleChannel () : channel (0) {} + + BundleChannel (boost::shared_ptr<ARDOUR::Bundle> b, uint32_t c) + : bundle (b), channel (c) {} + + bool operator== (BundleChannel const& other) const { + return bundle == other.bundle && channel == other.channel; + } + + bool operator!= (BundleChannel const& other) const { + return bundle != other.bundle || channel != other.channel; + } + + boost::shared_ptr<ARDOUR::Bundle> bundle; + uint32_t channel; +}; + + + + } #endif /* __ardour_bundle_h__ */ |