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