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>
39#include <wx/stattext.h>
40#include <wx/textctrl.h>
42#include <wx/scrolwin.h>
44#include "../../widgets/valnum.h"
46#include "../../widgets/NumericTextCtrl.h"
61 ?
static_cast<WXWidget
>(suil_instance_get_widget(
mSuilInstance.get()))
81 wxMacAutoreleasePool pool;
91 int count = CFGetRetainCount(widget);
108 const LV2Ports &ports, wxWindow *parent,
bool useGUI
121 mParent->PushEventHandler(
this);
134BEGIN_EVENT_TABLE(
LV2Editor, wxEvtHandler)
167 pMeter->Disconnect();
193 static std::weak_ptr<SuilHost> sSuilHost;
194 std::shared_ptr<SuilHost> result = sSuilHost.lock();
197 sSuilHost = result = SuilHostPtr{ suil_host_new(
207 auto &wrapper = *pWrapper;
211 const char *nativeType =
212#if defined(__WXGTK3__)
214#elif defined(__WXGTK__)
216#elif defined(__WXMSW__)
218#elif defined(__WXMAC__)
223 const LilvUI *ui =
nullptr;
224 const LilvNode *uiType =
nullptr;
226 LilvUIsPtr uis{ lilv_plugin_get_uis(&
mPlug) };
229 LILV_FOREACH(uis, iter, uis.get()) {
230 ui = lilv_uis_get(uis.get(), iter);
231 if (lilv_ui_is_supported(ui,
232 suil_ui_supported, containerType.get(), &uiType))
234 if (lilv_ui_is_a(ui, node_Gtk) || lilv_ui_is_a(ui, node_Gtk3)) {
245 LILV_FOREACH(uis, iter, uis.get()) {
246 ui = lilv_uis_get(uis.get(), iter);
247 if (lilv_ui_is_a(ui, node_ExternalUI) || lilv_ui_is_a(ui, node_ExternalUIOld)) {
248 uiType = node_ExternalUI;
259 const auto uinode = lilv_ui_get_uri(ui);
260 lilv_world_load_resource(
gWorld, uinode);
262 auto &instance = wrapper.GetInstance();
264 wrapper.GetFeatures(), &
handler, uinode, &instance,
265 (uiType == node_ExternalUI) ?
nullptr :
mParent);
269 const char *containerType;
270 if (uiType == node_ExternalUI)
273 containerType = nativeType;
274#if defined(__WXGTK__)
276 if (!gtk_widget_get_window(GTK_WIDGET(
mParent->m_wxwindow)))
277 gtk_widget_realize(GTK_WIDGET(
mParent->m_wxwindow));
289#if defined(__WXMSW__)
293 lilv_file_uri_parse(lilv_node_as_uri(lilv_ui_get_binary_uri(ui)),
296 const auto path = wxPathOnly(libPath.get());
297 SetDllDirectory(path.c_str());
298 auto cleanup =
finally([&]{ SetDllDirectory(
nullptr); });
302 lilv_file_uri_parse(lilv_node_as_uri(lilv_ui_get_bundle_uri(ui)),
nullptr)
305 lilv_file_uri_parse(lilv_node_as_uri(lilv_ui_get_binary_uri(ui)),
nullptr)
310 UIHandler *pHandler =
this;
315 pHandler, containerType,
316 lilv_node_as_uri(lilv_plugin_get_uri(&
mPlug)),
317 lilv_node_as_uri(lilv_ui_get_uri(ui)), lilv_node_as_uri(uiType),
318 bundlePath.get(), binaryPath.get(),
319 features.GetFeaturePointers().data()));
325 if (uiType == node_ExternalUI) {
326 mParent->SetMinSize(wxDefaultSize);
332 const auto widget =
static_cast<WXWidget
>(
335#if defined(__WXGTK__)
338 gtk_widget_show_all(widget);
345 if (!pNativeWin->Create(
mParent, widget))
355 wxSizerItem *si = NULL;
356 auto vs = std::make_unique<wxBoxSizer>(wxVERTICAL);
357 auto hs = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
358 if (features.mNoResize) {
359 si = hs->Add(pNativeWin.get(), 0, wxCENTER);
360 vs->Add(hs.release(), 1, wxCENTER);
362 si = hs->Add(pNativeWin.get(), 1, wxEXPAND);
363 vs->Add(hs.release(), 1, wxEXPAND);
367 mParent->SetSizerAndFit(vs.release());
371 suil_instance_extension_data(
mUI.
mSuilInstance.get(), LV2_UI__idleInterface));
374 suil_instance_extension_data(
mUI.
mSuilInstance.get(), LV2_UI__showInterface));
381#ifdef __WX_EVTLOOP_BUSY_WAITING__
382 wxEventLoop::SetBusyWaiting(
true);
401 wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL | wxTAB_TRAVERSAL);
404 auto outerSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
405 w->SetScrollRate(0, 20);
407 w->SetName(
wxT(
"\a"));
408 w->SetLabel(
wxT(
"\a"));
409 outerSizer->Add(w, 1, wxEXPAND);
411 auto uInnerSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
412 innerSizer = uInnerSizer.get();
416 auto sizer = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
417 auto item =
safenew wxStaticText(w, 0,
_(
"&Duration:"));
418 sizer->Add(item, 0, wxALIGN_CENTER | wxALL, 5);
426 sizer->Add(
mDuration, 0, wxALIGN_CENTER | wxALL, 5);
428 std::make_unique<wxStaticBoxSizer>(wxVERTICAL, w,
_(
"Generator"));
429 groupSizer->Add(sizer.release(), 0, wxALIGN_CENTER | wxALL, 5);
430 innerSizer->Add(groupSizer.release(), 0, wxEXPAND | wxALL, 5);
437 for (
auto &
label: groups) {
438 auto gridSizer = std::make_unique<wxFlexGridSizer>(numCols, 5, 5);
439 gridSizer->AddGrowableCol(3);
441 auto &state = portUIStates.mControlPortStates[p];
442 auto &port = state.mpPort;
444 const auto &value =
values[p];
445 auto labelText = port->mName;
446 if (!port->mUnits.empty())
447 labelText +=
XO(
"(%s)").Format(port->mUnits).Translation();
450 if (port->mTrigger) {
451 gridSizer->Add(1, 1, 0);
455 gridSizer->Add(b, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
458 gridSizer->Add(1, 1, 0);
459 gridSizer->Add(1, 1, 0);
460 gridSizer->Add(1, 1, 0);
465 auto item =
safenew wxStaticText(w, wxID_ANY, labelText +
wxT(
":"),
466 wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
467 gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
473 c->SetName(labelText);
474 c->SetValue(value > 0);
475 gridSizer->Add(c, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
478 gridSizer->Add(1, 1, 0);
479 gridSizer->Add(1, 1, 0);
480 gridSizer->Add(1, 1, 0);
482 else if (port->mEnumeration) {
486 auto s = port->Discretize(value);
488 c->SetName(labelText);
489 c->Append(port->mScaleLabels);
491 gridSizer->Add(c, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
494 gridSizer->Add(1, 1, 0);
495 gridSizer->Add(1, 1, 0);
496 gridSizer->Add(1, 1, 0);
498 else if (!port->mIsInput) {
500 gridSizer->Add(1, 1, 0);
501 gridSizer->Add(1, 1, 0);
504 const auto pOutputValues =
507 pOutputValues ? &pOutputValues->
values[p] : &sink;
510 gridSizer->Add(m, 0, wxALIGN_CENTER_VERTICAL | wxEXPAND);
513 gridSizer->Add(1, 1, 0);
518 t->SetName(labelText);
519 gridSizer->Add(t, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
521 auto rate = port->mSampleRate ?
mSampleRate : 1.0f;
522 state.mLo = port->mMin * rate;
523 state.mHi = port->mMax * rate;
524 state.mTmp = value * rate;
525 if (port->mInteger) {
526 IntegerValidator<float> vld(&state.mTmp);
527 vld.SetRange(state.mLo, state.mHi);
528 t->SetValidator(vld);
531 FloatingPointValidator<float> vld(6, &state.mTmp);
532 vld.SetRange(state.mLo, state.mHi);
535 float range = state.mHi - state.mLo;
536 auto style = range < 10
537 ? NumValidatorStyle::THREE_TRAILING_ZEROES
539 ? NumValidatorStyle::TWO_TRAILING_ZEROES
540 : NumValidatorStyle::ONE_TRAILING_ZERO;
542 t->SetValidator(vld);
548 if (port->mInteger || port->mSampleRate)
552 item =
safenew wxStaticText(w, wxID_ANY,
str);
553 gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
556 gridSizer->Add(1, 1, 0);
560 0, 0, 1000, wxDefaultPosition, { 150, -1 });
561 s->SetName(labelText);
562 gridSizer->Add(s, 0, wxALIGN_CENTER_VERTICAL | wxEXPAND);
568 if (port->mInteger || port->mSampleRate)
572 item =
safenew wxStaticText(w, wxID_ANY,
str);
573 gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
576 gridSizer->Add(1, 1, 0);
580 auto groupSizer = std::make_unique<wxStaticBoxSizer>(
582 groupSizer->Add(gridSizer.release(), 1, wxEXPAND | wxALL, 5);
583 innerSizer->Add(groupSizer.release(), 0, wxEXPAND | wxALL, 5);
586 innerSizer->Layout();
589 auto VisitCells = [&, cnt = innerSizer->GetChildren().GetCount()](
auto f){
592 auto groupSizer = innerSizer->GetItem(i)->GetSizer();
593 auto gridSizer =
static_cast<wxFlexGridSizer *
>(
594 groupSizer->GetItem(
size_t{0})->GetSizer());
595 auto items = gridSizer->GetChildren().GetCount();
596 size_t cols = gridSizer->GetCols();
597 for (
size_t j = 0; j < items; ++j) {
599 auto item = gridSizer->GetItem(j);
606 std::vector<int> widths(numCols);
607 VisitCells([&](wxSizerItem *item,
size_t j,
size_t cols){
608 auto &width = widths[j % cols];
609 width = std::max(width, item->GetSize().GetWidth());
613 VisitCells([&](wxSizerItem *item,
size_t j,
size_t cols){
614 int flags = item->GetFlag();
615 if (flags & wxEXPAND)
617 if (flags & wxALIGN_RIGHT)
618 flags = (flags & ~wxALL) | wxLEFT;
620 flags = (flags & ~wxALL) | wxRIGHT;
621 item->SetFlag(flags);
622 item->SetBorder(widths[j % cols] - item->GetMinSize().GetWidth());
625 w->SetSizer(uInnerSizer.release());
627 mParent->SetSizer(outerSizer.release());
631 wxSize sz1 = innerSizer->GetMinSize();
632 wxSize sz2 =
mParent->GetMinSize();
633 w->SetMinSize( { -1,
std::min(sz1.y, sz2.y) } );
636 mParent->SetMinSize(w->GetMinSize());
646 if (pMaster && mySettings.mpState) {
649 lilv_state_restore(mySettings.mpState.get(), &pMaster->GetInstance(),
650 nullptr,
nullptr, 0,
nullptr);
652 mySettings.mpState.reset();
655 auto &
values = mySettings.values;
658 auto &port = state.mpPort;
673 port->mIndex,
sizeof(
float),
686 for (
auto & param :
params) {
688 auto &port = state.mpPort;
690 auto &value =
values[param];
693 else if (port->mToggle)
694 ctrl.checkbox->SetValue(value > 0);
695 else if (port->mEnumeration)
696 ctrl.choice->SetSelection(port->Discretize(value));
697 else if (port->mIsInput) {
698 state.mTmp = value * (port->mSampleRate ?
mSampleRate : 1.0f);
711 float lo = state.
mLo;
712 float hi = state.
mHi;
713 float val = state.
mTmp;
714 if (state.
mpPort->mLogarithmic) {
719 ctrl.
slider->SetValue(
lrintf((val - lo) / (hi - lo) * 1000.0));
725 const auto currentValue =
settings.values[controlPortIndex];
733 const auto epsilon = 1e-5f;
735 if (std::abs(currentValue - value) < epsilon)
738 settings.values[controlPortIndex] = value;
775 size_t idx = evt.GetId() -
ID_Texts;
777 auto &port = state.mpPort;
779 if (ctrl.mText->GetValidator()->TransferFromWindow()) {
783 port->mSampleRate ? state.mTmp /
mSampleRate : state.mTmp);
794 auto &port = state.mpPort;
795 float lo = state.mLo;
796 float hi = state.mHi;
797 if (port->mLogarithmic) {
801 state.mTmp = (((float) evt.GetInt()) / 1000.0) * (hi - lo) + lo;
802 state.mTmp = std::clamp(state.mTmp, lo, hi);
803 state.mTmp = port->mLogarithmic ? expf(state.mTmp) : state.mTmp;
807 port->mSampleRate ? state.mTmp /
mSampleRate : state.mTmp);
845 if (
auto &atomState = portUIStates.mControlOut) {
846 atomState->SendToDialog([&](
const LV2_Atom *atom, uint32_t
size){
848 atomState->mpPort->mIndex,
size,
850 LV2Symbols::urid_EventTransfer, atom);
861 size_t index = 0;
for (
auto &state : portUIStates.mControlPortStates) {
862 auto &port = state.mpPort;
864 const auto pValue = port->mIsInput
866 : pOutputValues ? &pOutputValues->values[index]
869 auto &value = *pValue;
871 if (value != state.mLst) {
873 port->mIndex,
sizeof(value),
909 mParent->SetMinSize(wxDefaultSize);
911#if defined(__WXGTK__)
920 mDialog->SetMinSize(wxDefaultSize);
953 wxSizeEvent sw{ wxSize{ width, height } };
970 uint32_t buffer_size, uint32_t protocol,
const void *buffer)
973 if (protocol == 0 && buffer_size ==
sizeof(
float)) {
977 const auto value = *
static_cast<const float*
>(buffer);
986 Publish({ size_t(port_index), value });
990 else if (protocol == LV2Symbols::urid_EventTransfer) {
992 auto &atomPortState = portUIStates.
mControlIn;
993 if (atomPortState && port_index == atomPortState->mpPort->mIndex)
994 atomPortState->ReceiveFromDialog(buffer, buffer_size);
1000 for (
size_t i = 0, cnt = lilv_plugin_get_num_ports(&
mPlug); i < cnt; ++i) {
1001 const auto port = lilv_plugin_get_port_by_index(&
mPlug, i);
1002 if (strcmp(port_symbol,
1003 lilv_node_as_string(lilv_port_get_symbol(&
mPlug, port))) == 0)
1004 return lilv_port_get_index(&
mPlug, port);
1006 return LV2UI_INVALID_PORT_INDEX;
1009#if defined(__WXGTK__)
1028 gtk_widget_set_size_request(widget,
1036 wxSizeEvent se(wxSize(requisition->width, requisition->height));
wxEVT_COMMAND_BUTTON_CLICKED
EffectDistortionSettings params
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
const NumericConverterType & NumericConverterType_TIME()
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.
EffectSettingsAccess & mAccess
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.
static FormatterContext SampleRateContext(double sampleRate)
static wxString ToDisplayString(double numberToConvert, int digitsAfterDecimalPoint=-1)
Convert a number to a string, uses the user's locale's decimal separator.
wxWeakRef< wxDialog > mDialog
bool ValidateUI() override
Get settings data from the panel; may make error dialogs and return false.
void OnIdle(wxIdleEvent &evt)
LV2PortUIStates mPortUIStates
wxSize mNativeWinLastSize
std::shared_ptr< SuilHost > mSuilHost
void OnChoice(wxCommandEvent &evt)
std::vector< PlainUIControl > mPlainUIControls
Array in correspondence with the control ports.
std::unique_ptr< LV2Wrapper > mpWrapper
LV2Editor(const StatelessEffectUIServices &effect, EffectType type, const LilvPlugin &plug, LV2Instance &instance, EffectSettingsAccess &access, const EffectOutputs *pOutputs, double sampleRate, const LV2FeaturesList &features, const LV2Ports &ports, wxWindow *parent, bool useGUI)
static void size_request(GtkWidget *widget, GtkRequisition *requisition, LV2Editor *pEditor)
void OnSlider(wxCommandEvent &evt)
void OnTrigger(wxCommandEvent &evt)
bool UpdateUI() override
Update appearance of the panel for changes in settings.
bool BuildFancy(std::unique_ptr< LV2Wrapper > pWrapper, const EffectSettings &settings)
void OnSize(wxSizeEvent &evt)
void OnToggle(wxCommandEvent &evt)
void suil_port_write(uint32_t port_index, uint32_t buffer_size, uint32_t protocol, const void *buffer) override
void ui_closed() override
void UpdateControlPortValue(LV2EffectSettings &settings, size_t controlPortIndex, float value)
const EffectOutputs * mpOutputs
void SizeRequest(GtkWidget *widget, GtkRequisition *requisition)
uint32_t suil_port_index(const char *port_symbol) override
std::optional< const LV2UIFeaturesList > mUIFeatures
void OnText(wxCommandEvent &evt)
int ui_resize(int width, int height) override
NumericTextCtrl * mDuration
static std::shared_ptr< SuilHost > GetSuilHost()
const LV2UI_Show_Interface * mUIShowInterface
const LV2UI_Idle_Interface * mUIIdleInterface
wxSize mNativeWinInitialSize
void SetSlider(const LV2ControlPortState &state, const PlainUIControl &ctrl)
bool BuildPlain(EffectSettingsAccess &access)
void Disconnect() override
On the first call only, may disconnect from further event handling.
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 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
constexpr auto sampleRate
DynamicRangeProcessorSettings GetSettings(EffectSettingsAccess &access)
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
LV2_External_UI_Widget * mExternalWidget
wxWindowPtr< NativeWindow > mNativeWin
SuilInstancePtr mSuilInstance
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.
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)
Options & AutoPos(bool enable)