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 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
);
115 set_wmclass (X_("ardour_plugin_editor"), "Ardour");
117 signal_map_event().connect (mem_fun (*pu
, &GenericPluginUI::start_updating
));
118 signal_unmap_event().connect (mem_fun (*pu
, &GenericPluginUI::stop_updating
));
121 // set_position (Gtk::WIN_POS_MOUSE);
122 set_name ("PluginEditor");
123 add_events (Gdk::KEY_PRESS_MASK
|Gdk::KEY_RELEASE_MASK
|Gdk::BUTTON_PRESS_MASK
|Gdk::BUTTON_RELEASE_MASK
);
125 signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it
), reinterpret_cast<Window
*> (this)), false);
126 death_connection
= insert
->GoingAway
.connect (mem_fun(*this, &PluginUIWindow::plugin_going_away
));
128 gint h
= _pluginui
->get_preferred_height ();
129 gint w
= _pluginui
->get_preferred_width ();
132 if (h
> 600) h
= 600;
133 if (w
> 600) w
= 600;
140 set_default_size (w
, h
);
143 PluginUIWindow::~PluginUIWindow ()
149 PluginUIWindow::set_parent (Gtk::Window
* win
)
155 PluginUIWindow::on_map ()
158 set_keep_above (true);
162 PluginUIWindow::on_enter_notify_event (GdkEventCrossing
*ev
)
164 Keyboard::the_keyboard().enter_window (ev
, this);
169 PluginUIWindow::on_leave_notify_event (GdkEventCrossing
*ev
)
171 Keyboard::the_keyboard().leave_window (ev
, this);
176 PluginUIWindow::on_focus_in_event (GdkEventFocus
*ev
)
178 Window::on_focus_in_event (ev
);
179 //Keyboard::the_keyboard().magic_widget_grab_focus ();
184 PluginUIWindow::on_focus_out_event (GdkEventFocus
*ev
)
186 Window::on_focus_out_event (ev
);
187 //Keyboard::the_keyboard().magic_widget_drop_focus ();
192 PluginUIWindow::on_show ()
194 set_role("plugin_ui");
197 _pluginui
->update_presets ();
201 if (_pluginui
->on_window_show (_title
)) {
207 // set_transient_for (*parent);
212 PluginUIWindow::on_hide ()
217 _pluginui
->on_window_hide ();
222 PluginUIWindow::set_title(const Glib::ustring
& title
)
224 //cout << "PluginUIWindow::set_title(\"" << title << "\"" << endl;
225 Gtk::Window::set_title(title
);
230 PluginUIWindow::create_vst_editor(boost::shared_ptr
<PluginInsert
> insert
)
236 boost::shared_ptr
<VSTPlugin
> vp
;
238 if ((vp
= boost::dynamic_pointer_cast
<VSTPlugin
> (insert
->plugin())) == 0) {
239 error
<< _("unknown type of editor-supplying plugin (note: no VST support in this version of ardour)")
241 throw failed_constructor ();
243 VSTPluginUI
* vpu
= new VSTPluginUI (insert
, vp
);
247 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
);
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);
318 PluginUIWindow::on_key_press_event (GdkEventKey
* event
)
320 return relay_key_press (event
, this);
324 PluginUIWindow::on_key_release_event (GdkEventKey
* event
)
330 PluginUIWindow::plugin_going_away ()
332 ENSURE_GUI_THREAD(mem_fun(*this, &PluginUIWindow::plugin_going_away
));
335 _pluginui
->stop_updating(0);
338 death_connection
.disconnect ();
339 delete_when_idle (this);
342 PlugUIBase::PlugUIBase (boost::shared_ptr
<PluginInsert
> pi
)
344 plugin (insert
->plugin()),
345 save_button(_("Save")),
346 bypass_button (_("Bypass"))
348 //preset_combo.set_use_arrows_always(true);
349 preset_combo
.set_size_request (100, -1);
352 preset_combo
.signal_changed().connect(mem_fun(*this, &PlugUIBase::setting_selected
));
353 no_load_preset
= false;
355 save_button
.set_name ("PluginSaveButton");
356 save_button
.signal_clicked().connect(mem_fun(*this, &PlugUIBase::save_plugin_setting
));
358 insert
->active_changed
.connect (mem_fun(*this, &PlugUIBase::redirect_active_changed
));
359 bypass_button
.set_active (!pi
->active());
361 bypass_button
.set_name ("PluginBypassButton");
362 bypass_button
.signal_toggled().connect (mem_fun(*this, &PlugUIBase::bypass_toggled
));
363 focus_button
.add_events (Gdk::ENTER_NOTIFY_MASK
|Gdk::LEAVE_NOTIFY_MASK
);
365 focus_button
.signal_button_release_event().connect (mem_fun(*this, &PlugUIBase::focus_toggled
));
366 focus_button
.add_events (Gdk::ENTER_NOTIFY_MASK
|Gdk::LEAVE_NOTIFY_MASK
);
368 /* these images are not managed, so that we can remove them at will */
370 focus_out_image
= new Image (get_icon (X_("computer_keyboard")));
371 focus_in_image
= new Image (get_icon (X_("computer_keyboard_active")));
373 focus_button
.add (*focus_out_image
);
375 ARDOUR_UI::instance()->set_tip (&focus_button
, _("Click to allow the plugin to receive keyboard events that Ardour would normally use as a shortcut"), "");
376 ARDOUR_UI::instance()->set_tip (&bypass_button
, _("Click to enable/disable this plugin"), "");
378 insert
->GoingAway
.connect (mem_fun (*this, &PlugUIBase::plugin_going_away
));
381 PlugUIBase::~PlugUIBase ()
386 PlugUIBase::plugin_going_away ()
388 /* drop references to the plugin/insert */
394 PlugUIBase::redirect_active_changed (Redirect
* r
, void* src
)
396 ENSURE_GUI_THREAD(bind (mem_fun(*this, &PlugUIBase::redirect_active_changed
), r
, src
));
397 bypass_button
.set_active (!r
->active());
401 PlugUIBase::setting_selected()
403 if (no_load_preset
) {
407 if (preset_combo
.get_active_text().length() > 0) {
408 if (!plugin
->load_preset(preset_combo
.get_active_text())) {
409 warning
<< string_compose(_("Plugin preset %1 not found"), preset_combo
.get_active_text()) << endmsg
;
415 PlugUIBase::save_plugin_setting ()
417 ArdourPrompter
prompter (true);
418 prompter
.set_prompt(_("Name of New Preset:"));
419 prompter
.add_button (Gtk::Stock::ADD
, Gtk::RESPONSE_ACCEPT
);
420 prompter
.set_response_sensitive (Gtk::RESPONSE_ACCEPT
, false);
421 prompter
.set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY
);
426 switch (prompter
.run ()) {
427 case Gtk::RESPONSE_ACCEPT
:
431 prompter
.get_result(name
);
434 if (plugin
->save_preset(name
)) {
436 /* a rather inefficient way to add the newly saved preset
440 no_load_preset
= true;
441 set_popdown_strings (preset_combo
, plugin
->get_presets());
442 preset_combo
.set_active_text (name
);
443 no_load_preset
= false;
451 PlugUIBase::bypass_toggled ()
455 if ((x
= bypass_button
.get_active()) == insert
->active()) {
456 insert
->set_active (!x
, this);
461 PlugUIBase::focus_toggled (GdkEventButton
* ev
)
463 if (Keyboard::the_keyboard().some_magic_widget_has_focus()) {
464 Keyboard::the_keyboard().magic_widget_drop_focus();
465 focus_button
.remove ();
466 focus_button
.add (*focus_out_image
);
467 focus_out_image
->show ();
468 ARDOUR_UI::instance()->set_tip (&focus_button
, _("Click to allow the plugin to receive keyboard events that Ardour would normally use as a shortcut"), "");
470 Keyboard::the_keyboard().magic_widget_grab_focus();
471 focus_button
.remove ();
472 focus_button
.add (*focus_in_image
);
473 focus_in_image
->show ();
474 ARDOUR_UI::instance()->set_tip (&focus_button
, _("Click to allow normal use of Ardour keyboard shortcuts"), "");
481 PlugUIBase::update_presets ()
483 vector
<string
> presets
= plugin
->get_presets();
484 no_load_preset
= true;
486 set_popdown_strings (preset_combo
, plugin
->get_presets());
488 string current_preset
= plugin
->current_preset();
490 if (!current_preset
.empty()) {
491 for (vector
<string
>::iterator p
= presets
.begin(); p
!= presets
.end(); ++p
) {
492 if (*p
== current_preset
) {
493 preset_combo
.set_active_text (current_preset
);
498 no_load_preset
= false;