diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2008-12-08 16:07:28 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2008-12-08 16:07:28 +0000 |
commit | 3be16e8afbd891c0bfe7227158384ed0d127597f (patch) | |
tree | 73a8f761fc13cbd0613d3923a34748bb9aa761d2 | |
parent | a9bb336fc44ab4937978f5a0308e440ed632ea50 (diff) |
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
35 files changed, 1387 insertions, 920 deletions
diff --git a/gtk2_ardour/SConscript b/gtk2_ardour/SConscript index fef196e5ba..8bfccae2b4 100644 --- a/gtk2_ardour/SConscript +++ b/gtk2_ardour/SConscript @@ -194,6 +194,7 @@ lineset.cc location_ui.cc main.cc marker.cc +matrix.cc midi_channel_selector.cc midi_port_dialog.cc midi_region_view.cc diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index b3ac2e3db8..44280a3109 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -1736,8 +1736,8 @@ ARDOUR_UI::engine_halted () _("\ JACK has either been shutdown or it\n\ disconnected Ardour because Ardour\n\ -was not fast enough. You can save the\n\ -session and/or try to reconnect to JACK .")); +was not fast enough. Try to restart\n\ +JACK, reconnect and save the session.")); pop_back_splash (); msg.run (); } diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc index 40046cd9a1..e3dd980eee 100644 --- a/gtk2_ardour/audio_region_view.cc +++ b/gtk2_ardour/audio_region_view.cc @@ -196,6 +196,10 @@ AudioRegionView::init (Gdk::Color& basic_color, bool wfd) setup_fade_handle_positions (); + if (!Config->get_show_region_fades()) { + set_fade_visibility (false); + } + string line_name = _region->name(); line_name += ':'; line_name += "gain"; @@ -410,8 +414,10 @@ AudioRegionView::reset_width_dependent_items (double pixel_width) fade_in_handle->hide(); fade_out_handle->hide(); } else { - fade_in_handle->show(); - fade_out_handle->show(); + if (Config->get_show_region_fades()) { + fade_in_handle->show(); + fade_out_handle->show(); + } } } } diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 279de99298..394c1ad121 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -294,6 +294,7 @@ class Editor : public PublicEditor Width editor_mixer_strip_width; void maybe_add_mixer_strip_width (XMLNode&); void show_editor_mixer (bool yn); + void create_editor_mixer (); void show_editor_list (bool yn); void set_selected_mixer_strip (TimeAxisView&); void hide_track_in_display (TimeAxisView& tv, bool temporary = false); diff --git a/gtk2_ardour/editor_mixer.cc b/gtk2_ardour/editor_mixer.cc index 6bfc325f6d..cb10b2f551 100644 --- a/gtk2_ardour/editor_mixer.cc +++ b/gtk2_ardour/editor_mixer.cc @@ -58,13 +58,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 Editor::cms_deleted () { current_mixer_strip = 0; @@ -73,76 +66,108 @@ Editor::cms_deleted () void Editor::show_editor_mixer (bool yn) { + boost::shared_ptr<ARDOUR::Route> r; + show_editor_mixer_when_tracks_arrive = false; + if (!session) { + show_editor_mixer_when_tracks_arrive = yn; + return; + } + 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()) { - - if (track_views.empty()) { - show_editor_mixer_when_tracks_arrive = true; - return; - } + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + AudioTimeAxisView* atv; - 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; - } + if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) { + r = atv->route(); + break; } + } - } else { - - sort_track_selection (); - - for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { - AudioTimeAxisView* atv; + } else { - if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) { - cms_new (atv->route ()); - break; - } + 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) { - 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) { - 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.reorder_child (*current_mixer_strip, 0); - current_mixer_strip->show_all (); } } else { if (current_mixer_strip) { - editor_mixer_strip_width = current_mixer_strip->get_width (); if (current_mixer_strip->get_parent() != 0) { global_hpacker.remove (*current_mixer_strip); } } } + #ifdef GTKOSX /* XXX gtk problem here */ + ensure_all_elements_drawn(); +#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 (); - controls_layout.queue_draw (); -#endif } +#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 Editor::show_editor_list (bool yn) @@ -157,38 +182,52 @@ Editor::show_editor_list (bool yn) void Editor::set_selected_mixer_strip (TimeAxisView& view) { - RouteTimeAxisView* rt; + AudioTimeAxisView* at; bool show = false; + bool created; - if (!session || (rt = dynamic_cast<RouteTimeAxisView*>(&view)) == 0) { + if (!session || (at = dynamic_cast<AudioTimeAxisView*>(&view)) == 0) { return; } - - if (current_mixer_strip) { - /* might be nothing to do */ - - if (current_mixer_strip->route() == rt->route()) { + 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->get_parent()) { - show = true; - } - delete current_mixer_strip; - current_mixer_strip = 0; + if (current_mixer_strip == 0) { + create_editor_mixer (); + created = true; + } else { + created = false; } - 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)); + /* might be nothing to do */ + if (current_mixer_strip->route() == at->route()) { + return; + } + + if (current_mixer_strip->get_parent()) { + show = true; + } + + current_mixer_strip->set_route (at->route()); + + if (created) { + current_mixer_strip->set_width (editor_mixer_strip_width, (void*) this); + } + if (show) { show_editor_mixer (true); } } + double current = 0.0; bool currentInitialized = 0; @@ -276,7 +315,7 @@ void Editor::current_mixer_strip_removed () { if (current_mixer_strip) { - /* it is being deleted */ + /* it is being deleted elsewhere */ current_mixer_strip = 0; } } diff --git a/gtk2_ardour/gain_meter.cc b/gtk2_ardour/gain_meter.cc index a580ec6b38..b34c0b8d28 100644 --- a/gtk2_ardour/gain_meter.cc +++ b/gtk2_ardour/gain_meter.cc @@ -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, bool horizontal) - : _io (io), - _session (s), + : _session (s), // 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_automation_style_button (""), gain_automation_state_button ("") { + using namespace Menu_Helpers; + ignore_toggle = false; meter_menu = 0; next_release_selects = false; @@ -92,16 +93,14 @@ GainMeterBase::GainMeterBase (boost::shared_ptr<IO> io, Session& s, if (horizontal) { gain_slider = manage (new HSliderController (pix, &gain_adjustment, - _io->gain_control(), false)); } else { gain_slider = manage (new VSliderController (pix, &gain_adjustment, - _io->gain_control(), 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_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_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; @@ -146,6 +175,8 @@ GainMeterBase::GainMeterBase (boost::shared_ptr<IO> io, Session& s, using namespace Menu_Helpers; + gain_astate_menu.items().clear (); + gain_astate_menu.items().push_back (MenuElem (_("Manual"), bind (mem_fun (*_io, &IO::set_parameter_automation_state), 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), Evoral::Parameter(GainAutomation), (AutoState) Touch))); - 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"); + connections.push_back (gain_automation_style_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_style_button_event), false)); + connections.push_back (gain_automation_state_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_state_button_event), false)); - 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)); + connections.push_back (r->gain_control()->alist()->automation_state_changed.connect (mem_fun(*this, &GainMeter::gain_automation_state_changed))); + connections.push_back (r->gain_control()->alist()->automation_style_changed.connect (mem_fun(*this, &GainMeter::gain_automation_style_changed))); gain_automation_state_changed (); } } - _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); + connections.push_back (_io->gain_control()->Changed.connect (mem_fun(*this, &GainMeterBase::gain_changed))); gain_changed (); show_gain (); - 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 @@ -752,10 +754,9 @@ GainMeterBase::on_theme_changed() style_changed = true; } -GainMeter::GainMeter (boost::shared_ptr<IO> io, Session& s) - : GainMeterBase (io, s, slider, false) +GainMeter::GainMeter (Session& s) + : GainMeterBase (s, slider, false) { - gain_display_box.set_homogeneous (true); gain_display_box.set_spacing (2); 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.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; 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); } } - - 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 GainMeter::get_gm_width () { diff --git a/gtk2_ardour/gain_meter.h b/gtk2_ardour/gain_meter.h index d493edf0fb..820e9ef0e7 100644 --- a/gtk2_ardour/gain_meter.h +++ b/gtk2_ardour/gain_meter.h @@ -58,10 +58,12 @@ namespace Gtk { class GainMeterBase : virtual public sigc::trackable { 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); virtual ~GainMeterBase (); + virtual void set_io (boost::shared_ptr<ARDOUR::IO>); + void update_gain_sensitive (); void update_meters (); @@ -82,6 +84,7 @@ class GainMeterBase : virtual public sigc::trackable friend class MixerStrip; boost::shared_ptr<ARDOUR::IO> _io; ARDOUR::Session& _session; + std::vector<sigc::connection> connections; bool ignore_toggle; bool next_release_selects; @@ -169,9 +172,11 @@ class GainMeterBase : virtual public sigc::trackable class GainMeter : public GainMeterBase, public Gtk::VBox { public: - GainMeter (boost::shared_ptr<ARDOUR::IO>, ARDOUR::Session&); + GainMeter (ARDOUR::Session&); ~GainMeter () {} + void set_io (boost::shared_ptr<ARDOUR::IO>); + int get_gm_width (); void setup_meters (int len=0); diff --git a/gtk2_ardour/level_meter.cc b/gtk2_ardour/level_meter.cc index f6e3731aac..cd7308cfa2 100644 --- a/gtk2_ardour/level_meter.cc +++ b/gtk2_ardour/level_meter.cc @@ -58,9 +58,8 @@ using namespace std; //sigc::signal<void,RouteGroup*> LevelMeter::ResetGroupPeakDisplays; -LevelMeter::LevelMeter (boost::shared_ptr<IO> io, Session& s) - : _io (io), - _session (s) +LevelMeter::LevelMeter (Session& s) + : _session (s) { set_spacing (1); @@ -85,6 +84,12 @@ LevelMeter::~LevelMeter () } } +void +LevelMeter::set_io (boost::shared_ptr<IO> io) +{ + _io = io; +} + float LevelMeter::update_meters () { @@ -144,6 +149,10 @@ LevelMeter::hide_all_meters () void LevelMeter::setup_meters (int len, int initial_width) { + if (!_io) { + return; /* do it later */ + } + uint32_t nmeters = _io->n_outputs().n_total(); regular_meter_width = initial_width; diff --git a/gtk2_ardour/level_meter.h b/gtk2_ardour/level_meter.h index ce0aa125cb..521b9d1d8f 100644 --- a/gtk2_ardour/level_meter.h +++ b/gtk2_ardour/level_meter.h @@ -56,9 +56,11 @@ namespace Gtk { class LevelMeter : public Gtk::HBox { public: - LevelMeter (boost::shared_ptr<ARDOUR::IO>, ARDOUR::Session&); + LevelMeter (ARDOUR::Session&); ~LevelMeter (); + virtual void set_io (boost::shared_ptr<ARDOUR::IO> io); + void update_gain_sensitive (); float update_meters (); diff --git a/gtk2_ardour/main.cc b/gtk2_ardour/main.cc index edbdcd58cb..aecbc1f634 100644 --- a/gtk2_ardour/main.cc +++ b/gtk2_ardour/main.cc @@ -117,7 +117,10 @@ fixup_bundle_environment () Glib::ustring 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; if (cstr) { @@ -152,8 +155,10 @@ fixup_bundle_environment () if (cstr) { path = cstr; path += ':'; + } else { + path = ""; } - path = dir_path; + path += dir_path; path += "/../Plugins"; setenv ("LADSPA_PATH", path.c_str(), 1); @@ -162,8 +167,10 @@ fixup_bundle_environment () if (cstr) { path = cstr; path += ':'; + } else { + path = ""; } - path = dir_path; + path += dir_path; path += "/../Frameworks"; setenv ("VAMP_PATH", path.c_str(), 1); @@ -172,8 +179,10 @@ fixup_bundle_environment () if (cstr) { path = cstr; path += ':'; + } else { + path = ""; } - path = dir_path; + path += dir_path; path += "/../Surfaces"; setenv ("ARDOUR_CONTROL_SURFACE_PATH", path.c_str(), 1); @@ -182,8 +191,10 @@ fixup_bundle_environment () if (cstr) { path = cstr; path += ':'; + } else { + path = ""; } - path = dir_path; + path += dir_path; path += "/../Plugins"; setenv ("LV2_PATH", path.c_str(), 1); diff --git a/gtk2_ardour/matrix.cc b/gtk2_ardour/matrix.cc new file mode 100644 index 0000000000..db16362ca0 --- /dev/null +++ b/gtk2_ardour/matrix.cc @@ -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; +} diff --git a/gtk2_ardour/matrix.h b/gtk2_ardour/matrix.h new file mode 100644 index 0000000000..f859a881c7 --- /dev/null +++ b/gtk2_ardour/matrix.h @@ -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__ */ diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc index 373babf417..1a357dc002 100644 --- a/gtk2_ardour/mixer_strip.cc +++ b/gtk2_ardour/mixer_strip.cc @@ -82,34 +82,56 @@ speed_printer (char buf[32], Gtk::Adjustment& adj, void* arg) } #endif -MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt, bool in_mixer) - : AxisView(sess), - RouteUI (rt, sess, _("Mute"), _("Solo"), _("Record")), - _mixer(mx), - _mixer_owned (in_mixer), - pre_processor_box (PreFader, sess, rt, mx.plugin_selector(), mx.selection(), in_mixer), - post_processor_box (PostFader, sess, rt, mx.plugin_selector(), mx.selection(), in_mixer), - gpm (_route, sess), - panners (_route, 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) +MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, 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 (); +} +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) + { - if (set_color_from_route()) { - set_color (unique_random_color()); - } + init (); + set_route (rt); +} +void +MixerStrip::init () +{ input_selector = 0; output_selector = 0; group_menu = 0; - if (!_route->is_hidden()) { - _marked_for_display = true; - } + _marked_for_display = false; route_ops_menu = 0; ignore_comment_edit = false; ignore_toggle = false; @@ -118,40 +140,26 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt comment_area = 0; _width_owner = 0; - Gtk::Image *width_icon = manage (new Gtk::Image (::get_icon("strip_width"))); - Gtk::Image *hide_icon = manage (new Gtk::Image (::get_icon("hide"))); - width_button.add (*width_icon); - hide_button.add (*hide_icon); + width_button.add (*(manage (new Gtk::Image (::get_icon("strip_width"))))); + hide_button.add (*(manage (new Gtk::Image (::get_icon("hide"))))); input_label.set_text (_("Input")); + ARDOUR_UI::instance()->set_tip (&input_button, _("Click to choose inputs"), ""); input_button.add (input_label); input_button.set_name ("MixerIOButton"); input_label.set_name ("MixerIOButtonLabel"); output_label.set_text (_("Output")); + ARDOUR_UI::instance()->set_tip (&output_button, _("Click to choose outputs"), ""); output_button.add (output_label); output_button.set_name ("MixerIOButton"); 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.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 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.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.set_name ("MixerNameButton"); Gtkmm2ext::set_size_request_to_display_given_text (name_button, "longest label", 2, 2); name_label.set_name ("MixerNameButtonLabel"); - if (_route->phase_invert()) { - name_label.set_text (X_("Ø ") + name_label.get_text()); - } else { - name_label.set_text (_route->name()); - } - + ARDOUR_UI::instance()->set_tip (&group_button, _("Mix group"), ""); group_button.add (group_label); group_button.set_name ("MixerGroupButton"); group_label.set_name ("MixerGroupButtonLabel"); 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)); 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 (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.set_shadow_type (Gtk::SHADOW_IN); 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().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); 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_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); group_button.signal_button_press_event().connect (mem_fun(*this, &MixerStrip::select_mix_group), false); _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, in update_diskstream_display(). @@ -338,6 +290,126 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt else 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 */ 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); - whvbox->show(); - hide_icon->show(); - width_icon->show(); - gain_meter_alignment->show_all(); - pre_processor_box.show(); if (!route()->is_master() && !route()->is_control()) { @@ -402,19 +469,6 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt show(); } -MixerStrip::~MixerStrip () -{ - GoingAway(); /* EMIT_SIGNAL */ - - if (input_selector) { - delete input_selector; - } - - if (output_selector) { - delete output_selector; - } -} - void MixerStrip::set_stuff_from_route () { @@ -796,6 +850,7 @@ MixerStrip::update_output_display () break; } } + gpm.setup_meters (); panners.setup_pan (); } @@ -1292,22 +1347,22 @@ MixerStrip::meter_changed (void *src) ENSURE_GUI_THREAD (bind (mem_fun(*this, &MixerStrip::meter_changed), src)); switch (_route->meter_point()) { - case MeterInput: - meter_point_label.set_text (_("input")); - break; - - case MeterPreFader: - meter_point_label.set_text (_("pre")); - break; + case MeterInput: + meter_point_label.set_text (_("input")); + break; - case MeterPostFader: - meter_point_label.set_text (_("post")); - break; + case MeterPreFader: + meter_point_label.set_text (_("pre")); + break; + + case MeterPostFader: + meter_point_label.set_text (_("post")); + break; } gpm.setup_meters (); - // reset peak when meter point changes - gpm.reset_peak_display(); - set_width(_width, this); + // reset peak when meter point changes + gpm.reset_peak_display(); + set_width(_width, this); } diff --git a/gtk2_ardour/mixer_strip.h b/gtk2_ardour/mixer_strip.h index 63a47974cc..c4c28a06e9 100644 --- a/gtk2_ardour/mixer_strip.h +++ b/gtk2_ardour/mixer_strip.h @@ -83,6 +83,7 @@ class MixerStrip : public RouteUI, public Gtk::EventBox { public: MixerStrip (Mixer_UI&, ARDOUR::Session&, boost::shared_ptr<ARDOUR::Route>, bool in_mixer = true); + MixerStrip (Mixer_UI&, ARDOUR::Session&, bool in_mixer = true); ~MixerStrip (); void set_width (Width, void* owner); @@ -93,6 +94,7 @@ class MixerStrip : public RouteUI, public Gtk::EventBox void set_embedded (bool); ARDOUR::RouteGroup* mix_group() const; + void set_route (boost::shared_ptr<ARDOUR::Route>); protected: friend class Mixer_UI; @@ -105,6 +107,8 @@ class MixerStrip : public RouteUI, public Gtk::EventBox private: Mixer_UI& _mixer; + void init (); + bool _embedded; bool _packed; bool _mixer_owned; diff --git a/gtk2_ardour/option_editor.cc b/gtk2_ardour/option_editor.cc index ca598a363f..c261aba649 100644 --- a/gtk2_ardour/option_editor.cc +++ b/gtk2_ardour/option_editor.cc @@ -1117,7 +1117,8 @@ OptionEditor::setup_click_editor () click_emphasis_path_entry.set_sensitive (true); 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_gpm, false, false); @@ -1173,7 +1174,8 @@ void OptionEditor::connect_audition_editor () { 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_gpm, false, false); diff --git a/gtk2_ardour/panner_ui.cc b/gtk2_ardour/panner_ui.cc index 2be7be73ed..b1273aa460 100644 --- a/gtk2_ardour/panner_ui.cc +++ b/gtk2_ardour/panner_ui.cc @@ -47,9 +47,8 @@ using namespace sigc; const int PannerUI::pan_bar_height = 30; -PannerUI::PannerUI (boost::shared_ptr<IO> io, Session& s) - : _io (io), - _session (s), +PannerUI::PannerUI (Session& s) + : _session (s), hAdjustment(0.0, 0.0, 0.0), vAdjustment(0.0, 0.0, 0.0), panning_viewport(hAdjustment, vAdjustment), @@ -61,6 +60,8 @@ PannerUI::PannerUI (boost::shared_ptr<IO> io, Session& s) { ignore_toggle = false; pan_menu = 0; + pan_astate_menu = 0; + pan_astyle_menu = 0; in_pan_update = false; 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_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_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; set_width(Narrow); - - _io->panner().Changed.connect (mem_fun(*this, &PannerUI::panner_changed)); - _io->panner().LinkStateChanged.connect (mem_fun(*this, &PannerUI::update_pan_linkage)); - _io->panner().StateChanged.connect (mem_fun(*this, &PannerUI::update_pan_state)); +} + +void +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); update_pan_sensitive (); update_pan_linkage (); pan_automation_state_changed (); +#if WHERE_DOES_THIS_LIVE pan_bar_packer.show(); panning_viewport.show(); panning_up.show(); @@ -164,6 +174,46 @@ PannerUI::PannerUI (boost::shared_ptr<IO> io, Session& s) pan_automation_style_button.show(); pan_automation_state_button.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> @@ -262,7 +312,14 @@ PannerUI::~PannerUI () if (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) { 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; default: break; @@ -680,7 +740,10 @@ PannerUI::pan_automation_style_button_event (GdkEventButton *ev) switch (ev->button) { 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; default: break; diff --git a/gtk2_ardour/panner_ui.h b/gtk2_ardour/panner_ui.h index e10080a317..4501659750 100644 --- a/gtk2_ardour/panner_ui.h +++ b/gtk2_ardour/panner_ui.h @@ -54,9 +54,11 @@ namespace Gtk { class PannerUI : public Gtk::HBox { public: - PannerUI (boost::shared_ptr<ARDOUR::IO>, ARDOUR::Session&); + PannerUI (ARDOUR::Session&); ~PannerUI (); + virtual void set_io (boost::shared_ptr<ARDOUR::IO>); + void pan_changed (void *); void update_pan_sensitive (); @@ -75,6 +77,7 @@ class PannerUI : public Gtk::HBox boost::shared_ptr<ARDOUR::IO> _io; ARDOUR::Session& _session; + std::vector<sigc::connection> connections; bool ignore_toggle; bool in_pan_update; @@ -101,8 +104,8 @@ class PannerUI : public Gtk::HBox bool panning_link_button_press (GdkEventButton*); bool panning_link_button_release (GdkEventButton*); - Gtk::Menu pan_astate_menu; - Gtk::Menu pan_astyle_menu; + Gtk::Menu* pan_astate_menu; + Gtk::Menu* pan_astyle_menu; Gtk::Button pan_automation_style_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_linkage (); void update_pan_state (); + void build_astate_menu (); + void build_astyle_menu (); void panner_changed (); diff --git a/gtk2_ardour/port_group.h b/gtk2_ardour/port_group.h new file mode 100644 index 0000000000..d5334640b1 --- /dev/null +++ b/gtk2_ardour/port_group.h @@ -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__ */ diff --git a/gtk2_ardour/port_matrix.cc b/gtk2_ardour/port_matrix.cc index cff4a3328e..b1dd2a17ac 100644 --- a/gtk2_ardour/port_matrix.cc +++ b/gtk2_ardour/port_matrix.cc @@ -69,59 +69,8 @@ PortGroupUI::PortGroupUI (PortMatrix& m, PortGroup& g) , _ignore_check_button_toggle (false) , _visibility_checkbutton (g.name) { - int const ports = _port_group.ports.size(); - 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; - } - } - } - + _port_group.visible = true; _ignore_check_button_toggle = false; - _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 (); } -/** @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 */ Widget& PortGroupUI::get_visibility_checkbutton () @@ -173,324 +94,37 @@ void PortGroupUI::port_checkbutton_toggled (CheckButton* b, int r, int c) { 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 */ void 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) { - _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) - : _offer_inputs (offer_inputs), _port_group_list (session, type, offer_inputs, mask), _type (type), - _column_labels (_port_group_list) + : _offer_inputs (offer_inputs), _port_group_list (session, type, offer_inputs, mask), _type (type) { _row_labels_vbox = 0; _side_vbox_pad = 0; _visibility_checkbutton_box.pack_start (*(manage (new Label (_("Connections displayed: ")))), false, false, 10); pack_start (_visibility_checkbutton_box, false, false); - + _scrolled_window.set_policy (POLICY_ALWAYS, POLICY_AUTOMATIC); _scrolled_window.set_shadow_type (SHADOW_NONE); VBox* b = manage (new VBox); - if (offer_inputs) { - 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); - } + b->pack_start (_port_group_hbox, false, false); + b->pack_start (_port_group_hbox, false, false); - Alignment* a; - - 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); + _scrolled_window.add (matrix); if (offer_inputs) { _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) { - _port_group_hbox.remove ((*i)->get_table()); _visibility_checkbutton_box.remove ((*i)->get_visibility_checkbutton()); delete *i; } @@ -550,46 +183,16 @@ PortMatrix::clear () void 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 */ 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 (_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 { - _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); _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); @@ -666,23 +268,14 @@ PortMatrix::setup () void 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) { (*i)->setup_visibility (); if ((*i)->port_group().visible) { - if (even) { - (*i)->get_table().modify_bg (STATE_NORMAL, even_bg); - } else { - (*i)->get_table().modify_bg (STATE_NORMAL, odd_bg); - } - even = !even; + matrix.show_group ((*i)->port_group()); + } else { + matrix.hide_group ((*i)->port_group()); } } } diff --git a/gtk2_ardour/port_matrix.h b/gtk2_ardour/port_matrix.h index 89208f357a..b9a5f7e4c6 100644 --- a/gtk2_ardour/port_matrix.h +++ b/gtk2_ardour/port_matrix.h @@ -28,6 +28,8 @@ #include <gtkmm/scrolledwindow.h> #include "ardour_dialog.h" +#include "port_group.h" +#include "matrix.h" namespace ARDOUR { class Session; @@ -35,118 +37,6 @@ namespace ARDOUR { 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 { public: PortMatrix (ARDOUR::Session&, ARDOUR::DataType, bool, PortGroupList::Mask); @@ -184,10 +74,10 @@ class PortMatrix : public Gtk::VBox { private: PortGroupList _port_group_list; ARDOUR::DataType _type; + Matrix matrix; std::vector<PortGroupUI*> _port_group_ui; std::vector<Gtk::EventBox*> _row_labels; Gtk::VBox* _row_labels_vbox; - RotatedLabelSet _column_labels; Gtk::HBox _overall_hbox; Gtk::VBox _side_vbox; Gtk::HBox _port_group_hbox; diff --git a/gtk2_ardour/processor_box.cc b/gtk2_ardour/processor_box.cc index 370bb7548b..88bd7d0b15 100644 --- a/gtk2_ardour/processor_box.cc +++ b/gtk2_ardour/processor_box.cc @@ -82,10 +82,9 @@ bool ProcessorBox::get_colors = true; Gdk::Color* ProcessorBox::active_processor_color; Gdk::Color* ProcessorBox::inactive_processor_color; -ProcessorBox::ProcessorBox (Placement pcmnt, Session& sess, boost::shared_ptr<Route> rt, PluginSelector &plugsel, - RouteRedirectSelection & rsel, bool owner_is_mixer) - : _route(rt), - _session(sess), +ProcessorBox::ProcessorBox (Placement pcmnt, Session& sess, PluginSelector &plugsel, + RouteRedirectSelection & rsel, bool owner_is_mixer) + : _session(sess), _owner_is_mixer (owner_is_mixer), _placement(pcmnt), _plugin_selector(plugsel), @@ -138,21 +137,10 @@ ProcessorBox::ProcessorBox (Placement pcmnt, Session& sess, boost::shared_ptr<Ro 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_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)); - - /* 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 () @@ -160,6 +148,19 @@ 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 ProcessorBox::route_going_away () { /* don't keep updating display as processors are deleted */ diff --git a/gtk2_ardour/processor_box.h b/gtk2_ardour/processor_box.h index 5d3eb731ca..74d781a0d4 100644 --- a/gtk2_ardour/processor_box.h +++ b/gtk2_ardour/processor_box.h @@ -68,10 +68,10 @@ namespace ARDOUR { class ProcessorBox : public Gtk::HBox, public PluginInterestedObject { public: - ProcessorBox (ARDOUR::Placement, ARDOUR::Session&, - boost::shared_ptr<ARDOUR::Route>, PluginSelector &, RouteRedirectSelection &, bool owner_is_mixer = false); + ProcessorBox (ARDOUR::Placement, ARDOUR::Session&, PluginSelector &, RouteRedirectSelection &, bool owner_is_mixer = false); ~ProcessorBox (); + void set_route (boost::shared_ptr<ARDOUR::Route>); void set_width (Width); void update(); @@ -87,14 +87,12 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject static void register_actions(); - protected: - void set_stuff_from_route (); - private: boost::shared_ptr<ARDOUR::Route> _route; ARDOUR::Session & _session; bool _owner_is_mixer; bool ab_direction; + std::vector<sigc::connection> connections; ARDOUR::Placement _placement; diff --git a/gtk2_ardour/route_params_ui.cc b/gtk2_ardour/route_params_ui.cc index f39d41def5..00a4858c42 100644 --- a/gtk2_ardour/route_params_ui.cc +++ b/gtk2_ardour/route_params_ui.cc @@ -229,8 +229,11 @@ RouteParams_UI::setup_processor_boxes() cleanup_processor_boxes(); // construct new redirect boxes - pre_insert_box = new ProcessorBox(PreFader, *session, _route, *_plugin_selector, _rr_selection); - post_insert_box = new ProcessorBox(PostFader, *session, _route, *_plugin_selector, _rr_selection); + pre_insert_box = new ProcessorBox(PreFader, *session, *_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); post_redir_hpane.pack1 (*post_insert_box); diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index 71ad6e73bd..8985e85071 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -106,9 +106,9 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::sh size_button (_("h")), // height automation_button (_("a")), 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().setup_meters(50); diff --git a/gtk2_ardour/route_ui.cc b/gtk2_ardour/route_ui.cc index 44032a4ea5..3019d954fc 100644 --- a/gtk2_ardour/route_ui.cc +++ b/gtk2_ardour/route_ui.cc @@ -54,13 +54,33 @@ using namespace Gtkmm2ext; using namespace ARDOUR; using namespace PBD; -RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, const char* m_name, - const char* s_name, const char* r_name) - : AxisView(sess), - _route(rt), - mute_button(0), - solo_button(0), - rec_enable_button(0) +RouteUI::RouteUI (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); +} + +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; mute_menu = 0; @@ -73,27 +93,87 @@ RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, co polarity_menu_item = 0; denormal_menu_item = 0; - if (set_color_from_route()) { - set_color (unique_random_color()); + 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; } - new PairedShiva<Route,RouteUI> (*_route, *this); + if (mute_menu) { + delete mute_menu; + mute_menu = 0; + } + + if (remote_control_menu) { + delete remote_control_menu; + remote_control_menu = 0; + } - _route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)); + if (xml_node) { + /* do not delete the node - its owned by the route */ + xml_node = 0; + } - mute_button = manage (new BindableToggleButton (_route->mute_control(), m_name )); - mute_button->set_self_managed (true); + route_active_menu_item = 0; + polarity_menu_item = 0; + denormal_menu_item = 0; +} - solo_button = manage (new BindableToggleButton (_route->solo_control(), s_name )); - solo_button->set_self_managed (true); +void +RouteUI::set_button_names (const char* mute, const char* solo, const char* rec) +{ + m_name = mute; + s_name = solo; + r_name = rec; +} - mute_button->set_name ("MuteButton"); - solo_button->set_name ("SoloButton"); +void +RouteUI::set_route (boost::shared_ptr<Route> rp) +{ + reset (); + + _route = rp; + + if (set_color_from_route()) { + set_color (unique_random_color()); + } - _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)); + /* no, there is no memory leak here. This object cleans itself (and other stuff) + up when the route is destroyed. + */ + 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 */ _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()) { boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route); - t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)); - - _session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_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))); - 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->set_controllable (t->rec_enable_control()); + rec_enable_button->set_label (r_name); + update_rec_display (); } @@ -119,19 +197,13 @@ RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, co mute_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_frozen (); } -RouteUI::~RouteUI() -{ - GoingAway (); /* EMIT SIGNAL */ - delete mute_menu; -} - bool RouteUI::mute_press(GdkEventButton* ev) { diff --git a/gtk2_ardour/route_ui.h b/gtk2_ardour/route_ui.h index e18eda6871..67aa409dda 100644 --- a/gtk2_ardour/route_ui.h +++ b/gtk2_ardour/route_ui.h @@ -45,9 +45,14 @@ class BindableToggleButton; class RouteUI : public virtual AxisView { public: + RouteUI(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 void set_route (boost::shared_ptr<ARDOUR::Route>); + void set_button_names (const char*, const char*, const char*); + bool is_track() const; bool is_audio_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 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__ */ diff --git a/gtk2_ardour/send_ui.cc b/gtk2_ardour/send_ui.cc index 90ff3de717..6ce6edd303 100644 --- a/gtk2_ardour/send_ui.cc +++ b/gtk2_ardour/send_ui.cc @@ -30,11 +30,14 @@ using namespace ARDOUR; using namespace PBD; SendUI::SendUI (boost::shared_ptr<Send> s, Session& se) - : _send (s), - _session (se), - gpm (s->io(), se), - panners (s->io(), se) + : _send (s) + , _session (se) + , gpm (se) + , panners (se) { + panners.set_io (s->io()); + gpm.set_io (s->io()); + hbox.pack_start (gpm, true, true); set_name ("SendUIFrame"); diff --git a/gtk2_ardour/sfdb_ui.cc b/gtk2_ardour/sfdb_ui.cc index 601b83f0c0..915c3c6d3c 100644 --- a/gtk2_ardour/sfdb_ui.cc +++ b/gtk2_ardour/sfdb_ui.cc @@ -596,7 +596,8 @@ SoundFileBrowser::add_gain_meter () 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.pack_start (*gm, false, true); diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc index d4e995f0bf..0b5a14bf56 100644 --- a/libs/ardour/plugin_manager.cc +++ b/libs/ardour/plugin_manager.cc @@ -153,12 +153,45 @@ PluginManager::refresh () void PluginManager::ladspa_refresh () { - _ladspa_plugin_info.clear (); - - if (ladspa_path.length() == 0) { - ladspa_path = "/usr/local/lib64/ladspa:/usr/local/lib/ladspa:/usr/lib64/ladspa:/usr/lib/ladspa:/Library/Audio/Plug-Ins/LADSPA"; - } - + _ladspa_plugin_info.clear (); + + static const char *standard_paths[] = { + "/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); } diff --git a/libs/gtkmm2ext/binding_proxy.cc b/libs/gtkmm2ext/binding_proxy.cc index 6c60deaa8f..845146239d 100644 --- a/libs/gtkmm2ext/binding_proxy.cc +++ b/libs/gtkmm2ext/binding_proxy.cc @@ -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 () { if (prompter) { @@ -48,6 +56,13 @@ BindingProxy::~BindingProxy () } void +BindingProxy::set_controllable (boost::shared_ptr<Controllable> c) +{ + learning_finished (); + controllable = c; +} + +void BindingProxy::set_bind_button_state (guint button, guint statemask) { bind_button = button; @@ -64,7 +79,7 @@ BindingProxy::get_bind_button_state (guint &button, guint &statemask) bool 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())) { string prompt = _("operate controller now"); if (prompter == 0) { @@ -95,7 +110,9 @@ bool BindingProxy::prompter_hiding (GdkEventAny *ev) { learning_connection.disconnect (); - Controllable::StopLearning (controllable.get()); + if (controllable) { + Controllable::StopLearning (controllable.get()); + } return false; } diff --git a/libs/gtkmm2ext/gtkmm2ext/barcontroller.h b/libs/gtkmm2ext/gtkmm2ext/barcontroller.h index 5e9a6fed90..2c0ca948d9 100644 --- a/libs/gtkmm2ext/gtkmm2ext/barcontroller.h +++ b/libs/gtkmm2ext/gtkmm2ext/barcontroller.h @@ -63,7 +63,9 @@ class BarController : public Gtk::Frame /* export this to allow direct connection to button events */ Gtk::Widget& event_widget() { return darea; } + 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: Gtk::Adjustment& adjustment; diff --git a/libs/gtkmm2ext/gtkmm2ext/bindable_button.h b/libs/gtkmm2ext/gtkmm2ext/bindable_button.h index 844dc27d08..3fad7d1faa 100644 --- a/libs/gtkmm2ext/gtkmm2ext/bindable_button.h +++ b/libs/gtkmm2ext/gtkmm2ext/bindable_button.h @@ -32,10 +32,8 @@ namespace PBD { class BindableToggleButton : public Gtkmm2ext::StatefulToggleButton { public: - BindableToggleButton (boost::shared_ptr<PBD::Controllable> c) : binding_proxy (c) {} - - explicit BindableToggleButton (boost::shared_ptr<PBD::Controllable> c, const std::string &label) - : Gtkmm2ext::StatefulToggleButton (label), binding_proxy (c) {} + BindableToggleButton (const std::string &label) + : Gtkmm2ext::StatefulToggleButton (label) {} virtual ~BindableToggleButton() {} @@ -49,7 +47,8 @@ class BindableToggleButton : public Gtkmm2ext::StatefulToggleButton } 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: BindingProxy binding_proxy; }; @@ -58,10 +57,6 @@ class BindableButton : public Gtkmm2ext::StatefulButton { public: 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() {} 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(); } + void set_controllable (boost::shared_ptr<PBD::Controllable> c) { binding_proxy.set_controllable (c); } private: BindingProxy binding_proxy; diff --git a/libs/gtkmm2ext/gtkmm2ext/binding_proxy.h b/libs/gtkmm2ext/gtkmm2ext/binding_proxy.h index ecb95bf815..f684cce5c3 100644 --- a/libs/gtkmm2ext/gtkmm2ext/binding_proxy.h +++ b/libs/gtkmm2ext/gtkmm2ext/binding_proxy.h @@ -34,6 +34,7 @@ class BindingProxy : public sigc::trackable { public: BindingProxy (boost::shared_ptr<PBD::Controllable>); + BindingProxy (); virtual ~BindingProxy(); void set_bind_button_state (guint button, guint statemask); @@ -42,6 +43,7 @@ class BindingProxy : public sigc::trackable bool button_press_handler (GdkEventButton *); boost::shared_ptr<PBD::Controllable> get_controllable() { return controllable; } + void set_controllable (boost::shared_ptr<PBD::Controllable>); protected: Gtkmm2ext::PopUp* prompter; diff --git a/libs/gtkmm2ext/gtkmm2ext/slider_controller.h b/libs/gtkmm2ext/gtkmm2ext/slider_controller.h index 46f70dacd8..7fea4a40d7 100644 --- a/libs/gtkmm2ext/gtkmm2ext/slider_controller.h +++ b/libs/gtkmm2ext/gtkmm2ext/slider_controller.h @@ -41,7 +41,6 @@ class SliderController : public Gtkmm2ext::PixFader public: SliderController (Glib::RefPtr<Gdk::Pixbuf> image, Gtk::Adjustment* adj, int orientation, - boost::shared_ptr<PBD::Controllable>, bool with_numeric = true); virtual ~SliderController () {} @@ -52,6 +51,8 @@ class SliderController : public Gtkmm2ext::PixFader bool on_button_press_event (GdkEventButton *ev); + void set_controllable (boost::shared_ptr<PBD::Controllable> c) { binding_proxy.set_controllable (c); } + protected: BindingProxy binding_proxy; Glib::RefPtr<Gdk::Pixbuf> slider; @@ -59,6 +60,8 @@ class SliderController : public Gtkmm2ext::PixFader Gtk::SpinButton spin; Gtk::Frame spin_frame; Gtk::HBox spin_hbox; + + void init (); }; class VSliderController : public SliderController @@ -66,7 +69,6 @@ class VSliderController : public SliderController public: VSliderController (Glib::RefPtr<Gdk::Pixbuf> image, Gtk::Adjustment *adj, - boost::shared_ptr<PBD::Controllable>, bool with_numeric = true); }; @@ -75,7 +77,6 @@ class HSliderController : public SliderController public: HSliderController (Glib::RefPtr<Gdk::Pixbuf> image, Gtk::Adjustment *adj, - boost::shared_ptr<PBD::Controllable>, bool with_numeric = true); }; diff --git a/libs/gtkmm2ext/slider_controller.cc b/libs/gtkmm2ext/slider_controller.cc index 92fd9d078b..4eee6a6f36 100644 --- a/libs/gtkmm2ext/slider_controller.cc +++ b/libs/gtkmm2ext/slider_controller.cc @@ -30,11 +30,9 @@ using namespace PBD; SliderController::SliderController (Glib::RefPtr<Gdk::Pixbuf> image, Gtk::Adjustment *adj, int orientation, - boost::shared_ptr<Controllable> c, bool with_numeric) : PixFader (image, *adj, orientation), - binding_proxy (c), spin (*adj, 0, 2) { spin.set_name ("SliderControllerValue"); @@ -55,15 +53,15 @@ SliderController::on_button_press_event (GdkEventButton *ev) if (binding_proxy.button_press_handler (ev)) { return true; } + return PixFader::on_button_press_event (ev); } VSliderController::VSliderController (Glib::RefPtr<Gdk::Pixbuf> image, Gtk::Adjustment *adj, - boost::shared_ptr<Controllable> control, bool with_numeric) - : SliderController (image, adj, VERT, control, with_numeric) + : SliderController (image, adj, VERT, with_numeric) { if (with_numeric) { spin_frame.add (spin); @@ -76,10 +74,9 @@ VSliderController::VSliderController (Glib::RefPtr<Gdk::Pixbuf> image, HSliderController::HSliderController (Glib::RefPtr<Gdk::Pixbuf> image, Gtk::Adjustment *adj, - boost::shared_ptr<Controllable> control, bool with_numeric) - : SliderController (image, adj, HORIZ, control, with_numeric) + : SliderController (image, adj, HORIZ, with_numeric) { if (with_numeric) { spin_frame.add (spin); |