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>
36 #include <gtkmm2ext/application.h>
38 #include <midi++/manager.h>
40 #include <ardour/plugin.h>
41 #include <ardour/insert.h>
42 #include <ardour/ladspa_plugin.h>
44 #include <ardour/vst_plugin.h>
47 #include <ardour/lv2_plugin.h>
48 #include "lv2_plugin_ui.h"
53 #include "ardour_ui.h"
55 #include "plugin_ui.h"
57 #include "gui_thread.h"
58 #include "public_editor.h"
64 using namespace ARDOUR
;
66 using namespace Gtkmm2ext
;
70 PluginUIWindow::PluginUIWindow (Gtk::Window
* win
, boost::shared_ptr
<PluginInsert
> insert
, bool scrollable
)
73 , _keyboard_focused (false)
75 bool have_gui
= false;
78 if (insert
->plugin()->has_editor()) {
79 switch (insert
->type()) {
81 have_gui
= create_vst_editor (insert
);
84 case ARDOUR::AudioUnit
:
85 have_gui
= create_audiounit_editor (insert
);
89 error
<< _("Eh? LADSPA plugins don't have editors!") << endmsg
;
93 have_gui
= create_lv2_editor (insert
);
98 error
<< _("unknown type of editor-supplying plugin (note: no VST support in this version of ardour)")
101 error
<< _("unknown type of editor-supplying plugin")
104 throw failed_constructor ();
111 GenericPluginUI
* pu
= new GenericPluginUI (insert
, scrollable
);
114 _pluginui
->KeyboardFocused
.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused
));
117 set_wmclass (X_("ardour_plugin_editor"), PROGRAM_NAME
);
119 signal_map_event().connect (mem_fun (*pu
, &GenericPluginUI::start_updating
));
120 signal_unmap_event().connect (mem_fun (*pu
, &GenericPluginUI::stop_updating
));
123 // set_position (Gtk::WIN_POS_MOUSE);
124 set_name ("PluginEditor");
125 add_events (Gdk::KEY_PRESS_MASK
|Gdk::KEY_RELEASE_MASK
|Gdk::BUTTON_PRESS_MASK
|Gdk::BUTTON_RELEASE_MASK
);
127 signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it
), reinterpret_cast<Window
*> (this)), false);
128 death_connection
= insert
->GoingAway
.connect (mem_fun(*this, &PluginUIWindow::plugin_going_away
));
130 gint h
= _pluginui
->get_preferred_height ();
131 gint w
= _pluginui
->get_preferred_width ();
134 if (h
> 600) h
= 600;
135 if (w
> 600) w
= 600;
142 set_default_size (w
, h
);
145 PluginUIWindow::~PluginUIWindow ()
151 PluginUIWindow::set_parent (Gtk::Window
* win
)
157 PluginUIWindow::on_map ()
160 set_keep_above (true);
164 PluginUIWindow::on_enter_notify_event (GdkEventCrossing
*ev
)
166 Keyboard::the_keyboard().enter_window (ev
, this);
171 PluginUIWindow::on_leave_notify_event (GdkEventCrossing
*ev
)
173 Keyboard::the_keyboard().leave_window (ev
, this);
178 PluginUIWindow::on_focus_in_event (GdkEventFocus
*ev
)
180 Window::on_focus_in_event (ev
);
181 //Keyboard::the_keyboard().magic_widget_grab_focus ();
186 PluginUIWindow::on_focus_out_event (GdkEventFocus
*ev
)
188 Window::on_focus_out_event (ev
);
189 //Keyboard::the_keyboard().magic_widget_drop_focus ();
194 PluginUIWindow::on_show ()
196 set_role("plugin_ui");
199 _pluginui
->update_presets ();
203 if (_pluginui
->on_window_show (_title
)) {
209 // set_transient_for (*parent);
214 PluginUIWindow::on_hide ()
219 _pluginui
->on_window_hide ();
224 PluginUIWindow::set_title(const Glib::ustring
& title
)
226 //cout << "PluginUIWindow::set_title(\"" << title << "\"" << endl;
227 Gtk::Window::set_title(title
);
232 PluginUIWindow::create_vst_editor(boost::shared_ptr
<PluginInsert
> insert
)
238 boost::shared_ptr
<VSTPlugin
> vp
;
240 if ((vp
= boost::dynamic_pointer_cast
<VSTPlugin
> (insert
->plugin())) == 0) {
241 error
<< _("unknown type of editor-supplying plugin (note: no VST support in this version of ardour)")
243 throw failed_constructor ();
245 VSTPluginUI
* vpu
= new VSTPluginUI (insert
, vp
);
248 _pluginui
->KeyboardFocused
.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused
));
250 vpu
->package (*this);
257 PluginUIWindow::create_audiounit_editor (boost::shared_ptr
<PluginInsert
> insert
)
259 #if !defined(HAVE_AUDIOUNITS) || !defined(GTKOSX)
263 _pluginui
= create_au_gui (insert
, &box
);
264 _pluginui
->KeyboardFocused
.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused
));
267 Application::instance()->ActivationChanged
.connect (mem_fun (*this, &PluginUIWindow::app_activated
));
274 PluginUIWindow::app_activated (bool yn
)
276 #if defined (HAVE_AUDIOUNITS) && defined(GTKOSX)
280 _pluginui
->activate ();
286 was_visible
= is_visible();
288 _pluginui
->deactivate ();
295 PluginUIWindow::create_lv2_editor(boost::shared_ptr
<PluginInsert
> insert
)
301 boost::shared_ptr
<LV2Plugin
> vp
;
303 if ((vp
= boost::dynamic_pointer_cast
<LV2Plugin
> (insert
->plugin())) == 0) {
304 error
<< _("create_lv2_editor called on non-LV2 plugin") << endmsg
;
305 throw failed_constructor ();
307 LV2PluginUI
* lpu
= new LV2PluginUI (insert
, vp
);
310 lpu
->package (*this);
318 PluginUIWindow::keyboard_focused (bool yn
)
320 _keyboard_focused
= yn
;
324 PluginUIWindow::on_key_press_event (GdkEventKey
* event
)
326 if (_keyboard_focused
) {
328 _pluginui
->forward_key_event (event
);
332 if (_pluginui
->non_gtk_gui()) {
333 /* pass editor window as the window for the event
334 to be handled in, not this one, because there are
335 no widgets in this window that we want to have
338 return relay_key_press (event
, &PublicEditor::instance());
340 return relay_key_press (event
, this);
346 PluginUIWindow::on_key_release_event (GdkEventKey
* event
)
348 if (_keyboard_focused
) {
350 _pluginui
->forward_key_event (event
);
359 PluginUIWindow::plugin_going_away ()
361 ENSURE_GUI_THREAD(mem_fun(*this, &PluginUIWindow::plugin_going_away
));
364 _pluginui
->stop_updating(0);
367 death_connection
.disconnect ();
368 delete_when_idle (this);
371 PlugUIBase::PlugUIBase (boost::shared_ptr
<PluginInsert
> pi
)
373 plugin (insert
->plugin()),
374 save_button(_("Save")),
375 bypass_button (_("Bypass"))
377 //preset_combo.set_use_arrows_always(true);
378 preset_combo
.set_size_request (100, -1);
381 preset_combo
.signal_changed().connect(mem_fun(*this, &PlugUIBase::setting_selected
));
382 no_load_preset
= false;
384 save_button
.set_name ("PluginSaveButton");
385 save_button
.signal_clicked().connect(mem_fun(*this, &PlugUIBase::save_plugin_setting
));
387 insert
->active_changed
.connect (mem_fun(*this, &PlugUIBase::redirect_active_changed
));
388 bypass_button
.set_active (!pi
->active());
390 bypass_button
.set_name ("PluginBypassButton");
391 bypass_button
.signal_toggled().connect (mem_fun(*this, &PlugUIBase::bypass_toggled
));
392 focus_button
.add_events (Gdk::ENTER_NOTIFY_MASK
|Gdk::LEAVE_NOTIFY_MASK
);
394 focus_button
.signal_button_release_event().connect (mem_fun(*this, &PlugUIBase::focus_toggled
));
395 focus_button
.add_events (Gdk::ENTER_NOTIFY_MASK
|Gdk::LEAVE_NOTIFY_MASK
);
397 /* these images are not managed, so that we can remove them at will */
399 focus_out_image
= new Image (get_icon (X_("computer_keyboard")));
400 focus_in_image
= new Image (get_icon (X_("computer_keyboard_active")));
402 focus_button
.add (*focus_out_image
);
404 ARDOUR_UI::instance()->set_tip (&focus_button
, string_compose (_("Click to allow the plugin to receive keyboard events that %1 would normally use as a shortcut"), PROGRAM_NAME
).c_str(), "");
405 ARDOUR_UI::instance()->set_tip (&bypass_button
, _("Click to enable/disable this plugin"), "");
407 insert
->GoingAway
.connect (mem_fun (*this, &PlugUIBase::plugin_going_away
));
410 PlugUIBase::~PlugUIBase ()
415 PlugUIBase::plugin_going_away ()
417 /* drop references to the plugin/insert */
423 PlugUIBase::redirect_active_changed (Redirect
* r
, void* src
)
425 ENSURE_GUI_THREAD(bind (mem_fun(*this, &PlugUIBase::redirect_active_changed
), r
, src
));
426 bypass_button
.set_active (!r
->active());
430 PlugUIBase::setting_selected()
432 if (no_load_preset
) {
436 if (preset_combo
.get_active_text().length() > 0) {
437 if (!plugin
->load_preset(preset_combo
.get_active_text())) {
438 warning
<< string_compose(_("Plugin preset %1 not found"), preset_combo
.get_active_text()) << endmsg
;
444 PlugUIBase::save_plugin_setting ()
446 ArdourPrompter
prompter (true);
447 prompter
.set_prompt(_("Name of New Preset:"));
448 prompter
.add_button (Gtk::Stock::ADD
, Gtk::RESPONSE_ACCEPT
);
449 prompter
.set_response_sensitive (Gtk::RESPONSE_ACCEPT
, false);
450 prompter
.set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY
);
455 switch (prompter
.run ()) {
456 case Gtk::RESPONSE_ACCEPT
:
460 prompter
.get_result(name
);
463 if (plugin
->save_preset(name
)) {
465 /* a rather inefficient way to add the newly saved preset
469 no_load_preset
= true;
470 set_popdown_strings (preset_combo
, plugin
->get_presets());
471 preset_combo
.set_active_text (name
);
472 no_load_preset
= false;
480 PlugUIBase::bypass_toggled ()
484 if ((x
= bypass_button
.get_active()) == insert
->active()) {
485 insert
->set_active (!x
, this);
490 PlugUIBase::focus_toggled (GdkEventButton
* ev
)
492 if (Keyboard::the_keyboard().some_magic_widget_has_focus()) {
493 Keyboard::the_keyboard().magic_widget_drop_focus();
494 focus_button
.remove ();
495 focus_button
.add (*focus_out_image
);
496 focus_out_image
->show ();
497 ARDOUR_UI::instance()->set_tip (&focus_button
, string_compose (_("Click to allow the plugin to receive keyboard events that %1 would normally use as a shortcut"), PROGRAM_NAME
).c_str(), "");
498 KeyboardFocused (false);
500 Keyboard::the_keyboard().magic_widget_grab_focus();
501 focus_button
.remove ();
502 focus_button
.add (*focus_in_image
);
503 focus_in_image
->show ();
504 ARDOUR_UI::instance()->set_tip (&focus_button
, string_compose (_("Click to allow normal use of %1 keyboard shortcuts"), PROGRAM_NAME
).c_str(), "");
505 KeyboardFocused (true);
512 PlugUIBase::update_presets ()
514 vector
<string
> presets
= plugin
->get_presets();
515 no_load_preset
= true;
517 set_popdown_strings (preset_combo
, plugin
->get_presets());
519 string current_preset
= plugin
->current_preset();
521 if (!current_preset
.empty()) {
522 for (vector
<string
>::iterator p
= presets
.begin(); p
!= presets
.end(); ++p
) {
523 if (*p
== current_preset
) {
524 preset_combo
.set_active_text (current_preset
);
529 no_load_preset
= false;