/*
- Copyright (C) 2000-2004 Paul Davis
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
+ * Copyright (C) 2007-2014 David Robillard <d@drobilla.net>
+ * Copyright (C) 2007-2018 Paul Davis <paul@linuxaudiosystems.com>
+ * Copyright (C) 2007 Doug McLain <doug@nostar.net>
+ * Copyright (C) 2008-2012 Carl Hetherington <carl@carlh.net>
+ * Copyright (C) 2013-2015 John Emmas <john@creativepost.co.uk>
+ * Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
+ * Copyright (C) 2014-2015 Ben Loftis <ben@harrisonconsoles.com>
+ * Copyright (C) 2014-2016 Tim Mayberry <mojofunk@gmail.com>
+ * Copyright (C) 2017 Johannes Mueller <github@johannes-mueller.org>
+ * Copyright (C) 2018 Len Ovens <len@ovenwerks.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
#ifdef WAF_BUILD
#include "gtk2ardour-config.h"
#include <sigc++/bind.h>
-#include "canvas/utils.h"
-
#include <glibmm/miscutils.h>
#include <glibmm/fileutils.h>
#include <gtkmm/messagedialog.h>
-#include <gtkmm2ext/gtk_ui.h>
+#include "pbd/unwind.h"
+
+#include "gtkmm2ext/colors.h"
+#include "gtkmm2ext/gtk_ui.h"
#include "gtkmm2ext/menu_elems.h"
-#include <gtkmm2ext/utils.h>
-#include <gtkmm2ext/choice.h>
-#include <gtkmm2ext/utils.h>
-#include <gtkmm2ext/doi.h>
-#include <gtkmm2ext/rgb_macros.h>
+#include "gtkmm2ext/utils.h"
+#include "gtkmm2ext/doi.h"
+#include "gtkmm2ext/rgb_macros.h"
+
+#include "widgets/choice.h"
+#include "widgets/prompter.h"
+#include "widgets/tooltips.h"
#include "ardour/amp.h"
#include "ardour/audio_track.h"
#include "script_selector.h"
#include "send_ui.h"
#include "timers.h"
-#include "tooltips.h"
#include "new_plugin_preset_dialog.h"
#include "pbd/i18n.h"
using namespace Gtk;
using namespace Glib;
using namespace Gtkmm2ext;
+using namespace ArdourWidgets;
ProcessorBox* ProcessorBox::_current_processor_box = 0;
+bool ProcessorBox::_ignore_disk_io_change = false;
+
RefPtr<Action> ProcessorBox::paste_action;
RefPtr<Action> ProcessorBox::cut_action;
RefPtr<Action> ProcessorBox::copy_action;
RefPtr<Action> ProcessorBox::delete_action;
RefPtr<Action> ProcessorBox::backspace_action;
RefPtr<Action> ProcessorBox::manage_pins_action;
+RefPtr<Action> ProcessorBox::disk_io_action;
RefPtr<Action> ProcessorBox::edit_action;
RefPtr<Action> ProcessorBox::edit_generic_action;
RefPtr<ActionGroup> ProcessorBox::processor_box_actions;
-Gtkmm2ext::ActionMap ProcessorBox::myactions (X_("processor box"));
Gtkmm2ext::Bindings* ProcessorBox::bindings = 0;
boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (_processor);
if (pi && pi->plugin() && pi->plugin()->has_inline_display()) {
if (pi->plugin()->get_info()->type != ARDOUR::Lua) {
- _plugin_display = new PluginDisplay (*this, pi->plugin(),
+ _plugin_display = new PluginInlineDisplay (*this, pi->plugin(),
std::max (60.f, rintf(112.f * UIConfiguration::instance().get_ui_scale())));
} else {
assert (boost::dynamic_pointer_cast<LuaProc>(pi->plugin()));
_processor->PropertyChanged.connect (name_connection, invalidator (*this), boost::bind (&ProcessorEntry::processor_property_changed, this, _1), gui_context());
_processor->ConfigurationChanged.connect (config_connection, invalidator (*this), boost::bind (&ProcessorEntry::processor_configuration_changed, this, _1, _2), gui_context());
+ const uint32_t limit_inline_controls = UIConfiguration::instance().get_max_inline_controls ();
+
set<Evoral::Parameter> p = _processor->what_can_be_automated ();
for (set<Evoral::Parameter>::iterator i = p.begin(); i != p.end(); ++i) {
std::string label = _processor->describe_parameter (*i);
+ if (label == X_("hidden")) {
+ continue;
+ }
+
if (boost::dynamic_pointer_cast<Send> (_processor)) {
label = _("Send");
} else if (boost::dynamic_pointer_cast<Return> (_processor)) {
/* Add non-Amp (Fader & Trim) controls to the processor box */
_vbox.pack_start (c->box);
}
+
+ if (limit_inline_controls > 0 && _controls.size() >= limit_inline_controls) {
+ break;
+ }
}
setup_tooltip ();
}
if ((replicated = pi->get_count()) > 1) {
- postfix += string_compose(_("\nThis mono plugin has been replicated %1 times."), replicated);
+ postfix += string_compose(_("\nThis plugin has been replicated %1 times."), replicated);
}
if (pi->plugin()->has_editor()) {
- ARDOUR_UI_UTILS::set_tooltip (_button,
+ set_tooltip (_button,
string_compose (_("<b>%1</b>\nDouble-click to show GUI.\n%2+double-click to show generic GUI.%3"), name (Wide), Keyboard::secondary_modifier_name (), postfix));
} else {
- ARDOUR_UI_UTILS::set_tooltip (_button,
+ set_tooltip (_button,
string_compose (_("<b>%1</b>\nDouble-click to show generic GUI.%2"), name (Wide), postfix));
}
return;
if ((send = boost::dynamic_pointer_cast<Send> (_processor)) != 0 &&
!boost::dynamic_pointer_cast<InternalSend>(_processor)) {
if (send->remove_on_disconnect ()) {
- ARDOUR_UI_UTILS::set_tooltip (_button, string_compose ("<b>> %1</b>\nThis (sidechain) send will be removed when disconnected.", _processor->name()));
+ set_tooltip (_button, string_compose ("<b>> %1</b>\nThis (sidechain) send will be removed when disconnected.", _processor->name()));
} else {
- ARDOUR_UI_UTILS::set_tooltip (_button, string_compose ("<b>> %1</b>", _processor->name()));
+ set_tooltip (_button, string_compose ("<b>> %1</b>", _processor->name()));
}
return;
}
}
- ARDOUR_UI_UTILS::set_tooltip (_button, string_compose ("<b>%1</b>", name (Wide)));
+ set_tooltip (_button, string_compose ("<b>%1</b>", name (Wide)));
}
string
} else {
boost::shared_ptr<ARDOUR::PluginInsert> pi;
- uint32_t replicated;
- if ((pi = boost::dynamic_pointer_cast<ARDOUR::PluginInsert> (_processor)) != 0
- && (replicated = pi->get_count()) > 1)
- {
- name_display += string_compose(_("(%1x1) "), replicated);
+ if ((pi = boost::dynamic_pointer_cast<ARDOUR::PluginInsert> (_processor)) != 0 && pi->get_count() > 1) {
+ switch (w) {
+ case Wide:
+ name_display += "* ";
+ break;
+ case Narrow:
+ name_display += "*";
+ break;
+ }
}
switch (w) {
name_display += PBD::short_version (_processor->display_name(), 5);
break;
}
-
}
return name_display;
}
-Menu *
+Menu*
ProcessorEntry::build_controls_menu ()
{
using namespace Menu_Helpers;
+
+ if (!_plugin_display && _controls.empty ()) {
+ return NULL;
+ }
+
Menu* menu = manage (new Menu);
MenuList& items = menu->items ();
Gtk::CheckMenuItem* c = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
c->set_active (_plugin_display->is_visible ());
c->signal_toggled().connect (sigc::mem_fun (*this, &ProcessorEntry::toggle_inline_display_visibility));
+ }
+
+ if (_controls.empty ()) {
+ return menu;
+ } else {
items.push_back (SeparatorElem ());
}
MenuElem (_("Hide All Controls"), sigc::mem_fun (*this, &ProcessorEntry::hide_all_controls))
);
- if (!_controls.empty ()) {
- items.push_back (SeparatorElem ());
- }
+ items.push_back (SeparatorElem ());
for (list<Control*>::iterator i = _controls.begin(); i != _controls.end(); ++i) {
items.push_back (CheckMenuElemNoMnemonic ((*i)->name ()));
_parent->update_gui_object_state (this);
}
-Menu *
+Menu*
ProcessorEntry::build_send_options_menu ()
{
using namespace Menu_Helpers;
_button.signal_clicked.connect (sigc::mem_fun (*this, &Control::button_clicked));
_button.signal_led_clicked.connect (sigc::mem_fun (*this, &Control::button_clicked_event));
- // dup. currently timers are used :(
- //c->Changed.connect (_connection, MISSING_INVALIDATOR, boost::bind (&Control::control_changed, this), gui_context ());
+ c->Changed.connect (_connections, invalidator (*this), boost::bind (&Control::control_changed, this), gui_context ());
+ if (c->alist ()) {
+ c->alist()->automation_state_changed.connect (_connections, invalidator (*this), boost::bind (&Control::control_automation_state_changed, this), gui_context());
+ control_automation_state_changed ();
+ }
} else {
_adjustment.set_page_increment (largestep);
_slider.set_default_value (normal);
+ _slider.StartGesture.connect(sigc::mem_fun(*this, &Control::start_touch));
+ _slider.StopGesture.connect(sigc::mem_fun(*this, &Control::end_touch));
+
_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &Control::slider_adjusted));
- // dup. currently timers are used :(
- //c->Changed.connect (_connection, MISSING_INVALIDATOR, boost::bind (&Control::control_changed, this), gui_context ());
+ c->Changed.connect (_connections, invalidator (*this), boost::bind (&Control::control_changed, this), gui_context ());
+ if (c->alist ()) {
+ c->alist()->automation_state_changed.connect (_connections, invalidator (*this), boost::bind (&Control::control_automation_state_changed, this), gui_context());
+ control_automation_state_changed ();
+ }
}
- // yuck, do we really need to do this?
- // according to c404374 this is only needed for send automation
- timer_connection = Timers::rapid_connect (sigc::mem_fun (*this, &Control::control_changed));
-
control_changed ();
set_tooltip ();
ProcessorEntry::Control::~Control ()
{
- timer_connection.disconnect ();
}
void
std::string tt = _name + ": " + ARDOUR::value_as_string (c->desc(), c->get_value ());
string sm = Gtkmm2ext::markup_escape_text (tt);
_slider_persistant_tooltip.set_tip (sm);
- ARDOUR_UI_UTILS::set_tooltip (_button, sm);
+ ArdourWidgets::set_tooltip (_button, Gtkmm2ext::markup_escape_text (sm));
}
void
set_tooltip ();
}
+void
+ProcessorEntry::Control::start_touch ()
+{
+ boost::shared_ptr<AutomationControl> c = _control.lock ();
+ if (!c) {
+ return;
+ }
+ c->start_touch (c->session().transport_sample());
+}
+
+void
+ProcessorEntry::Control::end_touch ()
+{
+ boost::shared_ptr<AutomationControl> c = _control.lock ();
+ if (!c) {
+ return;
+ }
+ c->stop_touch (c->session().transport_sample());
+}
+
void
ProcessorEntry::Control::button_clicked ()
{
button_clicked ();
}
+void
+ProcessorEntry::Control::control_automation_state_changed ()
+{
+ boost::shared_ptr<AutomationControl> c = _control.lock ();
+ if (!c) {
+ return;
+ }
+ bool x = c->alist()->automation_state() & Play;
+ if (c->toggled ()) {
+ _button.set_sensitive (!x);
+ } else {
+ _slider.set_sensitive (!x);
+ }
+}
+
void
ProcessorEntry::Control::control_changed ()
{
_ignore_ui_adjustment = true;
if (c->toggled ()) {
-
_button.set_active (c->get_value() > 0.5);
-
} else {
- // as long as rapid timers are used, only update the tooltip
- // if the value has changed.
+ // Note: the _slider watches the controllable by itself
const double nval = c->internal_to_interface (c->get_value ());
if (_adjustment.get_value() != nval) {
_adjustment.set_value (nval);
set_visible (visible);
}
} else {
- set_visible (false);
+ boost::shared_ptr<AutomationControl> c = _control.lock ();
+ set_visible (c && (c->flags () & Controllable::InlineControl));
}
}
}
}
-ProcessorEntry::PluginDisplay::PluginDisplay (ProcessorEntry& e, boost::shared_ptr<ARDOUR::Plugin> p, uint32_t max_height)
- : _entry (e)
- , _plug (p)
- , _surf (0)
- , _max_height (max_height)
- , _cur_height (1)
+ProcessorEntry::PluginInlineDisplay::PluginInlineDisplay (ProcessorEntry& e, boost::shared_ptr<ARDOUR::Plugin> p, uint32_t max_height)
+ : PluginDisplay (p, max_height)
+ , _entry (e)
, _scroll (false)
+ , _given_max_height (max_height)
{
- set_name ("processor prefader");
- add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
- _plug->DropReferences.connect (_death_connection, invalidator (*this), boost::bind (&PluginDisplay::plugin_going_away, this), gui_context());
- _plug->QueueDraw.connect (_qdraw_connection, invalidator (*this),
- boost::bind (&Gtk::Widget::queue_draw, this), gui_context ());
-
std::string postfix = string_compose(_("\n%1+double-click to toggle inline-display"), Keyboard::tertiary_modifier_name ());
if (_plug->has_editor()) {
- ARDOUR_UI_UTILS::set_tooltip (*this,
+ set_tooltip (*this,
string_compose (_("<b>%1</b>\nDouble-click to show GUI.\n%2+double-click to show generic GUI.%3"), e.name (Wide), Keyboard::primary_modifier_name (), postfix));
} else {
- ARDOUR_UI_UTILS::set_tooltip (*this,
+ set_tooltip (*this,
string_compose (_("<b>%1</b>\nDouble-click to show generic GUI.%2"), e.name (Wide), postfix));
}
}
-ProcessorEntry::PluginDisplay::~PluginDisplay ()
-{
- if (_surf) {
- cairo_surface_destroy (_surf);
- }
-}
bool
-ProcessorEntry::PluginDisplay::on_button_press_event (GdkEventButton *ev)
+ProcessorEntry::PluginInlineDisplay::on_button_press_event (GdkEventButton *ev)
{
assert (_entry.processor ());
return false;
}
-bool
-ProcessorEntry::PluginDisplay::on_button_release_event (GdkEventButton *ev)
-{
- return false;
-}
-
void
-ProcessorEntry::PluginDisplay::on_size_request (Requisition* req)
+ProcessorEntry::PluginInlineDisplay::on_size_request (Requisition* req)
{
req->width = 56;
req->height = _cur_height;
void
-ProcessorEntry::PluginDisplay::update_height_alloc (uint32_t inline_height)
+ProcessorEntry::PluginInlineDisplay::update_height_alloc (uint32_t inline_height)
{
/* work-around scroll-bar + aspect ratio
* show inline-view -> height changes -> scrollbar gets added
}
if (shm != _cur_height) {
- if (_scroll == sc || _cur_height < shm) {
- queue_resize ();
+ queue_resize ();
+ if (!_scroll && sc) {
+ _max_height = shm;
+ } else {
+ _max_height = _given_max_height;
}
_cur_height = shm;
}
+
_scroll = sc;
}
-uint32_t
-ProcessorEntry::PluginDisplay::render_inline (cairo_t* cr, uint32_t width)
+void
+ProcessorEntry::PluginInlineDisplay::display_frame (cairo_t* cr, double w, double h)
{
- Plugin::Display_Image_Surface* dis = _plug->render_inline_display (width, _max_height);
- if (!dis) {
- return 0;
- }
-
- /* allocate a local image-surface,
- * We cannot re-use the data via cairo_image_surface_create_for_data(),
- * since pixman keeps a reference to it.
- * we'd need to hand over the data and ha cairo_surface_destroy to free it.
- * it might be possible to work around via cairo_surface_set_user_data().
- */
- if (!_surf
- || dis->width != cairo_image_surface_get_width (_surf)
- || dis->height != cairo_image_surface_get_height (_surf)
- ) {
- if (_surf) {
- cairo_surface_destroy (_surf);
- }
- _surf = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, dis->width, dis->height);
- }
-
- if (cairo_image_surface_get_stride (_surf) == dis->stride) {
- memcpy (cairo_image_surface_get_data (_surf), dis->data, dis->stride * dis->height);
- } else {
- unsigned char *src = dis->data;
- unsigned char *dst = cairo_image_surface_get_data (_surf);
- const int dst_stride = cairo_image_surface_get_stride (_surf);
- for (int y = 0; y < dis->height; ++y) {
- memcpy (dst, src, dis->width * 4 /*ARGB32*/);
- src += dis->stride;
- dst += dst_stride;
- }
- }
-
- cairo_surface_flush(_surf);
- cairo_surface_mark_dirty(_surf);
- const double xc = floor ((width - dis->width) * .5);
- cairo_set_source_surface(cr, _surf, xc, 0);
- cairo_paint (cr);
-
- return dis->height;
-}
-
-bool
-ProcessorEntry::PluginDisplay::on_expose_event (GdkEventExpose* ev)
-{
- Gtk::Allocation a = get_allocation();
- double const width = a.get_width();
- double const height = a.get_height();
-
- cairo_t* cr = gdk_cairo_create (get_window()->gobj());
- cairo_rectangle (cr, ev->area.x, ev->area.y, ev->area.width, ev->area.height);
- cairo_clip (cr);
-
- Gdk::Color const bg = get_style()->get_bg (STATE_NORMAL);
- cairo_set_source_rgb (cr, bg.get_red_p (), bg.get_green_p (), bg.get_blue_p ());
- cairo_rectangle (cr, 0, 0, width, height);
- cairo_fill (cr);
-
- cairo_save (cr);
- cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
- Gtkmm2ext::rounded_rectangle (cr, .5, -1.5, width - 1, height + 1, 7);
- cairo_clip (cr);
- cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
-
- uint32_t ht = render_inline (cr, width);
- cairo_restore (cr);
-
- if (ht == 0) {
- hide ();
- if (_cur_height != 1) {
- _cur_height = 1;
- queue_resize ();
- }
- cairo_destroy (cr);
- return true;
- } else {
- update_height_alloc (ht);
- }
-
- bool failed = false;
- std::string name = get_name();
- ArdourCanvas::Color fill_color = UIConfiguration::instance().color (string_compose ("%1: fill active", name), &failed);
-
- Gtkmm2ext::rounded_rectangle (cr, .5, -1.5, width - 1, height + 1, 7);
- cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
- cairo_set_line_width(cr, 1.0);
- ArdourCanvas::set_source_rgb_a (cr, fill_color, 1.0);
- cairo_stroke (cr);
-
- cairo_destroy(cr);
- return true;
+ Gtkmm2ext::rounded_rectangle (cr, .5, -1.5, w - 1, h + 1, 7);
}
ProcessorEntry::LuaPluginDisplay::LuaPluginDisplay (ProcessorEntry& e, boost::shared_ptr<ARDOUR::LuaProc> p, uint32_t max_height)
- : PluginDisplay (e, p, max_height)
+ : PluginInlineDisplay (e, p, max_height)
, _luaproc (p)
, _lua_render_inline (0)
{
#ifndef NDEBUG
cerr << "LuaException:" << e.what () << endl;
#endif
- }
+ } catch (...) { }
return 0;
}
);
}
- ARDOUR_UI_UTILS::set_tooltip (processor_display, _("Right-click to add/remove/edit\nplugins,inserts,sends and more"));
+ set_tooltip (processor_display, _("Right-click to add/remove/edit\nplugins,inserts,sends and more"));
}
ProcessorBox::~ProcessorBox ()
void
ProcessorBox::route_going_away ()
{
- /* don't keep updating display as processors are deleted */
no_processor_redisplay = true;
+ processor_display.clear ();
_route.reset ();
}
* otherwise we'll end up with duplicate ports-names.
* (this needs a better solution which retains connections)
*/
- state.remove_nodes ("Processor");
+ state.remove_nodes_and_delete ("Processor");
proc->set_state (state, Stateful::loading_state_version);
boost::dynamic_pointer_cast<PluginInsert>(proc)->update_id (id);
return;
if (boost::dynamic_pointer_cast<UnknownProcessor> ((*i)->processor())) {
continue;
}
+ if (boost::dynamic_pointer_cast<PortInsert> ((*i)->processor())) {
+ continue;
+ }
procs.push_back ((*i)->processor ());
}
}
return 0;
}
- if (_route->is_monitor ()) {
+ if (_route->is_monitor () || _route->is_foldbackbus ()) {
return 0;
}
MenuList& items = menu->items();
for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
- if (!_route->internal_send_for (*r) && *r != _route) {
- items.push_back (MenuElemNoMnemonic ((*r)->name(), sigc::bind (sigc::ptr_fun (ProcessorBox::rb_choose_aux), boost::weak_ptr<Route>(*r))));
+ if ((*r)->is_master() || (*r)->is_monitor () || *r == _route) {
+ /* don't allow sending to master or monitor or to self */
+ continue;
}
+ if ((*r)->is_foldbackbus ()) {
+ continue;
+ }
+ if (_route->internal_send_for (*r)) {
+ /* aux-send to target already exists */
+ continue;
+ }
+ items.push_back (MenuElemNoMnemonic ((*r)->name(), sigc::bind (sigc::ptr_fun (ProcessorBox::rb_choose_aux), boost::weak_ptr<Route>(*r))));
+ }
+
+ return menu;
+}
+
+Gtk::Menu*
+ProcessorBox::build_possible_listener_menu ()
+{
+ boost::shared_ptr<RouteList> rl = _session->get_routes_with_internal_returns();
+
+ if (rl->empty()) {
+ /* No aux sends if there are no busses */
+ return 0;
+ }
+
+ if (_route->is_monitor () || _route->is_foldbackbus ()) {
+ return 0;
+ }
+
+ using namespace Menu_Helpers;
+ Menu* menu = manage (new Menu);
+ MenuList& items = menu->items();
+
+ for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
+ if ((*r)->is_master() || (*r)->is_monitor () || *r == _route) {
+ /* don't allow sending to master or monitor or to self */
+ continue;
+ }
+ if (!(*r)->is_foldbackbus ()) {
+ continue;
+ }
+ if (_route->internal_send_for (*r)) {
+ /* aux-send to target already exists */
+ continue;
+ }
+ items.push_back (MenuElemNoMnemonic ((*r)->name(), sigc::bind (sigc::ptr_fun (ProcessorBox::rb_choose_aux), boost::weak_ptr<Route>(*r))));
+ }
+
+ return menu;
+}
+
+Gtk::Menu*
+ProcessorBox::build_possible_remove_listener_menu ()
+{
+ boost::shared_ptr<RouteList> rl = _session->get_routes_with_internal_returns();
+
+ if (rl->empty()) {
+ /* No aux sends if there are no busses */
+ return 0;
+ }
+
+ if (_route->is_monitor () || _route->is_foldbackbus ()) {
+ return 0;
+ }
+
+ using namespace Menu_Helpers;
+ Menu* menu = manage (new Menu);
+ MenuList& items = menu->items();
+
+ for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
+ if ((*r)->is_master() || (*r)->is_monitor () || *r == _route) {
+ /* don't allow sending to master or monitor or to self */
+ continue;
+ }
+ if (!(*r)->is_foldbackbus ()) {
+ continue;
+ }
+ if (!_route->internal_send_for (*r)) {
+ /* aux-send to target already exists */
+ continue;
+ }
+ items.push_back (MenuElemNoMnemonic ((*r)->name(), sigc::bind (sigc::ptr_fun (ProcessorBox::rb_remove_aux), boost::weak_ptr<Route>(*r))));
}
return menu;
aux_menu_item->set_submenu (*m);
aux_menu_item->set_sensitive (true);
} else {
+ delete m;
/* stupid gtkmm: we need to pass a null reference here */
gtk_menu_item_set_submenu (aux_menu_item->gobj(), 0);
aux_menu_item->set_sensitive (false);
}
}
- ActionManager::get_action (X_("ProcessorMenu"), "newinsert")->set_sensitive (!_route->is_monitor ());
- ActionManager::get_action (X_("ProcessorMenu"), "newsend")->set_sensitive (!_route->is_monitor ());
+ Gtk::MenuItem* listen_menu_item = dynamic_cast<Gtk::MenuItem*>(ActionManager::get_widget("/ProcessorMenu/newlisten"));
+
+ if (listen_menu_item) {
+ Menu* m = build_possible_listener_menu();
+ if (m && !m->items().empty()) {
+ listen_menu_item->set_submenu (*m);
+ listen_menu_item->set_sensitive (true);
+ } else {
+ delete m;
+ /* stupid gtkmm: we need to pass a null reference here */
+ gtk_menu_item_set_submenu (listen_menu_item->gobj(), 0);
+ listen_menu_item->set_sensitive (false);
+ }
+ }
+
+ Gtk::MenuItem* remove_listen_menu_item = dynamic_cast<Gtk::MenuItem*>(ActionManager::get_widget("/ProcessorMenu/removelisten"));
+
+ if (remove_listen_menu_item) {
+ Menu* m = build_possible_remove_listener_menu();
+ if (m && !m->items().empty()) {
+ remove_listen_menu_item->set_submenu (*m);
+ remove_listen_menu_item->set_sensitive (true);
+ } else {
+ delete m;
+ /* stupid gtkmm: we need to pass a null reference here */
+ gtk_menu_item_set_submenu (remove_listen_menu_item->gobj(), 0);
+ remove_listen_menu_item->set_sensitive (false);
+ }
+ }
+
+ ActionManager::get_action (X_("ProcessorMenu"), "newinsert")->set_sensitive (!_route->is_monitor () && !_route->is_foldbackbus ());
+ ActionManager::get_action (X_("ProcessorMenu"), "newsend")->set_sensitive (!_route->is_monitor () && !_route->is_foldbackbus ());
ProcessorEntry* single_selection = 0;
if (processor_display.selection().size() == 1) {
controls_menu_item->set_submenu (*m);
controls_menu_item->set_sensitive (true);
} else {
+ delete m;
gtk_menu_item_set_submenu (controls_menu_item->gobj(), 0);
controls_menu_item->set_sensitive (false);
}
send_menu_item->set_submenu (*m);
send_menu_item->set_sensitive (true);
} else {
+ delete m;
gtk_menu_item_set_submenu (send_menu_item->gobj(), 0);
send_menu_item->set_sensitive (false);
}
/* Sensitise actions as approprioate */
-
const bool sensitive = !processor_display.selection().empty() && ! stub_processor_selected ();
paste_action->set_sensitive (!_p_selection.processors.empty());
}
manage_pins_action->set_sensitive (pi != 0);
+ if (boost::dynamic_pointer_cast<Track>(_route)) {
+ disk_io_action->set_sensitive (true);
+ PBD::Unwinder<bool> uw (_ignore_disk_io_change, true);
+ ActionManager::get_toggle_action (X_("ProcessorMenu"), "disk-io-prefader")->set_active (_route->disk_io_point () == DiskIOPreFader);
+ ActionManager::get_toggle_action (X_("ProcessorMenu"), "disk-io-postfader")->set_active (_route->disk_io_point () == DiskIOPostFader);
+ ActionManager::get_toggle_action (X_("ProcessorMenu"), "disk-io-custom")->set_active (_route->disk_io_point () == DiskIOCustom);
+ } else {
+ disk_io_action->set_sensitive (false);
+ }
/* allow editing with an Ardour-generated UI for plugin inserts with editors */
edit_action->set_sensitive (pi && pi->plugin()->has_editor ());
if (processor && (Keyboard::is_edit_event (ev) || (ev->button == 1 && ev->type == GDK_2BUTTON_PRESS))) {
- if (_session->engine().connected()) {
- /* XXX giving an error message here is hard, because we may be in the midst of a button press */
-
- if (!one_processor_can_be_edited ()) {
- return true;
- }
+ if (!one_processor_can_be_edited ()) {
+ return true;
+ }
+ if (!ARDOUR_UI_UTILS::engine_is_running ()) {
+ return true;
+ }
- if (Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier)) {
- generic_edit_processor (processor);
- } else {
- edit_processor (processor);
- }
+ if (Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier)) {
+ generic_edit_processor (processor);
+ } else {
+ edit_processor (processor);
}
ret = true;
return true;
// XXX SHAREDPTR delete plugin here .. do we even need to care?
} else if (plugins.size() == 1 && UIConfiguration::instance().get_open_gui_after_adding_plugin()) {
- if (boost::dynamic_pointer_cast<PluginInsert>(processor)->plugin()->has_inline_display() && UIConfiguration::instance().get_prefer_inline_over_gui()) {
- ;
- } else if (_session->engine().connected () && processor_can_be_edited (processor)) {
- if ((*p)->has_editor ()) {
+ if (processor->what_can_be_automated ().size () == 0) {
+ ; /* plugin without controls, don't show ui */
+ }
+ else if (boost::dynamic_pointer_cast<PluginInsert>(processor)->plugin()->has_inline_display() && UIConfiguration::instance().get_prefer_inline_over_gui()) {
+ ; /* only show inline display */
+ }
+ else if (processor_can_be_edited (processor)) {
+ if (!ARDOUR_UI_UTILS::engine_is_running()) {
+ return true;
+ } else if ((*p)->has_editor ()) {
edit_processor (processor);
} else if (boost::dynamic_pointer_cast<PluginInsert>(processor)->plugin()->parameter_count() > 0) {
generic_edit_processor (processor);
return;
}
- _session->add_internal_send (target, _placement, _route);
+ if (target->is_foldbackbus ()) {
+ _route->add_foldback_send (target);
+ } else {
+ _session->add_internal_send (target, _placement, _route);
+ }
+}
+
+void
+ProcessorBox::remove_aux (boost::weak_ptr<Route> wr)
+{
+ if (!_route) {
+ return;
+ }
+
+ boost::shared_ptr<Route> target = wr.lock();
+
+ if (!target) {
+ return;
+ }
+ boost::shared_ptr<Send> send = _route->internal_send_for (target);
+ boost::shared_ptr<Processor> proc = boost::dynamic_pointer_cast<Processor> (send);
+ _route->remove_processor (proc);
+
}
void
return;
}
- /* not on the list; add it */
+ /* see also ProcessorBox::get_editor_window */
+ bool have_ui = false;
- string loc;
-#if 0 // is this still needed? Why?
- if (_parent_strip) {
- if (_parent_strip->mixer_owned()) {
- loc = X_("M");
- } else {
- loc = X_("R");
+ if (boost::dynamic_pointer_cast<PluginInsert> (p)) {
+ have_ui = true;
+ }
+ else if (boost::dynamic_pointer_cast<PortInsert> (p)) {
+ have_ui = true;
+ }
+ else if (boost::dynamic_pointer_cast<Send> (p)) {
+ if (!boost::dynamic_pointer_cast<InternalSend> (p)) {
+ have_ui = true;
}
- } else {
- loc = X_("P");
}
-#else
- loc = X_("P");
-#endif
+ else if (boost::dynamic_pointer_cast<Return> (p)) {
+ if (!boost::dynamic_pointer_cast<InternalReturn> (p)) {
+ have_ui = true;
+ }
+ }
+
+ if (!have_ui) {
+ return;
+ }
ProcessorWindowProxy* wp = new ProcessorWindowProxy (
- string_compose ("%1-%2-%3", loc, _route->id(), p->id()),
- this,
- w);
+ string_compose ("P-%1-%2", _route->id(), p->id()),
+ this,
+ w);
const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
if (!p || p->pinmgr_proxy ()) {
return;
}
+ if (!boost::dynamic_pointer_cast<PluginInsert> (p)) {
+ return;
+ }
PluginPinWindowProxy* wp = new PluginPinWindowProxy (
- string_compose ("PM-%2-%3", _route->id(), p->id()), w);
+ string_compose ("PM-%1-%2", _route->id(), p->id()), w);
wp->set_session (_session);
const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
boost::shared_ptr<UnknownProcessor> stub = boost::dynamic_pointer_cast<UnknownProcessor> (processor);
//faders and meters are not deletable, copy/paste-able, so they shouldn't be selectable
- if (!send && !plugin_insert && !ext && !stub)
+ if (!send && !plugin_insert && !ext && !stub) {
e->set_selectable(false);
-
- bool mark_send_visible = false;
- if (send && _parent_strip) {
- /* show controls of new sends by default */
- GUIObjectState& st = _parent_strip->gui_object_state ();
- XMLNode* strip = st.get_or_add_node (_parent_strip->state_id ());
- assert (strip);
- /* check if state exists, if not it must be a new send */
- if (!st.get_node(strip, e->state_id())) {
- mark_send_visible = true;
- }
}
/* Set up this entry's state from the GUIObjectState */
e->set_control_state (proc);
}
- if (mark_send_visible) {
- e->show_all_controls ();
- }
-
if (plugin_insert
#ifdef MIXBUS
&& !plugin_insert->plugin(0)->is_channelstrip()
void
ProcessorBox::rename_processor (boost::shared_ptr<Processor> processor)
{
- ArdourPrompter name_prompter (true);
+ Prompter name_prompter (true);
string result;
name_prompter.set_title (_("Rename Processor"));
name_prompter.set_prompt (_("New name:"));
* We really would want Stateful::ForceIDRegeneration here :(
*/
XMLNode state (**niter);
- state.remove_nodes ("Processor");
+ state.remove_nodes_and_delete ("Processor");
p->set_state (state, Stateful::current_state_version);
boost::dynamic_pointer_cast<PluginInsert>(p)->update_id (id);
ab_direction = !ab_direction;
}
+void
+ProcessorBox::set_disk_io_position (DiskIOPoint diop)
+{
+ boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (_route);
+ if (t) {
+ t->set_disk_io_point (diop);
+ }
+}
void
ProcessorBox::clear_processors ()
choices.push_back (_("Cancel"));
choices.push_back (_("Yes, remove them all"));
- Gtkmm2ext::Choice prompter (_("Remove processors"), prompt, choices);
+ ArdourWidgets::Choice prompter (_("Remove processors"), prompt, choices);
if (prompter.run () == 1) {
_route->clear_processors (PreFader);
choices.push_back (_("Cancel"));
choices.push_back (_("Yes, remove them all"));
- Gtkmm2ext::Choice prompter (_("Remove processors"), prompt, choices);
+ ArdourWidgets::Choice prompter (_("Remove processors"), prompt, choices);
if (prompter.run () == 1) {
_route->clear_processors (p);
} else if ((send = boost::dynamic_pointer_cast<Send> (processor)) != 0) {
- if (!_session->engine().connected()) {
+ if (!ARDOUR_UI_UTILS::engine_is_running ()) {
return 0;
}
return 0;
}
- if (!_session->engine().connected()) {
+ if (!ARDOUR_UI_UTILS::engine_is_running ()) {
return 0;
}
} else if ((port_insert = boost::dynamic_pointer_cast<PortInsert> (processor)) != 0) {
- if (!_session->engine().connected()) {
- MessageDialog msg ( _("Not connected to audio engine - no I/O changes are possible"));
- msg.run ();
+ if (!ARDOUR_UI_UTILS::engine_is_running ()) {
return 0;
}
void
ProcessorBox::register_actions ()
{
- processor_box_actions = myactions.create_action_group (X_("ProcessorMenu"));
+ /* We need to use a static object as the owner, since these actions
+ need to be considered ownable by all ProcessorBox objects
+ */
+
+ load_bindings ();
+
+ processor_box_actions = ActionManager::create_action_group (bindings, X_("ProcessorMenu"));
Glib::RefPtr<Action> act;
/* new stuff */
- myactions.register_action (processor_box_actions, X_("newplugin"), _("New Plugin"),
+ ActionManager::register_action (processor_box_actions, X_("newplugin"), _("New Plugin"),
sigc::ptr_fun (ProcessorBox::rb_choose_plugin));
- act = myactions.register_action (processor_box_actions, X_("newinsert"), _("New Insert"),
+ act = ActionManager::register_action (processor_box_actions, X_("newinsert"), _("New Insert"),
sigc::ptr_fun (ProcessorBox::rb_choose_insert));
ActionManager::engine_sensitive_actions.push_back (act);
- act = myactions.register_action (processor_box_actions, X_("newsend"), _("New External Send ..."),
+ act = ActionManager::register_action (processor_box_actions, X_("newsend"), _("New External Send ..."),
sigc::ptr_fun (ProcessorBox::rb_choose_send));
ActionManager::engine_sensitive_actions.push_back (act);
- myactions.register_action (processor_box_actions, X_("newaux"), _("New Aux Send ..."));
+ ActionManager::register_action (processor_box_actions, X_("newaux"), _("New Aux Send ..."));
+ ActionManager::register_action (processor_box_actions, X_("newlisten"), _("New Monitor Send ..."));
+ ActionManager::register_action (processor_box_actions, X_("removelisten"), _("Remove Monitor Send ..."));
- myactions.register_action (processor_box_actions, X_("controls"), _("Controls"));
- myactions.register_action (processor_box_actions, X_("send_options"), _("Send Options"));
+ ActionManager::register_action (processor_box_actions, X_("controls"), _("Controls"));
+ ActionManager::register_action (processor_box_actions, X_("send_options"), _("Send Options"));
- myactions.register_action (processor_box_actions, X_("clear"), _("Clear (all)"),
+ ActionManager::register_action (processor_box_actions, X_("clear"), _("Clear (all)"),
sigc::ptr_fun (ProcessorBox::rb_clear));
- myactions.register_action (processor_box_actions, X_("clear_pre"), _("Clear (pre-fader)"),
+ ActionManager::register_action (processor_box_actions, X_("clear_pre"), _("Clear (pre-fader)"),
sigc::ptr_fun (ProcessorBox::rb_clear_pre));
- myactions.register_action (processor_box_actions, X_("clear_post"), _("Clear (post-fader)"),
+ ActionManager::register_action (processor_box_actions, X_("clear_post"), _("Clear (post-fader)"),
sigc::ptr_fun (ProcessorBox::rb_clear_post));
/* standard editing stuff */
- cut_action = myactions.register_action (processor_box_actions, X_("cut"), _("Cut"),
+ cut_action = ActionManager::register_action (processor_box_actions, X_("cut"), _("Cut"),
sigc::ptr_fun (ProcessorBox::rb_cut));
- copy_action = myactions.register_action (processor_box_actions, X_("copy"), _("Copy"),
+ copy_action = ActionManager::register_action (processor_box_actions, X_("copy"), _("Copy"),
sigc::ptr_fun (ProcessorBox::rb_copy));
- delete_action = myactions.register_action (processor_box_actions, X_("delete"), _("Delete"),
+ delete_action = ActionManager::register_action (processor_box_actions, X_("delete"), _("Delete"),
sigc::ptr_fun (ProcessorBox::rb_delete));
- backspace_action = myactions.register_action (processor_box_actions, X_("backspace"), _("Delete"),
+ backspace_action = ActionManager::register_action (processor_box_actions, X_("backspace"), _("Delete"),
sigc::ptr_fun (ProcessorBox::rb_delete));
ActionManager::plugin_selection_sensitive_actions.push_back (cut_action);
ActionManager::plugin_selection_sensitive_actions.push_back (delete_action);
ActionManager::plugin_selection_sensitive_actions.push_back (backspace_action);
- paste_action = myactions.register_action (processor_box_actions, X_("paste"), _("Paste"),
+ paste_action = ActionManager::register_action (processor_box_actions, X_("paste"), _("Paste"),
sigc::ptr_fun (ProcessorBox::rb_paste));
- rename_action = myactions.register_action (processor_box_actions, X_("rename"), _("Rename"),
+ rename_action = ActionManager::register_action (processor_box_actions, X_("rename"), _("Rename"),
sigc::ptr_fun (ProcessorBox::rb_rename));
- myactions.register_action (processor_box_actions, X_("selectall"), _("Select All"),
+ ActionManager::register_action (processor_box_actions, X_("selectall"), _("Select All"),
sigc::ptr_fun (ProcessorBox::rb_select_all));
- myactions.register_action (processor_box_actions, X_("deselectall"), _("Deselect All"),
+ ActionManager::register_action (processor_box_actions, X_("deselectall"), _("Deselect All"),
sigc::ptr_fun (ProcessorBox::rb_deselect_all));
/* activation etc. */
- myactions.register_action (processor_box_actions, X_("activate_all"), _("Activate All"),
+ ActionManager::register_action (processor_box_actions, X_("activate_all"), _("Activate All"),
sigc::ptr_fun (ProcessorBox::rb_activate_all));
- myactions.register_action (processor_box_actions, X_("deactivate_all"), _("Deactivate All"),
+ ActionManager::register_action (processor_box_actions, X_("deactivate_all"), _("Deactivate All"),
sigc::ptr_fun (ProcessorBox::rb_deactivate_all));
- myactions.register_action (processor_box_actions, X_("ab_plugins"), _("A/B Plugins"),
+ ActionManager::register_action (processor_box_actions, X_("ab_plugins"), _("A/B Plugins"),
sigc::ptr_fun (ProcessorBox::rb_ab_plugins));
- manage_pins_action = myactions.register_action (
+ manage_pins_action = ActionManager::register_action (
processor_box_actions, X_("manage-pins"), _("Pin Connections..."),
sigc::ptr_fun (ProcessorBox::rb_manage_pins));
+ /* Disk IO stuff */
+ disk_io_action = ActionManager::register_action (processor_box_actions, X_("disk-io-menu"), _("Disk I/O ..."));
+ ActionManager::register_toggle_action (processor_box_actions, X_("disk-io-prefader"), _("Pre-Fader"), sigc::bind (sigc::ptr_fun (ProcessorBox::rb_set_disk_io_position), DiskIOPreFader));
+ ActionManager::register_toggle_action (processor_box_actions, X_("disk-io-postfader"), _("Post-Fader"), sigc::bind (sigc::ptr_fun (ProcessorBox::rb_set_disk_io_position), DiskIOPostFader));
+ ActionManager::register_toggle_action (processor_box_actions, X_("disk-io-custom"), _("Custom"), sigc::bind (sigc::ptr_fun (ProcessorBox::rb_set_disk_io_position), DiskIOCustom));
+
/* show editors */
- edit_action = myactions.register_action (
+ edit_action = ActionManager::register_action (
processor_box_actions, X_("edit"), _("Edit..."),
sigc::ptr_fun (ProcessorBox::rb_edit));
- edit_generic_action = myactions.register_action (
+ edit_generic_action = ActionManager::register_action (
processor_box_actions, X_("edit-generic"), _("Edit with generic controls..."),
sigc::ptr_fun (ProcessorBox::rb_edit_generic));
- load_bindings ();
}
void
_current_processor_box->ab_plugins ();
}
+void
+ProcessorBox::rb_set_disk_io_position (DiskIOPoint diop)
+{
+ if (_current_processor_box == 0) {
+ return;
+ }
+ if (_ignore_disk_io_change) {
+ return;
+ }
+
+ _current_processor_box->set_disk_io_position (diop);
+}
+
void
ProcessorBox::rb_manage_pins ()
{
_current_processor_box->choose_aux (wr);
}
+void
+ProcessorBox::rb_remove_aux (boost::weak_ptr<Route> wr)
+{
+ if (_current_processor_box == 0) {
+ return;
+ }
+
+ _current_processor_box->remove_aux (wr);
+}
+
void
ProcessorBox::rb_clear ()
{
if (edit_aux_send (processor)) {
return;
}
- if (!_session->engine().connected()) {
+ if (!ARDOUR_UI_UTILS::engine_is_running ()) {
return;
}
if (edit_aux_send (processor)) {
return;
}
- if (!_session->engine().connected()) {
+ if (!ARDOUR_UI_UTILS::engine_is_running ()) {
return;
}
void
ProcessorBox::load_bindings ()
{
- bindings = Bindings::get_bindings (X_("Processor Box"), myactions);
+ bindings = Bindings::get_bindings (X_("Processor Box"));
}