17#pragma GCC diagnostic ignored "-Wparentheses"
18#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
19#elif defined(__clang__)
20#pragma clang diagnostic ignored "-Wparentheses"
21#pragma clang diagnostic ignored "-Wdeprecated-declarations"
33#include <wx/checkbox.h>
38#include <wx/stattext.h>
39#include <wx/textctrl.h>
41#include <wx/scrolwin.h>
43#include "../../widgets/valnum.h"
45#include "../../widgets/NumericTextCtrl.h"
60 ?
static_cast<WXWidget
>(suil_instance_get_widget(
mSuilInstance.get()))
80 wxMacAutoreleasePool pool;
90 int count = CFGetRetainCount(widget);
107 const LV2Ports &ports, wxWindow *parent,
bool useGUI
110 ,
mType{ effect.GetType() }
120 mParent->PushEventHandler(
this);
166 pMeter->Disconnect();
192 static std::weak_ptr<SuilHost> sSuilHost;
193 std::shared_ptr<SuilHost> result = sSuilHost.lock();
196 sSuilHost = result = SuilHostPtr{ suil_host_new(
206 auto &wrapper = *pWrapper;
210 const char *nativeType =
211#if defined(__WXGTK3__)
213#elif defined(__WXGTK__)
215#elif defined(__WXMSW__)
217#elif defined(__WXMAC__)
222 const LilvUI *ui =
nullptr;
223 const LilvNode *uiType =
nullptr;
225 LilvUIsPtr uis{ lilv_plugin_get_uis(&
mPlug) };
228 LILV_FOREACH(uis, iter, uis.get()) {
229 ui = lilv_uis_get(uis.get(), iter);
230 if (lilv_ui_is_supported(ui,
231 suil_ui_supported, containerType.get(), &uiType))
233 if (lilv_ui_is_a(ui, node_Gtk) || lilv_ui_is_a(ui, node_Gtk3)) {
244 LILV_FOREACH(uis, iter, uis.get()) {
245 ui = lilv_uis_get(uis.get(), iter);
246 if (lilv_ui_is_a(ui, node_ExternalUI) || lilv_ui_is_a(ui, node_ExternalUIOld)) {
247 uiType = node_ExternalUI;
258 const auto uinode = lilv_ui_get_uri(ui);
259 lilv_world_load_resource(
gWorld, uinode);
261 auto &instance = wrapper.GetInstance();
263 wrapper.GetFeatures(), &
handler, uinode, &instance,
264 (uiType == node_ExternalUI) ?
nullptr :
mParent);
268 const char *containerType;
269 if (uiType == node_ExternalUI)
272 containerType = nativeType;
273#if defined(__WXGTK__)
275 if (!gtk_widget_get_window(GTK_WIDGET(
mParent->m_wxwindow)))
276 gtk_widget_realize(GTK_WIDGET(
mParent->m_wxwindow));
288#if defined(__WXMSW__)
292 lilv_file_uri_parse(lilv_node_as_uri(lilv_ui_get_binary_uri(ui)),
295 const auto path = wxPathOnly(libPath.get());
296 SetDllDirectory(path.c_str());
297 auto cleanup =
finally([&]{ SetDllDirectory(
nullptr); });
301 lilv_file_uri_parse(lilv_node_as_uri(lilv_ui_get_bundle_uri(ui)),
nullptr)
304 lilv_file_uri_parse(lilv_node_as_uri(lilv_ui_get_binary_uri(ui)),
nullptr)
309 UIHandler *pHandler =
this;
314 pHandler, containerType,
315 lilv_node_as_uri(lilv_plugin_get_uri(&
mPlug)),
316 lilv_node_as_uri(lilv_ui_get_uri(ui)), lilv_node_as_uri(uiType),
317 bundlePath.get(), binaryPath.get(),
318 features.GetFeaturePointers().data()));
324 if (uiType == node_ExternalUI) {
325 mParent->SetMinSize(wxDefaultSize);
331 const auto widget =
static_cast<WXWidget
>(
334#if defined(__WXGTK__)
337 gtk_widget_show_all(widget);
344 if (!pNativeWin->Create(
mParent, widget))
354 wxSizerItem *si = NULL;
355 auto vs = std::make_unique<wxBoxSizer>(wxVERTICAL);
356 auto hs = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
357 if (features.mNoResize) {
358 si = hs->Add(pNativeWin.get(), 0, wxCENTER);
359 vs->Add(hs.release(), 1, wxCENTER);
361 si = hs->Add(pNativeWin.get(), 1, wxEXPAND);
362 vs->Add(hs.release(), 1, wxEXPAND);
366 mParent->SetSizerAndFit(vs.release());
370 suil_instance_extension_data(
mUI.
mSuilInstance.get(), LV2_UI__idleInterface));
373 suil_instance_extension_data(
mUI.
mSuilInstance.get(), LV2_UI__showInterface));
380#ifdef __WX_EVTLOOP_BUSY_WAITING__
381 wxEventLoop::SetBusyWaiting(
true);
400 wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL | wxTAB_TRAVERSAL);
403 auto outerSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
404 w->SetScrollRate(0, 20);
406 w->SetName(
wxT(
"\a"));
407 w->SetLabel(
wxT(
"\a"));
408 outerSizer->Add(w, 1, wxEXPAND);
410 auto uInnerSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
411 innerSizer = uInnerSizer.get();
415 auto sizer = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
416 auto item =
safenew wxStaticText(w, 0,
_(
"&Duration:"));
417 sizer->Add(item, 0, wxALIGN_CENTER | wxALL, 5);
424 sizer->Add(
mDuration, 0, wxALIGN_CENTER | wxALL, 5);
426 std::make_unique<wxStaticBoxSizer>(wxVERTICAL, w,
_(
"Generator"));
427 groupSizer->Add(sizer.release(), 0, wxALIGN_CENTER | wxALL, 5);
428 innerSizer->Add(groupSizer.release(), 0, wxEXPAND | wxALL, 5);
435 for (
auto &
label: groups) {
436 auto gridSizer = std::make_unique<wxFlexGridSizer>(numCols, 5, 5);
437 gridSizer->AddGrowableCol(3);
439 auto &state = portUIStates.mControlPortStates[p];
440 auto &port = state.mpPort;
442 const auto &value =
values[p];
443 auto labelText = port->mName;
444 if (!port->mUnits.empty())
445 labelText +=
XO(
"(%s)").Format(port->mUnits).Translation();
448 if (port->mTrigger) {
449 gridSizer->Add(1, 1, 0);
453 gridSizer->Add(b, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
456 gridSizer->Add(1, 1, 0);
457 gridSizer->Add(1, 1, 0);
458 gridSizer->Add(1, 1, 0);
463 auto item =
safenew wxStaticText(w, wxID_ANY, labelText +
wxT(
":"),
464 wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
465 gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
471 c->SetName(labelText);
472 c->SetValue(value > 0);
473 gridSizer->Add(c, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
476 gridSizer->Add(1, 1, 0);
477 gridSizer->Add(1, 1, 0);
478 gridSizer->Add(1, 1, 0);
480 else if (port->mEnumeration) {
484 auto s = port->Discretize(value);
486 c->SetName(labelText);
487 c->Append(port->mScaleLabels);
489 gridSizer->Add(c, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
492 gridSizer->Add(1, 1, 0);
493 gridSizer->Add(1, 1, 0);
494 gridSizer->Add(1, 1, 0);
496 else if (!port->mIsInput) {
498 gridSizer->Add(1, 1, 0);
499 gridSizer->Add(1, 1, 0);
502 const auto pOutputValues =
505 pOutputValues ? &pOutputValues->
values[p] : &sink;
508 gridSizer->Add(m, 0, wxALIGN_CENTER_VERTICAL | wxEXPAND);
511 gridSizer->Add(1, 1, 0);
516 t->SetName(labelText);
517 gridSizer->Add(t, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
519 auto rate = port->mSampleRate ?
mSampleRate : 1.0f;
520 state.mLo = port->mMin * rate;
521 state.mHi = port->mMax * rate;
522 state.mTmp = value * rate;
523 if (port->mInteger) {
524 IntegerValidator<float> vld(&state.mTmp);
525 vld.SetRange(state.mLo, state.mHi);
526 t->SetValidator(vld);
529 FloatingPointValidator<float> vld(6, &state.mTmp);
530 vld.SetRange(state.mLo, state.mHi);
533 float range = state.mHi - state.mLo;
534 auto style = range < 10
535 ? NumValidatorStyle::THREE_TRAILING_ZEROES
537 ? NumValidatorStyle::TWO_TRAILING_ZEROES
538 : NumValidatorStyle::ONE_TRAILING_ZERO;
540 t->SetValidator(vld);
546 if (port->mInteger || port->mSampleRate)
550 item =
safenew wxStaticText(w, wxID_ANY,
str);
551 gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
554 gridSizer->Add(1, 1, 0);
558 0, 0, 1000, wxDefaultPosition, { 150, -1 });
559 s->SetName(labelText);
560 gridSizer->Add(s, 0, wxALIGN_CENTER_VERTICAL | wxEXPAND);
566 if (port->mInteger || port->mSampleRate)
570 item =
safenew wxStaticText(w, wxID_ANY,
str);
571 gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
574 gridSizer->Add(1, 1, 0);
578 auto groupSizer = std::make_unique<wxStaticBoxSizer>(
580 groupSizer->Add(gridSizer.release(), 1, wxEXPAND | wxALL, 5);
581 innerSizer->Add(groupSizer.release(), 0, wxEXPAND | wxALL, 5);
584 innerSizer->Layout();
587 auto VisitCells = [&, cnt = innerSizer->GetChildren().GetCount()](
auto f){
590 auto groupSizer = innerSizer->GetItem(i)->GetSizer();
591 auto gridSizer =
static_cast<wxFlexGridSizer *
>(
592 groupSizer->GetItem(
size_t{0})->GetSizer());
593 auto items = gridSizer->GetChildren().GetCount();
594 size_t cols = gridSizer->GetCols();
595 for (
size_t j = 0; j < items; ++j) {
597 auto item = gridSizer->GetItem(j);
604 std::vector<int> widths(numCols);
605 VisitCells([&](wxSizerItem *item,
size_t j,
size_t cols){
606 auto &width = widths[j % cols];
607 width = std::max(width, item->GetSize().GetWidth());
611 VisitCells([&](wxSizerItem *item,
size_t j,
size_t cols){
612 int flags = item->GetFlag();
613 if (flags & wxEXPAND)
615 if (flags & wxALIGN_RIGHT)
616 flags = (flags & ~wxALL) | wxLEFT;
618 flags = (flags & ~wxALL) | wxRIGHT;
619 item->SetFlag(flags);
620 item->SetBorder(widths[j % cols] - item->GetMinSize().GetWidth());
623 w->SetSizer(uInnerSizer.release());
625 mParent->SetSizer(outerSizer.release());
629 wxSize sz1 = innerSizer->GetMinSize();
630 wxSize sz2 =
mParent->GetMinSize();
631 w->SetMinSize( { -1,
std::min(sz1.y, sz2.y) } );
634 mParent->SetMinSize(w->GetMinSize());
644 if (pMaster && mySettings.mpState) {
647 lilv_state_restore(mySettings.mpState.get(), &pMaster->GetInstance(),
648 nullptr,
nullptr, 0,
nullptr);
650 mySettings.mpState.reset();
653 auto &
values = mySettings.values;
656 auto &port = state.mpPort;
671 port->mIndex,
sizeof(
float),
684 for (
auto & param :
params) {
686 auto &port = state.mpPort;
688 auto &value =
values[param];
691 else if (port->mToggle)
692 ctrl.checkbox->SetValue(value > 0);
693 else if (port->mEnumeration)
694 ctrl.choice->SetSelection(port->Discretize(value));
695 else if (port->mIsInput) {
696 state.mTmp = value * (port->mSampleRate ?
mSampleRate : 1.0f);
709 float lo = state.
mLo;
710 float hi = state.
mHi;
711 float val = state.
mTmp;
712 if (state.
mpPort->mLogarithmic) {
717 ctrl.
slider->SetValue(
lrintf((val - lo) / (hi - lo) * 1000.0));
723 const auto currentValue =
settings.values[controlPortIndex];
731 const auto epsilon = 1e-5f;
733 if (std::abs(currentValue - value) < epsilon)
736 settings.values[controlPortIndex] = value;
773 size_t idx = evt.GetId() -
ID_Texts;
775 auto &port = state.mpPort;
777 if (ctrl.mText->GetValidator()->TransferFromWindow()) {
781 port->mSampleRate ? state.mTmp /
mSampleRate : state.mTmp);
792 auto &port = state.mpPort;
793 float lo = state.mLo;
794 float hi = state.mHi;
795 if (port->mLogarithmic) {
799 state.mTmp = (((float) evt.GetInt()) / 1000.0) * (hi - lo) + lo;
800 state.mTmp = std::clamp(state.mTmp, lo, hi);
801 state.mTmp = port->mLogarithmic ? expf(state.mTmp) : state.mTmp;
805 port->mSampleRate ? state.mTmp /
mSampleRate : state.mTmp);
843 if (
auto &atomState = portUIStates.mControlOut) {
844 atomState->SendToDialog([&](
const LV2_Atom *atom, uint32_t
size){
846 atomState->mpPort->mIndex,
size,
848 LV2Symbols::urid_EventTransfer, atom);
859 size_t index = 0;
for (
auto &state : portUIStates.mControlPortStates) {
860 auto &port = state.mpPort;
862 const auto pValue = port->mIsInput
864 : pOutputValues ? &pOutputValues->values[index]
867 auto &value = *pValue;
869 if (value != state.mLst) {
871 port->mIndex,
sizeof(value),
907 mParent->SetMinSize(wxDefaultSize);
909#if defined(__WXGTK__)
918 mDialog->SetMinSize(wxDefaultSize);
951 wxSizeEvent sw{ wxSize{ width, height } };
968 uint32_t buffer_size, uint32_t protocol,
const void *buffer)
971 if (protocol == 0 && buffer_size ==
sizeof(
float)) {
975 const auto value = *
static_cast<const float*
>(buffer);
984 Publish({ size_t(port_index), value });
988 else if (protocol == LV2Symbols::urid_EventTransfer) {
990 auto &atomPortState = portUIStates.
mControlIn;
991 if (atomPortState && port_index == atomPortState->mpPort->mIndex)
992 atomPortState->ReceiveFromDialog(buffer, buffer_size);
998 for (
size_t i = 0, cnt = lilv_plugin_get_num_ports(&
mPlug); i < cnt; ++i) {
999 const auto port = lilv_plugin_get_port_by_index(&
mPlug, i);
1000 if (strcmp(port_symbol,
1001 lilv_node_as_string(lilv_port_get_symbol(&
mPlug, port))) == 0)
1002 return lilv_port_get_index(&
mPlug, port);
1004 return LV2UI_INVALID_PORT_INDEX;
1007#if defined(__WXGTK__)
1026 gtk_widget_set_size_request(widget,
1034 wxSizeEvent se(wxSize(requisition->width, requisition->height));
wxEVT_COMMAND_BUTTON_CLICKED
EffectDistortionSettings params
LV2EffectSettings & GetSettings(EffectSettings &settings)
std::unique_ptr< Type, Lilv_deleter< Type, f > > Lilv_ptr
Generate classes of smart pointers to lv2 resources.
Lilv_ptr< LilvNode, lilv_node_free > LilvNodePtr
Lilv_ptr< char, free_chars > LilvCharsPtr
wxEVT_COMMAND_TEXT_UPDATED
EVT_COMMAND_RANGE(ID_Slider, ID_Slider+99, wxEVT_COMMAND_SLIDER_UPDATED, NyquistEffect::OnSlider) EVT_COMMAND_RANGE(ID_Text
static Settings & settings()
bool TranslationLess(const TranslatableString &a, const TranslatableString &b)
A commonly needed sort comparator, which depends on the language setting.
Base class for many of the effects in Audacity.
Hold values to send to effect output meters.
void ModifySettings(Function &&function)
Do a correct read-modify-write of settings.
virtual const EffectSettings & Get()=0
virtual void Flush()=0
Make the last Set changes "persistent" in underlying storage.
Interface for transferring values from a panel of effect controls.
EffectSettingsAccess & mAccess
static wxString ToDisplayString(double numberToConvert, int digitsAfterDecimalPoint=-1)
Convert a number to a string, uses the user's locale's decimal separator.
UI widget that watches a floating point location and then updates a bar.
const LV2Wrapper * GetMaster() const
LV2AtomPortStatePtr mControlIn
LV2ControlPortStateArray mControlPortStates
std::unordered_map< TranslatableString, std::vector< int > > mGroupMap
TranslatableStrings mGroups
LV2ControlPortArray mControlPorts
std::unordered_map< uint32_t, size_t > mControlPortMap
void OnSize(wxSizeEvent &evt)
NumericTextCtrl * mDuration
const LV2UI_Idle_Interface * mUIIdleInterface
void SetSlider(const LV2ControlPortState &state, const PlainUIControl &ctrl)
std::vector< PlainUIControl > mPlainUIControls
Array in correspondence with the control ports.
bool BuildFancy(std::unique_ptr< LV2Wrapper > pWrapper, const EffectSettings &settings)
bool BuildPlain(EffectSettingsAccess &access)
const EffectOutputs * mpOutputs
std::shared_ptr< SuilHost > mSuilHost
void Disconnect() override
On the first call only, may disconnect from further event handling.
bool ValidateUI() override
Get settings data from the panel; may make error dialogs and return false.
bool UpdateUI() override
Update appearance of the panel for changes in settings.
void OnSlider(wxCommandEvent &evt)
void suil_port_write(uint32_t port_index, uint32_t buffer_size, uint32_t protocol, const void *buffer) override
LV2PortUIStates mPortUIStates
void OnIdle(wxIdleEvent &evt)
wxSize mNativeWinInitialSize
struct LV2Validator::UI mUI
static std::shared_ptr< SuilHost > GetSuilHost()
void OnTrigger(wxCommandEvent &evt)
int ui_resize(int width, int height) override
LV2Validator::Timer mTimer
void OnText(wxCommandEvent &evt)
void OnChoice(wxCommandEvent &evt)
wxSize mNativeWinLastSize
LV2Validator(EffectBase &effect, const LilvPlugin &plug, LV2Instance &instance, EffectSettingsAccess &access, const EffectOutputs *pOutputs, double sampleRate, const LV2FeaturesList &features, const LV2Ports &ports, wxWindow *parent, bool useGUI)
void ui_closed() override
void UpdateControlPortValue(LV2EffectSettings &settings, size_t controlPortIndex, float value)
std::optional< const LV2UIFeaturesList > mUIFeatures
const LV2UI_Show_Interface * mUIShowInterface
void OnToggle(wxCommandEvent &evt)
static void size_request(GtkWidget *widget, GtkRequisition *requisition, LV2Validator *pValidator)
std::unique_ptr< LV2Wrapper > mpWrapper
void SizeRequest(GtkWidget *widget, GtkRequisition *requisition)
wxWeakRef< wxDialog > mDialog
uint32_t suil_port_index(const char *port_symbol) override
void SetName(const TranslatableString &name)
CallbackReturn Publish(const EffectSettingChanged &message)
Send a message to connected callbacks.
wxString Translation() const
#define LV2_EXTERNAL_UI_SHOW(ptr)
#define LV2_EXTERNAL_UI_RUN(ptr)
#define LV2_EXTERNAL_UI__Widget
AuthorizationHandler handler
Externalized state of a plug-in.
Other UI related state of an instance of an LV2 Control port.
float mLo
Lower bound, as scaled by sample rate if that is required.
float mHi
Upper bound, as scaled by sample rate if that is required.
float mTmp
Value of UI control, as scaled by sample rate if that is required.
const LV2ControlPortPtr mpPort
Carry output control port information back to main thread.
std::vector< float > values
vector of values in correspondence with the control ports
Storage locations to be connected to LV2 control ports.
std::vector< float > values
vector of values in correspondence with the control ports
Abstraction of host services that a plug-ins native UI needs.
static uint32_t suil_port_index(SuilController controller, const char *port_symbol)
static void suil_port_write(SuilController controller, uint32_t port_index, uint32_t buffer_size, uint32_t protocol, const void *buffer)
LV2_External_UI_Widget * mExternalWidget
wxWindowPtr< NativeWindow > mNativeWin
SuilInstancePtr mSuilInstance
Options & AutoPos(bool enable)