partial patch/partial by-hand merge of 2.X commits 3169&3170 to 3.X codebase

git-svn-id: svn://localhost/ardour2/branches/3.0@4300 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2008-12-08 16:07:28 +00:00
parent a9bb336fc4
commit 3be16e8afb
35 changed files with 1399 additions and 932 deletions

View file

@ -194,6 +194,7 @@ 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

View file

@ -1736,8 +1736,8 @@ ARDOUR_UI::engine_halted ()
_("\ _("\
JACK has either been shutdown or it\n\ JACK has either been shutdown or it\n\
disconnected Ardour because Ardour\n\ disconnected Ardour because Ardour\n\
was not fast enough. You can save the\n\ was not fast enough. Try to restart\n\
session and/or try to reconnect to JACK .")); JACK, reconnect and save the session."));
pop_back_splash (); pop_back_splash ();
msg.run (); msg.run ();
} }

View file

@ -196,6 +196,10 @@ AudioRegionView::init (Gdk::Color& basic_color, bool wfd)
setup_fade_handle_positions (); setup_fade_handle_positions ();
if (!Config->get_show_region_fades()) {
set_fade_visibility (false);
}
string line_name = _region->name(); string line_name = _region->name();
line_name += ':'; line_name += ':';
line_name += "gain"; line_name += "gain";
@ -410,8 +414,10 @@ AudioRegionView::reset_width_dependent_items (double pixel_width)
fade_in_handle->hide(); fade_in_handle->hide();
fade_out_handle->hide(); fade_out_handle->hide();
} else { } else {
fade_in_handle->show(); if (Config->get_show_region_fades()) {
fade_out_handle->show(); fade_in_handle->show();
fade_out_handle->show();
}
} }
} }
} }

View file

@ -294,6 +294,7 @@ class Editor : public PublicEditor
Width editor_mixer_strip_width; Width editor_mixer_strip_width;
void maybe_add_mixer_strip_width (XMLNode&); void maybe_add_mixer_strip_width (XMLNode&);
void show_editor_mixer (bool yn); void show_editor_mixer (bool yn);
void create_editor_mixer ();
void show_editor_list (bool yn); void show_editor_list (bool yn);
void set_selected_mixer_strip (TimeAxisView&); void set_selected_mixer_strip (TimeAxisView&);
void hide_track_in_display (TimeAxisView& tv, bool temporary = false); void hide_track_in_display (TimeAxisView& tv, bool temporary = false);

View file

@ -57,13 +57,6 @@ Editor::editor_list_button_toggled ()
} }
} }
void
Editor::cms_new (boost::shared_ptr<ARDOUR::Route> r)
{
current_mixer_strip = new MixerStrip (*ARDOUR_UI::instance()->the_mixer(), *session, r);
current_mixer_strip->GoingAway.connect (mem_fun (*this, &Editor::cms_deleted));
}
void void
Editor::cms_deleted () Editor::cms_deleted ()
{ {
@ -73,77 +66,109 @@ Editor::cms_deleted ()
void void
Editor::show_editor_mixer (bool yn) Editor::show_editor_mixer (bool yn)
{ {
boost::shared_ptr<ARDOUR::Route> r;
show_editor_mixer_when_tracks_arrive = false; show_editor_mixer_when_tracks_arrive = false;
if (!session) {
show_editor_mixer_when_tracks_arrive = yn;
return;
}
if (yn) { if (yn) {
if (current_mixer_strip == 0) { if (selection->tracks.empty()) {
if (track_views.empty()) {
show_editor_mixer_when_tracks_arrive = true;
return;
}
if (selection->tracks.empty()) { for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
AudioTimeAxisView* atv;
if (track_views.empty()) { if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
show_editor_mixer_when_tracks_arrive = true; r = atv->route();
return; break;
}
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
AudioTimeAxisView* atv;
if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
cms_new (atv->route ());
break;
}
} }
} else {
sort_track_selection ();
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
AudioTimeAxisView* atv;
if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
cms_new (atv->route ());
break;
}
}
} }
} else {
sort_track_selection ();
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
AudioTimeAxisView* atv;
if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
r = atv->route();
break;
}
}
}
if (r) {
bool created;
if (current_mixer_strip == 0) { if (current_mixer_strip == 0) {
return; create_editor_mixer ();
} created = true;
} else {
created = false;
}
current_mixer_strip->set_route (r);
if (created) {
current_mixer_strip->set_width (editor_mixer_strip_width, (void*) this);
}
} }
if (current_mixer_strip->get_parent() == 0) { if (current_mixer_strip->get_parent() == 0) {
current_mixer_strip->set_embedded (true);
current_mixer_strip->Hiding.connect (mem_fun(*this, &Editor::current_mixer_strip_hidden));
current_mixer_strip->GoingAway.connect (mem_fun(*this, &Editor::current_mixer_strip_removed));
current_mixer_strip->set_width (editor_mixer_strip_width, (void*) this);
global_hpacker.pack_start (*current_mixer_strip, Gtk::PACK_SHRINK ); global_hpacker.pack_start (*current_mixer_strip, Gtk::PACK_SHRINK );
global_hpacker.reorder_child (*current_mixer_strip, 0); global_hpacker.reorder_child (*current_mixer_strip, 0);
current_mixer_strip->show_all (); current_mixer_strip->show_all ();
} }
} else { } else {
if (current_mixer_strip) { if (current_mixer_strip) {
editor_mixer_strip_width = current_mixer_strip->get_width ();
if (current_mixer_strip->get_parent() != 0) { if (current_mixer_strip->get_parent() != 0) {
global_hpacker.remove (*current_mixer_strip); global_hpacker.remove (*current_mixer_strip);
} }
} }
} }
#ifdef GTKOSX #ifdef GTKOSX
/* XXX gtk problem here */ /* XXX gtk problem here */
ruler_label_event_box.queue_draw (); ensure_all_elements_drawn();
time_button_event_box.queue_draw ();
controls_layout.queue_draw ();
#endif #endif
} }
#ifdef GTKOSX
void
Editor::ensure_all_elements_drawn ()
{
controls_layout.queue_draw ();
ruler_label_event_box.queue_draw ();
time_button_event_box.queue_draw ();
}
#endif
void
Editor::create_editor_mixer ()
{
current_mixer_strip = new MixerStrip (*ARDOUR_UI::instance()->the_mixer(),
*session,
false);
current_mixer_strip->Hiding.connect (mem_fun(*this, &Editor::current_mixer_strip_hidden));
current_mixer_strip->GoingAway.connect (mem_fun(*this, &Editor::current_mixer_strip_removed));
#ifdef GTKOSX
current_mixer_strip->WidthChanged.connect (mem_fun(*this, &Editor::ensure_all_elements_drawn));
#endif
current_mixer_strip->set_embedded (true);
}
void void
Editor::show_editor_list (bool yn) Editor::show_editor_list (bool yn)
{ {
@ -157,38 +182,52 @@ Editor::show_editor_list (bool yn)
void void
Editor::set_selected_mixer_strip (TimeAxisView& view) Editor::set_selected_mixer_strip (TimeAxisView& view)
{ {
RouteTimeAxisView* rt; AudioTimeAxisView* at;
bool show = false; bool show = false;
bool created;
if (!session || (rt = dynamic_cast<RouteTimeAxisView*>(&view)) == 0) { if (!session || (at = dynamic_cast<AudioTimeAxisView*>(&view)) == 0) {
return;
}
Glib::RefPtr<Gtk::Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
if (act) {
Glib::RefPtr<Gtk::ToggleAction> tact = Glib::RefPtr<Gtk::ToggleAction>::cast_dynamic(act);
if (!tact || !tact->get_active()) {
/* not showing mixer strip presently */
return;
}
}
if (current_mixer_strip == 0) {
create_editor_mixer ();
created = true;
} else {
created = false;
}
/* might be nothing to do */
if (current_mixer_strip->route() == at->route()) {
return; return;
} }
if (current_mixer_strip) { if (current_mixer_strip->get_parent()) {
show = true;
/* might be nothing to do */ }
if (current_mixer_strip->route() == rt->route()) { current_mixer_strip->set_route (at->route());
return;
} if (created) {
current_mixer_strip->set_width (editor_mixer_strip_width, (void*) this);
if (current_mixer_strip->get_parent()) {
show = true;
}
delete current_mixer_strip;
current_mixer_strip = 0;
} }
current_mixer_strip = new MixerStrip (*ARDOUR_UI::instance()->the_mixer(),
*session,
rt->route(), false);
current_mixer_strip->GoingAway.connect (mem_fun(*this, &Editor::cms_deleted));
if (show) { if (show) {
show_editor_mixer (true); show_editor_mixer (true);
} }
} }
double current = 0.0; double current = 0.0;
bool currentInitialized = 0; bool currentInitialized = 0;
@ -276,7 +315,7 @@ void
Editor::current_mixer_strip_removed () Editor::current_mixer_strip_removed ()
{ {
if (current_mixer_strip) { if (current_mixer_strip) {
/* it is being deleted */ /* it is being deleted elsewhere */
current_mixer_strip = 0; current_mixer_strip = 0;
} }
} }

View file

@ -72,17 +72,18 @@ GainMeter::setup_slider_pix ()
} }
} }
GainMeterBase::GainMeterBase (boost::shared_ptr<IO> io, Session& s, GainMeterBase::GainMeterBase (Session& s,
const Glib::RefPtr<Gdk::Pixbuf>& pix, const Glib::RefPtr<Gdk::Pixbuf>& pix,
bool horizontal) bool horizontal)
: _io (io), : _session (s),
_session (s),
// 0.781787 is the value needed for gain to be set to 0. // 0.781787 is the value needed for gain to be set to 0.
gain_adjustment (0.781787, 0.0, 1.0, 0.01, 0.1), gain_adjustment (0.781787, 0.0, 1.0, 0.01, 0.1),
gain_automation_style_button (""), gain_automation_style_button (""),
gain_automation_state_button ("") gain_automation_state_button ("")
{ {
using namespace Menu_Helpers;
ignore_toggle = false; ignore_toggle = false;
meter_menu = 0; meter_menu = 0;
next_release_selects = false; next_release_selects = false;
@ -92,16 +93,14 @@ GainMeterBase::GainMeterBase (boost::shared_ptr<IO> io, Session& s,
if (horizontal) { if (horizontal) {
gain_slider = manage (new HSliderController (pix, gain_slider = manage (new HSliderController (pix,
&gain_adjustment, &gain_adjustment,
_io->gain_control(),
false)); false));
} else { } else {
gain_slider = manage (new VSliderController (pix, gain_slider = manage (new VSliderController (pix,
&gain_adjustment, &gain_adjustment,
_io->gain_control(),
false)); false));
} }
level_meter = new LevelMeter(_io, _session); level_meter = new LevelMeter(_session);
gain_slider->signal_button_press_event().connect (mem_fun(*this, &GainMeter::start_gain_touch)); gain_slider->signal_button_press_event().connect (mem_fun(*this, &GainMeter::start_gain_touch));
gain_slider->signal_button_release_event().connect (mem_fun(*this, &GainMeter::end_gain_touch)); gain_slider->signal_button_release_event().connect (mem_fun(*this, &GainMeter::end_gain_touch));
@ -133,10 +132,40 @@ GainMeterBase::GainMeterBase (boost::shared_ptr<IO> io, Session& s,
gain_automation_state_button.set_size_request(15, 15); gain_automation_state_button.set_size_request(15, 15);
gain_automation_style_button.set_size_request(15, 15); gain_automation_style_button.set_size_request(15, 15);
gain_astyle_menu.items().push_back (MenuElem (_("Trim")));
gain_astyle_menu.items().push_back (MenuElem (_("Abs")));
gain_astate_menu.set_name ("ArdourContextMenu");
gain_astyle_menu.set_name ("ArdourContextMenu");
gain_adjustment.signal_value_changed().connect (mem_fun(*this, &GainMeterBase::gain_adjusted));
peak_display.signal_button_release_event().connect (mem_fun(*this, &GainMeterBase::peak_button_release), false);
gain_display.signal_key_press_event().connect (mem_fun(*this, &GainMeterBase::gain_key_press), false);
ResetAllPeakDisplays.connect (mem_fun(*this, &GainMeterBase::reset_peak_display));
ResetGroupPeakDisplays.connect (mem_fun(*this, &GainMeterBase::reset_group_peak_display));
UI::instance()->theme_changed.connect (mem_fun(*this, &GainMeterBase::on_theme_changed));
ColorsChanged.connect (bind(mem_fun (*this, &GainMeterBase::color_handler), false));
DPIReset.connect (bind(mem_fun (*this, &GainMeterBase::color_handler), true));
}
GainMeterBase::~GainMeterBase ()
{
delete meter_menu;
delete level_meter;
}
void
GainMeterBase::set_io (boost::shared_ptr<IO> io)
{
connections.clear ();
_io = io;
level_meter->set_io (_io);
gain_slider->set_controllable (_io->gain_control());
boost::shared_ptr<Route> r; boost::shared_ptr<Route> r;
@ -146,6 +175,8 @@ GainMeterBase::GainMeterBase (boost::shared_ptr<IO> io, Session& s,
using namespace Menu_Helpers; using namespace Menu_Helpers;
gain_astate_menu.items().clear ();
gain_astate_menu.items().push_back (MenuElem (_("Manual"), gain_astate_menu.items().push_back (MenuElem (_("Manual"),
bind (mem_fun (*_io, &IO::set_parameter_automation_state), bind (mem_fun (*_io, &IO::set_parameter_automation_state),
Evoral::Parameter(GainAutomation), (AutoState) Off))); Evoral::Parameter(GainAutomation), (AutoState) Off)));
@ -159,50 +190,21 @@ GainMeterBase::GainMeterBase (boost::shared_ptr<IO> io, Session& s,
bind (mem_fun (*_io, &IO::set_parameter_automation_state), bind (mem_fun (*_io, &IO::set_parameter_automation_state),
Evoral::Parameter(GainAutomation), (AutoState) Touch))); Evoral::Parameter(GainAutomation), (AutoState) Touch)));
gain_astyle_menu.items().push_back (MenuElem (_("Trim"))); connections.push_back (gain_automation_style_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_style_button_event), false));
gain_astyle_menu.items().push_back (MenuElem (_("Abs"))); connections.push_back (gain_automation_state_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_state_button_event), false));
gain_astate_menu.set_name ("ArdourContextMenu"); connections.push_back (r->gain_control()->alist()->automation_state_changed.connect (mem_fun(*this, &GainMeter::gain_automation_state_changed)));
gain_astyle_menu.set_name ("ArdourContextMenu"); connections.push_back (r->gain_control()->alist()->automation_style_changed.connect (mem_fun(*this, &GainMeter::gain_automation_style_changed)));
gain_automation_style_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_style_button_event), false);
gain_automation_state_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_state_button_event), false);
r->gain_control()->alist()->automation_state_changed.connect (mem_fun(*this, &GainMeter::gain_automation_state_changed));
r->gain_control()->alist()->automation_style_changed.connect (mem_fun(*this, &GainMeter::gain_automation_style_changed));
gain_automation_state_changed (); gain_automation_state_changed ();
} }
} }
_io->gain_control()->Changed.connect (mem_fun(*this, &GainMeterBase::gain_changed)); connections.push_back (_io->gain_control()->Changed.connect (mem_fun(*this, &GainMeterBase::gain_changed)));
gain_adjustment.signal_value_changed().connect (mem_fun(*this, &GainMeterBase::gain_adjusted));
peak_display.signal_button_release_event().connect (mem_fun(*this, &GainMeterBase::peak_button_release), false);
gain_display.signal_key_press_event().connect (mem_fun(*this, &GainMeterBase::gain_key_press), false);
gain_changed (); gain_changed ();
show_gain (); show_gain ();
update_gain_sensitive (); update_gain_sensitive ();
ResetAllPeakDisplays.connect (mem_fun(*this, &GainMeterBase::reset_peak_display));
ResetGroupPeakDisplays.connect (mem_fun(*this, &GainMeterBase::reset_group_peak_display));
UI::instance()->theme_changed.connect (mem_fun(*this, &GainMeterBase::on_theme_changed));
ColorsChanged.connect (bind(mem_fun (*this, &GainMeterBase::color_handler), false));
DPIReset.connect (bind(mem_fun (*this, &GainMeterBase::color_handler), true));
}
GainMeterBase::~GainMeterBase ()
{
if (meter_menu) {
delete meter_menu;
}
if (level_meter) {
delete level_meter;
}
} }
void void
@ -752,10 +754,9 @@ GainMeterBase::on_theme_changed()
style_changed = true; style_changed = true;
} }
GainMeter::GainMeter (boost::shared_ptr<IO> io, Session& s) GainMeter::GainMeter (Session& s)
: GainMeterBase (io, s, slider, false) : GainMeterBase (s, slider, false)
{ {
gain_display_box.set_homogeneous (true); gain_display_box.set_homogeneous (true);
gain_display_box.set_spacing (2); gain_display_box.set_spacing (2);
gain_display_box.pack_start (gain_display, true, true); gain_display_box.pack_start (gain_display, true, true);
@ -785,6 +786,31 @@ GainMeter::GainMeter (boost::shared_ptr<IO> io, Session& s)
hbox.set_spacing (2); hbox.set_spacing (2);
hbox.pack_start (*fader_vbox, true, true); hbox.pack_start (*fader_vbox, true, true);
set_spacing (2);
pack_start (gain_display_box, Gtk::PACK_SHRINK);
pack_start (hbox, Gtk::PACK_SHRINK);
meter_metric_area.signal_expose_event().connect (mem_fun(*this, &GainMeter::meter_metrics_expose));
}
void
GainMeter::set_io (boost::shared_ptr<IO> io)
{
if (level_meter->get_parent()) {
hbox.remove (*level_meter);
}
if (peak_display.get_parent()) {
gain_display_box.remove (peak_display);
}
if (gain_automation_state_button.get_parent()) {
fader_vbox->remove (gain_automation_state_button);
}
GainMeterBase::set_io (io);
boost::shared_ptr<Route> r; boost::shared_ptr<Route> r;
if ((r = boost::dynamic_pointer_cast<Route> (_io)) != 0) { if ((r = boost::dynamic_pointer_cast<Route> (_io)) != 0) {
@ -801,16 +827,8 @@ GainMeter::GainMeter (boost::shared_ptr<IO> io, Session& s)
fader_vbox->pack_start (gain_automation_state_button, false, false, 0); fader_vbox->pack_start (gain_automation_state_button, false, false, 0);
} }
} }
set_spacing (2);
pack_start (gain_display_box, Gtk::PACK_SHRINK);
pack_start (hbox, Gtk::PACK_SHRINK);
meter_metric_area.signal_expose_event().connect (mem_fun(*this, &GainMeter::meter_metrics_expose));
} }
int int
GainMeter::get_gm_width () GainMeter::get_gm_width ()
{ {

View file

@ -58,10 +58,12 @@ namespace Gtk {
class GainMeterBase : virtual public sigc::trackable class GainMeterBase : virtual public sigc::trackable
{ {
public: public:
GainMeterBase (boost::shared_ptr<ARDOUR::IO>, ARDOUR::Session&, const Glib::RefPtr<Gdk::Pixbuf>& pix, GainMeterBase ( ARDOUR::Session&, const Glib::RefPtr<Gdk::Pixbuf>& pix,
bool horizontal); bool horizontal);
virtual ~GainMeterBase (); virtual ~GainMeterBase ();
virtual void set_io (boost::shared_ptr<ARDOUR::IO>);
void update_gain_sensitive (); void update_gain_sensitive ();
void update_meters (); void update_meters ();
@ -82,6 +84,7 @@ class GainMeterBase : virtual public sigc::trackable
friend class MixerStrip; friend class MixerStrip;
boost::shared_ptr<ARDOUR::IO> _io; boost::shared_ptr<ARDOUR::IO> _io;
ARDOUR::Session& _session; ARDOUR::Session& _session;
std::vector<sigc::connection> connections;
bool ignore_toggle; bool ignore_toggle;
bool next_release_selects; bool next_release_selects;
@ -169,9 +172,11 @@ class GainMeterBase : virtual public sigc::trackable
class GainMeter : public GainMeterBase, public Gtk::VBox class GainMeter : public GainMeterBase, public Gtk::VBox
{ {
public: public:
GainMeter (boost::shared_ptr<ARDOUR::IO>, ARDOUR::Session&); GainMeter (ARDOUR::Session&);
~GainMeter () {} ~GainMeter () {}
void set_io (boost::shared_ptr<ARDOUR::IO>);
int get_gm_width (); int get_gm_width ();
void setup_meters (int len=0); void setup_meters (int len=0);

View file

@ -58,9 +58,8 @@ using namespace std;
//sigc::signal<void,RouteGroup*> LevelMeter::ResetGroupPeakDisplays; //sigc::signal<void,RouteGroup*> LevelMeter::ResetGroupPeakDisplays;
LevelMeter::LevelMeter (boost::shared_ptr<IO> io, Session& s) LevelMeter::LevelMeter (Session& s)
: _io (io), : _session (s)
_session (s)
{ {
set_spacing (1); set_spacing (1);
@ -85,6 +84,12 @@ LevelMeter::~LevelMeter ()
} }
} }
void
LevelMeter::set_io (boost::shared_ptr<IO> io)
{
_io = io;
}
float float
LevelMeter::update_meters () LevelMeter::update_meters ()
{ {
@ -144,6 +149,10 @@ LevelMeter::hide_all_meters ()
void void
LevelMeter::setup_meters (int len, int initial_width) LevelMeter::setup_meters (int len, int initial_width)
{ {
if (!_io) {
return; /* do it later */
}
uint32_t nmeters = _io->n_outputs().n_total(); uint32_t nmeters = _io->n_outputs().n_total();
regular_meter_width = initial_width; regular_meter_width = initial_width;

View file

@ -56,9 +56,11 @@ namespace Gtk {
class LevelMeter : public Gtk::HBox class LevelMeter : public Gtk::HBox
{ {
public: public:
LevelMeter (boost::shared_ptr<ARDOUR::IO>, ARDOUR::Session&); LevelMeter (ARDOUR::Session&);
~LevelMeter (); ~LevelMeter ();
virtual void set_io (boost::shared_ptr<ARDOUR::IO> io);
void update_gain_sensitive (); void update_gain_sensitive ();
float update_meters (); float update_meters ();

View file

@ -117,7 +117,10 @@ fixup_bundle_environment ()
Glib::ustring path; Glib::ustring path;
const char *cstr = getenv ("PATH"); const char *cstr = getenv ("PATH");
/* ensure that we find any bundled executables (e.g. JACK) */ /* ensure that we find any bundled executables (e.g. JACK),
and find them before any instances of the same name
elsewhere in PATH
*/
path = dir_path; path = dir_path;
if (cstr) { if (cstr) {
@ -152,8 +155,10 @@ fixup_bundle_environment ()
if (cstr) { if (cstr) {
path = cstr; path = cstr;
path += ':'; path += ':';
} else {
path = "";
} }
path = dir_path; path += dir_path;
path += "/../Plugins"; path += "/../Plugins";
setenv ("LADSPA_PATH", path.c_str(), 1); setenv ("LADSPA_PATH", path.c_str(), 1);
@ -162,8 +167,10 @@ fixup_bundle_environment ()
if (cstr) { if (cstr) {
path = cstr; path = cstr;
path += ':'; path += ':';
} else {
path = "";
} }
path = dir_path; path += dir_path;
path += "/../Frameworks"; path += "/../Frameworks";
setenv ("VAMP_PATH", path.c_str(), 1); setenv ("VAMP_PATH", path.c_str(), 1);
@ -172,8 +179,10 @@ fixup_bundle_environment ()
if (cstr) { if (cstr) {
path = cstr; path = cstr;
path += ':'; path += ':';
} else {
path = "";
} }
path = dir_path; path += dir_path;
path += "/../Surfaces"; path += "/../Surfaces";
setenv ("ARDOUR_CONTROL_SURFACE_PATH", path.c_str(), 1); setenv ("ARDOUR_CONTROL_SURFACE_PATH", path.c_str(), 1);
@ -182,8 +191,10 @@ fixup_bundle_environment ()
if (cstr) { if (cstr) {
path = cstr; path = cstr;
path += ':'; path += ':';
} else {
path = "";
} }
path = dir_path; path += dir_path;
path += "/../Plugins"; path += "/../Plugins";
setenv ("LV2_PATH", path.c_str(), 1); setenv ("LV2_PATH", path.c_str(), 1);

427
gtk2_ardour/matrix.cc Normal file
View file

@ -0,0 +1,427 @@
#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"
using namespace std;
using namespace Gtk;
using namespace ARDOUR;
Matrix::Matrix ()
{
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;
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));
}
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;
}
}
reset_size ();
}
void
Matrix::hide_group (PortGroup& pg)
{
reset_size();
}
void
Matrix::show_group (PortGroup& pg)
{
reset_size ();
}
void
Matrix::setup_nodes ()
{
int n, x, y;
list<string>::iterator m;
list<OtherPort>::iterator s;
for (vector<MatrixNode*>::iterator p = nodes.begin(); p != nodes.end(); ++p) {
delete *p;
}
nodes.clear ();
list<OtherPort>::size_type visible_others = 0;
for (list<OtherPort>::iterator s = others.begin(); s != others.end(); ++s) {
if ((*s).visible()) {
++visible_others;
}
}
nodes.assign (ours.size() * visible_others, 0);
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()) {
nodes[n] = new MatrixNode (*m, *s, x, y);
n++;
x++;
}
}
}
}
void
Matrix::reset_size ()
{
list<OtherPort>::size_type visible_others = 0;
for (list<OtherPort>::iterator s = others.begin(); s != others.end(); ++s) {
if ((*s).visible()) {
++visible_others;
}
}
border = 10;
if (alloc_width > line_width) {
xstep = (alloc_width - labels_x_shift - (2 * border) - (2 * arc_radius)) / visible_others;
line_width = xstep * (others.size() - 1);
ystep = (alloc_height - labels_y_shift - (2 * border) - (2 * arc_radius)) / (ours.size() - 1);
line_height = ystep * (ours.size() - 1);
} else {
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);
/* scan all the port names that will be rotated, and compute
how much space we need for them
*/
float w = 0;
float w1;
float h = 0;
cairo_text_extents_t extents;
cairo_t* cr;
GdkPixmap* pm;
pm = gdk_pixmap_new (NULL, 1, 1, 24);
gdk_drawable_set_colormap (pm, gdk_colormap_get_system());
cr = gdk_cairo_create (pm);
for (list<OtherPort>::iterator s = others.begin(); s != others.end(); ++s) {
if ((*s).visible()) {
cairo_text_extents (cr, (*s).name().c_str(), &extents);
w = max ((float) extents.width, w);
h = max ((float) extents.height, h);
}
}
cairo_destroy (cr);
gdk_pixmap_unref (pm);
/* transform */
w = fabs (w * cos (angle_radians) + h * sin (angle_radians));
h = fabs (w * sin (angle_radians) + h * cos (angle_radians));
labels_y_shift = (int) ceil (h) + 10;
labels_x_shift = (int) ceil (w);
setup_nodes ();
}
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)
{
req->width = labels_x_shift + line_width + (2*border) + (2*arc_radius);
req->height = labels_y_shift + line_height + (2*border) + (2*arc_radius);
}
MatrixNode*
Matrix::get_node (int32_t x, int32_t y)
{
int half_xstep = xstep / 2;
int 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*ours.size() + x;
if (x >= 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) {
cerr << "Event in node " << node->our_name() << " x " << node->their_name () << endl;
node->set_connected (!node->connected());
drawn = false;
queue_draw();
}
}
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;
uint32_t top_shift, bottom_shift, left_shift, right_shift;
cairo_t* cr;
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);
top_shift = labels_y_shift + border;
left_shift = labels_x_shift + border;
bottom_shift = 0;
right_shift = 0;
/* 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).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_stroke (cr);
} else {
cairo_set_source_rgba (cr, 1.0, 0, 0, 0.7);
cairo_fill (cr);
}
}
}
/* motion indicators */
if (motion_x >= left_shift && motion_y >= top_shift) {
int col_left = left_shift + ((motion_x - left_shift) / xstep) * xstep;
int row_top = top_shift + ((motion_y - 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;
}

106
gtk2_ardour/matrix.h Normal file
View file

@ -0,0 +1,106 @@
#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"
class OtherPort {
public:
OtherPort (const std::string& n, PortGroup& g)
: _name (n), _group (g) {}
std::string name() const { return _name; }
PortGroup& group() const { return _group; }
bool visible() const { return _group.visible; }
public:
std::string _name;
PortGroup& _group;
};
class MatrixNode {
public:
MatrixNode (std::string a, OtherPort o, int32_t x, int32_t y)
: _name (a), them (o), _connected (random()%3), _x(x), _y(y) {}
~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();
void set_ports (const std::list<std::string>&);
void add_group (PortGroup&);
void remove_group (PortGroup&);
void hide_group (PortGroup&);
void show_group (PortGroup&);
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:
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 ();
GdkPixmap* pixmap;
};
#endif /* __gtk_ardour_matrix_h__ */

View file

@ -82,34 +82,56 @@ speed_printer (char buf[32], Gtk::Adjustment& adj, void* arg)
} }
#endif #endif
MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt, bool in_mixer) MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, bool in_mixer)
: AxisView(sess), : AxisView(sess)
RouteUI (rt, sess, _("Mute"), _("Solo"), _("Record")), , RouteUI (sess, _("Mute"), _("Solo"), _("Record"))
_mixer(mx), ,_mixer(mx)
_mixer_owned (in_mixer), , _mixer_owned (in_mixer)
pre_processor_box (PreFader, sess, rt, mx.plugin_selector(), mx.selection(), in_mixer), , pre_processor_box (PreFader, sess, mx.plugin_selector(), mx.selection(), in_mixer)
post_processor_box (PostFader, sess, rt, mx.plugin_selector(), mx.selection(), in_mixer), , post_processor_box (PostFader, sess, mx.plugin_selector(), mx.selection(), in_mixer)
gpm (_route, sess), , gpm (sess)
panners (_route, sess), , panners (sess)
button_table (3, 2), , button_table (3, 2)
middle_button_table (1, 2), , middle_button_table (1, 2)
bottom_button_table (1, 2), , bottom_button_table (1, 2)
meter_point_label (_("pre")), , meter_point_label (_("pre"))
comment_button (_("Comments")), , comment_button (_("Comments"))
speed_adjustment (1.0, 0.001, 4.0, 0.001, 0.1), , speed_adjustment (1.0, 0.001, 4.0, 0.001, 0.1)
speed_spinner (&speed_adjustment, "MixerStripSpeedBase", true) , speed_spinner (&speed_adjustment, "MixerStripSpeedBase", true)
{ {
if (set_color_from_route()) { init ();
set_color (unique_random_color()); }
}
MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt, bool in_mixer)
: AxisView(sess)
, RouteUI (sess, _("Mute"), _("Solo"), _("Record"))
,_mixer(mx)
, _mixer_owned (in_mixer)
, pre_processor_box (PreFader, sess, mx.plugin_selector(), mx.selection(), in_mixer)
, post_processor_box (PostFader, sess, mx.plugin_selector(), mx.selection(), in_mixer)
, gpm (sess)
, panners (sess)
, button_table (3, 2)
, middle_button_table (1, 2)
, bottom_button_table (1, 2)
, meter_point_label (_("pre"))
, comment_button (_("Comments"))
, speed_adjustment (1.0, 0.001, 4.0, 0.001, 0.1)
, speed_spinner (&speed_adjustment, "MixerStripSpeedBase", true)
{
init ();
set_route (rt);
}
void
MixerStrip::init ()
{
input_selector = 0; input_selector = 0;
output_selector = 0; output_selector = 0;
group_menu = 0; group_menu = 0;
if (!_route->is_hidden()) { _marked_for_display = false;
_marked_for_display = true;
}
route_ops_menu = 0; route_ops_menu = 0;
ignore_comment_edit = false; ignore_comment_edit = false;
ignore_toggle = false; ignore_toggle = false;
@ -118,40 +140,26 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
comment_area = 0; comment_area = 0;
_width_owner = 0; _width_owner = 0;
Gtk::Image *width_icon = manage (new Gtk::Image (::get_icon("strip_width"))); width_button.add (*(manage (new Gtk::Image (::get_icon("strip_width")))));
Gtk::Image *hide_icon = manage (new Gtk::Image (::get_icon("hide"))); hide_button.add (*(manage (new Gtk::Image (::get_icon("hide")))));
width_button.add (*width_icon);
hide_button.add (*hide_icon);
input_label.set_text (_("Input")); input_label.set_text (_("Input"));
ARDOUR_UI::instance()->set_tip (&input_button, _("Click to choose inputs"), "");
input_button.add (input_label); input_button.add (input_label);
input_button.set_name ("MixerIOButton"); input_button.set_name ("MixerIOButton");
input_label.set_name ("MixerIOButtonLabel"); input_label.set_name ("MixerIOButtonLabel");
output_label.set_text (_("Output")); output_label.set_text (_("Output"));
ARDOUR_UI::instance()->set_tip (&output_button, _("Click to choose outputs"), "");
output_button.add (output_label); output_button.add (output_label);
output_button.set_name ("MixerIOButton"); output_button.set_name ("MixerIOButton");
output_label.set_name ("MixerIOButtonLabel"); output_label.set_name ("MixerIOButtonLabel");
_route->meter_change.connect (mem_fun(*this, &MixerStrip::meter_changed)); ARDOUR_UI::instance()->set_tip (&meter_point_button, _("Select metering point"), "");
meter_point_button.add (meter_point_label); meter_point_button.add (meter_point_label);
meter_point_button.set_name ("MixerStripMeterPreButton"); meter_point_button.set_name ("MixerStripMeterPreButton");
meter_point_label.set_name ("MixerStripMeterPreButton"); meter_point_label.set_name ("MixerStripMeterPreButton");
switch (_route->meter_point()) {
case MeterInput:
meter_point_label.set_text (_("input"));
break;
case MeterPreFader:
meter_point_label.set_text (_("pre"));
break;
case MeterPostFader:
meter_point_label.set_text (_("post"));
break;
}
/* TRANSLATORS: this string should be longest of the strings /* TRANSLATORS: this string should be longest of the strings
used to describe meter points. In english, it's "input". used to describe meter points. In english, it's "input".
*/ */
@ -183,56 +191,18 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
bottom_button_table.set_homogeneous (true); bottom_button_table.set_homogeneous (true);
bottom_button_table.attach (group_button, 0, 1, 0, 1); bottom_button_table.attach (group_button, 0, 1, 0, 1);
if (is_audio_track()) {
boost::shared_ptr<AudioTrack> at = audio_track();
at->FreezeChange.connect (mem_fun(*this, &MixerStrip::map_frozen));
#ifdef VARISPEED_IN_MIXER_STRIP
speed_adjustment.signal_value_changed().connect (mem_fun(*this, &MixerStrip::speed_adjustment_changed));
speed_frame.set_name ("BaseFrame");
speed_frame.set_shadow_type (Gtk::SHADOW_IN);
speed_frame.add (speed_spinner);
speed_spinner.set_print_func (speed_printer, 0);
ARDOUR_UI::instance()->tooltips().set_tip (speed_spinner, _("Varispeed"));
button_table.attach (speed_frame, 0, 2, 5, 6);
#endif /* VARISPEED_IN_MIXER_STRIP */
}
if(rec_enable_button) {
rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press), false);
rec_enable_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::rec_enable_release));
rec_enable_button->set_name ("MixerRecordEnableButton");
button_table.attach (*rec_enable_button, 0, 2, 2, 3);
}
name_button.add (name_label); name_button.add (name_label);
name_button.set_name ("MixerNameButton"); name_button.set_name ("MixerNameButton");
Gtkmm2ext::set_size_request_to_display_given_text (name_button, "longest label", 2, 2); Gtkmm2ext::set_size_request_to_display_given_text (name_button, "longest label", 2, 2);
name_label.set_name ("MixerNameButtonLabel"); name_label.set_name ("MixerNameButtonLabel");
if (_route->phase_invert()) { ARDOUR_UI::instance()->set_tip (&group_button, _("Mix group"), "");
name_label.set_text (X_("Ø ") + name_label.get_text());
} else {
name_label.set_text (_route->name());
}
group_button.add (group_label); group_button.add (group_label);
group_button.set_name ("MixerGroupButton"); group_button.set_name ("MixerGroupButton");
group_label.set_name ("MixerGroupButtonLabel"); group_label.set_name ("MixerGroupButtonLabel");
comment_button.set_name ("MixerCommentButton"); comment_button.set_name ("MixerCommentButton");
ARDOUR_UI::instance()->tooltips().set_tip (comment_button, _route->comment()=="" ?
_("Click to Add/Edit Comments"):
_route->comment());
comment_button.signal_clicked().connect (mem_fun(*this, &MixerStrip::comment_button_clicked)); comment_button.signal_clicked().connect (mem_fun(*this, &MixerStrip::comment_button_clicked));
global_vpacker.set_border_width (0); global_vpacker.set_border_width (0);
@ -269,19 +239,6 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK); global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
global_vpacker.pack_start (comment_button, Gtk::PACK_SHRINK); global_vpacker.pack_start (comment_button, Gtk::PACK_SHRINK);
if (route()->is_master() || route()->is_control()) {
if (scrollbar_height == 0) {
HScrollbar scrollbar;
Gtk::Requisition requisition(scrollbar.size_request ());
scrollbar_height = requisition.height;
}
EventBox* spacer = manage (new EventBox);
spacer->set_size_request (-1, scrollbar_height);
global_vpacker.pack_start (*spacer, false, false);
}
global_frame.add (global_vpacker); global_frame.add (global_vpacker);
global_frame.set_shadow_type (Gtk::SHADOW_IN); global_frame.set_shadow_type (Gtk::SHADOW_IN);
global_frame.set_name ("BaseFrame"); global_frame.set_name ("BaseFrame");
@ -298,22 +255,6 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
_session.engine().Stopped.connect (mem_fun(*this, &MixerStrip::engine_stopped)); _session.engine().Stopped.connect (mem_fun(*this, &MixerStrip::engine_stopped));
_session.engine().Running.connect (mem_fun(*this, &MixerStrip::engine_running)); _session.engine().Running.connect (mem_fun(*this, &MixerStrip::engine_running));
_route->input_changed.connect (mem_fun(*this, &MixerStrip::input_changed));
_route->output_changed.connect (mem_fun(*this, &MixerStrip::output_changed));
_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed));
_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
_route->mix_group_changed.connect (mem_fun(*this, &MixerStrip::mix_group_changed));
_route->panner().Changed.connect (mem_fun(*this, &MixerStrip::connect_to_pan));
if (is_audio_track()) {
audio_track()->DiskstreamChanged.connect (mem_fun(*this, &MixerStrip::diskstream_changed));
get_diskstream()->SpeedChanged.connect (mem_fun(*this, &MixerStrip::speed_changed));
}
_route->NameChanged.connect (mem_fun(*this, &RouteUI::name_changed));
_route->comment_changed.connect (mem_fun(*this, &MixerStrip::comment_changed));
_route->gui_changed.connect (mem_fun(*this, &MixerStrip::route_gui_changed));
input_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::input_press), false); input_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::input_press), false);
output_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::output_press), false); output_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::output_press), false);
@ -323,11 +264,22 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
mute_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::mute_press), false); mute_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::mute_press), false);
mute_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::mute_release), false); mute_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::mute_release), false);
/* we don't need this if its not an audio track, but we don't know that yet and it doesn't
hurt (much).
*/
rec_enable_button->set_name ("MixerRecordEnableButton");
rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press), false);
rec_enable_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::rec_enable_release));
name_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::name_button_button_press), false); name_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::name_button_button_press), false);
group_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::select_mix_group), false); group_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::select_mix_group), false);
_width = (Width) -1; _width = (Width) -1;
set_stuff_from_route ();
/* start off as a passthru strip. we'll correct this, if necessary,
in update_diskstream_display().
*/
/* start off as a passthru strip. we'll correct this, if necessary, /* start off as a passthru strip. we'll correct this, if necessary,
in update_diskstream_display(). in update_diskstream_display().
@ -338,6 +290,126 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
else else
set_name ("AudioTrackStripBase"); set_name ("AudioTrackStripBase");
add_events (Gdk::BUTTON_RELEASE_MASK);
}
MixerStrip::~MixerStrip ()
{
GoingAway(); /* EMIT_SIGNAL */
if (input_selector) {
delete input_selector;
}
if (output_selector) {
delete output_selector;
}
}
void
MixerStrip::set_route (boost::shared_ptr<Route> rt)
{
if (rec_enable_button->get_parent()) {
button_table.remove (*rec_enable_button);
}
#ifdef VARISPEED_IN_MIXER_STRIP
if (speed_frame->get_parent()) {
button_table.remove (*speed_frame);
}
#endif
RouteUI::set_route (rt);
panners.set_io (rt);
gpm.set_io (rt);
pre_processor_box.set_route (rt);
post_processor_box.set_route (rt);
if (set_color_from_route()) {
set_color (unique_random_color());
}
if (_mixer_owned && (route()->is_master() || route()->is_control())) {
if (scrollbar_height == 0) {
HScrollbar scrollbar;
Gtk::Requisition requisition(scrollbar.size_request ());
scrollbar_height = requisition.height;
}
EventBox* spacer = manage (new EventBox);
spacer->set_size_request (-1, scrollbar_height);
global_vpacker.pack_start (*spacer, false, false);
}
if (is_audio_track()) {
boost::shared_ptr<AudioTrack> at = audio_track();
connections.push_back (at->FreezeChange.connect (mem_fun(*this, &MixerStrip::map_frozen)));
#ifdef VARISPEED_IN_MIXER_STRIP
speed_adjustment.signal_value_changed().connect (mem_fun(*this, &MixerStrip::speed_adjustment_changed));
speed_frame.set_name ("BaseFrame");
speed_frame.set_shadow_type (Gtk::SHADOW_IN);
speed_frame.add (speed_spinner);
speed_spinner.set_print_func (speed_printer, 0);
ARDOUR_UI::instance()->tooltips().set_tip (speed_spinner, _("Varispeed"));
button_table.attach (speed_frame, 0, 2, 5, 6);
#endif /* VARISPEED_IN_MIXER_STRIP */
button_table.attach (*rec_enable_button, 0, 2, 2, 3);
}
if (_route->phase_invert()) {
name_label.set_text (X_("Ø ") + name_label.get_text());
} else {
name_label.set_text (_route->name());
}
switch (_route->meter_point()) {
case MeterInput:
meter_point_label.set_text (_("input"));
break;
case MeterPreFader:
meter_point_label.set_text (_("pre"));
break;
case MeterPostFader:
meter_point_label.set_text (_("post"));
break;
}
ARDOUR_UI::instance()->tooltips().set_tip (comment_button, _route->comment().empty() ?
_("Click to Add/Edit Comments"):
_route->comment());
connections.push_back (_route->meter_change.connect (mem_fun(*this, &MixerStrip::meter_changed)));
connections.push_back (_route->input_changed.connect (mem_fun(*this, &MixerStrip::input_changed)));
connections.push_back (_route->output_changed.connect (mem_fun(*this, &MixerStrip::output_changed)));
connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
connections.push_back (_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
connections.push_back (_route->mix_group_changed.connect (mem_fun(*this, &MixerStrip::mix_group_changed)));
connections.push_back (_route->panner().Changed.connect (mem_fun(*this, &MixerStrip::connect_to_pan)));
if (is_audio_track()) {
connections.push_back (audio_track()->DiskstreamChanged.connect (mem_fun(*this, &MixerStrip::diskstream_changed)));
connections.push_back (get_diskstream()->SpeedChanged.connect (mem_fun(*this, &MixerStrip::speed_changed)));
}
connections.push_back (_route->NameChanged.connect (mem_fun(*this, &RouteUI::name_changed)));
connections.push_back (_route->comment_changed.connect (mem_fun(*this, &MixerStrip::comment_changed)));
connections.push_back (_route->gui_changed.connect (mem_fun(*this, &MixerStrip::route_gui_changed)));
set_stuff_from_route ();
/* now force an update of all the various elements */ /* now force an update of all the various elements */
pre_processor_box.update(); pre_processor_box.update();
@ -362,11 +434,6 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
add_events (Gdk::BUTTON_RELEASE_MASK); add_events (Gdk::BUTTON_RELEASE_MASK);
whvbox->show();
hide_icon->show();
width_icon->show();
gain_meter_alignment->show_all();
pre_processor_box.show(); pre_processor_box.show();
if (!route()->is_master() && !route()->is_control()) { if (!route()->is_master() && !route()->is_control()) {
@ -402,19 +469,6 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
show(); show();
} }
MixerStrip::~MixerStrip ()
{
GoingAway(); /* EMIT_SIGNAL */
if (input_selector) {
delete input_selector;
}
if (output_selector) {
delete output_selector;
}
}
void void
MixerStrip::set_stuff_from_route () MixerStrip::set_stuff_from_route ()
{ {
@ -796,6 +850,7 @@ MixerStrip::update_output_display ()
break; break;
} }
} }
gpm.setup_meters (); gpm.setup_meters ();
panners.setup_pan (); panners.setup_pan ();
} }
@ -1292,22 +1347,22 @@ MixerStrip::meter_changed (void *src)
ENSURE_GUI_THREAD (bind (mem_fun(*this, &MixerStrip::meter_changed), src)); ENSURE_GUI_THREAD (bind (mem_fun(*this, &MixerStrip::meter_changed), src));
switch (_route->meter_point()) { switch (_route->meter_point()) {
case MeterInput: case MeterInput:
meter_point_label.set_text (_("input")); meter_point_label.set_text (_("input"));
break; break;
case MeterPreFader: case MeterPreFader:
meter_point_label.set_text (_("pre")); meter_point_label.set_text (_("pre"));
break; break;
case MeterPostFader: case MeterPostFader:
meter_point_label.set_text (_("post")); meter_point_label.set_text (_("post"));
break; break;
} }
gpm.setup_meters (); gpm.setup_meters ();
// reset peak when meter point changes // reset peak when meter point changes
gpm.reset_peak_display(); gpm.reset_peak_display();
set_width(_width, this); set_width(_width, this);
} }

View file

@ -83,6 +83,7 @@ class MixerStrip : public RouteUI, public Gtk::EventBox
{ {
public: public:
MixerStrip (Mixer_UI&, ARDOUR::Session&, boost::shared_ptr<ARDOUR::Route>, bool in_mixer = true); MixerStrip (Mixer_UI&, ARDOUR::Session&, boost::shared_ptr<ARDOUR::Route>, bool in_mixer = true);
MixerStrip (Mixer_UI&, ARDOUR::Session&, bool in_mixer = true);
~MixerStrip (); ~MixerStrip ();
void set_width (Width, void* owner); void set_width (Width, void* owner);
@ -93,6 +94,7 @@ class MixerStrip : public RouteUI, public Gtk::EventBox
void set_embedded (bool); void set_embedded (bool);
ARDOUR::RouteGroup* mix_group() const; ARDOUR::RouteGroup* mix_group() const;
void set_route (boost::shared_ptr<ARDOUR::Route>);
protected: protected:
friend class Mixer_UI; friend class Mixer_UI;
@ -105,6 +107,8 @@ class MixerStrip : public RouteUI, public Gtk::EventBox
private: private:
Mixer_UI& _mixer; Mixer_UI& _mixer;
void init ();
bool _embedded; bool _embedded;
bool _packed; bool _packed;
bool _mixer_owned; bool _mixer_owned;

View file

@ -1117,7 +1117,8 @@ OptionEditor::setup_click_editor ()
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(), false);
click_gpm = new GainMeter (session->click_io(), *session); click_gpm = new GainMeter (*session);
click_gpm->set_io (session->click_io());
click_hpacker.pack_start (*click_io_selector, false, false); click_hpacker.pack_start (*click_io_selector, false, false);
click_hpacker.pack_start (*click_gpm, false, false); click_hpacker.pack_start (*click_gpm, false, false);
@ -1173,7 +1174,8 @@ 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(), false);
auditioner_gpm = new GainMeter (session->the_auditioner(), *session); auditioner_gpm = new GainMeter (*session);
auditioner_gpm->set_io (session->the_auditioner());
audition_hpacker.pack_start (*auditioner_io_selector, false, false); audition_hpacker.pack_start (*auditioner_io_selector, false, false);
audition_hpacker.pack_start (*auditioner_gpm, false, false); audition_hpacker.pack_start (*auditioner_gpm, false, false);

View file

@ -47,9 +47,8 @@ using namespace sigc;
const int PannerUI::pan_bar_height = 30; const int PannerUI::pan_bar_height = 30;
PannerUI::PannerUI (boost::shared_ptr<IO> io, Session& s) PannerUI::PannerUI (Session& s)
: _io (io), : _session (s),
_session (s),
hAdjustment(0.0, 0.0, 0.0), hAdjustment(0.0, 0.0, 0.0),
vAdjustment(0.0, 0.0, 0.0), vAdjustment(0.0, 0.0, 0.0),
panning_viewport(hAdjustment, vAdjustment), panning_viewport(hAdjustment, vAdjustment),
@ -61,6 +60,8 @@ PannerUI::PannerUI (boost::shared_ptr<IO> io, Session& s)
{ {
ignore_toggle = false; ignore_toggle = false;
pan_menu = 0; pan_menu = 0;
pan_astate_menu = 0;
pan_astyle_menu = 0;
in_pan_update = false; in_pan_update = false;
pan_automation_style_button.set_name ("MixerAutomationModeButton"); pan_automation_style_button.set_name ("MixerAutomationModeButton");
@ -84,22 +85,6 @@ PannerUI::PannerUI (boost::shared_ptr<IO> io, Session& s)
pan_automation_style_button.unset_flags (Gtk::CAN_FOCUS); pan_automation_style_button.unset_flags (Gtk::CAN_FOCUS);
pan_automation_state_button.unset_flags (Gtk::CAN_FOCUS); pan_automation_state_button.unset_flags (Gtk::CAN_FOCUS);
using namespace Menu_Helpers;
pan_astate_menu.items().push_back (MenuElem (_("Manual"),
bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Off)));
pan_astate_menu.items().push_back (MenuElem (_("Play"),
bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Play)));
pan_astate_menu.items().push_back (MenuElem (_("Write"),
bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Write)));
pan_astate_menu.items().push_back (MenuElem (_("Touch"),
bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Touch)));
pan_astyle_menu.items().push_back (MenuElem (_("Trim")));
pan_astyle_menu.items().push_back (MenuElem (_("Abs")));
pan_astate_menu.set_name ("ArdourContextMenu");
pan_astyle_menu.set_name ("ArdourContextMenu");
pan_automation_style_button.signal_button_press_event().connect (mem_fun(*this, &PannerUI::pan_automation_style_button_event), false); pan_automation_style_button.signal_button_press_event().connect (mem_fun(*this, &PannerUI::pan_automation_style_button_event), false);
pan_automation_state_button.signal_button_press_event().connect (mem_fun(*this, &PannerUI::pan_automation_state_button_event), false); pan_automation_state_button.signal_button_press_event().connect (mem_fun(*this, &PannerUI::pan_automation_state_button_event), false);
@ -141,16 +126,41 @@ PannerUI::PannerUI (boost::shared_ptr<IO> io, Session& s)
panner = 0; panner = 0;
set_width(Narrow); set_width(Narrow);
}
_io->panner().Changed.connect (mem_fun(*this, &PannerUI::panner_changed));
_io->panner().LinkStateChanged.connect (mem_fun(*this, &PannerUI::update_pan_linkage)); void
_io->panner().StateChanged.connect (mem_fun(*this, &PannerUI::update_pan_state)); PannerUI::set_io (boost::shared_ptr<IO> io)
{
connections.clear ();
if (pan_astyle_menu) {
delete pan_astyle_menu;
pan_astyle_menu = 0;
}
if (pan_astate_menu) {
delete pan_astate_menu;
pan_astate_menu = 0;
}
_io = io;
connections.push_back (_io->panner().Changed.connect (mem_fun(*this, &PannerUI::panner_changed)));
connections.push_back (_io->panner().LinkStateChanged.connect (mem_fun(*this, &PannerUI::update_pan_linkage)));
connections.push_back (_io->panner().StateChanged.connect (mem_fun(*this, &PannerUI::update_pan_state)));
if (panner) {
delete panner;
panner = 0;
}
pan_changed (0); pan_changed (0);
update_pan_sensitive (); update_pan_sensitive ();
update_pan_linkage (); update_pan_linkage ();
pan_automation_state_changed (); pan_automation_state_changed ();
#if WHERE_DOES_THIS_LIVE
pan_bar_packer.show(); pan_bar_packer.show();
panning_viewport.show(); panning_viewport.show();
panning_up.show(); panning_up.show();
@ -164,6 +174,46 @@ PannerUI::PannerUI (boost::shared_ptr<IO> io, Session& s)
pan_automation_style_button.show(); pan_automation_style_button.show();
pan_automation_state_button.show(); pan_automation_state_button.show();
show(); show();
#endif
}
void
PannerUI::build_astate_menu ()
{
using namespace Menu_Helpers;
if (pan_astate_menu == 0) {
pan_astate_menu = new Menu;
pan_astate_menu->set_name ("ArdourContextMenu");
} else {
pan_astate_menu->items().clear ();
}
pan_astate_menu->items().push_back (MenuElem (_("Manual"),
bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Off)));
pan_astate_menu->items().push_back (MenuElem (_("Play"),
bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Play)));
pan_astate_menu->items().push_back (MenuElem (_("Write"),
bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Write)));
pan_astate_menu->items().push_back (MenuElem (_("Touch"),
bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Touch)));
}
void
PannerUI::build_astyle_menu ()
{
using namespace Menu_Helpers;
if (pan_astyle_menu == 0) {
pan_astyle_menu = new Menu;
pan_astyle_menu->set_name ("ArdourContextMenu");
} else {
pan_astyle_menu->items().clear();
}
pan_astyle_menu->items().push_back (MenuElem (_("Trim")));
pan_astyle_menu->items().push_back (MenuElem (_("Abs")));
} }
boost::shared_ptr<PBD::Controllable> boost::shared_ptr<PBD::Controllable>
@ -262,7 +312,14 @@ PannerUI::~PannerUI ()
if (pan_menu) { if (pan_menu) {
delete pan_menu; delete pan_menu;
} }
if (pan_astyle_menu) {
delete pan_astyle_menu;
}
if (pan_astate_menu) {
delete pan_astate_menu;
}
} }
@ -662,7 +719,10 @@ PannerUI::pan_automation_state_button_event (GdkEventButton *ev)
switch (ev->button) { switch (ev->button) {
case 1: case 1:
pan_astate_menu.popup (1, ev->time); if (pan_astate_menu == 0) {
build_astate_menu ();
}
pan_astate_menu->popup (1, ev->time);
break; break;
default: default:
break; break;
@ -680,7 +740,10 @@ PannerUI::pan_automation_style_button_event (GdkEventButton *ev)
switch (ev->button) { switch (ev->button) {
case 1: case 1:
pan_astyle_menu.popup (1, ev->time); if (pan_astyle_menu == 0) {
build_astyle_menu ();
}
pan_astyle_menu->popup (1, ev->time);
break; break;
default: default:
break; break;

View file

@ -54,9 +54,11 @@ namespace Gtk {
class PannerUI : public Gtk::HBox class PannerUI : public Gtk::HBox
{ {
public: public:
PannerUI (boost::shared_ptr<ARDOUR::IO>, ARDOUR::Session&); PannerUI (ARDOUR::Session&);
~PannerUI (); ~PannerUI ();
virtual void set_io (boost::shared_ptr<ARDOUR::IO>);
void pan_changed (void *); void pan_changed (void *);
void update_pan_sensitive (); void update_pan_sensitive ();
@ -75,6 +77,7 @@ class PannerUI : public Gtk::HBox
boost::shared_ptr<ARDOUR::IO> _io; boost::shared_ptr<ARDOUR::IO> _io;
ARDOUR::Session& _session; ARDOUR::Session& _session;
std::vector<sigc::connection> connections;
bool ignore_toggle; bool ignore_toggle;
bool in_pan_update; bool in_pan_update;
@ -101,8 +104,8 @@ class PannerUI : public Gtk::HBox
bool panning_link_button_press (GdkEventButton*); bool panning_link_button_press (GdkEventButton*);
bool panning_link_button_release (GdkEventButton*); bool panning_link_button_release (GdkEventButton*);
Gtk::Menu pan_astate_menu; Gtk::Menu* pan_astate_menu;
Gtk::Menu pan_astyle_menu; Gtk::Menu* pan_astyle_menu;
Gtk::Button pan_automation_style_button; Gtk::Button pan_automation_style_button;
Gtk::ToggleButton pan_automation_state_button; Gtk::ToggleButton pan_automation_state_button;
@ -118,6 +121,8 @@ class PannerUI : public Gtk::HBox
void update_pan_bars (bool only_if_aplay); void update_pan_bars (bool only_if_aplay);
void update_pan_linkage (); void update_pan_linkage ();
void update_pan_state (); void update_pan_state ();
void build_astate_menu ();
void build_astyle_menu ();
void panner_changed (); void panner_changed ();

90
gtk2_ardour/port_group.h Normal file
View file

@ -0,0 +1,90 @@
#ifndef __gtk_ardour_port_group_h__
#define __gtk_ardour_port_group_h__
#include <vector>
#include <string>
#include <gtkmm/widget.h>
#include <gtkmm/checkbutton.h>
#include <ardour/data_type.h>
namespace ARDOUR {
class Session;
class IO;
class PortInsert;
}
class PortMatrix;
/// A list of port names, grouped by some aspect of their type e.g. busses, tracks, system
class PortGroup
{
public:
/** PortGroup constructor.
* @param n Name.
* @param p Port name prefix.
* @param v true if group should be visible in the UI, otherwise false.
*/
PortGroup (std::string const & n, std::string const & p, bool v) : name (n), prefix (p), visible (v) {}
void add (std::string const & p);
std::string name; ///< name for the group
std::string prefix; ///< prefix (before colon) e.g. "ardour:"
std::vector<std::string> ports; ///< port names
bool visible; ///< true if the group is visible in the UI
};
/// The UI for a PortGroup
class PortGroupUI
{
public:
PortGroupUI (PortMatrix&, PortGroup&);
Gtk::Widget& get_visibility_checkbutton ();
PortGroup& port_group () { return _port_group; }
void setup_visibility ();
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 ();
PortMatrix& _port_matrix; ///< the PortMatrix that we are working for
PortGroup& _port_group; ///< the PortGroup that we are representing
bool _ignore_check_button_toggle;
Gtk::CheckButton _visibility_checkbutton;
};
/// A list of PortGroups
class PortGroupList : public std::list<PortGroup*>
{
public:
enum Mask {
BUSS = 0x1,
TRACK = 0x2,
SYSTEM = 0x4,
OTHER = 0x8
};
PortGroupList (ARDOUR::Session &, ARDOUR::DataType, bool, Mask);
void refresh ();
int n_visible_ports () const;
std::string get_port_by_index (int, bool with_prefix = true) const;
void set_type (ARDOUR::DataType);
void set_offer_inputs (bool);
private:
ARDOUR::Session& _session;
ARDOUR::DataType _type;
bool _offer_inputs;
PortGroup buss;
PortGroup track;
PortGroup system;
PortGroup other;
};
#endif /* __gtk_ardour_port_group_h__ */

View file

@ -69,59 +69,8 @@ PortGroupUI::PortGroupUI (PortMatrix& m, PortGroup& g)
, _ignore_check_button_toggle (false) , _ignore_check_button_toggle (false)
, _visibility_checkbutton (g.name) , _visibility_checkbutton (g.name)
{ {
int const ports = _port_group.ports.size(); _port_group.visible = true;
int const rows = _port_matrix.n_rows ();
if (rows == 0 || ports == 0) {
return;
}
/* Sort out the table and the checkbuttons inside it */
_table.resize (rows, ports);
_port_checkbuttons.resize (rows);
for (int i = 0; i < rows; ++i) {
_port_checkbuttons[i].resize (ports);
}
for (int i = 0; i < rows; ++i) {
for (uint32_t j = 0; j < _port_group.ports.size(); ++j) {
CheckButton* b = new CheckButton;
b->signal_toggled().connect (
sigc::bind (sigc::mem_fun (*this, &PortGroupUI::port_checkbutton_toggled), b, i, j));
b->signal_button_release_event().connect (
sigc::bind (sigc::mem_fun (*this, &PortGroupUI::port_checkbutton_release), b, i, j), false);
_port_checkbuttons[i][j] = b;
cerr << this << " bind to " << &_port_checkbuttons << " via " << b
<< endl;
_table.attach (*b, j, j + 1, i, i + 1);
}
}
_table_box.add (_table);
_ignore_check_button_toggle = true;
/* Set the state of the check boxes according to current connections */
for (int i = 0; i < rows; ++i) {
for (uint32_t j = 0; j < _port_group.ports.size(); ++j) {
std::string const t = _port_group.prefix + _port_group.ports[j];
bool const s = _port_matrix.get_state (i, t);
_port_checkbuttons[i][j]->set_active (s);
if (s) {
_port_group.visible = true;
}
}
}
_ignore_check_button_toggle = false; _ignore_check_button_toggle = false;
_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));
} }
@ -132,34 +81,6 @@ PortGroupUI::visibility_checkbutton_toggled ()
_port_group.visible = _visibility_checkbutton.get_active (); _port_group.visible = _visibility_checkbutton.get_active ();
} }
/** @return Width and height of a single checkbutton in a port group table */
std::pair<int, int>
PortGroupUI::unit_size () const
{
if (_port_checkbuttons.empty() || _port_checkbuttons[0].empty())
{
return std::pair<int, int> (0, 0);
}
int r = 0;
/* We can't ask for row spacing unless there >1 rows, otherwise we get a warning */
if (_table.property_n_rows() > 1) {
r = _table.get_row_spacing (0);
}
return std::make_pair (
_port_checkbuttons[0][0]->get_width() + _table.get_col_spacing (0),
_port_checkbuttons[0][0]->get_height() + r
);
}
/** @return Table widget containing the port checkbuttons */
Widget&
PortGroupUI::get_table ()
{
return _table_box;
}
/** @return Checkbutton used to toggle visibility */ /** @return Checkbutton used to toggle visibility */
Widget& Widget&
PortGroupUI::get_visibility_checkbutton () PortGroupUI::get_visibility_checkbutton ()
@ -173,324 +94,37 @@ void
PortGroupUI::port_checkbutton_toggled (CheckButton* b, int r, int c) PortGroupUI::port_checkbutton_toggled (CheckButton* b, int r, int c)
{ {
if (_ignore_check_button_toggle == false) { if (_ignore_check_button_toggle == false) {
_port_matrix.set_state (r, _port_group.prefix + _port_group.ports[c], b->get_active(), 0); // _port_matrix.hide_group (_port_group);
} }
} }
bool
PortGroupUI::port_checkbutton_release (GdkEventButton* ev, CheckButton* b, int r, int c)
{
cerr << this << " RELEASE on " << b << " state = " << ev->state << endl;
if (ev->state == 0) {
/* let usual toggle handler take care of it */
return false;
}
/* The fun starts here
*/
const size_t ports = _port_group.ports.size();
const size_t rows = _port_matrix.n_rows ();
if (rows == 0 || ports == 0) {
return true;
}
/* For each port in the group, change the state of
the connection for the corresponding "connector" port.
*/
for (size_t j = c; j < ports; ++j) {
/* we've got a port to connect, now lets find the thing to
connect it too ... (search "down" the rows)
*/
cerr << "we're going to connect port " << j << " of " << ports << endl;
for (size_t i = r; i < rows; ++i) {
cerr << this << " going to connect to row " << i << " of " << rows << endl;
cerr << "access [" << i << "][" << j << "]\n";
cerr << " @ " << &_port_checkbuttons << endl;
_port_checkbuttons[i][j]->set_active (!_port_checkbuttons[i][j]->get_active());
/* next time, get at least as far as this port before looking
for more.
*/
r = i + 1;
/* changed connection state, stop looking for more */
break;
}
}
return true;
}
/** Set up visibility of the port group according to PortGroup::visible */ /** Set up visibility of the port group according to PortGroup::visible */
void void
PortGroupUI::setup_visibility () PortGroupUI::setup_visibility ()
{ {
if (!_port_group.ports.empty() && _port_group.visible) {
_table_box.show ();
} else {
_table_box.hide ();
}
if (_visibility_checkbutton.get_active () != _port_group.visible) { if (_visibility_checkbutton.get_active () != _port_group.visible) {
_visibility_checkbutton.set_active (_port_group.visible); _visibility_checkbutton.set_active (_port_group.visible);
} }
} }
RotatedLabelSet::RotatedLabelSet (PortGroupList& g)
: Glib::ObjectBase ("RotatedLabelSet"), Widget (), _port_group_list (g), _base_width (128)
{
set_flags (NO_WINDOW);
if (getenv ("AD_ANGLE") != 0) {
set_angle (atoi (getenv ("AD_ANGLE")));
} else {
set_angle (45);
}
}
RotatedLabelSet::~RotatedLabelSet ()
{
}
/** Set the angle that the labels are drawn at.
* @param degrees New angle in degrees.
*/
void
RotatedLabelSet::set_angle (int degrees)
{
_angle_degrees = degrees;
_angle_radians = M_PI * _angle_degrees / 180;
queue_resize ();
}
void
RotatedLabelSet::on_size_request (Requisition* requisition)
{
*requisition = Requisition ();
if (_pango_layout == 0) {
return;
}
/* Our height is the highest label */
requisition->height = 0;
for (PortGroupList::const_iterator i = _port_group_list.begin(); i != _port_group_list.end(); ++i) {
for (std::vector<std::string>::const_iterator j = (*i)->ports.begin(); j != (*i)->ports.end(); ++j) {
std::pair<int, int> const d = setup_layout (*j);
if (d.second > requisition->height) {
requisition->height = d.second;
}
}
}
/* And our width is the base plus the width of the last label */
requisition->width = _base_width;
int const n = _port_group_list.n_visible_ports ();
if (n > 0) {
std::pair<int, int> const d = setup_layout (_port_group_list.get_port_by_index (n - 1, false));
requisition->width += d.first;
}
cerr << "Labels will be " << requisition->width << " x " << requisition->height << endl;
}
void
RotatedLabelSet::on_size_allocate (Allocation& allocation)
{
set_allocation (allocation);
if (_gdk_window) {
_gdk_window->move_resize (allocation.get_x(), allocation.get_y(), allocation.get_width(), allocation.get_height());
}
}
void
RotatedLabelSet::on_realize ()
{
Widget::on_realize ();
Glib::RefPtr<Style> style = get_style ();
if (!_gdk_window) {
GdkWindowAttr attributes;
memset (&attributes, 0, sizeof (attributes));
Allocation allocation = get_allocation ();
attributes.x = allocation.get_x ();
attributes.y = allocation.get_y ();
attributes.width = allocation.get_width ();
attributes.height = allocation.get_height ();
attributes.event_mask = get_events () | Gdk::EXPOSURE_MASK;
attributes.window_type = GDK_WINDOW_CHILD;
attributes.wclass = GDK_INPUT_OUTPUT;
_gdk_window = Gdk::Window::create (get_window (), &attributes, GDK_WA_X | GDK_WA_Y);
unset_flags (NO_WINDOW);
set_window (_gdk_window);
_bg_colour = style->get_bg (STATE_NORMAL );
modify_bg (STATE_NORMAL, _bg_colour);
_fg_colour = style->get_fg (STATE_NORMAL);
_gdk_window->set_user_data (gobj ());
/* Set up Pango stuff */
_pango_context = create_pango_context ();
Pango::Matrix matrix = PANGO_MATRIX_INIT;
pango_matrix_rotate (&matrix, _angle_degrees);
_pango_context->set_matrix (matrix);
_pango_layout = Pango::Layout::create (_pango_context);
_gc = Gdk::GC::create (get_window ());
}
}
void
RotatedLabelSet::on_unrealize()
{
_gdk_window.clear ();
Widget::on_unrealize ();
}
/** Set up our Pango layout to plot a given string, and compute its dimensions once
* it has been rotated.
* @param s String to use.
* @return width and height of the rotated string, in pixels.
*/
std::pair<int, int>
RotatedLabelSet::setup_layout (std::string const & s)
{
_pango_layout->set_text (s);
/* Here's the unrotated size */
int w;
int h;
_pango_layout->get_pixel_size (w, h);
/* Rotate the width and height as appropriate. I thought Pango might be able
to do this for us, but I can't find out how...
*/
std::pair<int, int> d;
// cerr << "\"" << s << "\" was " << w << " x " << h << endl;
d.first = int (fabs (w * cos (_angle_radians) + h * sin (_angle_radians)));
d.second = int (fabs (w * sin (_angle_radians) + h * cos (_angle_radians)));
// cerr << "\trotated by " << _angle_degrees << " = " << d.first << " x " << d.second << endl;
return d;
}
bool
RotatedLabelSet::on_expose_event (GdkEventExpose* event)
{
if (!_gdk_window) {
return true;
}
int const height = get_allocation().get_height ();
double const spacing = double (_base_width) / _port_group_list.n_visible_ports();
/* Plot all the visible labels; really we should clip for efficiency */
int n = 0;
for (PortGroupList::const_iterator i = _port_group_list.begin(); i != _port_group_list.end(); ++i) {
if ((*i)->visible) {
for (uint32_t j = 0; j < (*i)->ports.size(); ++j) {
std::pair<int, int> const d = setup_layout ((*i)->ports[j]);
int x, y;
if (getenv ("AD_X_SHIFT") != 0) {
x = atoi (getenv ("AD_X_SHIFT"));
} else {
x = 0;
}
if (getenv ("AD_Y_SHIFT") != 0) {
y = atoi (getenv ("AD_Y_SHIFT"));
} else {
y = 0;
}
get_window()->draw_layout (_gc, int ((n + 0.25) * spacing) + x, height - d.second + y, _pango_layout, _fg_colour, _bg_colour);
++n;
}
}
}
return true;
}
/** Set the `base width'. This is the width of the base of the label set, ie:
*
* L L L L
* E E E E
* B B B B
* A A A A
* L L L L
* <--w-->
*/
void
RotatedLabelSet::set_base_width (int w)
{
_base_width = w;
queue_resize ();
}
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), : _offer_inputs (offer_inputs), _port_group_list (session, type, offer_inputs, mask), _type (type)
_column_labels (_port_group_list)
{ {
_row_labels_vbox = 0; _row_labels_vbox = 0;
_side_vbox_pad = 0; _side_vbox_pad = 0;
_visibility_checkbutton_box.pack_start (*(manage (new Label (_("Connections displayed: ")))), false, false, 10); _visibility_checkbutton_box.pack_start (*(manage (new Label (_("Connections displayed: ")))), false, false, 10);
pack_start (_visibility_checkbutton_box, false, false); pack_start (_visibility_checkbutton_box, false, false);
_scrolled_window.set_policy (POLICY_ALWAYS, POLICY_AUTOMATIC); _scrolled_window.set_policy (POLICY_ALWAYS, POLICY_AUTOMATIC);
_scrolled_window.set_shadow_type (SHADOW_NONE); _scrolled_window.set_shadow_type (SHADOW_NONE);
VBox* b = manage (new VBox); VBox* b = manage (new VBox);
if (offer_inputs) { b->pack_start (_port_group_hbox, false, false);
b->pack_start (_port_group_hbox, false, false); b->pack_start (_port_group_hbox, false, false);
b->pack_start (_column_labels, false, false);
} else {
b->pack_start (_column_labels, false, false);
b->pack_start (_port_group_hbox, false, false);
}
Alignment* a; _scrolled_window.add (matrix);
if (offer_inputs) {
a = manage (new Alignment (1, 0, 0, 0));
} else {
a = manage (new Alignment (0, 1, 0, 0));
}
a->add (*b);
_scrolled_window.add (*a);
if (offer_inputs) { if (offer_inputs) {
_overall_hbox.pack_start (_side_vbox, false, false, 6); _overall_hbox.pack_start (_side_vbox, false, false, 6);
@ -535,7 +169,6 @@ PortMatrix::clear ()
} }
for (std::vector<PortGroupUI*>::iterator i = _port_group_ui.begin(); i != _port_group_ui.end(); ++i) { for (std::vector<PortGroupUI*>::iterator i = _port_group_ui.begin(); i != _port_group_ui.end(); ++i) {
_port_group_hbox.remove ((*i)->get_table());
_visibility_checkbutton_box.remove ((*i)->get_visibility_checkbutton()); _visibility_checkbutton_box.remove ((*i)->get_visibility_checkbutton());
delete *i; delete *i;
} }
@ -550,46 +183,16 @@ PortMatrix::clear ()
void void
PortMatrix::setup_dimensions () PortMatrix::setup_dimensions ()
{ {
/* Get some dimensions from various places */
int const scrollbar_height = _scrolled_window.get_hscrollbar()->get_height();
std::pair<int, int> unit_size (0, 0);
int port_group_tables_height = 0;
for (std::vector<PortGroupUI*>::iterator i = _port_group_ui.begin(); i != _port_group_ui.end(); ++i) {
std::pair<int, int> const u = (*i)->unit_size ();
unit_size.first = std::max (unit_size.first, u.first);
unit_size.second = std::max (unit_size.second, u.second);
port_group_tables_height = std::max (
port_group_tables_height, (*i)->get_table().get_height()
);
}
/* Column labels */
_column_labels.set_base_width (_port_group_list.n_visible_ports () * unit_size.first);
/* Scrolled window */
/* XXX: really shouldn't set a minimum horizontal size here, but if we don't
the window starts up very small.
The constant value in the set_size_request() computation will control
how big the scrolled window will be if we fill the port matrix will a gajillion
ports.
*/
_scrolled_window.set_size_request (
std::min (_column_labels.get_width(), 400),
_column_labels.get_height() + port_group_tables_height + scrollbar_height + 16
);
/* Row labels */ /* Row labels */
for (std::vector<EventBox*>::iterator j = _row_labels.begin(); j != _row_labels.end(); ++j) { for (std::vector<EventBox*>::iterator j = _row_labels.begin(); j != _row_labels.end(); ++j) {
(*j)->get_child()->set_size_request (-1, unit_size.second); (*j)->get_child()->set_size_request (-1, matrix.row_spacing());
} }
if (_side_vbox_pad) { if (_side_vbox_pad) {
if (_offer_inputs) { if (_offer_inputs) {
_side_vbox_pad->set_size_request (-1, unit_size.second / 4); _side_vbox_pad->set_size_request (-1, matrix.row_spacing() / 4);
} else { } else {
_side_vbox_pad->set_size_request (-1, scrollbar_height + unit_size.second / 4); _side_vbox_pad->set_size_request (-1, matrix.row_spacing() / 4);
} }
} }
} }
@ -647,7 +250,6 @@ PortMatrix::setup ()
PortGroupUI* t = new PortGroupUI (*this, **i); PortGroupUI* t = new PortGroupUI (*this, **i);
_port_group_ui.push_back (t); _port_group_ui.push_back (t);
_port_group_hbox.pack_start (t->get_table(), false, false);
_visibility_checkbutton_box.pack_start (t->get_visibility_checkbutton(), false, false); _visibility_checkbutton_box.pack_start (t->get_visibility_checkbutton(), false, false);
@ -666,23 +268,14 @@ PortMatrix::setup ()
void void
PortMatrix::reset_visibility () PortMatrix::reset_visibility ()
{ {
/* now adjust visibility and coloring */
bool even = true;
Gdk::Color odd_bg (color_from_style ("OddPortGroups", STATE_NORMAL, "fg"));
Gdk::Color even_bg (color_from_style ("EvenPortGroups", STATE_NORMAL, "fg"));
for (std::vector<PortGroupUI*>::iterator i = _port_group_ui.begin(); i != _port_group_ui.end(); ++i) { for (std::vector<PortGroupUI*>::iterator i = _port_group_ui.begin(); i != _port_group_ui.end(); ++i) {
(*i)->setup_visibility (); (*i)->setup_visibility ();
if ((*i)->port_group().visible) { if ((*i)->port_group().visible) {
if (even) { matrix.show_group ((*i)->port_group());
(*i)->get_table().modify_bg (STATE_NORMAL, even_bg); } else {
} else { matrix.hide_group ((*i)->port_group());
(*i)->get_table().modify_bg (STATE_NORMAL, odd_bg);
}
even = !even;
} }
} }
} }

View file

@ -28,6 +28,8 @@
#include <gtkmm/scrolledwindow.h> #include <gtkmm/scrolledwindow.h>
#include "ardour_dialog.h" #include "ardour_dialog.h"
#include "port_group.h"
#include "matrix.h"
namespace ARDOUR { namespace ARDOUR {
class Session; class Session;
@ -35,118 +37,6 @@ namespace ARDOUR {
class PortInsert; class PortInsert;
} }
class PortMatrix;
/// A list of port names, grouped by some aspect of their type e.g. busses, tracks, system
class PortGroup
{
public:
/** PortGroup constructor.
* @param n Name.
* @param p Port name prefix.
* @param v true if group should be visible in the UI, otherwise false.
*/
PortGroup (std::string const & n, std::string const & p, bool v) : name (n), prefix (p), visible (v) {}
void add (std::string const & p);
std::string name; ///< name for the group
std::string prefix; ///< prefix (before colon) e.g. "ardour:"
std::vector<std::string> ports; ///< port names
bool visible; ///< true if the group is visible in the UI
};
/// The UI for a PortGroup
class PortGroupUI
{
public:
PortGroupUI (PortMatrix&, PortGroup&);
Gtk::Widget& get_table ();
Gtk::Widget& get_visibility_checkbutton ();
std::pair<int, int> unit_size () const;
PortGroup& port_group () { return _port_group; }
void setup_visibility ();
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 ();
PortMatrix& _port_matrix; ///< the PortMatrix that we are working for
PortGroup& _port_group; ///< the PortGroup that we are representing
bool _ignore_check_button_toggle;
Gtk::Table _table;
Gtk::EventBox _table_box;
std::vector<std::vector<Gtk::CheckButton* > > _port_checkbuttons;
Gtk::CheckButton _visibility_checkbutton;
};
/// A list of PortGroups
class PortGroupList : public std::list<PortGroup*>
{
public:
enum Mask {
BUSS = 0x1,
TRACK = 0x2,
SYSTEM = 0x4,
OTHER = 0x8
};
PortGroupList (ARDOUR::Session &, ARDOUR::DataType, bool, Mask);
void refresh ();
int n_visible_ports () const;
std::string get_port_by_index (int, bool with_prefix = true) const;
void set_type (ARDOUR::DataType);
void set_offer_inputs (bool);
private:
ARDOUR::Session& _session;
ARDOUR::DataType _type;
bool _offer_inputs;
PortGroup buss;
PortGroup track;
PortGroup system;
PortGroup other;
};
/// A widget which provides a set of rotated text labels
class RotatedLabelSet : public Gtk::Widget {
public:
RotatedLabelSet (PortGroupList&);
virtual ~RotatedLabelSet ();
void set_angle (int);
void set_base_width (int);
void update_visibility ();
protected:
virtual void on_size_request (Gtk::Requisition*);
virtual void on_size_allocate (Gtk::Allocation&);
virtual void on_realize ();
virtual void on_unrealize ();
virtual bool on_expose_event (GdkEventExpose*);
Glib::RefPtr<Gdk::Window> _gdk_window;
private:
std::pair<int, int> setup_layout (std::string const &);
PortGroupList& _port_group_list; ///< list of ports to display
int _angle_degrees; ///< label rotation angle in degrees
double _angle_radians; ///< label rotation angle in radians
int _base_width; ///< width of labels; see set_base_width() for more details
Glib::RefPtr<Pango::Context> _pango_context;
Glib::RefPtr<Pango::Layout> _pango_layout;
Glib::RefPtr<Gdk::GC> _gc;
Gdk::Color _fg_colour;
Gdk::Color _bg_colour;
};
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);
@ -184,10 +74,10 @@ class PortMatrix : public Gtk::VBox {
private: private:
PortGroupList _port_group_list; PortGroupList _port_group_list;
ARDOUR::DataType _type; ARDOUR::DataType _type;
Matrix matrix;
std::vector<PortGroupUI*> _port_group_ui; std::vector<PortGroupUI*> _port_group_ui;
std::vector<Gtk::EventBox*> _row_labels; std::vector<Gtk::EventBox*> _row_labels;
Gtk::VBox* _row_labels_vbox; Gtk::VBox* _row_labels_vbox;
RotatedLabelSet _column_labels;
Gtk::HBox _overall_hbox; Gtk::HBox _overall_hbox;
Gtk::VBox _side_vbox; Gtk::VBox _side_vbox;
Gtk::HBox _port_group_hbox; Gtk::HBox _port_group_hbox;

View file

@ -82,10 +82,9 @@ bool ProcessorBox::get_colors = true;
Gdk::Color* ProcessorBox::active_processor_color; Gdk::Color* ProcessorBox::active_processor_color;
Gdk::Color* ProcessorBox::inactive_processor_color; Gdk::Color* ProcessorBox::inactive_processor_color;
ProcessorBox::ProcessorBox (Placement pcmnt, Session& sess, boost::shared_ptr<Route> rt, PluginSelector &plugsel, ProcessorBox::ProcessorBox (Placement pcmnt, Session& sess, PluginSelector &plugsel,
RouteRedirectSelection & rsel, bool owner_is_mixer) RouteRedirectSelection & rsel, bool owner_is_mixer)
: _route(rt), : _session(sess),
_session(sess),
_owner_is_mixer (owner_is_mixer), _owner_is_mixer (owner_is_mixer),
_placement(pcmnt), _placement(pcmnt),
_plugin_selector(plugsel), _plugin_selector(plugsel),
@ -138,27 +137,29 @@ ProcessorBox::ProcessorBox (Placement pcmnt, Session& sess, boost::shared_ptr<Ro
pack_start (processor_eventbox, true, true); pack_start (processor_eventbox, true, true);
_route->processors_changed.connect (mem_fun(*this, &ProcessorBox::redisplay_processors));
_route->GoingAway.connect (mem_fun (*this, &ProcessorBox::route_going_away));
processor_eventbox.signal_enter_notify_event().connect (bind (sigc::ptr_fun (ProcessorBox::enter_box), this)); processor_eventbox.signal_enter_notify_event().connect (bind (sigc::ptr_fun (ProcessorBox::enter_box), this));
processor_display.signal_button_press_event().connect (mem_fun(*this, &ProcessorBox::processor_button_press_event), false); processor_display.signal_button_press_event().connect (mem_fun(*this, &ProcessorBox::processor_button_press_event), false);
processor_display.signal_button_release_event().connect (mem_fun(*this, &ProcessorBox::processor_button_release_event)); processor_display.signal_button_release_event().connect (mem_fun(*this, &ProcessorBox::processor_button_release_event));
/* start off as a passthru strip. we'll correct this, if necessary,
in update_diskstream_display().
*/
/* now force an update of all the various elements */
redisplay_processors ();
} }
ProcessorBox::~ProcessorBox () ProcessorBox::~ProcessorBox ()
{ {
} }
void
ProcessorBox::set_route (boost::shared_ptr<Route> r)
{
connections.clear ();
_route = r;
connections.push_back (_route->processors_changed.connect (mem_fun(*this, &ProcessorBox::redisplay_processors)));
connections.push_back (_route->GoingAway.connect (mem_fun (*this, &ProcessorBox::route_going_away)));
redisplay_processors ();
}
void void
ProcessorBox::route_going_away () ProcessorBox::route_going_away ()
{ {

View file

@ -68,10 +68,10 @@ namespace ARDOUR {
class ProcessorBox : public Gtk::HBox, public PluginInterestedObject class ProcessorBox : public Gtk::HBox, public PluginInterestedObject
{ {
public: public:
ProcessorBox (ARDOUR::Placement, ARDOUR::Session&, ProcessorBox (ARDOUR::Placement, ARDOUR::Session&, PluginSelector &, RouteRedirectSelection &, bool owner_is_mixer = false);
boost::shared_ptr<ARDOUR::Route>, PluginSelector &, RouteRedirectSelection &, bool owner_is_mixer = false);
~ProcessorBox (); ~ProcessorBox ();
void set_route (boost::shared_ptr<ARDOUR::Route>);
void set_width (Width); void set_width (Width);
void update(); void update();
@ -87,14 +87,12 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject
static void register_actions(); static void register_actions();
protected:
void set_stuff_from_route ();
private: private:
boost::shared_ptr<ARDOUR::Route> _route; boost::shared_ptr<ARDOUR::Route> _route;
ARDOUR::Session & _session; ARDOUR::Session & _session;
bool _owner_is_mixer; bool _owner_is_mixer;
bool ab_direction; bool ab_direction;
std::vector<sigc::connection> connections;
ARDOUR::Placement _placement; ARDOUR::Placement _placement;

View file

@ -229,8 +229,11 @@ RouteParams_UI::setup_processor_boxes()
cleanup_processor_boxes(); cleanup_processor_boxes();
// construct new redirect boxes // construct new redirect boxes
pre_insert_box = new ProcessorBox(PreFader, *session, _route, *_plugin_selector, _rr_selection); pre_insert_box = new ProcessorBox(PreFader, *session, *_plugin_selector, _rr_selection);
post_insert_box = new ProcessorBox(PostFader, *session, _route, *_plugin_selector, _rr_selection); post_insert_box = new ProcessorBox(PostFader, *session, *_plugin_selector, _rr_selection);
pre_insert_box->set_route (_route);
post_insert_box->set_route (_route);
pre_redir_hpane.pack1 (*pre_insert_box); pre_redir_hpane.pack1 (*pre_insert_box);
post_redir_hpane.pack1 (*post_insert_box); post_redir_hpane.pack1 (*post_insert_box);

View file

@ -106,9 +106,9 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::sh
size_button (_("h")), // height size_button (_("h")), // height
automation_button (_("a")), automation_button (_("a")),
visual_button (_("v")), visual_button (_("v")),
gm (rt, sess, slider, true) gm (sess, slider, true)
{ {
gm.set_io (rt);
gm.get_level_meter().set_no_show_all(); gm.get_level_meter().set_no_show_all();
gm.get_level_meter().setup_meters(50); gm.get_level_meter().setup_meters(50);

View file

@ -54,13 +54,33 @@ using namespace Gtkmm2ext;
using namespace ARDOUR; using namespace ARDOUR;
using namespace PBD; using namespace PBD;
RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, const char* m_name, RouteUI::RouteUI (ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
const char* s_name, const char* r_name) : AxisView(sess)
: AxisView(sess), {
_route(rt), init ();
mute_button(0), set_button_names (mute_name, solo_name, rec_name);
solo_button(0), }
rec_enable_button(0)
RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt,
ARDOUR::Session& sess, const char* mute_name, const char* solo_name, const char* rec_name)
: AxisView(sess)
{
init ();
set_button_names (mute_name, solo_name, rec_name);
set_route (rt);
}
RouteUI::~RouteUI()
{
GoingAway (); /* EMIT SIGNAL */
delete solo_menu;
delete mute_menu;
delete remote_control_menu;
}
void
RouteUI::init ()
{ {
xml_node = 0; xml_node = 0;
mute_menu = 0; mute_menu = 0;
@ -73,27 +93,87 @@ RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, co
polarity_menu_item = 0; polarity_menu_item = 0;
denormal_menu_item = 0; denormal_menu_item = 0;
mute_button = manage (new BindableToggleButton (""));
mute_button->set_self_managed (true);
mute_button->set_name ("MuteButton");
solo_button = manage (new BindableToggleButton (""));
solo_button->set_self_managed (true);
solo_button->set_name ("SoloButton");
rec_enable_button = manage (new BindableToggleButton (""));
rec_enable_button->set_name ("RecordEnableButton");
rec_enable_button->set_self_managed (true);
_session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
}
void
RouteUI::reset ()
{
connections.clear ();
if (solo_menu) {
delete solo_menu;
solo_menu = 0;
}
if (mute_menu) {
delete mute_menu;
mute_menu = 0;
}
if (remote_control_menu) {
delete remote_control_menu;
remote_control_menu = 0;
}
if (xml_node) {
/* do not delete the node - its owned by the route */
xml_node = 0;
}
route_active_menu_item = 0;
polarity_menu_item = 0;
denormal_menu_item = 0;
}
void
RouteUI::set_button_names (const char* mute, const char* solo, const char* rec)
{
m_name = mute;
s_name = solo;
r_name = rec;
}
void
RouteUI::set_route (boost::shared_ptr<Route> rp)
{
reset ();
_route = rp;
if (set_color_from_route()) { if (set_color_from_route()) {
set_color (unique_random_color()); set_color (unique_random_color());
} }
new PairedShiva<Route,RouteUI> (*_route, *this); /* no, there is no memory leak here. This object cleans itself (and other stuff)
up when the route is destroyed.
_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)); */
mute_button = manage (new BindableToggleButton (_route->mute_control(), m_name ));
mute_button->set_self_managed (true);
solo_button = manage (new BindableToggleButton (_route->solo_control(), s_name ));
solo_button->set_self_managed (true);
mute_button->set_name ("MuteButton");
solo_button->set_name ("SoloButton");
_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed));
_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
new PairedShiva<Route,RouteUI> (*_route, *this);
mute_button->set_controllable (_route->mute_control());
mute_button->set_label (m_name);
solo_button->set_controllable (_route->solo_control());
solo_button->set_label (s_name);
connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
connections.push_back (_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
/* when solo changes, update mute state too, in case the user wants us to display it */ /* when solo changes, update mute state too, in case the user wants us to display it */
_session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute)); _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
@ -101,15 +181,13 @@ RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, co
if (is_track()) { if (is_track()) {
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route); boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)); connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed));
rec_enable_button = manage (new BindableToggleButton (t->rec_enable_control(), r_name ));
rec_enable_button->set_name ("RecordEnableButton");
rec_enable_button->set_self_managed (true);
rec_enable_button->show(); rec_enable_button->show();
rec_enable_button->set_controllable (t->rec_enable_control());
rec_enable_button->set_label (r_name);
update_rec_display (); update_rec_display ();
} }
@ -119,19 +197,13 @@ RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, co
mute_button->show(); mute_button->show();
solo_button->show(); solo_button->show();
_route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu)); connections.push_back (_route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu)));
/* map the current state */ /* map the current state */
map_frozen (); map_frozen ();
} }
RouteUI::~RouteUI()
{
GoingAway (); /* EMIT SIGNAL */
delete mute_menu;
}
bool bool
RouteUI::mute_press(GdkEventButton* ev) RouteUI::mute_press(GdkEventButton* ev)
{ {

View file

@ -45,9 +45,14 @@ class BindableToggleButton;
class RouteUI : public virtual AxisView class RouteUI : public virtual AxisView
{ {
public: public:
RouteUI(ARDOUR::Session&, const char*, const char*, const char*);
RouteUI(boost::shared_ptr<ARDOUR::Route>, ARDOUR::Session&, const char*, const char*, const char*); RouteUI(boost::shared_ptr<ARDOUR::Route>, ARDOUR::Session&, const char*, const char*, const char*);
virtual ~RouteUI(); virtual ~RouteUI();
virtual void set_route (boost::shared_ptr<ARDOUR::Route>);
void set_button_names (const char*, const char*, const char*);
bool is_track() const; bool is_track() const;
bool is_audio_track() const; bool is_audio_track() const;
bool is_midi_track() const; bool is_midi_track() const;
@ -161,6 +166,15 @@ class RouteUI : public virtual AxisView
void reversibly_apply_track_boolean (string name, void (ARDOUR::Track::*func)(bool, void*), bool, void *); void reversibly_apply_track_boolean (string name, void (ARDOUR::Track::*func)(bool, void*), bool, void *);
void adjust_latency (); void adjust_latency ();
protected:
std::vector<sigc::connection> connections;
std::string s_name;
std::string m_name;
std::string r_name;
void init ();
void reset ();
}; };
#endif /* __ardour_route_ui__ */ #endif /* __ardour_route_ui__ */

View file

@ -30,11 +30,14 @@ using namespace ARDOUR;
using namespace PBD; using namespace PBD;
SendUI::SendUI (boost::shared_ptr<Send> s, Session& se) SendUI::SendUI (boost::shared_ptr<Send> s, Session& se)
: _send (s), : _send (s)
_session (se), , _session (se)
gpm (s->io(), se), , gpm (se)
panners (s->io(), se) , panners (se)
{ {
panners.set_io (s->io());
gpm.set_io (s->io());
hbox.pack_start (gpm, true, true); hbox.pack_start (gpm, true, true);
set_name ("SendUIFrame"); set_name ("SendUIFrame");

View file

@ -596,7 +596,8 @@ SoundFileBrowser::add_gain_meter ()
delete gm; delete gm;
} }
gm = new GainMeter (session->the_auditioner(), *session); gm = new GainMeter (*session);
gm->set_io (session->the_auditioner());
meter_packer.set_border_width (12); meter_packer.set_border_width (12);
meter_packer.pack_start (*gm, false, true); meter_packer.pack_start (*gm, false, true);

View file

@ -153,12 +153,45 @@ PluginManager::refresh ()
void void
PluginManager::ladspa_refresh () PluginManager::ladspa_refresh ()
{ {
_ladspa_plugin_info.clear (); _ladspa_plugin_info.clear ();
if (ladspa_path.length() == 0) { static const char *standard_paths[] = {
ladspa_path = "/usr/local/lib64/ladspa:/usr/local/lib/ladspa:/usr/lib64/ladspa:/usr/lib/ladspa:/Library/Audio/Plug-Ins/LADSPA"; "/usr/local/lib64/ladspa",
} "/usr/local/lib/ladspa",
"/usr/lib64/ladspa",
"/usr/lib/ladspa",
"/Library/Audio/Plug-Ins/LADSPA",
""
};
/* allow LADSPA_PATH to augment, not override standard locations */
/* Only add standard locations to ladspa_path if it doesn't
* already contain them. Check for trailing '/'s too.
*/
int i;
for (i = 0; standard_paths[i][0]; i++) {
size_t found = ladspa_path.find(standard_paths[i]);
if (found != ladspa_path.npos) {
switch (ladspa_path[found + strlen(standard_paths[i])]) {
case ':' :
case '\0':
continue;
case '/' :
if (ladspa_path[found + strlen(standard_paths[i]) + 1] == ':' ||
ladspa_path[found + strlen(standard_paths[i]) + 1] == '\0') {
continue;
}
}
}
if (!ladspa_path.empty())
ladspa_path += ":";
ladspa_path += standard_paths[i];
}
ladspa_discover_from_path (ladspa_path); ladspa_discover_from_path (ladspa_path);
} }

View file

@ -40,6 +40,14 @@ BindingProxy::BindingProxy (boost::shared_ptr<Controllable> c)
{ {
} }
BindingProxy::BindingProxy ()
: prompter (0),
bind_button (2),
bind_statemask (Gdk::CONTROL_MASK)
{
}
BindingProxy::~BindingProxy () BindingProxy::~BindingProxy ()
{ {
if (prompter) { if (prompter) {
@ -47,6 +55,13 @@ BindingProxy::~BindingProxy ()
} }
} }
void
BindingProxy::set_controllable (boost::shared_ptr<Controllable> c)
{
learning_finished ();
controllable = c;
}
void void
BindingProxy::set_bind_button_state (guint button, guint statemask) BindingProxy::set_bind_button_state (guint button, guint statemask)
{ {
@ -64,7 +79,7 @@ BindingProxy::get_bind_button_state (guint &button, guint &statemask)
bool bool
BindingProxy::button_press_handler (GdkEventButton *ev) BindingProxy::button_press_handler (GdkEventButton *ev)
{ {
if ((ev->state & bind_statemask) && ev->button == bind_button) { if (controllable && (ev->state & bind_statemask) && ev->button == bind_button) {
if (Controllable::StartLearning (controllable.get())) { if (Controllable::StartLearning (controllable.get())) {
string prompt = _("operate controller now"); string prompt = _("operate controller now");
if (prompter == 0) { if (prompter == 0) {
@ -95,7 +110,9 @@ bool
BindingProxy::prompter_hiding (GdkEventAny *ev) BindingProxy::prompter_hiding (GdkEventAny *ev)
{ {
learning_connection.disconnect (); learning_connection.disconnect ();
Controllable::StopLearning (controllable.get()); if (controllable) {
Controllable::StopLearning (controllable.get());
}
return false; return false;
} }

View file

@ -63,7 +63,9 @@ class BarController : public Gtk::Frame
/* export this to allow direct connection to button events */ /* export this to allow direct connection to button events */
Gtk::Widget& event_widget() { return darea; } Gtk::Widget& event_widget() { return darea; }
boost::shared_ptr<PBD::Controllable> get_controllable() { return binding_proxy.get_controllable(); } boost::shared_ptr<PBD::Controllable> get_controllable() { return binding_proxy.get_controllable(); }
void set_controllable(boost::shared_ptr<PBD::Controllable> c) { binding_proxy.set_controllable(c); }
protected: protected:
Gtk::Adjustment& adjustment; Gtk::Adjustment& adjustment;

View file

@ -32,10 +32,8 @@ namespace PBD {
class BindableToggleButton : public Gtkmm2ext::StatefulToggleButton class BindableToggleButton : public Gtkmm2ext::StatefulToggleButton
{ {
public: public:
BindableToggleButton (boost::shared_ptr<PBD::Controllable> c) : binding_proxy (c) {} BindableToggleButton (const std::string &label)
: Gtkmm2ext::StatefulToggleButton (label) {}
explicit BindableToggleButton (boost::shared_ptr<PBD::Controllable> c, const std::string &label)
: Gtkmm2ext::StatefulToggleButton (label), binding_proxy (c) {}
virtual ~BindableToggleButton() {} virtual ~BindableToggleButton() {}
@ -49,7 +47,8 @@ class BindableToggleButton : public Gtkmm2ext::StatefulToggleButton
} }
boost::shared_ptr<PBD::Controllable> get_controllable() { return binding_proxy.get_controllable(); } boost::shared_ptr<PBD::Controllable> get_controllable() { return binding_proxy.get_controllable(); }
void set_controllable (boost::shared_ptr<PBD::Controllable> c) { binding_proxy.set_controllable (c); }
private: private:
BindingProxy binding_proxy; BindingProxy binding_proxy;
}; };
@ -58,10 +57,6 @@ class BindableButton : public Gtkmm2ext::StatefulButton
{ {
public: public:
BindableButton (boost::shared_ptr<PBD::Controllable> c) : binding_proxy (c) {} BindableButton (boost::shared_ptr<PBD::Controllable> c) : binding_proxy (c) {}
explicit BindableButton (boost::shared_ptr<PBD::Controllable> c, const std::string &label)
: Gtkmm2ext::StatefulButton (label), binding_proxy (c) {}
~BindableButton() {} ~BindableButton() {}
bool on_button_press_event (GdkEventButton *ev) { bool on_button_press_event (GdkEventButton *ev) {
@ -74,6 +69,7 @@ class BindableButton : public Gtkmm2ext::StatefulButton
} }
boost::shared_ptr<PBD::Controllable> get_controllable() { return binding_proxy.get_controllable(); } boost::shared_ptr<PBD::Controllable> get_controllable() { return binding_proxy.get_controllable(); }
void set_controllable (boost::shared_ptr<PBD::Controllable> c) { binding_proxy.set_controllable (c); }
private: private:
BindingProxy binding_proxy; BindingProxy binding_proxy;

View file

@ -34,6 +34,7 @@ class BindingProxy : public sigc::trackable
{ {
public: public:
BindingProxy (boost::shared_ptr<PBD::Controllable>); BindingProxy (boost::shared_ptr<PBD::Controllable>);
BindingProxy ();
virtual ~BindingProxy(); virtual ~BindingProxy();
void set_bind_button_state (guint button, guint statemask); void set_bind_button_state (guint button, guint statemask);
@ -42,6 +43,7 @@ class BindingProxy : public sigc::trackable
bool button_press_handler (GdkEventButton *); bool button_press_handler (GdkEventButton *);
boost::shared_ptr<PBD::Controllable> get_controllable() { return controllable; } boost::shared_ptr<PBD::Controllable> get_controllable() { return controllable; }
void set_controllable (boost::shared_ptr<PBD::Controllable>);
protected: protected:
Gtkmm2ext::PopUp* prompter; Gtkmm2ext::PopUp* prompter;

View file

@ -41,7 +41,6 @@ class SliderController : public Gtkmm2ext::PixFader
public: public:
SliderController (Glib::RefPtr<Gdk::Pixbuf> image, SliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Gtk::Adjustment* adj, int orientation, Gtk::Adjustment* adj, int orientation,
boost::shared_ptr<PBD::Controllable>,
bool with_numeric = true); bool with_numeric = true);
virtual ~SliderController () {} virtual ~SliderController () {}
@ -52,6 +51,8 @@ class SliderController : public Gtkmm2ext::PixFader
bool on_button_press_event (GdkEventButton *ev); bool on_button_press_event (GdkEventButton *ev);
void set_controllable (boost::shared_ptr<PBD::Controllable> c) { binding_proxy.set_controllable (c); }
protected: protected:
BindingProxy binding_proxy; BindingProxy binding_proxy;
Glib::RefPtr<Gdk::Pixbuf> slider; Glib::RefPtr<Gdk::Pixbuf> slider;
@ -59,6 +60,8 @@ class SliderController : public Gtkmm2ext::PixFader
Gtk::SpinButton spin; Gtk::SpinButton spin;
Gtk::Frame spin_frame; Gtk::Frame spin_frame;
Gtk::HBox spin_hbox; Gtk::HBox spin_hbox;
void init ();
}; };
class VSliderController : public SliderController class VSliderController : public SliderController
@ -66,7 +69,6 @@ class VSliderController : public SliderController
public: public:
VSliderController (Glib::RefPtr<Gdk::Pixbuf> image, VSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Gtk::Adjustment *adj, Gtk::Adjustment *adj,
boost::shared_ptr<PBD::Controllable>,
bool with_numeric = true); bool with_numeric = true);
}; };
@ -75,7 +77,6 @@ class HSliderController : public SliderController
public: public:
HSliderController (Glib::RefPtr<Gdk::Pixbuf> image, HSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Gtk::Adjustment *adj, Gtk::Adjustment *adj,
boost::shared_ptr<PBD::Controllable>,
bool with_numeric = true); bool with_numeric = true);
}; };

View file

@ -30,11 +30,9 @@ using namespace PBD;
SliderController::SliderController (Glib::RefPtr<Gdk::Pixbuf> image, SliderController::SliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Gtk::Adjustment *adj, int orientation, Gtk::Adjustment *adj, int orientation,
boost::shared_ptr<Controllable> c,
bool with_numeric) bool with_numeric)
: PixFader (image, *adj, orientation), : PixFader (image, *adj, orientation),
binding_proxy (c),
spin (*adj, 0, 2) spin (*adj, 0, 2)
{ {
spin.set_name ("SliderControllerValue"); spin.set_name ("SliderControllerValue");
@ -55,15 +53,15 @@ SliderController::on_button_press_event (GdkEventButton *ev)
if (binding_proxy.button_press_handler (ev)) { if (binding_proxy.button_press_handler (ev)) {
return true; return true;
} }
return PixFader::on_button_press_event (ev); return PixFader::on_button_press_event (ev);
} }
VSliderController::VSliderController (Glib::RefPtr<Gdk::Pixbuf> image, VSliderController::VSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Gtk::Adjustment *adj, Gtk::Adjustment *adj,
boost::shared_ptr<Controllable> control,
bool with_numeric) bool with_numeric)
: SliderController (image, adj, VERT, control, with_numeric) : SliderController (image, adj, VERT, with_numeric)
{ {
if (with_numeric) { if (with_numeric) {
spin_frame.add (spin); spin_frame.add (spin);
@ -76,10 +74,9 @@ VSliderController::VSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
HSliderController::HSliderController (Glib::RefPtr<Gdk::Pixbuf> image, HSliderController::HSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Gtk::Adjustment *adj, Gtk::Adjustment *adj,
boost::shared_ptr<Controllable> control,
bool with_numeric) bool with_numeric)
: SliderController (image, adj, HORIZ, control, with_numeric) : SliderController (image, adj, HORIZ, with_numeric)
{ {
if (with_numeric) { if (with_numeric) {
spin_frame.add (spin); spin_frame.add (spin);