/* * Copyright (C) 2007-2014 David Robillard * Copyright (C) 2007-2018 Paul Davis * Copyright (C) 2008-2012 Carl Hetherington * Copyright (C) 2013-2019 Robin Gareus * Copyright (C) 2014-2018 Ben Loftis * Copyright (C) 2017 Johannes Mueller * * 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. */ #ifndef __ardour_gtk_processor_box__ #define __ardour_gtk_processor_box__ #include #include #include #include #include #include #include "gtkmm2ext/bindings.h" #include "gtkmm2ext/dndtreeview.h" #include "gtkmm2ext/dndvbox.h" #include "gtkmm2ext/persistent_tooltip.h" #include "pbd/stateful.h" #include "pbd/signals.h" #include "ardour/types.h" #include "ardour/ardour.h" #include "ardour/plugin_insert.h" #include "ardour/luaproc.h" #include "ardour/port_insert.h" #include "ardour/processor.h" #include "ardour/route.h" #include "ardour/session_handle.h" #include "pbd/fastlog.h" #include "widgets/ardour_button.h" #include "widgets/ardour_fader.h" #include "widgets/slider_controller.h" #ifdef HAVE_BEATBOX #include "beatbox_gui.h" #endif #include "plugin_interest.h" #include "plugin_display.h" #include "io_selector.h" #include "send_ui.h" #include "enums.h" #include "window_manager.h" class MotionController; class PluginSelector; class PluginUIWindow; class ProcessorSelection; class MixerStrip; namespace ARDOUR { class Connection; class IO; class Insert; class Plugin; class PluginInsert; class PortInsert; class Route; class Session; } class ProcessorBox; class ProcessorWindowProxy : public WM::ProxyBase { public: ProcessorWindowProxy (std::string const &, ProcessorBox *, std::weak_ptr); ~ProcessorWindowProxy(); Gtk::Window* get (bool create = false); std::weak_ptr processor () const { return _processor; } ARDOUR::SessionHandlePtr* session_handle(); void show_the_right_window (bool show_not_toggle = false); void set_custom_ui_mode(bool use_custom) { want_custom = use_custom; } int set_state (const XMLNode&, int); XMLNode& get_state () const; bool visible() const; bool fully_visible() const; private: ProcessorBox* _processor_box; std::weak_ptr _processor; bool is_custom; bool want_custom; void processor_going_away (); sigc::connection _unmap_connection; sigc::connection _drop_window_connection; PBD::ScopedConnection going_away_connection; PBD::ScopedConnectionList gui_connections; }; class PluginPinWindowProxy : public WM::ProxyBase { public: PluginPinWindowProxy (std::string const &, std::weak_ptr); ~PluginPinWindowProxy(); Gtk::Window* get (bool create = false); ARDOUR::SessionHandlePtr* session_handle(); private: std::weak_ptr _processor; void processor_going_away (); PBD::ScopedConnection going_away_connection; }; class ProcessorEntry : public Gtkmm2ext::DnDVBoxChild, public sigc::trackable { public: ProcessorEntry (ProcessorBox *, std::shared_ptr, Width); ~ProcessorEntry (); Gtk::EventBox& action_widget (); Gtk::Widget& widget (); std::string drag_text () const; void set_visual_state (Gtkmm2ext::VisualState, bool); bool is_selectable() const {return _selectable;} void set_selectable(bool s) { _selectable = s; } bool drag_data_get (Glib::RefPtr const, Gtk::SelectionData &); bool can_copy_state (Gtkmm2ext::DnDVBoxChild*) const; enum ProcessorPosition { PreFader, Fader, PostFader }; void set_position (ProcessorPosition, uint32_t); bool unknown_processor () const { return _unknown_processor; } ; std::shared_ptr processor () const; void set_enum_width (Width); /** Hide any widgets that should be hidden */ virtual void hide_things (); void toggle_inline_display_visibility (); void show_all_controls (); void hide_all_controls (); void add_control_state (XMLNode *) const; void set_control_state (XMLNode const *); std::string state_id () const; Gtk::Menu* build_controls_menu (); Gtk::Menu* build_send_options_menu (); Gtk::Menu* build_presets_menu (); protected: ArdourWidgets::ArdourButton _button; Gtk::VBox _vbox; ProcessorPosition _position; uint32_t _position_num; ProcessorBox* _parent; virtual void setup_visuals (); private: bool _selectable; bool _unknown_processor; bool _ignore_preset_select; void led_clicked(GdkEventButton *); void processor_active_changed (); void processor_property_changed (const PBD::PropertyChange&); void processor_configuration_changed (const ARDOUR::ChanCount in, const ARDOUR::ChanCount out); std::string name (Width) const; void setup_tooltip (); std::shared_ptr _processor; Width _width; PBD::ScopedConnection active_connection; PBD::ScopedConnection name_connection; PBD::ScopedConnection config_connection; ARDOUR::PluginPresetPtr _plugin_preset_pointer; class Control : public sigc::trackable { public: Control (ProcessorEntry&, std::shared_ptr, std::string const &); ~Control (); void set_visible (bool); void add_state (XMLNode *) const; void set_state (XMLNode const *); void hide_things (); bool visible () const { return _visible; } std::string name () const { return _name; } Gtk::Alignment box; private: void slider_adjusted (); void button_clicked (); void button_clicked_event (GdkEventButton *); void control_changed (); void control_automation_state_changed (); std::string state_id () const; void set_tooltip (); void start_touch (int); void end_touch (int); bool button_released (GdkEventButton*); ProcessorEntry& _entry; std::weak_ptr _control; /* things for a slider */ Gtk::Adjustment _adjustment; ArdourWidgets::HSliderController _slider; Gtkmm2ext::PersistentTooltip _slider_persistant_tooltip; /* things for a button */ ArdourWidgets::ArdourButton _button; bool _ignore_ui_adjustment; PBD::ScopedConnectionList _connections; bool _visible; std::string _name; }; std::list _controls; friend class Control; void toggle_control_visibility (Control *); void toggle_panner_link (); void toggle_allow_feedback (); void plugin_preset_selected (ARDOUR::Plugin::PresetRecord); void plugin_preset_add (); void plugin_preset_delete (); void reset_plugin(); class PluginInlineDisplay : public PluginDisplay { public: PluginInlineDisplay(ProcessorEntry&, std::shared_ptr, uint32_t max_height = 80); ~PluginInlineDisplay() {} protected: void on_size_request (Gtk::Requisition* req); bool on_button_press_event (GdkEventButton *ev); void update_height_alloc (uint32_t inline_height); void display_frame (cairo_t* cr, double w, double h); ProcessorEntry& _entry; bool _scroll; const uint32_t _given_max_height; }; class LuaPluginDisplay : public PluginInlineDisplay { public: LuaPluginDisplay(ProcessorEntry&, std::shared_ptr, uint32_t max_height = 80); ~LuaPluginDisplay(); protected: virtual uint32_t render_inline (cairo_t *, uint32_t width); private: std::shared_ptr _luaproc; LuaState lua_gui; luabridge::LuaRef * _lua_render_inline; }; class PortIcon : public Gtk::DrawingArea { public: PortIcon(bool input); void set_ports(ARDOUR::ChanCount const ports) { _ports = ports; } private: bool on_expose_event (GdkEventExpose *); bool _input; ARDOUR::ChanCount _ports; }; class RoutingIcon : public Gtk::DrawingArea { public: RoutingIcon(bool inputrouting = true); void set ( const ARDOUR::ChanCount&, const ARDOUR::ChanCount&, const ARDOUR::ChanCount&, const ARDOUR::ChanCount&, const ARDOUR::ChanMapping&, const ARDOUR::ChanMapping&, const ARDOUR::ChanMapping&); void set_fed_by ( const ARDOUR::ChanCount&, const ARDOUR::ChanCount&, const ARDOUR::ChanMapping&, const ARDOUR::ChanMapping&); void set_feeding ( const ARDOUR::ChanCount&, const ARDOUR::ChanCount&, const ARDOUR::ChanMapping&, const ARDOUR::ChanMapping&); void set_terminal (bool b); void copy_state (const RoutingIcon& other) { _in = other._in; _out = other._out; _sources = other._sources; _sinks = other._sinks; _in_map = other._in_map; _out_map = other._out_map; _thru_map = other._thru_map; _f_out = other._f_out; _f_out_map = other._f_out_map; _f_thru_map = other._f_thru_map; _f_sources = other._f_sources; _i_in = other._i_in; _i_in_map = other._i_in_map; _i_thru_map = other._i_thru_map; _i_sinks = other._i_sinks; _fed_by = other._fed_by; _feeding = other._feeding; } void unset_fed_by () { _fed_by = false ; } void unset_feeding () { _feeding = false ; } bool in_identity () const; bool out_identity () const; bool can_coalesce () const; static double pin_x_pos (uint32_t, double, uint32_t, uint32_t, bool); static void draw_connection (cairo_t*, double, double, double, double, bool, bool dashed = false); static void draw_gnd (cairo_t*, double, double, double, bool); static void draw_sidechain (cairo_t*, double, double, double, bool); static void draw_thru_src (cairo_t*, double, double, double, bool); static void draw_thru_sink (cairo_t*, double, double, double, bool); private: bool on_expose_event (GdkEventExpose *); void expose_input_map (cairo_t*, const double, const double); void expose_coalesced_input_map (cairo_t*, const double, const double); void expose_output_map (cairo_t*, const double, const double); ARDOUR::ChanCount _in; ARDOUR::ChanCount _out; ARDOUR::ChanCount _sources; ARDOUR::ChanCount _sinks; ARDOUR::ChanMapping _in_map; ARDOUR::ChanMapping _out_map; ARDOUR::ChanMapping _thru_map; ARDOUR::ChanCount _f_out; ARDOUR::ChanMapping _f_out_map; ARDOUR::ChanMapping _f_thru_map; ARDOUR::ChanCount _f_sources; ARDOUR::ChanCount _i_in; ARDOUR::ChanMapping _i_in_map; ARDOUR::ChanMapping _i_thru_map; ARDOUR::ChanCount _i_sinks; bool _fed_by; bool _feeding; bool _input; bool _terminal; }; public: PortIcon input_icon; PortIcon output_icon; RoutingIcon routing_icon; // sits on top of every processor (input routing) RoutingIcon output_routing_icon; // only used by last processor in the chain protected: PluginDisplay *_plugin_display ; }; class PluginInsertProcessorEntry : public ProcessorEntry { public: PluginInsertProcessorEntry (ProcessorBox *, std::shared_ptr, Width); void hide_things (); private: void iomap_changed (); std::shared_ptr _plugin_insert; PBD::ScopedConnectionList _iomap_connection; }; class ProcessorBox : public Gtk::HBox, public PluginInterestedObject, public ARDOUR::SessionHandlePtr { public: enum ProcessorOperation { ProcessorsCut, ProcessorsCopy, ProcessorsPaste, ProcessorsDelete, ProcessorsSelectAll, ProcessorsSelectNone, ProcessorsToggleActive, ProcessorsAB, }; ProcessorBox (ARDOUR::Session*, std::function get_plugin_selector, ProcessorSelection&, MixerStrip* parent, bool owner_is_mixer = false); ~ProcessorBox (); void set_route (std::shared_ptr); void set_width (Width); bool processor_operation (ProcessorOperation); void select_all_processors (); void deselect_all_processors (); void select_all_plugins (); void select_all_inserts (); void select_all_sends (); void all_visible_processors_active(bool state); void setup_routing_feeds (); void hide_things (); bool edit_aux_send (std::shared_ptr); /* Everything except a WindowProxy object should use this to get the window */ Gtk::Window* get_processor_ui (std::shared_ptr) const; /* a WindowProxy object can use this */ Gtk::Window* get_editor_window (std::shared_ptr, bool); Gtk::Window* get_generic_editor_window (std::shared_ptr); void manage_pins (std::shared_ptr); void edit_processor (std::shared_ptr); void generic_edit_processor (std::shared_ptr); void update_gui_object_state (ProcessorEntry *, bool emit = false); sigc::signal > ProcessorSelected; sigc::signal > ProcessorUnselected; static Glib::RefPtr processor_box_actions; static Gtkmm2ext::Bindings* bindings; static void register_actions(); typedef std::vector > ProcSelection; static ProcSelection current_processor_selection () { ProcSelection ps; if (_current_processor_box) { _current_processor_box->get_selected_processors (ps); } return ps; } #ifndef NDEBUG static bool show_all_processors; #endif private: /* prevent copy construction */ ProcessorBox (ProcessorBox const &); std::shared_ptr _route; MixerStrip* _parent_strip; // null if in RouteParamsUI bool _owner_is_mixer; bool ab_direction; PBD::ScopedConnectionList _mixer_strip_connections; PBD::ScopedConnectionList _route_connections; std::function _get_plugin_selector; std::shared_ptr _processor_being_created; /** Index at which to place a new plugin (based on where the menu was opened), or -1 to * put at the end of the plugin list. */ int _placement; ProcessorSelection& _p_selection; static void load_bindings (); void route_going_away (); bool is_editor_mixer_strip() const; Gtkmm2ext::DnDVBox processor_display; Gtk::ScrolledWindow processor_scroller; std::shared_ptr find_drop_position (ProcessorEntry* position); void _drop_plugin_preset (Gtk::SelectionData const &, ARDOUR::Route::ProcessorList &); void _drop_plugin (Gtk::SelectionData const &, ARDOUR::Route::ProcessorList &); void plugin_drop (Gtk::SelectionData const &, ProcessorEntry* position, Glib::RefPtr const & context); void object_drop (Gtkmm2ext::DnDVBox *, ProcessorEntry *, Glib::RefPtr const &); Width _width; bool _redisplay_pending; Gtk::Menu *processor_menu; gint processor_menu_map_handler (GdkEventAny *ev); Gtk::Menu * build_processor_menu (); void show_processor_menu (int); Gtk::Menu* build_possible_aux_menu(); Gtk::Menu* build_possible_listener_menu(); Gtk::Menu* build_possible_remove_listener_menu(); void choose_aux (std::weak_ptr); void remove_aux (std::weak_ptr); void choose_send (); void send_io_finished (IOSelector::Result, std::weak_ptr, IOSelectorWindow*); void return_io_finished (IOSelector::Result, std::weak_ptr, IOSelectorWindow*); void choose_insert (); void choose_plugin (); bool use_plugins (const SelectedPlugins&); bool no_processor_redisplay; bool enter_notify (GdkEventCrossing *ev); bool leave_notify (GdkEventCrossing *ev); bool processor_button_press_event (GdkEventButton *, ProcessorEntry *); bool processor_button_release_event (GdkEventButton *, ProcessorEntry *); void redisplay_processors (); void add_processor_to_display (std::weak_ptr); void reordered (); void report_failed_reorder (); void route_processors_changed (ARDOUR::RouteProcessorChange); void processor_menu_unmapped (); void processors_reordered (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator&, int*); void compute_processor_sort_keys (); void ab_plugins (); void cut_processors (const ProcSelection&); void copy_processors (const ProcSelection&); void delete_processors (const ProcSelection&); void paste_processors (); void paste_processors (std::shared_ptr before); void delete_dragged_processors (const std::list >&); void clear_processors (); void clear_processors (ARDOUR::Placement); void rename_processors (); void for_selected_processors (void (ProcessorBox::*pmf)(std::shared_ptr)); void get_selected_processors (ProcSelection&) const; void set_disk_io_position (ARDOUR::DiskIOPoint); void toggle_custom_loudness_pos (); bool can_cut() const; bool stub_processor_selected() const; bool channelstrip_selected() const; bool surrsend_selected() const; static Glib::RefPtr cut_action; static Glib::RefPtr copy_action; static Glib::RefPtr paste_action; static Glib::RefPtr rename_action; static Glib::RefPtr delete_action; static Glib::RefPtr backspace_action; static Glib::RefPtr manage_pins_action; static Glib::RefPtr disk_io_action; static Glib::RefPtr edit_action; static Glib::RefPtr edit_generic_action; void paste_processor_state (const XMLNodeList&, std::shared_ptr); void hide_processor_editor (std::shared_ptr); void rename_processor (std::shared_ptr); gint idle_delete_processor (std::weak_ptr); void weird_plugin_dialog (ARDOUR::Plugin& p, ARDOUR::Route::ProcessorStreams streams); void setup_entry_positions (); static ProcessorBox* _current_processor_box; static void rb_choose_aux (std::weak_ptr); static void rb_remove_aux (std::weak_ptr); static void rb_choose_plugin (); static void rb_choose_insert (); static void rb_choose_send (); static void rb_clear (); static void rb_clear_pre (); static void rb_clear_post (); static void rb_cut (); static void rb_copy (); static void rb_paste (); static void rb_delete (); static void rb_rename (); static void rb_select_all (); static void rb_deselect_all (); static void rb_activate_all (); static void rb_deactivate_all (); static void rb_ab_plugins (); static void rb_manage_pins (); static void rb_set_disk_io_position (ARDOUR::DiskIOPoint); static void rb_toggle_custom_loudness_pos (); static void rb_edit (); static void rb_edit_generic (); void route_property_changed (const PBD::PropertyChange&); std::string generate_processor_title (std::shared_ptr pi); //typedef std::list ProcessorWindowProxies; //ProcessorWindowProxies _processor_window_info; ProcessorWindowProxy* find_window_proxy (std::shared_ptr) const; void set_processor_ui (std::shared_ptr, Gtk::Window *); void maybe_add_processor_to_ui_list (std::weak_ptr); void maybe_add_processor_pin_mgr (std::weak_ptr); bool one_processor_can_be_edited (); bool processor_can_be_edited (std::shared_ptr); void mixer_strip_delivery_changed (std::weak_ptr); XMLNode* entry_gui_object_state (ProcessorEntry *); PBD::ScopedConnection amp_config_connection; static bool _ignore_rb_change; void selection_added (ProcessorEntry&); }; #endif /* __ardour_gtk_processor_box__ */