1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
/*
* 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<const CVstPlugin &>(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<CVstPlugin &>(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<CVstPlugin &>(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<CVstPlugin &>(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
|