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;
77 if (insert
->plugin()->has_editor()) {
78 switch (insert
->type()) {
80 have_gui
= create_vst_editor (insert
);
83 case ARDOUR::AudioUnit
:
84 have_gui
= create_audiounit_editor (insert
);
88 error
<< _("Eh? LADSPA plugins don't have editors!") << endmsg
;
92 have_gui
= create_lv2_editor (insert
);
97 error
<< _("unknown type of editor-supplying plugin (note: no VST support in this version of ardour)")
100 error
<< _("unknown type of editor-supplying plugin")
103 throw failed_constructor ();
110 GenericPluginUI
* pu
= new GenericPluginUI (insert
, scrollable
);
113 _pluginui
->KeyboardFocused
.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused
));
116 set_wmclass (X_("ardour_plugin_editor"), PROGRAM_NAME
);
118 signal_map_event().connect (mem_fun (*pu
, &GenericPluginUI::start_updating
));
119 signal_unmap_event().connect (mem_fun (*pu
, &GenericPluginUI::stop_updating
));
122 // set_position (Gtk::WIN_POS_MOUSE);
123 set_name ("PluginEditor");
124 add_events (Gdk::KEY_PRESS_MASK
|Gdk::KEY_RELEASE_MASK
|Gdk::BUTTON_PRESS_MASK
|Gdk::BUTTON_RELEASE_MASK
);
126 signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it
), reinterpret_cast<Window
*> (this)), false);
127 death_connection
= insert
->GoingAway
.connect (mem_fun(*this, &PluginUIWindow::plugin_going_away
));
129 gint h
= _pluginui
->get_preferred_height ();
130 gint w
= _pluginui
->get_preferred_width ();
133 if (h
> 600) h
= 600;
134 if (w
> 600) w
= 600;
141 set_default_size (w
, h
);
144 PluginUIWindow::~PluginUIWindow ()
150 PluginUIWindow::set_parent (Gtk::Window
* win
)
156 PluginUIWindow::on_map ()
159 set_keep_above (true);
163 PluginUIWindow::on_enter_notify_event (GdkEventCrossing
*ev
)
165 Keyboard::the_keyboard().enter_window (ev
, this);
170 PluginUIWindow::on_leave_notify_event (GdkEventCrossing
*ev
)
172 Keyboard::the_keyboard().leave_window (ev
, this);
177 PluginUIWindow::on_focus_in_event (GdkEventFocus
*ev
)
179 Window::on_focus_in_event (ev
);
180 //Keyboard::the_keyboard().magic_widget_grab_focus ();
185 PluginUIWindow::on_focus_out_event (GdkEventFocus
*ev
)
187 Window::on_focus_out_event (ev
);
188 //Keyboard::the_keyboard().magic_widget_drop_focus ();
193 PluginUIWindow::on_show ()
195 set_role("plugin_ui");
198 _pluginui
->update_presets ();
202 if (_pluginui
->on_window_show (_title
)) {
208 // set_transient_for (*parent);
213 PluginUIWindow::on_hide ()
218 _pluginui
->on_window_hide ();
223 PluginUIWindow::set_title(const Glib::ustring
& title
)
225 //cout << "PluginUIWindow::set_title(\"" << title << "\"" << endl;
226 Gtk::Window::set_title(title
);
231 PluginUIWindow::create_vst_editor(boost::shared_ptr
<PluginInsert
> insert
)
237 boost::shared_ptr
<VSTPlugin
> vp
;
239 if ((vp
= boost::dynamic_pointer_cast
<VSTPlugin
> (insert
->plugin())) == 0) {
240 error
<< _("unknown type of editor-supplying plugin (note: no VST support in this version of ardour)")
242 throw failed_constructor ();
244 VSTPluginUI
* vpu
= new VSTPluginUI (insert
, vp
);
247 _pluginui
->KeyboardFocused
.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused
));
249 vpu
->package (*this);
256 PluginUIWindow::create_audiounit_editor (boost::shared_ptr
<PluginInsert
> insert
)
258 #if !defined(HAVE_AUDIOUNITS) || !defined(GTKOSX)
262 _pluginui
= create_au_gui (insert
, &box
);
263 _pluginui
->KeyboardFocused
.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused
));
266 Application::instance()->ActivationChanged
.connect (mem_fun (*this, &PluginUIWindow::app_activated
));
273 PluginUIWindow::app_activated (bool yn
)
275 #if defined (HAVE_AUDIOUNITS) && defined(GTKOSX)
279 _pluginui
->activate ();
285 was_visible
= is_visible();
287 _pluginui
->deactivate ();
294 PluginUIWindow::create_lv2_editor(boost::shared_ptr
<PluginInsert
> insert
)
300 boost::shared_ptr
<LV2Plugin
> vp
;
302 if ((vp
= boost::dynamic_pointer_cast
<LV2Plugin
> (insert
->plugin())) == 0) {
303 error
<< _("create_lv2_editor called on non-LV2 plugin") << endmsg
;
304 throw failed_constructor ();
306 LV2PluginUI
* lpu
= new LV2PluginUI (insert
, vp
);
309 lpu
->package (*this);
317 PluginUIWindow::keyboard_focused (bool yn
)
319 _keyboard_focused
= yn
;
323 PluginUIWindow::on_key_press_event (GdkEventKey
* event
)
325 if (_keyboard_focused
) {
327 _pluginui
->forward_key_event (event
);
331 if (_pluginui
->non_gtk_gui()) {
332 /* pass editor window as the window for the event
333 to be handled in, not this one, because there are
334 no widgets in this window that we want to have
337 return relay_key_press (event
, &PublicEditor::instance());
339 return relay_key_press (event
, this);
345 PluginUIWindow::on_key_release_event (GdkEventKey
* event
)
347 if (_keyboard_focused
) {
349 _pluginui
->forward_key_event (event
);
358 PluginUIWindow::plugin_going_away ()
360 ENSURE_GUI_THREAD(mem_fun(*this, &PluginUIWindow::plugin_going_away
));
363 _pluginui
->stop_updating(0);
366 death_connection
.disconnect ();
367 delete_when_idle (this);
370 PlugUIBase::PlugUIBase (boost::shared_ptr
<PluginInsert
> pi
)
372 plugin (insert
->plugin()),
373 save_button(_("Save")),
374 bypass_button (_("Bypass"))
376 //preset_combo.set_use_arrows_always(true);
377 preset_combo
.set_size_request (100, -1);
380 preset_combo
.signal_changed().connect(mem_fun(*this, &PlugUIBase::setting_selected
));
381 no_load_preset
= false;
383 save_button
.set_name ("PluginSaveButton");
384 save_button
.signal_clicked().connect(mem_fun(*this, &PlugUIBase::save_plugin_setting
));
386 insert
->active_changed
.connect (mem_fun(*this, &PlugUIBase::redirect_active_changed
));
387 bypass_button
.set_active (!pi
->active());
389 bypass_button
.set_name ("PluginBypassButton");
390 bypass_button
.signal_toggled().connect (mem_fun(*this, &PlugUIBase::bypass_toggled
));
391 focus_button
.add_events (Gdk::ENTER_NOTIFY_MASK
|Gdk::LEAVE_NOTIFY_MASK
);
393 focus_button
.signal_button_release_event().connect (mem_fun(*this, &PlugUIBase::focus_toggled
));
394 focus_button
.add_events (Gdk::ENTER_NOTIFY_MASK
|Gdk::LEAVE_NOTIFY_MASK
);
396 /* these images are not managed, so that we can remove them at will */
398 focus_out_image
= new Image (get_icon (X_("computer_keyboard")));
399 focus_in_image
= new Image (get_icon (X_("computer_keyboard_active")));
401 focus_button
.add (*focus_out_image
);
403 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(), "");
404 ARDOUR_UI::instance()->set_tip (&bypass_button
, _("Click to enable/disable this plugin"), "");
406 insert
->GoingAway
.connect (mem_fun (*this, &PlugUIBase::plugin_going_away
));
409 PlugUIBase::~PlugUIBase ()
414 PlugUIBase::plugin_going_away ()
416 /* drop references to the plugin/insert */
422 PlugUIBase::redirect_active_changed (Redirect
* r
, void* src
)
424 ENSURE_GUI_THREAD(bind (mem_fun(*this, &PlugUIBase::redirect_active_changed
), r
, src
));
425 bypass_button
.set_active (!r
->active());
429 PlugUIBase::setting_selected()
431 if (no_load_preset
) {
435 if (preset_combo
.get_active_text().length() > 0) {
436 if (!plugin
->load_preset(preset_combo
.get_active_text())) {
437 warning
<< string_compose(_("Plugin preset %1 not found"), preset_combo
.get_active_text()) << endmsg
;
443 PlugUIBase::save_plugin_setting ()
445 ArdourPrompter
prompter (true);
446 prompter
.set_prompt(_("Name of New Preset:"));
447 prompter
.add_button (Gtk::Stock::ADD
, Gtk::RESPONSE_ACCEPT
);
448 prompter
.set_response_sensitive (Gtk::RESPONSE_ACCEPT
, false);
449 prompter
.set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY
);
454 switch (prompter
.run ()) {
455 case Gtk::RESPONSE_ACCEPT
:
459 prompter
.get_result(name
);
462 if (plugin
->save_preset(name
)) {
464 /* a rather inefficient way to add the newly saved preset
468 no_load_preset
= true;
469 set_popdown_strings (preset_combo
, plugin
->get_presets());
470 preset_combo
.set_active_text (name
);
471 no_load_preset
= false;
479 PlugUIBase::bypass_toggled ()
483 if ((x
= bypass_button
.get_active()) == insert
->active()) {
484 insert
->set_active (!x
, this);
489 PlugUIBase::focus_toggled (GdkEventButton
* ev
)
491 if (Keyboard::the_keyboard().some_magic_widget_has_focus()) {
492 Keyboard::the_keyboard().magic_widget_drop_focus();
493 focus_button
.remove ();
494 focus_button
.add (*focus_out_image
);
495 focus_out_image
->show ();
496 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(), "");
497 KeyboardFocused (false);
499 Keyboard::the_keyboard().magic_widget_grab_focus();
500 focus_button
.remove ();
501 focus_button
.add (*focus_in_image
);
502 focus_in_image
->show ();
503 ARDOUR_UI::instance()->set_tip (&focus_button
, string_compose (_("Click to allow normal use of %1 keyboard shortcuts"), PROGRAM_NAME
).c_str(), "");
504 KeyboardFocused (true);
511 PlugUIBase::update_presets ()
513 vector
<string
> presets
= plugin
->get_presets();
514 no_load_preset
= true;
516 set_popdown_strings (preset_combo
, plugin
->get_presets());
518 string current_preset
= plugin
->current_preset();
520 if (!current_preset
.empty()) {
521 for (vector
<string
>::iterator p
= presets
.begin(); p
!= presets
.end(); ++p
) {
522 if (*p
== current_preset
) {
523 preset_combo
.set_active_text (current_preset
);
528 no_load_preset
= false;