2#define IPLUG_STRINGIFY_HELPER(x) #x
3#define IPLUG_STRINGIFY(x) IPLUG_STRINGIFY_HELPER(x)
5ReaperExtBase::ReaperExtBase(reaper_plugin_info_t* pRec)
6: EDITOR_DELEGATE_CLASS(0)
9 mTimer = std::unique_ptr<Timer>(Timer::Create(std::bind(&ReaperExtBase::OnTimer,
this, std::placeholders::_1), IDLE_TIMER_RATE));
10 mDockId.Set(IPLUG_STRINGIFY(PLUG_CLASS_NAME));
15ReaperExtBase::~ReaperExtBase()
20 mSaveStateOnDestroy =
false;
25void ReaperExtBase::OnTimer(
Timer& t)
30auto ClientResize = [](HWND hWnd,
int nWidth,
int nHeight) {
31 RECT rcClient, rcWindow;
33 int screenwidth, screenheight;
36 screenwidth = GetSystemMetrics(SM_CXSCREEN);
37 screenheight = GetSystemMetrics(SM_CYSCREEN);
38 x = (screenwidth / 2) - (nWidth / 2);
39 y = (screenheight / 2) - (nHeight / 2);
41 GetClientRect(hWnd, &rcClient);
42 GetWindowRect(hWnd, &rcWindow);
43 ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
44 ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
46 SetWindowPos(hWnd, 0, x, y, nWidth + ptDiff.x, nHeight + ptDiff.y, 0);
49bool ReaperExtBase::EditorResizeFromUI(
int viewWidth,
int viewHeight,
bool needsPlatformResize)
51 if (viewWidth != GetEditorWidth() || viewHeight != GetEditorHeight())
54 if (!
IsDocked() && needsPlatformResize)
57#define TITLEBAR_BODGE 22
59 GetWindowRect(gHWND, &r);
60 SetWindowPos(gHWND, 0, r.left, r.bottom - viewHeight - TITLEBAR_BODGE, viewWidth, viewHeight + TITLEBAR_BODGE, 0);
70void ReaperExtBase::CreateMainWindow()
82 gHWND = CreateDialog(gHINSTANCE, MAKEINTRESOURCE(IDD_DIALOG_MAIN), gParent, ReaperExtBase::MainDlgProc);
85void ReaperExtBase::DestroyMainWindow()
92 DockWindowRemove(gHWND);
103 DockWindowActivate(gHWND);
118 GetWindowRect(gHWND, &mDockState.r);
121 mSaveStateOnDestroy =
false;
122 gPlug->CloseWindow();
123 DockWindowRemove(gHWND);
124 DestroyWindow(gHWND);
128 mDockState.state ^= 2;
129 mSaveStateOnDestroy =
true;
134 DockWindowActivate(gHWND);
137void ReaperExtBase::SaveDockState()
139 const char* iniFile = get_ini_file();
145 int dockIdx = DockIsChildOfDock(gHWND, NULL);
147 mDockState.whichdock = dockIdx;
149 GetWindowRect(gHWND, &mDockState.r);
153 if (gHWND != NULL && IsWindowVisible(gHWND))
154 mDockState.state |= 1;
156 mDockState.state &= ~1;
162 REAPER_MAKELEINTMEM(&((
int*)&stateLE)[i]);
164 WritePrivateProfileStruct(
"iPlug2", mDockId.Get(), &stateLE,
sizeof(
ReaperExtDockState), iniFile);
167void ReaperExtBase::LoadDockState()
169 const char* iniFile = get_ini_file();
174 if (GetPrivateProfileStruct(
"iPlug2", mDockId.Get(), &stateLE,
sizeof(
ReaperExtDockState), iniFile))
178 REAPER_MAKELEINTMEM(&((
int*)&stateLE)[i]);
187 int commandID = mRec->Register(
"command_id", (
void*) actionName );
192 action.accel.accel.cmd = commandID;
193 action.accel.desc = actionName;
194 action.addMenuItem = addMenuItem;
195 action.pToggle = pToggle;
197 gActions.push_back(action);
199 mRec->Register(
"gaccel", (
void*) &gActions.back().accel);
203bool ReaperExtBase::HookCommandProc(
int command,
int flag)
205 std::vector<ReaperAction>::iterator it = std::find_if (gActions.begin(), gActions.end(), [&](
const auto& e) { return e.accel.accel.cmd == command; });
207 if(it != gActions.end())
216int ReaperExtBase::ToggleActionCallback(
int command)
218 std::vector<ReaperAction>::iterator it = std::find_if (gActions.begin(), gActions.end(), [&](
const auto& e) { return e.accel.accel.cmd == command; });
220 if(it != gActions.end())
222 if(it->pToggle ==
nullptr)
232WDL_DLGRET ReaperExtBase::MainDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
234 extern float GetScaleForHWND(HWND hWnd);
240 auto scale = GetScaleForHWND(hwnd);
242 if (gPlug->IsDocked())
245 DockWindowAddEx(hwnd, (
char*)gPlug->mDockId.Get(), gPlug->mDockId.Get(),
true);
250 if (gPlug->mDockState.r.left || gPlug->mDockState.r.top ||
251 gPlug->mDockState.r.right || gPlug->mDockState.r.bottom)
253 EnsureNotCompletelyOffscreen(&gPlug->mDockState.r);
254 SetWindowPos(hwnd, NULL,
255 gPlug->mDockState.r.left, gPlug->mDockState.r.top,
256 gPlug->mDockState.r.right - gPlug->mDockState.r.left,
257 gPlug->mDockState.r.bottom - gPlug->mDockState.r.top,
262 ClientResize(hwnd,
static_cast<int>(PLUG_WIDTH * scale),
static_cast<int>(PLUG_HEIGHT * scale));
264 AttachWindowTopmostButton(hwnd);
265 ShowWindow(hwnd, SW_SHOW);
268 gPlug->OpenWindow(hwnd);
274 GetClientRect(hwnd, &r);
275 int w = r.right - r.left;
276 int h = r.bottom - r.top;
278 gPlug->OnParentWindowResize(w, h);
281 GetWindowRect(hwnd, &gPrevBounds);
287 if (gPlug->mSaveStateOnDestroy)
288 gPlug->SaveDockState();
290 DockWindowRemove(hwnd);
299 GetClientRect(hwnd, &r);
300 int w = r.right - r.left;
301 int h = r.bottom - r.top;
303 gPlug->OnParentWindowResize(w, h);
308 gPlug->CloseWindow();
State structure for dock window persistence - matches SWS pattern.
void ShowHideMainWindow()
Toggles the visibility of the main extension window.
bool IsDocked() const
Returns true if the window is currently docked.
void ToggleDocking()
Toggles between docked and floating state.
void RegisterAction(const char *actionName, std::function< void()> func, bool addMenuItem=false, int *pToggle=nullptr)
Registers an action with the REAPER extension system.
virtual void OnIdle()
Called during idle processing - override to perform periodic tasks.
Helper struct for registering Reaper Actions.