From 47f8d10de3d8188c6b42b073603763980c777a0f Mon Sep 17 00:00:00 2001 From: Leland Lucius Date: Fri, 17 Jul 2015 23:18:55 -0500 Subject: [PATCH] Round 9 of wx3 changes VST GUI handling greatly simplied on OSX --- src/effects/Effect.cpp | 36 ++-- src/effects/VST/VSTControlOSX.h | 18 +- src/effects/VST/VSTControlOSX.mm | 288 +++++-------------------------- src/effects/VST/VSTEffect.cpp | 78 +++++---- src/effects/VST/VSTEffect.h | 1 + 5 files changed, 108 insertions(+), 313 deletions(-) diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index 7377e60cd..a2fe7f57c 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -53,24 +53,24 @@ greater use in future. #include #endif -static const int kDummyID = 30000; -static const int kSaveAsID = 30001; -static const int kImportID = 30002; -static const int kExportID = 30003; -static const int kDefaultsID = 30004; -static const int kOptionsID = 30005; -static const int kUserPresetsDummyID = 30006; -static const int kDeletePresetDummyID = 30007; -static const int kMenuID = 30100; -static const int kEnableID = 30101; -static const int kPlayID = 30102; -static const int kRewindID = 30103; -static const int kFFwdID = 30104; -static const int kPlaybackID = 30105; -static const int kCaptureID = 30106; -static const int kUserPresetsID = 31000; -static const int kDeletePresetID = 32000; -static const int kFactoryPresetsID = 33000; +static const int kDummyID = 20000; +static const int kSaveAsID = 20001; +static const int kImportID = 20002; +static const int kExportID = 20003; +static const int kDefaultsID = 20004; +static const int kOptionsID = 20005; +static const int kUserPresetsDummyID = 20006; +static const int kDeletePresetDummyID = 20007; +static const int kMenuID = 20100; +static const int kEnableID = 20101; +static const int kPlayID = 20102; +static const int kRewindID = 20103; +static const int kFFwdID = 20104; +static const int kPlaybackID = 20105; +static const int kCaptureID = 20106; +static const int kUserPresetsID = 21000; +static const int kDeletePresetID = 22000; +static const int kFactoryPresetsID = 23000; const wxString Effect::kUserPresetIdent = wxT("User Preset:"); const wxString Effect::kFactoryPresetIdent = wxT("Factory Preset:"); diff --git a/src/effects/VST/VSTControlOSX.h b/src/effects/VST/VSTControlOSX.h index d1ed795d4..353e09e6e 100644 --- a/src/effects/VST/VSTControlOSX.h +++ b/src/effects/VST/VSTControlOSX.h @@ -36,36 +36,22 @@ public: bool Create(wxWindow *parent, VSTEffectLink *link); +private: void CreateCocoa(); - void CocoaViewResized(); - - void OnSize(wxSizeEvent & evt); #if !defined(_LP64) void CreateCarbon(); - void CreateCarbonOverlay(); - void CarbonViewResized(); - static pascal OSStatus ControlEventHandlerCallback(EventHandlerCallRef handler, - EventRef event, - void *data); + void OnSize(wxSizeEvent & evt); #endif private: NSView *mVSTView; NSView *mView; - wxSize mLastMin; - bool mSettingSize; - #if !defined(_LP64) - WindowRef mWindowRef; - WindowRef mPreviousRef; HIViewRef mHIView; - #endif - - DECLARE_EVENT_TABLE(); }; #endif diff --git a/src/effects/VST/VSTControlOSX.mm b/src/effects/VST/VSTControlOSX.mm index 25ae773c9..c04c29a13 100644 --- a/src/effects/VST/VSTControlOSX.mm +++ b/src/effects/VST/VSTControlOSX.mm @@ -25,7 +25,6 @@ @interface VSTView : NSView { - VSTControl *mControl; } @end @@ -40,29 +39,6 @@ wxOSXCocoaClassAddWXMethods(self); } } - -- (instancetype)initWithControl:(VSTControl *)control -{ - // Make sure a parameters were provided - NSParameterAssert(control); - - mControl = control; - - [super init]; - - return self; -} - -- (BOOL)autoresizesSubviews -{ - return NO; -} - -- (void)cocoaViewResized:(NSNotification *)notification -{ - mControl->CocoaViewResized(); -} - @end VSTControlImpl::VSTControlImpl(wxWindowMac *peer, NSView *view) @@ -74,33 +50,27 @@ VSTControlImpl::~VSTControlImpl() { } -BEGIN_EVENT_TABLE(VSTControl, VSTControlBase) - EVT_SIZE(VSTControl::OnSize) -END_EVENT_TABLE() - VSTControl::VSTControl() : VSTControlBase() { mVSTView = nil; mView = nil; - mSettingSize = false; - #if !defined(_LP64) mHIView = NULL; mWindowRef = NULL; - #endif } VSTControl::~VSTControl() { +#if !defined(_LP64) if (mWindowRef) { mLink->callDispatcher(effEditClose, 0, 0, mWindowRef, 0.0); mWindowRef = 0; } - +#endif } bool VSTControl::Create(wxWindow *parent, VSTEffectLink *link) @@ -117,9 +87,11 @@ bool VSTControl::Create(wxWindow *parent, VSTEffectLink *link) { return false; } - [(VSTView *)mVSTView initWithControl:this]; + [mVSTView init]; [mVSTView retain]; + SetPeer(new VSTControlImpl(this, mVSTView)); + CreateCocoa(); #if !defined(_LP64) @@ -128,18 +100,12 @@ bool VSTControl::Create(wxWindow *parent, VSTEffectLink *link) CreateCarbon(); } #endif + if (!mView && !mHIView) { return false; } - SetPeer(new VSTControlImpl(this, mVSTView)); - - if (mHIView) - { - CreateCarbonOverlay(); - } - // Must get the size again since SetPeer() could cause it to change SetInitialSize(GetMinSize()); @@ -148,78 +114,18 @@ bool VSTControl::Create(wxWindow *parent, VSTEffectLink *link) return true; } -void VSTControl::OnSize(wxSizeEvent & evt) -{ - evt.Skip(); - - if (mSettingSize) - { - return; - } - mSettingSize = true; - - wxSize sz = GetSize(); - - if (mView) - { - int mask = [mView autoresizingMask]; - - NSRect viewFrame = [mVSTView frame]; - NSRect viewRect = [mView frame]; - - if (mask & NSViewWidthSizable) - { - viewRect.size.width = sz.GetWidth(); - } - - if (mask & NSViewHeightSizable) - { - viewRect.size.height = sz.GetHeight(); - } - - viewRect.origin.x = (viewFrame.size.width - viewRect.size.width) / 2; - viewRect.origin.y = (viewFrame.size.height - viewRect.size.height) / 2; - - [mView setFrame:viewRect]; - } - -#if !defined(_LP64) - else if (mHIView) - { - HIRect rect; - HIViewGetFrame(mHIView, &rect); - - CGFloat x = (sz.x - rect.size.width) / 2; - CGFloat y = (sz.y - rect.size.height) / 2; - - SizeWindow(mWindowRef, sz.x, sz.y, true); - HIViewPlaceInSuperviewAt(mHIView, x, y); - - wxWindow *w = wxGetTopLevelParent(this); - - wxSize min = w->GetMinSize(); - min.x += (rect.size.width - mLastMin.GetWidth()); - min.y += (rect.size.height - mLastMin.GetHeight()); - - w->SetSizeHints(min, min); - - mLastMin = wxSize(rect.size.width, rect.size.height); - } -#endif - - mSettingSize = false; - - return; -} - void VSTControl::CreateCocoa() { - bool mIsCocoa = (mLink->callDispatcher(effCanDo, 0, 0, (void *) "hasCockosViewAsConfig", 0.0) & 0xffff0000) == 0xbeef0000; - if (!mIsCocoa) + if ((mLink->callDispatcher(effCanDo, 0, 0, (void *) "hasCockosViewAsConfig", 0.0) & 0xffff0000) != 0xbeef0000) { return; } + VstRect *rect; + + // Some effects like to have us get their rect before opening them. + mLink->callDispatcher(effEditGetRect, 0, 0, &rect, 0.0); + // Ask the effect to add its GUI mLink->callDispatcher(effEditOpen, 0, 0, mVSTView, 0.0); @@ -234,78 +140,35 @@ void VSTControl::CreateCocoa() return; } - NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; - [center addObserver:mVSTView - selector:@selector(cocoaViewResized:) - name:NSViewFrameDidChangeNotification - object:mView]; + // Get the final bounds of the effect GUI + mLink->callDispatcher(effEditGetRect, 0, 0, &rect, 0.0); + + NSRect frame = { 0, 0, rect->right - rect->left, rect->bottom - rect->top }; + + [mView setFrame:frame]; [mVSTView addSubview:mView]; - NSSize viewSize = [mView frame].size; - - mLastMin = wxSize(viewSize.width, viewSize.height); - - SetMinSize(mLastMin); - - [mVSTView setAutoresizingMask:[mView autoresizingMask]]; + SetMinSize(wxSize(frame.size.width, frame.size.height)); return; } -void VSTControl::CocoaViewResized() -{ - if (mSettingSize) - { - return; - } - - NSSize viewSize = [mView frame].size; - NSSize frameSize = [mVSTView frame].size; - - [mVSTView setFrameSize:viewSize]; - - int diffW = (viewSize.width - frameSize.width); - int diffH = (viewSize.height - frameSize.height); - - wxWindow *w = wxGetTopLevelParent(this); - - wxSize min = w->GetMinSize(); - if ([mView autoresizingMask] == NSViewNotSizable) - { - min.x += (viewSize.width - mLastMin.GetWidth()); - min.y += (viewSize.height - mLastMin.GetHeight()); - mLastMin = wxSize(viewSize.width, viewSize.height);; - } - else - { - min.x += diffW; - min.y += diffH; - } - w->SetMinSize(min); - - wxSize size = w->GetSize(); - size.x += diffW; - size.y += diffH; - w->SetSize(size); -} - #if !defined(_LP64) void VSTControl::CreateCarbon() { OSStatus result; - struct - { - short top, left, bottom, right; - } *rect; + Connect(wxEVT_SIZE, wxSizeEventHandler(VSTControl::OnSize)); + + VstRect *rect; // Some effects like to have us get their rect before opening them. mLink->callDispatcher(effEditGetRect, 0, 0, &rect, 0.0); // Suggest a dummy size - Rect bounds = { 100, 100, 200, 200 }; + Rect bounds = { 0, 0, 0, 0 }; // And create the window result = CreateNewWindow(kOverlayWindowClass, @@ -330,11 +193,9 @@ void VSTControl::CreateCarbon() DisposeWindow(mWindowRef); mWindowRef = NULL; - return nil; + return; } - SetWindowActivationScope(mWindowRef, kWindowActivationScopeIndependent); - // Some effects (iZotope Vinyl) seem to need an existing subview // of the content view. So just use a "dummy" scrollview. result = HIScrollViewCreate(kHIScrollViewOptionsVertScroll, &mHIView); @@ -352,12 +213,11 @@ void VSTControl::CreateCarbon() HIViewRef subview = HIViewGetFirstSubview(content); if (subview) { - // The scrollview was used, so it leave it. + // The scrollview was used, so leave it. if (subview == mHIView) { subview = HIViewGetFirstSubview(mHIView); } - // The effect didn't use our scrollview, so dispose of it. else { @@ -373,6 +233,11 @@ void VSTControl::CreateCarbon() // just fall back to the textual interface. if (subview == NULL) { + mLink->callDispatcher(effEditClose, 0, 0, mWindowRef, 0.0); + DisposeWindow(mWindowRef); + mWindowRef = NULL; + mHIView = NULL; + return; } @@ -381,97 +246,36 @@ void VSTControl::CreateCarbon() // Set the size of the scrollview to match HIRect r = { 0, 0, rect->right - rect->left, rect->bottom - rect->top }; + + // One effect, mutagene lipredemuco, doesn't return a valid rect so + // try to detect it and use the created view dimensions instead. + if (rect->left < 0 || rect->top < 0 || rect->right <= 0 || rect->bottom <= 0) + { + HIViewGetFrame(subview, &r); + } + + // Make sure container is the same size as the effect GUI HIViewSetFrame(mHIView, &r); + HIViewPlaceInSuperviewAt(mHIView, 0, 0); - // Make sure it can be seen - HIViewSetVisible(mHIView, TRUE); - + // Establish the minimum size SetMinSize(wxSize(r.size.width, r.size.height)); - mLastMin = GetMinSize(); - - EventTypeSpec controlEventList[] = - { - {kEventClassControl, kEventControlBoundsChanged}, - }; - - InstallControlEventHandler(mHIView, - ControlEventHandlerCallback, - GetEventTypeCount(controlEventList), - controlEventList, - (void *) this, - NULL); - - return; -} - -void VSTControl::CreateCarbonOverlay() -{ NSWindow *parent = [mVSTView window]; - WindowRef parentRef = (WindowRef)[parent windowRef]; - NSWindow *host = [[[NSWindow alloc] initWithWindowRef:mWindowRef] autorelease]; [parent addChildWindow:host ordered:NSWindowAbove]; - WindowGroupRef group; - - CreateWindowGroup(0, &group); - SetWindowGroupParent(group, GetWindowGroup(parentRef)); - ChangeWindowGroupAttributes(group, - kWindowGroupAttrLayerTogether | - kWindowGroupAttrSharedActivation | - kWindowGroupAttrHideOnCollapse, - 0); - SetWindowGroup(parentRef, group); - SetWindowGroup(mWindowRef, group); - - Rect location; - GetWindowBounds(parentRef, kWindowContentRgn, &location); - MoveWindow(mWindowRef, location.left, location.top, true); ShowWindow(mWindowRef); } -pascal OSStatus -VSTControl::ControlEventHandlerCallback(EventHandlerCallRef handler, EventRef event, void *data) +void VSTControl::OnSize(wxSizeEvent & evt) { - ((VSTControl *) data)->CarbonViewResized(); + evt.Skip(); - return eventNotHandledErr; -} + wxRect rect = GetScreenRect(); -void VSTControl::CarbonViewResized() -{ - if (mSettingSize) - { - return; - } - - // resize and move window - HIRect rect; - HIViewGetFrame(mHIView, &rect); - - HIViewPlaceInSuperviewAt(mHIView, 0, 0); - SizeWindow(mWindowRef, rect.size.width, rect.size.height, true); - - NSSize frameSize = [mVSTView frame].size; - - [mVSTView setFrameSize:NSMakeSize(rect.size.width, rect.size.height)]; - - wxWindow *w = wxGetTopLevelParent(this); - wxSize size = w->GetSize(); - size.x += (rect.size.width - frameSize.width); - size.y += (rect.size.height - frameSize.height); - - // Reset the current max/min - w->SetSizeHints(wxDefaultSize, wxDefaultSize); - - // Set the dialog size - w->SetSize(size); - - // And finally set the new max/min - w->SetSizeHints(size, size); - - mLastMin = wxSize(rect.size.width, rect.size.height); + MoveWindow(mWindowRef, rect.x, rect.y, true); + SizeWindow(mWindowRef, rect.width, rect.height, true); } #endif diff --git a/src/effects/VST/VSTEffect.cpp b/src/effects/VST/VSTEffect.cpp index caba60a6a..795534590 100644 --- a/src/effects/VST/VSTEffect.cpp +++ b/src/effects/VST/VSTEffect.cpp @@ -2803,46 +2803,27 @@ void VSTEffect::BuildFancy() // Turn the power on...some effects need this when the editor is open PowerOn(); + mControl = new VSTControl; + if (!mControl) + { + return; + } + + if (!mControl->Create(mParent, this)) + { + return; + } + wxBoxSizer *mainSizer = new wxBoxSizer(wxVERTICAL); - wxPanel *container = new wxPanel(mParent, wxID_ANY); - mainSizer->Add(container, 1, wxEXPAND); + mainSizer->Add(mControl, 0, wxALIGN_CENTER); + mParent->SetMinSize(wxDefaultSize); mParent->SetSizer(mainSizer); -#if 0 - if (mUIType == wxT("Plain")) - { - if (!CreatePlain(mParent)) - { - return false; - } - } - else -#endif - { - mControl = new VSTControl; - if (!mControl) - { - return; - } - - if (!mControl->Create(container, this)) - { - return; - } - - wxBoxSizer *innerSizer = new wxBoxSizer(wxVERTICAL); - - innerSizer->Add(mControl, 0, wxALIGN_CENTER); - container->SetSizer(innerSizer); - - mParent->SetMinSize(wxDefaultSize); - } - NeedEditIdle(true); -// mParent->PushEventHandler(this); + mDialog->Connect(wxEVT_SIZE, wxSizeEventHandler(VSTEffect::OnSize)); return; } @@ -3017,6 +2998,24 @@ void VSTEffect::RefreshParameters(int skip) } } +void VSTEffect::OnSize(wxSizeEvent & evt) +{ + evt.Skip(); + + // Once the parent dialog reaches it's final size as indicated by + // a non-default minimum size, we set the maximum size to match. + // This is a bit of a hack to prevent VSTs GUI windows from resizing + // there's no real reason to allow it. But, there should be a better + // way of handling it. + wxWindow *w = (wxWindow *) evt.GetEventObject(); + wxSize sz = w->GetMinSize(); + + if (sz != wxDefaultSize) + { + w->SetMaxSize(sz); + } +} + void VSTEffect::OnSizeWindow(wxCommandEvent & evt) { if (!mControl) @@ -3024,13 +3023,18 @@ void VSTEffect::OnSizeWindow(wxCommandEvent & evt) return; } - // This really needs some work. We shouldn't know anything about the parent... mControl->SetMinSize(wxSize(evt.GetInt(), (int) evt.GetExtraLong())); mControl->SetSize(wxSize(evt.GetInt(), (int) evt.GetExtraLong())); - mParent->SetMinSize(wxDefaultSize); - mDialog->SetMinSize(wxDefaultSize); -// mParent->SetMinSize(mControl->GetMinSize()); + + // DO NOT CHANGE THE ORDER OF THESE + // + // Guitar Rig (and possibly others) Cocoa VSTs can resize too large + // if the bounds are unlimited. + mDialog->SetMinSize(wxDefaultSize); + mDialog->SetMaxSize(wxDefaultSize); mDialog->Layout(); + mDialog->SetMinSize(mDialog->GetBestSize()); + mDialog->SetMaxSize(mDialog->GetBestSize()); mDialog->Fit(); } diff --git a/src/effects/VST/VSTEffect.h b/src/effects/VST/VSTEffect.h index 5a69dfc31..e3c8f38bd 100644 --- a/src/effects/VST/VSTEffect.h +++ b/src/effects/VST/VSTEffect.h @@ -183,6 +183,7 @@ private: // UI void OnSlider(wxCommandEvent & evt); + void OnSize(wxSizeEvent & evt); void OnSizeWindow(wxCommandEvent & evt); void OnUpdateDisplay(wxCommandEvent & evt);