/* * VSTEditor.cpp * ------------- * Purpose: Implementation of the custom plugin editor window that is used if a plugin provides an own editor GUI. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "resource.h" #include "Vstplug.h" #include "VSTEditor.h" OPENMPT_NAMESPACE_BEGIN #ifdef MPT_WITH_VST BEGIN_MESSAGE_MAP(COwnerVstEditor, CAbstractVstEditor) ON_WM_ERASEBKGND() ON_WM_PAINT() // Messages from plugin bridge to check whether a key would be handled by OpenMPT // We need an offset to WM_USER because the editor window receives some spurious WM_USER messages (from MFC?) when it gets activated ON_MESSAGE(WM_USER + 4000 + WM_KEYDOWN - WM_KEYFIRST, &COwnerVstEditor::OnPreTranslateKeyDown) ON_MESSAGE(WM_USER + 4000 + WM_KEYUP - WM_KEYFIRST, &COwnerVstEditor::OnPreTranslateKeyUp) ON_MESSAGE(WM_USER + 4000 + WM_SYSKEYDOWN - WM_KEYFIRST, &COwnerVstEditor::OnPreTranslateSysKeyDown) ON_MESSAGE(WM_USER + 4000 + WM_SYSKEYUP - WM_KEYFIRST, &COwnerVstEditor::OnPreTranslateSysKeyUp) END_MESSAGE_MAP() void COwnerVstEditor::OnPaint() { CAbstractVstEditor::OnPaint(); auto &plugin = static_cast(m_VstPlugin); if(plugin.isBridged) { // Force redrawing for the plugin window in the bridged process. // Otherwise, bridged plugin GUIs will not always be refreshed properly (e.g. when restoring OpenMPT from minimized state). // Synth1 is a good candidate for testing this behaviour. CRect rect; if(m_plugWindow.GetUpdateRect(&rect, FALSE)) { CWnd *child = m_plugWindow.GetWindow(GW_CHILD | GW_HWNDFIRST); if(child) child->RedrawWindow(&rect, nullptr, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW); } } else { // For plugins that change their size without telling the host through audioMasterSizeWindow, e.g. Roland D-50 CRect rect; m_plugWindow.GetClientRect(rect); if(rect.Width() != m_width || rect.Height() != m_height) { SetSize(rect.Width(), rect.Height()); } } } void COwnerVstEditor::UpdateParamDisplays() { CAbstractVstEditor::UpdateParamDisplays(); // We trust that the plugin GUI can update its display with a bit of idle time. static_cast(m_VstPlugin).Dispatch(Vst::effEditIdle, 0, 0, nullptr, 0.0f); } bool COwnerVstEditor::OpenEditor(CWnd *parent) { Create(IDD_PLUGINEDITOR, parent); // Some plugins (e.g. ProteusVX) need to be planted into another control or else they will break our window proc, making the window unusable. m_plugWindow.Create(nullptr, WS_CHILD | WS_VISIBLE, CRect(0, 0, 100, 100), this); // Set editor window size Vst::ERect rect{}; Vst::ERect *pRect = nullptr; CVstPlugin &vstPlug = static_cast(m_VstPlugin); vstPlug.Dispatch(Vst::effEditGetRect, 0, 0, &pRect, 0); if(pRect) rect = *pRect; vstPlug.Dispatch(Vst::effEditOpen, 0, 0, m_plugWindow.m_hWnd, 0); vstPlug.Dispatch(Vst::effEditGetRect, 0, 0, &pRect, 0); if(pRect) rect = *pRect; if(rect.right > rect.left && rect.bottom > rect.top) { // Plugin provided valid window size. SetSize(rect.Width(), rect.Height()); } vstPlug.Dispatch(Vst::effEditTop, 0,0, nullptr, 0.0f); vstPlug.Dispatch(Vst::effEditIdle, 0,0, nullptr, 0.0f); // Set knob mode to linear (2) instead of circular (0) for those plugins that support it (e.g. Steinberg VB-1) vstPlug.Dispatch(Vst::effSetEditKnobMode, 0, 2, nullptr, 0.0f); return CAbstractVstEditor::OpenEditor(parent); } void COwnerVstEditor::DoClose() { // Prevent some plugins from storing a bogus window size (e.g. Electri-Q) ShowWindow(SW_HIDE); if(m_isMinimized) OnNcLButtonDblClk(HTCAPTION, CPoint(0, 0)); static_cast(m_VstPlugin).Dispatch(Vst::effEditClose, 0, 0, nullptr, 0.0f); CAbstractVstEditor::DoClose(); } bool COwnerVstEditor::SetSize(int contentWidth, int contentHeight) { if(contentWidth < 0 || contentHeight < 0 || !m_hWnd) { return false; } m_width = contentWidth; m_height = contentHeight; CRect rcWnd, rcClient; // Get border / menu size. GetWindowRect(&rcWnd); GetClientRect(&rcClient); // Narrow plugin GUIs may force the number of menu bar lines (and thus the required window height) to change WindowSizeAdjuster adjuster(*this); const int windowWidth = rcWnd.Width() - rcClient.Width() + contentWidth; const int windowHeight = rcWnd.Height() - rcClient.Height() + contentHeight; SetWindowPos(NULL, 0, 0, windowWidth, windowHeight, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); m_plugWindow.SetWindowPos(NULL, 0, 0, contentWidth, contentHeight, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); return true; } #endif // MPT_WITH_VST OPENMPT_NAMESPACE_END