VSTEditor.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /*
  2. * VSTEditor.cpp
  3. * -------------
  4. * Purpose: Implementation of the custom plugin editor window that is used if a plugin provides an own editor GUI.
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #include "stdafx.h"
  10. #include "resource.h"
  11. #include "Vstplug.h"
  12. #include "VSTEditor.h"
  13. OPENMPT_NAMESPACE_BEGIN
  14. #ifdef MPT_WITH_VST
  15. BEGIN_MESSAGE_MAP(COwnerVstEditor, CAbstractVstEditor)
  16. ON_WM_ERASEBKGND()
  17. ON_WM_PAINT()
  18. // Messages from plugin bridge to check whether a key would be handled by OpenMPT
  19. // We need an offset to WM_USER because the editor window receives some spurious WM_USER messages (from MFC?) when it gets activated
  20. ON_MESSAGE(WM_USER + 4000 + WM_KEYDOWN - WM_KEYFIRST, &COwnerVstEditor::OnPreTranslateKeyDown)
  21. ON_MESSAGE(WM_USER + 4000 + WM_KEYUP - WM_KEYFIRST, &COwnerVstEditor::OnPreTranslateKeyUp)
  22. ON_MESSAGE(WM_USER + 4000 + WM_SYSKEYDOWN - WM_KEYFIRST, &COwnerVstEditor::OnPreTranslateSysKeyDown)
  23. ON_MESSAGE(WM_USER + 4000 + WM_SYSKEYUP - WM_KEYFIRST, &COwnerVstEditor::OnPreTranslateSysKeyUp)
  24. END_MESSAGE_MAP()
  25. void COwnerVstEditor::OnPaint()
  26. {
  27. CAbstractVstEditor::OnPaint();
  28. auto &plugin = static_cast<const CVstPlugin &>(m_VstPlugin);
  29. if(plugin.isBridged)
  30. {
  31. // Force redrawing for the plugin window in the bridged process.
  32. // Otherwise, bridged plugin GUIs will not always be refreshed properly (e.g. when restoring OpenMPT from minimized state).
  33. // Synth1 is a good candidate for testing this behaviour.
  34. CRect rect;
  35. if(m_plugWindow.GetUpdateRect(&rect, FALSE))
  36. {
  37. CWnd *child = m_plugWindow.GetWindow(GW_CHILD | GW_HWNDFIRST);
  38. if(child)
  39. child->RedrawWindow(&rect, nullptr, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW);
  40. }
  41. } else
  42. {
  43. // For plugins that change their size without telling the host through audioMasterSizeWindow, e.g. Roland D-50
  44. CRect rect;
  45. m_plugWindow.GetClientRect(rect);
  46. if(rect.Width() != m_width || rect.Height() != m_height)
  47. {
  48. SetSize(rect.Width(), rect.Height());
  49. }
  50. }
  51. }
  52. void COwnerVstEditor::UpdateParamDisplays()
  53. {
  54. CAbstractVstEditor::UpdateParamDisplays();
  55. // We trust that the plugin GUI can update its display with a bit of idle time.
  56. static_cast<CVstPlugin &>(m_VstPlugin).Dispatch(Vst::effEditIdle, 0, 0, nullptr, 0.0f);
  57. }
  58. bool COwnerVstEditor::OpenEditor(CWnd *parent)
  59. {
  60. Create(IDD_PLUGINEDITOR, parent);
  61. // Some plugins (e.g. ProteusVX) need to be planted into another control or else they will break our window proc, making the window unusable.
  62. m_plugWindow.Create(nullptr, WS_CHILD | WS_VISIBLE, CRect(0, 0, 100, 100), this);
  63. // Set editor window size
  64. Vst::ERect rect{};
  65. Vst::ERect *pRect = nullptr;
  66. CVstPlugin &vstPlug = static_cast<CVstPlugin &>(m_VstPlugin);
  67. vstPlug.Dispatch(Vst::effEditGetRect, 0, 0, &pRect, 0);
  68. if(pRect) rect = *pRect;
  69. vstPlug.Dispatch(Vst::effEditOpen, 0, 0, m_plugWindow.m_hWnd, 0);
  70. vstPlug.Dispatch(Vst::effEditGetRect, 0, 0, &pRect, 0);
  71. if(pRect) rect = *pRect;
  72. if(rect.right > rect.left && rect.bottom > rect.top)
  73. {
  74. // Plugin provided valid window size.
  75. SetSize(rect.Width(), rect.Height());
  76. }
  77. vstPlug.Dispatch(Vst::effEditTop, 0,0, nullptr, 0.0f);
  78. vstPlug.Dispatch(Vst::effEditIdle, 0,0, nullptr, 0.0f);
  79. // Set knob mode to linear (2) instead of circular (0) for those plugins that support it (e.g. Steinberg VB-1)
  80. vstPlug.Dispatch(Vst::effSetEditKnobMode, 0, 2, nullptr, 0.0f);
  81. return CAbstractVstEditor::OpenEditor(parent);
  82. }
  83. void COwnerVstEditor::DoClose()
  84. {
  85. // Prevent some plugins from storing a bogus window size (e.g. Electri-Q)
  86. ShowWindow(SW_HIDE);
  87. if(m_isMinimized) OnNcLButtonDblClk(HTCAPTION, CPoint(0, 0));
  88. static_cast<CVstPlugin &>(m_VstPlugin).Dispatch(Vst::effEditClose, 0, 0, nullptr, 0.0f);
  89. CAbstractVstEditor::DoClose();
  90. }
  91. bool COwnerVstEditor::SetSize(int contentWidth, int contentHeight)
  92. {
  93. if(contentWidth < 0 || contentHeight < 0 || !m_hWnd)
  94. {
  95. return false;
  96. }
  97. m_width = contentWidth;
  98. m_height = contentHeight;
  99. CRect rcWnd, rcClient;
  100. // Get border / menu size.
  101. GetWindowRect(&rcWnd);
  102. GetClientRect(&rcClient);
  103. // Narrow plugin GUIs may force the number of menu bar lines (and thus the required window height) to change
  104. WindowSizeAdjuster adjuster(*this);
  105. const int windowWidth = rcWnd.Width() - rcClient.Width() + contentWidth;
  106. const int windowHeight = rcWnd.Height() - rcClient.Height() + contentHeight;
  107. SetWindowPos(NULL, 0, 0,
  108. windowWidth, windowHeight,
  109. SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
  110. m_plugWindow.SetWindowPos(NULL, 0, 0,
  111. contentWidth, contentHeight,
  112. SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
  113. return true;
  114. }
  115. #endif // MPT_WITH_VST
  116. OPENMPT_NAMESPACE_END