2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <pbd/stl_delete.h>
26 #include <pbd/xml++.h>
27 #include <pbd/failed_constructor.h>
29 #include <gtkmm/widget.h>
30 #include <gtkmm2ext/click_box.h>
31 #include <gtkmm2ext/fastmeter.h>
32 #include <gtkmm2ext/barcontroller.h>
33 #include <gtkmm2ext/utils.h>
34 #include <gtkmm2ext/doi.h>
35 #include <gtkmm2ext/slider_controller.h>
37 #include <midi++/manager.h>
39 #include <ardour/plugin.h>
40 #include <ardour/insert.h>
41 #include <ardour/ladspa_plugin.h>
43 #include <ardour/vst_plugin.h>
46 #include <ardour/lv2_plugin.h>
47 #include "lv2_plugin_ui.h"
52 #include "ardour_ui.h"
54 #include "plugin_ui.h"
56 #include "gui_thread.h"
57 #include "public_editor.h"
63 using namespace ARDOUR
;
65 using namespace Gtkmm2ext
;
69 PluginUIWindow::PluginUIWindow (Gtk::Window
* win
, boost::shared_ptr
<PluginInsert
> insert
, bool scrollable
)
72 bool have_gui
= false;
76 if (insert
->plugin()->has_editor()) {
77 switch (insert
->type()) {
79 have_gui
= create_vst_editor (insert
);
82 case ARDOUR::AudioUnit
:
83 have_gui
= create_audiounit_editor (insert
);
87 error
<< _("Eh? LADSPA plugins don't have editors!") << endmsg
;
91 have_gui
= create_lv2_editor (insert
);
96 error
<< _("unknown type of editor-supplying plugin (note: no VST support in this version of ardour)")
99 error
<< _("unknown type of editor-supplying plugin")
102 throw failed_constructor ();
109 GenericPluginUI
* pu
= new GenericPluginUI (insert
, scrollable
);
114 set_wmclass (X_("ardour_plugin_editor"), "Ardour");
116 signal_map_event().connect (mem_fun (*pu
, &GenericPluginUI::start_updating
));
117 signal_unmap_event().connect (mem_fun (*pu
, &GenericPluginUI::stop_updating
));
120 // set_position (Gtk::WIN_POS_MOUSE);
121 set_name ("PluginEditor");
122 add_events (Gdk::KEY_PRESS_MASK
|Gdk::KEY_RELEASE_MASK
|Gdk::BUTTON_PRESS_MASK
|Gdk::BUTTON_RELEASE_MASK
);
124 signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it
), reinterpret_cast<Window
*> (this)), false);
125 death_connection
= insert
->GoingAway
.connect (mem_fun(*this, &PluginUIWindow::plugin_going_away
));
127 gint h
= _pluginui
->get_preferred_height ();
128 gint w
= _pluginui
->get_preferred_width ();
131 if (h
> 600) h
= 600;
132 if (w
> 600) w
= 600;
139 set_default_size (w
, h
);
142 PluginUIWindow::~PluginUIWindow ()
148 PluginUIWindow::set_parent (Gtk::Window
* win
)
154 PluginUIWindow::on_map ()
157 set_keep_above (true);
161 PluginUIWindow::on_enter_notify_event (GdkEventCrossing
*ev
)
163 Keyboard::the_keyboard().enter_window (ev
, this);
168 PluginUIWindow::on_leave_notify_event (GdkEventCrossing
*ev
)
170 Keyboard::the_keyboard().leave_window (ev
, this);
175 PluginUIWindow::on_focus_in_event (GdkEventFocus
*ev
)
177 Window::on_focus_in_event (ev
);
178 //Keyboard::the_keyboard().magic_widget_grab_focus ();
183 PluginUIWindow::on_focus_out_event (GdkEventFocus
*ev
)
185 Window::on_focus_out_event (ev
);
186 //Keyboard::the_keyboard().magic_widget_drop_focus ();
191 PluginUIWindow::on_show ()
194 _pluginui
->update_presets ();
200 // set_transient_for (*parent);
205 PluginUIWindow::on_hide ()
211 PluginUIWindow::create_vst_editor(boost::shared_ptr
<PluginInsert
> insert
)
217 boost::shared_ptr
<VSTPlugin
> vp
;
219 if ((vp
= boost::dynamic_pointer_cast
<VSTPlugin
> (insert
->plugin())) == 0) {
220 error
<< _("unknown type of editor-supplying plugin (note: no VST support in this version of ardour)")
222 throw failed_constructor ();
224 VSTPluginUI
* vpu
= new VSTPluginUI (insert
, vp
);
228 vpu
->package (*this);
237 PluginUIWindow::create_audiounit_editor (boost::shared_ptr
<PluginInsert
> insert
)
239 #if !defined(HAVE_AUDIOUNITS) || !defined(GTKOSX)
243 _pluginui
= create_au_gui (insert
, &box
);
247 extern sigc::signal
<void,bool> ApplicationActivationChanged
;
248 ApplicationActivationChanged
.connect (mem_fun (*this, &PluginUIWindow::app_activated
));
255 PluginUIWindow::app_activated (bool yn
)
257 #if defined (HAVE_AUDIOUNITS) && defined(GTKOSX)
258 cerr
<< "APP activated ? " << yn
<< endl
;
262 _pluginui
->activate ();
267 was_visible
= is_visible();
269 _pluginui
->deactivate ();
276 PluginUIWindow::create_lv2_editor(boost::shared_ptr
<PluginInsert
> insert
)
282 boost::shared_ptr
<LV2Plugin
> vp
;
284 if ((vp
= boost::dynamic_pointer_cast
<LV2Plugin
> (insert
->plugin())) == 0) {
285 error
<< _("create_lv2_editor called on non-LV2 plugin") << endmsg
;
286 throw failed_constructor ();
288 LV2PluginUI
* lpu
= new LV2PluginUI (insert
, vp
);
291 lpu
->package (*this);
300 PluginUIWindow::on_key_press_event (GdkEventKey
* event
)
302 if (!key_press_focus_accelerator_handler (*this, event
)) {
303 return PublicEditor::instance().on_key_press_event(event
);
310 PluginUIWindow::on_key_release_event (GdkEventKey
* event
)
316 PluginUIWindow::plugin_going_away ()
318 ENSURE_GUI_THREAD(mem_fun(*this, &PluginUIWindow::plugin_going_away
));
321 _pluginui
->stop_updating(0);
324 death_connection
.disconnect ();
325 delete_when_idle (this);
328 PlugUIBase::PlugUIBase (boost::shared_ptr
<PluginInsert
> pi
)
330 plugin (insert
->plugin()),
331 save_button(_("Save")),
332 bypass_button (_("Bypass"))
334 //preset_combo.set_use_arrows_always(true);
335 preset_combo
.set_size_request (100, -1);
338 preset_combo
.signal_changed().connect(mem_fun(*this, &PlugUIBase::setting_selected
));
339 no_load_preset
= false;
341 save_button
.set_name ("PluginSaveButton");
342 save_button
.signal_clicked().connect(mem_fun(*this, &PlugUIBase::save_plugin_setting
));
344 insert
->active_changed
.connect (mem_fun(*this, &PlugUIBase::redirect_active_changed
));
345 bypass_button
.set_active (!pi
->active());
347 bypass_button
.set_name ("PluginBypassButton");
348 bypass_button
.signal_toggled().connect (mem_fun(*this, &PlugUIBase::bypass_toggled
));
349 focus_button
.add_events (Gdk::ENTER_NOTIFY_MASK
|Gdk::LEAVE_NOTIFY_MASK
);
351 focus_button
.signal_button_release_event().connect (mem_fun(*this, &PlugUIBase::focus_toggled
));
352 focus_button
.add_events (Gdk::ENTER_NOTIFY_MASK
|Gdk::LEAVE_NOTIFY_MASK
);
354 /* these images are not managed, so that we can remove them at will */
356 focus_out_image
= new Image (get_icon (X_("computer_keyboard")));
357 focus_in_image
= new Image (get_icon (X_("computer_keyboard_active")));
359 focus_button
.add (*focus_out_image
);
361 ARDOUR_UI::instance()->set_tip (&focus_button
, _("Click to allow the plugin to receive keyboard events that Ardour would normally use as a shortcut"), "");
362 ARDOUR_UI::instance()->set_tip (&bypass_button
, _("Click to enable/disable this plugin"), "");
364 insert
->GoingAway
.connect (mem_fun (*this, &PlugUIBase::plugin_going_away
));
367 PlugUIBase::~PlugUIBase ()
372 PlugUIBase::plugin_going_away ()
374 /* drop references to the plugin/insert */
380 PlugUIBase::redirect_active_changed (Redirect
* r
, void* src
)
382 ENSURE_GUI_THREAD(bind (mem_fun(*this, &PlugUIBase::redirect_active_changed
), r
, src
));
383 bypass_button
.set_active (!r
->active());
387 PlugUIBase::setting_selected()
389 if (no_load_preset
) {
393 if (preset_combo
.get_active_text().length() > 0) {
394 if (!plugin
->load_preset(preset_combo
.get_active_text())) {
395 warning
<< string_compose(_("Plugin preset %1 not found"), preset_combo
.get_active_text()) << endmsg
;
401 PlugUIBase::save_plugin_setting ()
403 ArdourPrompter
prompter (true);
404 prompter
.set_prompt(_("Name of New Preset:"));
405 prompter
.add_button (Gtk::Stock::ADD
, Gtk::RESPONSE_ACCEPT
);
406 prompter
.set_response_sensitive (Gtk::RESPONSE_ACCEPT
, false);
407 prompter
.set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY
);
412 switch (prompter
.run ()) {
413 case Gtk::RESPONSE_ACCEPT
:
417 prompter
.get_result(name
);
420 if (plugin
->save_preset(name
)) {
422 /* a rather inefficient way to add the newly saved preset
426 set_popdown_strings (preset_combo
, plugin
->get_presets());
427 no_load_preset
= true;
428 preset_combo
.set_active_text (name
);
429 no_load_preset
= false;
437 PlugUIBase::bypass_toggled ()
441 if ((x
= bypass_button
.get_active()) == insert
->active()) {
442 insert
->set_active (!x
, this);
447 PlugUIBase::focus_toggled (GdkEventButton
* ev
)
449 if (Keyboard::the_keyboard().some_magic_widget_has_focus()) {
450 Keyboard::the_keyboard().magic_widget_drop_focus();
451 focus_button
.remove ();
452 focus_button
.add (*focus_out_image
);
453 focus_out_image
->show ();
454 ARDOUR_UI::instance()->set_tip (&focus_button
, _("Click to allow the plugin to receive keyboard events that Ardour would normally use as a shortcut"), "");
456 Keyboard::the_keyboard().magic_widget_grab_focus();
457 focus_button
.remove ();
458 focus_button
.add (*focus_in_image
);
459 focus_in_image
->show ();
460 ARDOUR_UI::instance()->set_tip (&focus_button
, _("Click to allow normal use of Ardour keyboard shortcuts"), "");
467 PlugUIBase::update_presets ()
469 vector
<string
> presets
= plugin
->get_presets();
470 set_popdown_strings (preset_combo
, plugin
->get_presets());
472 string current_preset
= plugin
->current_preset();
474 if (!current_preset
.empty()) {
475 for (vector
<string
>::iterator p
= presets
.begin(); p
!= presets
.end(); ++p
) {
476 if (*p
== current_preset
) {
477 preset_combo
.set_active_text (current_preset
);