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
This commit is contained in:
Carl Hetherington 2009-01-30 15:08:09 +00:00
parent 24aab941eb
commit a384dab130
23 changed files with 843 additions and 726 deletions

View file

@ -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);
}
BundleEditorMatrix::~BundleEditorMatrix ()
{
delete _port_group;
_ports[OURS].add_group (_port_group);
}
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::setup ()
{
ARDOUR::Bundle::PortList const& pl = bb->channel_ports (bc);
_ports[OTHER].gather (_session, _bundle->ports_are_inputs());
PortMatrix::setup ();
}
void
BundleEditorMatrix::set_state (ARDOUR::BundleChannel c[2], bool s)
{
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

View file

@ -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 rename_channel (boost::shared_ptr<ARDOUR::Bundle>, uint32_t);
void remove_channel (ARDOUR::BundleChannel);
bool can_rename_channels (int d) const {
return d == OURS;
}
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

View file

@ -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);

View file

@ -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,
};
};

View file

@ -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());

View file

@ -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 ();
};

View file

@ -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
{

View file

@ -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
@ -84,60 +90,46 @@ PortGroup::only_bundle ()
}
/** 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));
}
/** 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 ();
}
/** 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());
uint32_t n = 0;
for (ARDOUR::BundleList::const_iterator i = _bundles.begin(); i != _bundles.end(); ++i) {
n += (*i)->nchannels ();
}
n += ports.size();
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;
}
@ -259,26 +245,12 @@ 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,39 +318,9 @@ PortGroupList::common_prefix (std::vector<std::string> const & p) const
}
void
PortGroupList::visibility_changed ()
PortGroupList::clear ()
{
VisibilityChanged ();
}
void
PortGroupList::take_visibility_from (PortGroupList const & o)
{
iterator i = begin ();
const_iterator j = o.begin ();
while (i != end() && j != o.end()) {
(*i)->set_visible ((*j)->visible());
++i;
++j;
}
}
void
PortGroupList::clear_list ()
{
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 ();
}
_visibility_connections.clear ();
_groups.clear ();
_bundles_dirty = true;
}
@ -391,3 +333,31 @@ PortGroupList::bundles () const
return _bundles;
}
uint32_t
PortGroupList::total_visible_ports () const
{
uint32_t n = 0;
for (PortGroupList::List::const_iterator i = begin(); i != end(); ++i) {
if ((*i)->visible()) {
n += (*i)->total_ports ();
}
}
return n;
}
void
PortGroupList::group_modified ()
{
_bundles_dirty = true;
}
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;
}

View file

@ -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();
}
sigc::signal<void> VisibilityChanged;
List::const_iterator begin () const {
return _groups.begin();
}
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__ */

View file

@ -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 ();
_ports[0].set_type (type);
_ports[1].set_type (type);
/* 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);
}
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 ();
/* XXX hard-coded initial size suggestion */
set_size_request (400, 200);
reconnect_to_routes ();
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) {
set_state (
r.front(), k, *i, j, false, 0
);
ARDOUR::BundleChannel c[2] = {
ARDOUR::BundleChannel (*i, j),
ARDOUR::BundleChannel (*k, l)
};
set_state (c, false);
}
}
}
}
_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));
}

View file

@ -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,22 +46,66 @@ 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 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
};
/** @return Arrangement in use */
Arrangement arrangement () const {
return _arrangement;
}
void disassociate_all ();
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.
*/
virtual void set_state (ARDOUR::BundleChannel c[2], bool s) = 0;
enum State {
ASSOCIATED, ///< the ports are associaed
NOT_ASSOCIATED, ///< the ports are not associated
UNKNOWN ///< we don't know anything about these two ports' relationship
};
/** @param c Channels; where c[0] is from _ports[0] and c[1] is from _ports[1].
* @return state
*/
virtual State get_state (ARDOUR::BundleChannel c[2]) const = 0;
virtual void add_channel (boost::shared_ptr<ARDOUR::Bundle>) = 0;
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) {}
enum Result {
Cancelled,
@ -70,70 +114,48 @@ public:
sigc::signal<void, Result> Finished;
/** @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 (
boost::shared_ptr<ARDOUR::Bundle> ab,
uint32_t ac,
boost::shared_ptr<ARDOUR::Bundle> bb,
uint32_t bc,
bool s,
uint32_t k
) = 0;
enum State {
ASSOCIATED,
NOT_ASSOCIATED,
UNKNOWN
};
/** @param ab Our bundle.
* @param ac Channel on our bundle.
* @param bb Other bundle.
* @arapm bc Channel on other bundle.
* @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 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) {}
void setup_scrollbars ();
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

View file

@ -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;
/* Connect to bundles so that we find out when their names change */
ARDOUR::BundleList r = _row_ports.bundles ();
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;

View file

@ -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;

View file

@ -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,45 +286,57 @@ 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);
set_source_rgb (cr, background_colour());
@ -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;
}
}
}

View file

@ -25,22 +25,18 @@
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;
@ -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

View file

@ -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)

View file

@ -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

View file

@ -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());
@ -122,7 +121,11 @@ PortMatrixGrid::render (cairo_t* cr)
y = by;
for (uint32_t l = 0; l < (*j)->nchannels (); ++l) {
PortMatrix::State const s = _port_matrix->get_state (*j, l, *i, k);
ARDOUR::BundleChannel c[2];
c[_matrix->column_index()] = ARDOUR::BundleChannel (*i, k);
c[_matrix->row_index()] = ARDOUR::BundleChannel (*j, l);
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
{
@ -225,20 +228,21 @@ PortMatrixGrid::button_press (double x, double y, int b)
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);
_port_matrix->set_state (
node.row.bundle, node.row.channel,
node.column.bundle, node.column.channel,
n, 0
);
ARDOUR::BundleChannel c[2];
c[_matrix->row_index()] = node.row;
c[_matrix->column_index()] = node.column;
_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),

View file

@ -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

View file

@ -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))
if (!_matrix->can_rename_channels (_matrix->row_index()) &&
!_matrix->can_remove_channels (_matrix->row_index())) {
return;
}
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))
) {
delete _menu;
_matrix->popup_channel_context_menu (_matrix->row_index(), y / row_height(), t);
_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) {
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);
}
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

View file

@ -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

View file

@ -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

View file

@ -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__ */