18 #include "IGraphicsWin.h" 23 #include <VersionHelpers.h> 25 using namespace iplug;
26 using namespace igraphics;
28 #pragma warning(disable:4244) // Pointer size cast mismatch. 29 #pragma warning(disable:4312) // Pointer size cast mismatch. 30 #pragma warning(disable:4311) // Pointer size cast mismatch. 32 static int nWndClassReg = 0;
33 static const char* wndClassName =
"IPlugWndClass";
34 static double sFPS = 0.0;
36 #define PARAM_EDIT_ID 99 37 #define IPLUG_TIMER_ID 2 39 #define TOOLTIPWND_MAXWIDTH 250 41 #define WM_VBLANK (WM_USER+1) 44 typedef HGLRC(WINAPI* PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext,
const int* attribList);
45 #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 46 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 47 #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 48 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 51 #pragma mark - Private Classes and Structs 59 : mFontHandle(
nullptr)
64 mFontHandle = AddFontMemResourceEx(data, resSize, NULL, &numFonts);
71 RemoveFontMemResourceEx(mFontHandle);
77 bool IsValid()
const {
return mFontHandle; }
87 LOGFONT lFont = { 0 };
88 GetObject(hfont,
sizeof(LOGFONT), &lFont);
89 mHFont = CreateFontIndirect(&lFont);
95 class IGraphicsWin::Font :
public PlatformFont
98 Font(HFONT font,
const char* styleName,
bool system)
99 : PlatformFont(system), mFont(font), mStyleName(styleName) {}
105 FontDescriptor GetDescriptor()
override {
return mFont; }
106 IFontDataPtr GetFontData()
override;
110 WDL_String mStyleName;
113 IFontDataPtr IGraphicsWin::Font::GetFontData()
115 HDC hdc = CreateCompatibleDC(NULL);
116 IFontDataPtr fontData(
new IFontData());
120 SelectObject(hdc, mFont);
121 const size_t size = ::GetFontData(hdc, 0, 0, NULL, 0);
123 if (size != GDI_ERROR)
125 fontData = std::make_unique<IFontData>(size);
127 if (fontData->GetSize() == size)
129 size_t result = ::GetFontData(hdc, 0x66637474, 0, fontData->Get(), size);
130 if (result == GDI_ERROR)
131 result = ::GetFontData(hdc, 0, 0, fontData->Get(), size);
133 fontData->SetFaceIdx(GetFaceIdx(fontData->Get(), fontData->GetSize(), mStyleName.Get()));
143 StaticStorage<IGraphicsWin::InstalledFont> IGraphicsWin::sPlatformFontCache;
144 StaticStorage<IGraphicsWin::HFontHolder> IGraphicsWin::sHFontCache;
146 #pragma mark - Mouse and tablet helpers 148 extern float GetScaleForHWND(HWND hWnd);
150 inline IMouseInfo IGraphicsWin::GetMouseInfo(LPARAM lParam, WPARAM wParam)
153 const float scale = GetTotalScale();
154 info.x = mCursorX = GET_X_LPARAM(lParam) / scale;
155 info.y = mCursorY = GET_Y_LPARAM(lParam) / scale;
156 info.ms =
IMouseMod((wParam & MK_LBUTTON), (wParam & MK_RBUTTON), (wParam & MK_SHIFT), (wParam & MK_CONTROL),
158 GetAsyncKeyState(VK_MENU) < 0
160 GetKeyState(VK_MENU) < 0
167 void IGraphicsWin::CheckTabletInput(UINT msg)
169 if ((msg == WM_LBUTTONDOWN) || (msg == WM_RBUTTONDOWN) || (msg == WM_MBUTTONDOWN) || (msg == WM_MOUSEMOVE)
170 || (msg == WM_RBUTTONDBLCLK) || (msg == WM_LBUTTONDBLCLK) || (msg == WM_MBUTTONDBLCLK)
171 || (msg == WM_RBUTTONUP) || (msg == WM_LBUTTONUP) || (msg == WM_MBUTTONUP)
172 || (msg == WM_MOUSEHOVER) || (msg == WM_MOUSELEAVE))
174 const LONG_PTR c_SIGNATURE_MASK = 0xFFFFFF00;
175 const LONG_PTR c_MOUSEEVENTF_FROMTOUCH = 0xFF515700;
177 LONG_PTR extraInfo = GetMessageExtraInfo();
178 SetTabletInput(((extraInfo & c_SIGNATURE_MASK) == c_MOUSEEVENTF_FROMTOUCH));
179 mCursorLock &= !mTabletInput;
183 void IGraphicsWin::DestroyEditWindow()
187 SetWindowLongPtr(mParamEditWnd, GWLP_WNDPROC, (LPARAM) mDefEditProc);
188 DestroyWindow(mParamEditWnd);
189 mParamEditWnd =
nullptr;
190 mDefEditProc =
nullptr;
191 DeleteObject(mEditFont);
196 void IGraphicsWin::OnDisplayTimer(
int vBlankCount)
199 DWORD msgCount = vBlankCount;
200 DWORD curCount = mVBlankCount;
205 if (mVBlankSkipUntil != 0 && mVBlankSkipUntil > mVBlankCount)
210 mVBlankSkipUntil = 0;
212 if (msgCount != curCount)
220 if (mParamEditWnd && mParamEditMsg != kNone)
222 switch (mParamEditMsg)
226 WCHAR wtxt[MAX_WIN32_PARAM_LEN];
228 SendMessageW(mParamEditWnd, WM_GETTEXT, MAX_WIN32_PARAM_LEN, (LPARAM)wtxt);
229 UTF16ToUTF8(tempUTF8, wtxt);
230 SetControlValueAfterTextEdit(tempUTF8.Get());
239 mParamEditMsg = kNone;
247 float scale = GetScaleForHWND(mPlugWnd);
248 if (scale != GetScreenScale())
249 SetScreenScale(scale);
255 const float totalScale = GetTotalScale();
258 SetAllControlsClean();
260 for (
int i = 0; i < rects.
Size(); i++)
263 dirtyR.
Scale(totalScale);
265 RECT r = { (LONG)dirtyR.
L, (LONG)dirtyR.
T, (LONG)dirtyR.
R, (LONG)dirtyR.
B };
266 InvalidateRect(mPlugWnd, &r, FALSE);
271 IRECT notDirtyR = mEditRECT;
272 notDirtyR.
Scale(totalScale);
274 RECT r2 = { (LONG)notDirtyR.
L, (LONG)notDirtyR.
T, (LONG)notDirtyR.
R, (LONG)notDirtyR.
B };
275 ValidateRect(mPlugWnd, &r2);
276 UpdateWindow(mPlugWnd);
277 mParamEditMsg = kUpdate;
282 UpdateWindow(mPlugWnd);
287 curCount = mVBlankCount;
288 if (msgCount != curCount)
291 mVBlankSkipUntil = curCount+1;
301 LRESULT CALLBACK IGraphicsWin::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
303 if (msg == WM_CREATE)
305 LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
306 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LPARAM)(lpcs->lpCreateParams));
309 if(pGraphics->mVSYNCEnabled)
311 assert((pGraphics->FPS() == 60) &&
"If you want to run at frame rates other than 60FPS");
312 pGraphics->StartVBlankThread(hWnd);
316 int mSec =
static_cast<int>(std::floorf(1000.0f / (pGraphics->FPS())));
317 if (mSec < 20) mSec = 15;
318 SetTimer(hWnd, IPLUG_TIMER_ID, mSec, NULL);
322 DragAcceptFiles(hWnd,
true);
328 if (!pGraphics || hWnd != pGraphics->mPlugWnd)
330 return DefWindowProc(hWnd, msg, wParam, lParam);
333 if (pGraphics->mParamEditWnd && pGraphics->mParamEditMsg == kEditing)
335 if (msg == WM_RBUTTONDOWN || (msg == WM_LBUTTONDOWN))
337 pGraphics->mParamEditMsg = kCancel;
340 return DefWindowProc(hWnd, msg, wParam, lParam);
343 auto IsTouchEvent = []() {
344 const LONG_PTR c_SIGNATURE_MASK = 0xFFFFFF00;
345 const LONG_PTR c_MOUSEEVENTF_FROMTOUCH = 0xFF515700;
346 LONG_PTR extraInfo = GetMessageExtraInfo();
347 return ((extraInfo & c_SIGNATURE_MASK) == c_MOUSEEVENTF_FROMTOUCH);
350 pGraphics->CheckTabletInput(msg);
355 pGraphics->OnDisplayTimer(wParam);
359 if (wParam == IPLUG_TIMER_ID)
360 pGraphics->OnDisplayTimer(0);
374 pGraphics->HideTooltip();
375 if (pGraphics->mParamEditWnd)
377 pGraphics->mParamEditMsg = kCommit;
382 IMouseInfo info = pGraphics->GetMouseInfo(lParam, wParam);
383 std::vector<IMouseInfo> list{ info };
384 pGraphics->OnMouseDown(list);
389 pGraphics->OnSetCursor();
397 if (!(wParam & (MK_LBUTTON | MK_RBUTTON)))
399 IMouseInfo info = pGraphics->GetMouseInfo(lParam, wParam);
400 if (pGraphics->OnMouseOver(info.x, info.y, info.ms))
402 TRACKMOUSEEVENT eventTrack = {
sizeof(TRACKMOUSEEVENT), TME_LEAVE, hWnd, HOVER_DEFAULT };
403 if (pGraphics->TooltipsEnabled())
405 int c = pGraphics->GetMouseOver();
406 if (c != pGraphics->mTooltipIdx)
408 if (c >= 0) eventTrack.dwFlags |= TME_HOVER;
409 pGraphics->mTooltipIdx = c;
410 pGraphics->HideTooltip();
414 TrackMouseEvent(&eventTrack);
417 else if (GetCapture() == hWnd && !pGraphics->IsInPlatformTextEntry())
419 float oldX = pGraphics->mCursorX;
420 float oldY = pGraphics->mCursorY;
422 IMouseInfo info = pGraphics->GetMouseInfo(lParam, wParam);
424 info.dX = info.x - oldX;
425 info.dY = info.y - oldY;
427 if (info.dX || info.dY)
429 std::vector<IMouseInfo> list{ info };
430 pGraphics->OnMouseDrag(list);
432 if (pGraphics->MouseCursorIsLocked())
434 const float x = pGraphics->mHiddenCursorX;
435 const float y = pGraphics->mHiddenCursorY;
437 pGraphics->MoveMouseCursor(x, y);
438 pGraphics->mHiddenCursorX = x;
439 pGraphics->mHiddenCursorY = y;
448 pGraphics->ShowTooltip();
453 pGraphics->HideTooltip();
454 pGraphics->OnMouseOut();
461 IMouseInfo info = pGraphics->GetMouseInfo(lParam, wParam);
462 std::vector<IMouseInfo> list{ info };
463 pGraphics->OnMouseUp(list);
466 case WM_LBUTTONDBLCLK:
471 IMouseInfo info = pGraphics->GetMouseInfo(lParam, wParam);
472 if (pGraphics->OnMouseDblClick(info.x, info.y, info.ms))
480 if (pGraphics->mParamEditWnd)
482 pGraphics->mParamEditMsg = kCancel;
487 IMouseInfo info = pGraphics->GetMouseInfo(lParam, wParam);
488 float d = GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA;
489 const float scale = pGraphics->GetTotalScale();
491 GetWindowRect(hWnd, &r);
492 pGraphics->OnMouseWheel(info.x - (r.left / scale), info.y - (r.top / scale), info.ms, d);
498 UINT nTouches = LOWORD(wParam);
502 WDL_TypedBuf<TOUCHINPUT> touches;
503 touches.Resize(nTouches);
504 HTOUCHINPUT hTouchInput = (HTOUCHINPUT) lParam;
505 std::vector<IMouseInfo> downlist;
506 std::vector<IMouseInfo> uplist;
507 std::vector<IMouseInfo> movelist;
508 const float scale = pGraphics->GetTotalScale();
510 GetTouchInputInfo(hTouchInput, nTouches, touches.Get(),
sizeof(TOUCHINPUT));
512 for (
int i = 0; i < nTouches; i++)
514 TOUCHINPUT* pTI = touches.Get() +i;
517 pt.x = TOUCH_COORD_TO_PIXEL(pTI->x);
518 pt.y = TOUCH_COORD_TO_PIXEL(pTI->y);
519 ScreenToClient(pGraphics->mPlugWnd, &pt);
522 info.x =
static_cast<float>(pt.x) / scale;
523 info.y =
static_cast<float>(pt.y) / scale;
526 info.ms.touchRadius = 0;
528 if (pTI->dwMask & TOUCHINPUTMASKF_CONTACTAREA)
530 info.ms.touchRadius = pTI->cxContact;
533 info.ms.touchID =
static_cast<ITouchID
>(pTI->dwID);
535 if (pTI->dwFlags & TOUCHEVENTF_DOWN)
537 downlist.push_back(info);
538 pGraphics->mDeltaCapture.insert(std::make_pair(info.ms.touchID, info));
540 else if (pTI->dwFlags & TOUCHEVENTF_UP)
542 pGraphics->mDeltaCapture.erase(info.ms.touchID);
543 uplist.push_back(info);
545 else if (pTI->dwFlags & TOUCHEVENTF_MOVE)
547 IMouseInfo previous = pGraphics->mDeltaCapture.find(info.ms.touchID)->second;
548 info.dX = info.x - previous.x;
549 info.dY = info.y - previous.y;
550 movelist.push_back(info);
551 pGraphics->mDeltaCapture[info.ms.touchID] = info;
556 pGraphics->OnMouseDown(downlist);
559 pGraphics->OnMouseUp(uplist);
562 pGraphics->OnMouseDrag(movelist);
564 CloseTouchInputHandle(hTouchInput);
569 return DLGC_WANTALLKEYS;
575 ScreenToClient(hWnd, &p);
577 BYTE keyboardState[256] = {};
578 GetKeyboardState(keyboardState);
579 const int keyboardScanCode = (lParam >> 16) & 0x00ff;
581 const int len = ToAscii(wParam, keyboardScanCode, keyboardState, &character, 0);
586 if (len == 0 || len == 1)
589 str[0] =
static_cast<char>(character);
592 IKeyPress keyPress{ str,
static_cast<int>(wParam),
593 static_cast<bool>(GetKeyState(VK_SHIFT) & 0x8000),
594 static_cast<bool>(GetKeyState(VK_CONTROL) & 0x8000),
595 static_cast<bool>(GetKeyState(VK_MENU) & 0x8000) };
597 const float scale = pGraphics->GetTotalScale();
599 if(msg == WM_KEYDOWN)
600 handle = pGraphics->OnKeyDown(p.x / scale, p.y / scale, keyPress);
602 handle = pGraphics->OnKeyUp(p.x / scale, p.y / scale, keyPress);
607 HWND rootHWnd = GetAncestor( hWnd, GA_ROOT);
608 SendMessage(rootHWnd, msg, wParam, lParam);
609 return DefWindowProc(hWnd, msg, wParam, lParam);
616 const float scale = pGraphics->GetTotalScale();
617 auto addDrawRect = [pGraphics, scale](
IRECTList& rects, RECT r) {
618 IRECT ir(r.left, r.top, r.right, r.bottom);
624 HRGN region = CreateRectRgn(0, 0, 0, 0);
625 int regionType = GetUpdateRgn(hWnd, region, FALSE);
627 if ((regionType == COMPLEXREGION) || (regionType == SIMPLEREGION))
630 const int bufferSize =
sizeof(RECT) * 64;
631 unsigned char stackBuffer[
sizeof(RGNDATA) + bufferSize];
632 RGNDATA* regionData = (RGNDATA*)stackBuffer;
634 if (regionType == COMPLEXREGION && GetRegionData(region, bufferSize, regionData))
636 for (
int i = 0; i < regionData->rdh.nCount; i++)
637 addDrawRect(rects, *(((RECT*)regionData->Buffer) + i));
642 GetRgnBox(region, &r);
643 addDrawRect(rects, r);
646 #if defined IGRAPHICS_GL //|| IGRAPHICS_D2D 648 BeginPaint(hWnd, &ps);
652 pGraphics->ActivateGLContext();
655 pGraphics->Draw(rects);
658 SwapBuffers((HDC) pGraphics->GetPlatformContext());
659 pGraphics->DeactivateGLContext();
662 #if defined IGRAPHICS_GL || IGRAPHICS_D2D 670 ValidateRect(hWnd, 0);
672 DeleteObject(region);
677 case WM_CTLCOLOREDIT:
679 if(!pGraphics->mParamEditWnd)
682 const IText& text = pGraphics->mEditText;
683 HDC dc = (HDC) wParam;
684 SetBkColor(dc, RGB(text.mTextEntryBGColor.R, text.mTextEntryBGColor.G, text.mTextEntryBGColor.B));
685 SetTextColor(dc, RGB(text.mTextEntryFGColor.R, text.mTextEntryFGColor.G, text.mTextEntryFGColor.B));
686 SetBkMode(dc, OPAQUE);
687 SetDCBrushColor(dc, RGB(text.mTextEntryBGColor.R, text.mTextEntryBGColor.G, text.mTextEntryBGColor.B));
688 return (LRESULT)GetStockObject(DC_BRUSH);
692 HDROP hdrop = (HDROP)wParam;
694 char pathToFile[1025];
695 DragQueryFile(hdrop, 0, pathToFile, 1024);
698 DragQueryPoint(hdrop, &point);
700 pGraphics->OnDrop(pathToFile, point.x, point.y);
706 pGraphics->CloseWindow();
718 return DefWindowProc(hWnd, msg, wParam, lParam);
722 LRESULT CALLBACK IGraphicsWin::ParamEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
726 if (pGraphics && pGraphics->mParamEditWnd && pGraphics->mParamEditWnd == hWnd)
728 pGraphics->HideTooltip();
735 if(pGraphics->mEditParam)
741 switch (pGraphics->mEditParam->
Type())
743 case IParam::kTypeEnum:
744 case IParam::kTypeInt:
745 case IParam::kTypeBool:
746 if (c >=
'0' && c <=
'9')
break;
747 else if (c ==
'-')
break;
748 else if (c ==
'+')
break;
750 case IParam::kTypeDouble:
751 if (c >=
'0' && c <=
'9')
break;
752 else if (c ==
'-')
break;
753 else if (c ==
'+')
break;
754 else if (c ==
'.')
break;
764 if (wParam == VK_RETURN)
766 pGraphics->mParamEditMsg = kCommit;
769 else if (wParam == VK_ESCAPE)
771 pGraphics->mParamEditMsg = kCancel;
778 pGraphics->mParamEditMsg = kEditing;
783 pGraphics->mParamEditMsg = kCommit;
792 lres = CallWindowProc(pGraphics->mDefEditProc, hWnd, WM_GETDLGCODE, wParam, lParam);
794 if (lParam && ((MSG*)lParam)->message == WM_KEYDOWN && wParam == VK_RETURN)
796 lres |= DLGC_WANTMESSAGE;
802 switch HIWORD(wParam)
806 if (pGraphics->mParamEditWnd)
808 pGraphics->mParamEditMsg = kCommit;
817 return CallWindowProc(pGraphics->mDefEditProc, hWnd, msg, wParam, lParam);
819 return DefWindowProc(hWnd, msg, wParam, lParam);
822 IGraphicsWin::IGraphicsWin(
IGEditorDelegate& dlg,
int w,
int h,
int fps,
float scale)
823 : IGRAPHICS_DRAW_CLASS(dlg, w, h, fps, scale)
825 StaticStorage<InstalledFont>::Accessor fontStorage(sPlatformFontCache);
826 StaticStorage<HFontHolder>::Accessor hfontStorage(sHFontCache);
827 fontStorage.Retain();
828 hfontStorage.Retain();
830 #ifndef IGRAPHICS_DISABLE_VSYNC 831 mVSYNCEnabled = IsWindows8OrGreater();
835 IGraphicsWin::~IGraphicsWin()
837 StaticStorage<InstalledFont>::Accessor fontStorage(sPlatformFontCache);
838 StaticStorage<HFontHolder>::Accessor hfontStorage(sHFontCache);
839 fontStorage.Release();
840 hfontStorage.Release();
845 static void GetWindowSize(HWND pWnd,
int* pW,
int* pH)
850 GetWindowRect(pWnd, &r);
851 *pW = r.right - r.left;
852 *pH = r.bottom - r.top;
860 static bool IsChildWindow(HWND pWnd)
864 int style = GetWindowLong(pWnd, GWL_STYLE);
865 int exStyle = GetWindowLong(pWnd, GWL_EXSTYLE);
866 return ((style & WS_CHILD) && !(exStyle & WS_EX_MDICHILD));
871 void IGraphicsWin::ForceEndUserEdit()
873 mParamEditMsg = kCancel;
876 static UINT SETPOS_FLAGS = SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE;
878 void IGraphicsWin::PlatformResize(
bool parentHasResized)
882 HWND pParent = 0, pGrandparent = 0;
883 int dlgW = 0, dlgH = 0, parentW = 0, parentH = 0, grandparentW = 0, grandparentH = 0;
884 GetWindowSize(mPlugWnd, &dlgW, &dlgH);
885 int dw = (WindowWidth() * GetScreenScale()) - dlgW, dh = (WindowHeight()* GetScreenScale()) - dlgH;
887 if (IsChildWindow(mPlugWnd))
889 pParent = GetParent(mPlugWnd);
890 GetWindowSize(pParent, &parentW, &parentH);
892 if (IsChildWindow(pParent))
894 pGrandparent = GetParent(pParent);
895 GetWindowSize(pGrandparent, &grandparentW, &grandparentH);
902 SetWindowPos(mPlugWnd, 0, 0, 0, dlgW + dw, dlgH + dh, SETPOS_FLAGS);
904 if(pParent && !parentHasResized)
906 SetWindowPos(pParent, 0, 0, 0, parentW + dw, parentH + dh, SETPOS_FLAGS);
909 if(pGrandparent && !parentHasResized)
911 SetWindowPos(pGrandparent, 0, 0, 0, grandparentW + dw, grandparentH + dh, SETPOS_FLAGS);
917 void IGraphicsWin::DrawResize()
920 IGRAPHICS_DRAW_CLASS::DrawResize();
921 DeactivateGLContext();
925 void IGraphicsWin::HideMouseCursor(
bool hide,
bool lock)
927 if (mCursorHidden == hide)
932 mHiddenCursorX = mCursorX;
933 mHiddenCursorY = mCursorY;
936 mCursorHidden =
true;
937 mCursorLock = lock && !mTabletInput;
942 MoveMouseCursor(mHiddenCursorX, mHiddenCursorY);
945 mCursorHidden =
false;
950 void IGraphicsWin::MoveMouseCursor(
float x,
float y)
955 const float scale = GetTotalScale();
958 p.x = std::round(x * scale);
959 p.y = std::round(y * scale);
961 ::ClientToScreen(mPlugWnd, &p);
963 if (SetCursorPos(p.x, p.y))
966 ScreenToClient(mPlugWnd, &p);
968 mHiddenCursorX = mCursorX = p.x / scale;
969 mHiddenCursorY = mCursorY = p.y / scale;
973 ECursor IGraphicsWin::SetMouseCursor(ECursor cursorType)
979 case ECursor::ARROW: cursor = LoadCursor(NULL, IDC_ARROW);
break;
980 case ECursor::IBEAM: cursor = LoadCursor(NULL, IDC_IBEAM);
break;
981 case ECursor::WAIT: cursor = LoadCursor(NULL, IDC_WAIT);
break;
982 case ECursor::CROSS: cursor = LoadCursor(NULL, IDC_CROSS);
break;
983 case ECursor::UPARROW: cursor = LoadCursor(NULL, IDC_UPARROW);
break;
984 case ECursor::SIZENWSE: cursor = LoadCursor(NULL, IDC_SIZENWSE);
break;
985 case ECursor::SIZENESW: cursor = LoadCursor(NULL, IDC_SIZENESW);
break;
986 case ECursor::SIZEWE: cursor = LoadCursor(NULL, IDC_SIZEWE);
break;
987 case ECursor::SIZENS: cursor = LoadCursor(NULL, IDC_SIZENS);
break;
988 case ECursor::SIZEALL: cursor = LoadCursor(NULL, IDC_SIZEALL);
break;
989 case ECursor::INO: cursor = LoadCursor(NULL, IDC_NO);
break;
990 case ECursor::HAND: cursor = LoadCursor(NULL, IDC_HAND);
break;
991 case ECursor::APPSTARTING: cursor = LoadCursor(NULL, IDC_APPSTARTING);
break;
992 case ECursor::HELP: cursor = LoadCursor(NULL, IDC_HELP);
break;
994 cursor = LoadCursor(NULL, IDC_ARROW);
1001 bool IGraphicsWin::MouseCursorIsLocked()
1006 void IGraphicsWin::GetMouseLocation(
float& x,
float&y)
const 1010 ScreenToClient(mPlugWnd, &p);
1012 const float scale = GetTotalScale();
1019 void IGraphicsWin::CreateGLContext()
1021 PIXELFORMATDESCRIPTOR pfd =
1023 sizeof(PIXELFORMATDESCRIPTOR),
1025 PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
1041 HDC dc = GetDC(mPlugWnd);
1042 int fmt = ChoosePixelFormat(dc, &pfd);
1043 SetPixelFormat(dc, fmt, &pfd);
1044 mHGLRC = wglCreateContext(dc);
1045 wglMakeCurrent(dc, mHGLRC);
1047 #ifdef IGRAPHICS_GL3 1050 auto wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress(
"wglCreateContextAttribsARB");
1052 if (wglCreateContextAttribsARB)
1054 wglDeleteContext(mHGLRC);
1056 const int attribList[] = {
1057 WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
1058 WGL_CONTEXT_MINOR_VERSION_ARB, 3,
1059 WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
1063 mHGLRC = wglCreateContextAttribsARB(dc, 0, attribList);
1064 wglMakeCurrent(dc, mHGLRC);
1071 DBGMSG(
"Error initializing glad");
1075 ReleaseDC(mPlugWnd, dc);
1078 void IGraphicsWin::DestroyGLContext()
1080 wglMakeCurrent(NULL, NULL);
1081 wglDeleteContext(mHGLRC);
1084 void IGraphicsWin::ActivateGLContext()
1086 mStartHDC = wglGetCurrentDC();
1087 mStartHGLRC = wglGetCurrentContext();
1088 HDC dc = GetDC(mPlugWnd);
1089 wglMakeCurrent(dc, mHGLRC);
1092 void IGraphicsWin::DeactivateGLContext()
1094 ReleaseDC(mPlugWnd, (HDC) GetPlatformContext());
1095 wglMakeCurrent(mStartHDC, mStartHGLRC);
1099 EMsgBoxResult IGraphicsWin::ShowMessageBox(
const char* text,
const char* caption, EMsgBoxType type, IMsgBoxCompletionHanderFunc completionHandler)
1101 ReleaseMouseCapture();
1103 EMsgBoxResult result =
static_cast<EMsgBoxResult
>(MessageBox(GetMainWnd(), text, caption, static_cast<int>(type)));
1105 if(completionHandler)
1106 completionHandler(result);
1111 void* IGraphicsWin::OpenWindow(
void* pParent)
1113 mParentWnd = (HWND) pParent;
1114 int screenScale = GetScaleForHWND(mParentWnd);
1115 int x = 0, y = 0, w = WindowWidth() * screenScale, h = WindowHeight() * screenScale;
1120 GetWindowRect((HWND) pParent, &pR);
1121 GetWindowRect(mPlugWnd, &cR);
1123 x = cR.left - pR.left;
1124 y = cR.top - pR.top;
1125 w = cR.right - cR.left;
1126 h = cR.bottom - cR.top;
1129 if (nWndClassReg++ == 0)
1131 WNDCLASS wndClass = { CS_DBLCLKS | CS_OWNDC, WndProc, 0, 0, mHInstance, 0, 0, 0, 0, wndClassName };
1132 RegisterClass(&wndClass);
1135 mPlugWnd = CreateWindow(wndClassName,
"IPlug", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, x, y, w, h, mParentWnd, 0, mHInstance,
this);
1137 HDC dc = GetDC(mPlugWnd);
1138 SetPlatformContext(dc);
1139 ReleaseDC(mPlugWnd, dc);
1145 OnViewInitialized((
void*) dc);
1147 SetScreenScale(screenScale);
1149 GetDelegate()->LayoutUI(
this);
1151 if (MultiTouchEnabled() && GetSystemMetrics(SM_DIGITIZER) & NID_MULTI_INPUT)
1153 RegisterTouchWindow(mPlugWnd, 0);
1156 if (!mPlugWnd && --nWndClassReg == 0)
1158 UnregisterClass(wndClassName, mHInstance);
1162 SetAllControlsDirty();
1165 if (mPlugWnd && TooltipsEnabled())
1168 static const INITCOMMONCONTROLSEX iccex = {
sizeof(INITCOMMONCONTROLSEX), ICC_TAB_CLASSES };
1170 if (InitCommonControlsEx(&iccex))
1172 mTooltipWnd = CreateWindowEx(0, TOOLTIPS_CLASS, NULL, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TTS_NOPREFIX | TTS_ALWAYSTIP,
1173 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, mPlugWnd, NULL, mHInstance, NULL);
1176 SetWindowPos(mTooltipWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
1177 TOOLINFO ti = { TTTOOLINFOA_V2_SIZE, TTF_IDISHWND | TTF_SUBCLASS, mPlugWnd, (UINT_PTR)mPlugWnd };
1178 ti.lpszText = (LPTSTR)NULL;
1179 SendMessage(mTooltipWnd, TTM_ADDTOOL, 0, (LPARAM)&ti);
1180 SendMessage(mTooltipWnd, TTM_SETMAXTIPWIDTH, 0, TOOLTIPWND_MAXWIDTH);
1185 if (!ok) EnableTooltips(ok);
1188 wglMakeCurrent(NULL, NULL);
1192 GetDelegate()->OnUIOpen();
1197 static void GetWndClassName(HWND hWnd, WDL_String* pStr)
1199 char cStr[MAX_CLASSNAME_LEN];
1201 GetClassName(hWnd, cStr, MAX_CLASSNAME_LEN);
1205 BOOL CALLBACK IGraphicsWin::FindMainWindow(HWND hWnd, LPARAM lParam)
1211 GetWindowThreadProcessId(hWnd, &wPID);
1213 GetWndClassName(hWnd, &str);
1214 if (wPID == pGraphics->mPID && !strcmp(str.Get(), pGraphics->mMainWndClassName.Get()))
1216 pGraphics->mMainWnd = hWnd;
1223 HWND IGraphicsWin::GetMainWnd()
1229 HWND parentWnd = mParentWnd;
1232 mMainWnd = parentWnd;
1233 parentWnd = GetParent(mMainWnd);
1236 GetWndClassName(mMainWnd, &mMainWndClassName);
1238 else if (CStringHasContents(mMainWndClassName.Get()))
1240 mPID = GetCurrentProcessId();
1241 EnumWindows(FindMainWindow, (LPARAM)
this);
1247 IRECT IGraphicsWin::GetWindowRECT()
1252 GetWindowRect(mPlugWnd, &r);
1253 r.right -= TOOLWIN_BORDER_W;
1254 r.bottom -= TOOLWIN_BORDER_H;
1255 return IRECT(r.left, r.top, r.right, r.bottom);
1260 void IGraphicsWin::SetWindowTitle(
const char* str)
1262 SetWindowText(mPlugWnd, str);
1265 void IGraphicsWin::CloseWindow()
1272 KillTimer(mPlugWnd, IPLUG_TIMER_ID);
1275 ActivateGLContext();
1281 DeactivateGLContext();
1285 SetPlatformContext(
nullptr);
1289 DestroyWindow(mTooltipWnd);
1291 mShowingTooltip =
false;
1295 DestroyWindow(mPlugWnd);
1298 if (--nWndClassReg == 0)
1300 UnregisterClass(wndClassName, mHInstance);
1305 bool IGraphicsWin::PlatformSupportsMultiTouch()
const 1307 return GetSystemMetrics(SM_DIGITIZER) & NID_MULTI_INPUT;
1310 IPopupMenu* IGraphicsWin::GetItemMenu(
long idx,
long& idxInMenu,
long& offsetIdx,
IPopupMenu& baseMenu)
1312 long oldIDx = offsetIdx;
1313 offsetIdx += baseMenu.NItems();
1315 if (idx < offsetIdx)
1317 idxInMenu = idx - oldIDx;
1323 for(
int i = 0; i< baseMenu.NItems(); i++)
1326 if(pMenuItem->GetSubmenu())
1328 pMenu = GetItemMenu(idx, idxInMenu, offsetIdx, *pMenuItem->GetSubmenu());
1338 HMENU IGraphicsWin::CreateMenu(
IPopupMenu& menu,
long* pOffsetIdx)
1340 HMENU hMenu = ::CreatePopupMenu();
1342 WDL_String escapedText;
1345 long offset = *pOffsetIdx;
1346 long nItems = menu.NItems();
1347 *pOffsetIdx += nItems;
1350 for(
int i = 0; i < nItems; i++)
1354 if (pMenuItem->GetIsSeparator())
1356 AppendMenu(hMenu, MF_SEPARATOR, 0, 0);
1360 const char* str = pMenuItem->GetText();
1361 int maxlen = strlen(str) + menu.GetPrefix() ? 50 : 0;
1362 WDL_String entryText(str);
1364 if (menu.GetPrefix())
1366 switch (menu.GetPrefix())
1370 entryText.SetFormatted(maxlen,
"%1d: %s", i+1, str);
break;
1374 entryText.SetFormatted(maxlen,
"%02d: %s", i+1, str);
break;
1378 entryText.SetFormatted(maxlen,
"%03d: %s", i+1, str);
break;
1385 if (strchr(entryText.Get(),
'&'))
1387 for (
int c = 0; c < entryText.GetLength(); c++)
1388 if (entryText.Get()[c] ==
'&')
1389 entryText.Insert(
"&", c++);
1393 if (nItems < 160 && menu.NItemsPerColumn() > 0 && inc && !(inc % menu.NItemsPerColumn()))
1394 flags |= MF_MENUBARBREAK;
1396 if (pMenuItem->GetEnabled())
1397 flags |= MF_ENABLED;
1400 if (pMenuItem->GetIsTitle())
1401 flags |= MF_DISABLED;
1402 if (pMenuItem->GetChecked())
1403 flags |= MF_CHECKED;
1405 flags |= MF_UNCHECKED;
1407 if (pMenuItem->GetSubmenu())
1409 HMENU submenu = CreateMenu(*pMenuItem->GetSubmenu(), pOffsetIdx);
1412 AppendMenu(hMenu, flags|MF_POPUP, (UINT_PTR)submenu, (
const TCHAR*)entryText.Get());
1417 AppendMenu(hMenu, flags, offset + inc, entryText.Get());
1429 HMENU hMenu = CreateMenu(menu, &offsetIdx);
1436 const float scale = GetTotalScale();
1438 cPos.x = bounds.
L * scale;
1439 cPos.y = bounds.
B * scale;
1441 ::ClientToScreen(mPlugWnd, &cPos);
1443 if (TrackPopupMenu(hMenu, TPM_LEFTALIGN, cPos.x, cPos.y, 0, mPlugWnd, 0))
1446 if (PeekMessage(&msg, mPlugWnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
1448 if (HIWORD(msg.wParam) == 0)
1450 long res = LOWORD(msg.wParam);
1455 IPopupMenu* pReturnMenu = GetItemMenu(res, idx, offsetIdx, menu);
1458 result = pReturnMenu;
1459 result->SetChosenItemIdx(idx);
1462 if(pReturnMenu && pReturnMenu->GetFunction())
1463 pReturnMenu->ExecFunction();
1471 RECT r = { 0, 0,
static_cast<LONG
>(WindowWidth() * GetScreenScale()), static_cast<LONG>(WindowHeight() * GetScreenScale()) };
1472 InvalidateRect(mPlugWnd, &r, FALSE);
1480 void IGraphicsWin::CreatePlatformTextEntry(
int paramIdx,
const IText& text,
const IRECT& bounds,
int length,
const char* str)
1487 switch ( text.mAlign )
1489 case EAlign::Near: editStyle = ES_LEFT;
break;
1490 case EAlign::Far: editStyle = ES_RIGHT;
break;
1491 case EAlign::Center:
1492 default: editStyle = ES_CENTER;
break;
1495 const float scale = GetTotalScale();
1498 WCHAR strWide[MAX_PARAM_DISPLAY_LEN];
1499 UTF8ToUTF16(strWide, str, MAX_PARAM_DISPLAY_LEN);
1501 mParamEditWnd = CreateWindowW(L
"EDIT", strWide, ES_AUTOHSCROLL | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE | ES_MULTILINE | editStyle,
1502 scaledBounds.
L, scaledBounds.
T, scaledBounds.
W()+1, scaledBounds.
H()+1,
1503 mPlugWnd, (HMENU) PARAM_EDIT_ID, mHInstance, 0);
1505 StaticStorage<HFontHolder>::Accessor hfontStorage(sHFontCache);
1507 LOGFONT lFont = { 0 };
1508 HFontHolder* hfontHolder = hfontStorage.Find(text.mFont);
1509 GetObject(hfontHolder->mHFont,
sizeof(LOGFONT), &lFont);
1510 lFont.lfHeight = text.mSize * scale;
1511 mEditFont = CreateFontIndirect(&lFont);
1513 assert(hfontHolder &&
"font not found - did you forget to load it?");
1515 mEditParam = paramIdx > kNoParameter ? GetDelegate()->GetParam(paramIdx) :
nullptr;
1519 SendMessage(mParamEditWnd, EM_LIMITTEXT, (WPARAM) length, 0);
1520 SendMessage(mParamEditWnd, WM_SETFONT, (WPARAM)mEditFont, 0);
1521 SendMessage(mParamEditWnd, EM_SETSEL, 0, -1);
1523 if (text.mVAlign == EVAlign::Middle)
1525 double size = text.mSize * scale;
1526 double offset = (scaledBounds.
H() - size) / 2.0;
1527 RECT formatRect{0, (LONG) offset, (LONG) scaledBounds.
W() + 1, (LONG) scaledBounds.
H() + 1};
1528 SendMessage(mParamEditWnd, EM_SETRECT, 0, (LPARAM)&formatRect);
1531 SetFocus(mParamEditWnd);
1533 mDefEditProc = (WNDPROC) SetWindowLongPtr(mParamEditWnd, GWLP_WNDPROC, (LONG_PTR) ParamEditProc);
1534 SetWindowLongPtr(mParamEditWnd, GWLP_USERDATA, 0xdeadf00b);
1537 bool IGraphicsWin::RevealPathInExplorerOrFinder(WDL_String& path,
bool select)
1539 bool success =
false;
1541 if (path.GetLength())
1543 WCHAR winDir[IPLUG_WIN_MAX_WIDE_PATH];
1544 WCHAR explorerWide[IPLUG_WIN_MAX_WIDE_PATH];
1545 UINT len = GetSystemDirectoryW(winDir, IPLUG_WIN_MAX_WIDE_PATH);
1547 if (len || !(len > MAX_PATH - 2))
1549 winDir[len] = L
'\\';
1550 winDir[++len] = L
'\0';
1552 WDL_String explorerParams;
1555 explorerParams.Append(
"/select,");
1557 explorerParams.Append(
"\"");
1558 explorerParams.Append(path.Get());
1559 explorerParams.Append(
"\\\"");
1561 UTF8ToUTF16(explorerWide, explorerParams.Get(), IPLUG_WIN_MAX_WIDE_PATH);
1564 if ((result=::ShellExecuteW(NULL, L
"open", L
"explorer.exe", explorerWide, winDir, SW_SHOWNORMAL)) <= (HINSTANCE) 32)
1572 void IGraphicsWin::PromptForFile(WDL_String& fileName, WDL_String& path, EFileAction action,
const char* extensions)
1574 if (!WindowIsOpen())
1580 wchar_t fnCStr[_MAX_PATH];
1581 wchar_t dirCStr[_MAX_PATH];
1583 if (fileName.GetLength())
1584 UTF8ToUTF16(fnCStr, fileName.Get(), _MAX_PATH);
1593 UTF8ToUTF16(dirCStr, path.Get(), _MAX_PATH);
1596 memset(&ofn, 0,
sizeof(OPENFILENAMEW));
1598 ofn.lStructSize =
sizeof(OPENFILENAMEW);
1599 ofn.hwndOwner = (HWND) GetWindow();
1600 ofn.lpstrFile = fnCStr;
1601 ofn.nMaxFile = _MAX_PATH - 1;
1602 ofn.lpstrInitialDir = dirCStr;
1603 ofn.Flags = OFN_PATHMUSTEXIST;
1605 if (CStringHasContents(extensions))
1607 wchar_t extStr[256];
1608 wchar_t defExtStr[16];
1609 int i, p, n = strlen(extensions);
1610 bool seperator =
true;
1612 for (i = 0, p = 0; i < n; ++i)
1624 if (extensions[i] ==
' ')
1627 extStr[p++] = extensions[i];
1631 wcscpy(&extStr[p], extStr);
1632 extStr[p + p] =
'\0';
1633 ofn.lpstrFilter = extStr;
1635 for (i = 0, p = 0; i < n && extensions[i] !=
' '; ++i)
1636 defExtStr[p++] = extensions[i];
1638 defExtStr[p++] =
'\0';
1639 ofn.lpstrDefExt = defExtStr;
1646 case EFileAction::Save:
1647 ofn.Flags |= OFN_OVERWRITEPROMPT;
1648 rc = GetSaveFileNameW(&ofn);
1650 case EFileAction::Open:
1652 ofn.Flags |= OFN_FILEMUSTEXIST;
1653 rc = GetOpenFileNameW(&ofn);
1659 char drive[_MAX_DRIVE];
1660 char directoryOutCStr[_MAX_PATH];
1662 WDL_String tempUTF8;
1663 UTF16ToUTF8(tempUTF8, ofn.lpstrFile);
1665 if (_splitpath_s(tempUTF8.Get(), drive,
sizeof(drive), directoryOutCStr,
sizeof(directoryOutCStr), NULL, 0, NULL, 0) == 0)
1668 path.Append(directoryOutCStr);
1671 fileName.Set(tempUTF8.Get());
1678 ReleaseMouseCapture();
1681 void IGraphicsWin::PromptForDirectory(WDL_String& dir)
1684 memset(&bi, 0,
sizeof(bi));
1686 bi.ulFlags = BIF_USENEWUI;
1687 bi.hwndOwner = mPlugWnd;
1688 bi.lpszTitle =
"Choose a Directory";
1691 ::OleInitialize(NULL);
1692 LPITEMIDLIST pIDL = ::SHBrowseForFolder(&bi);
1696 char buffer[_MAX_PATH] = {
'\0'};
1698 if(::SHGetPathFromIDList(pIDL, buffer) != 0)
1705 CoTaskMemFree(pIDL);
1712 ReleaseMouseCapture();
1714 ::OleUninitialize();
1717 static UINT_PTR CALLBACK CCHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
1719 if (uiMsg == WM_INITDIALOG && lParam)
1721 CHOOSECOLOR* cc = (CHOOSECOLOR*) lParam;
1722 if (cc && cc->lCustData)
1724 char* str = (
char*) cc->lCustData;
1725 SetWindowText(hdlg, str);
1727 uiSetRGB = RegisterWindowMessage(SETRGBSTRING);
1728 SendMessage(hdlg, uiSetRGB, 0, (LPARAM) cc->rgbResult);
1734 bool IGraphicsWin::PromptForColor(
IColor& color,
const char* prompt, IColorPickerHandlerFunc func)
1736 ReleaseMouseCapture();
1741 const COLORREF w = RGB(255, 255, 255);
1742 static COLORREF customColorStorage[16] = { w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w };
1745 memset(&cc, 0,
sizeof(CHOOSECOLOR));
1746 cc.lStructSize =
sizeof(CHOOSECOLOR);
1747 cc.hwndOwner = mPlugWnd;
1748 cc.rgbResult = RGB(color.R, color.G, color.B);
1749 cc.lpCustColors = customColorStorage;
1750 cc.lCustData = (LPARAM) prompt;
1751 cc.lpfnHook = CCHookProc;
1752 cc.Flags = CC_RGBINIT | CC_ANYCOLOR | CC_FULLOPEN | CC_SOLIDCOLOR | CC_ENABLEHOOK;
1754 if (ChooseColor(&cc))
1756 color.R = GetRValue(cc.rgbResult);
1757 color.G = GetGValue(cc.rgbResult);
1758 color.B = GetBValue(cc.rgbResult);
1768 bool IGraphicsWin::OpenURL(
const char* url,
const char* msgWindowTitle,
const char* confirmMsg,
const char* errMsgOnFailure)
1770 if (confirmMsg && MessageBox(mPlugWnd, confirmMsg, msgWindowTitle, MB_YESNO) != IDYES)
1774 DWORD inetStatus = 0;
1775 if (InternetGetConnectedState(&inetStatus, 0))
1777 WCHAR urlWide[IPLUG_WIN_MAX_WIDE_PATH];
1778 UTF8ToUTF16(urlWide, url, IPLUG_WIN_MAX_WIDE_PATH);
1779 if (ShellExecuteW(mPlugWnd, L
"open", urlWide, 0, 0, SW_SHOWNORMAL) > HINSTANCE(32))
1784 if (errMsgOnFailure)
1786 MessageBox(mPlugWnd, errMsgOnFailure, msgWindowTitle, MB_OK);
1791 void IGraphicsWin::SetTooltip(
const char* tooltip)
1793 TOOLINFO ti = { TTTOOLINFOA_V2_SIZE, 0, mPlugWnd, (UINT_PTR)mPlugWnd };
1794 ti.lpszText = (LPTSTR)tooltip;
1795 SendMessage(mTooltipWnd, TTM_UPDATETIPTEXT, 0, (LPARAM)&ti);
1798 void IGraphicsWin::ShowTooltip()
1800 if (mTooltipIdx > -1)
1802 const char* tooltip = GetControl(mTooltipIdx)->GetTooltip();
1805 SetTooltip(tooltip);
1806 mShowingTooltip =
true;
1811 void IGraphicsWin::HideTooltip()
1813 if (mShowingTooltip)
1816 mShowingTooltip =
false;
1820 bool IGraphicsWin::GetTextFromClipboard(WDL_String& str)
1824 if (IsClipboardFormatAvailable(CF_UNICODETEXT))
1826 if(OpenClipboard(0))
1828 HGLOBAL hglb = GetClipboardData(CF_UNICODETEXT);
1832 WCHAR *origStr = (WCHAR*)GlobalLock(hglb);
1834 if (origStr != NULL)
1838 int newLen = WideCharToMultiByte(CP_UTF8, 0, origStr, -1, 0, 0, NULL, NULL);
1842 WDL_TypedBuf<char> utf8;
1843 utf8.Resize(newLen);
1844 numChars = WideCharToMultiByte(CP_UTF8, 0, origStr, -1, utf8.Get(), utf8.GetSize(), NULL, NULL);
1845 str.Set(utf8.Get());
1862 bool IGraphicsWin::SetTextInClipboard(
const char* str)
1864 if (!OpenClipboard(mMainWnd))
1869 const int len = strlen(str);
1873 int wchar_len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
1876 HGLOBAL hglbCopy = GlobalAlloc(GMEM_MOVEABLE, wchar_len*
sizeof(WCHAR));
1877 if (hglbCopy == NULL)
1884 LPWSTR lpstrCopy = (LPWSTR)GlobalLock(hglbCopy);
1885 MultiByteToWideChar(CP_UTF8, 0, str, -1, lpstrCopy, wchar_len);
1886 GlobalUnlock(hglbCopy);
1889 SetClipboardData(CF_UNICODETEXT, hglbCopy);
1897 static HFONT GetHFont(
const char* fontName,
int weight,
bool italic,
bool underline, DWORD quality = DEFAULT_QUALITY,
bool enumerate =
false)
1899 HDC hdc = GetDC(NULL);
1900 HFONT font =
nullptr;
1905 lFont.lfEscapement = 0;
1906 lFont.lfOrientation = 0;
1907 lFont.lfWeight = weight;
1908 lFont.lfItalic = italic;
1909 lFont.lfUnderline = underline;
1910 lFont.lfStrikeOut =
false;
1911 lFont.lfCharSet = DEFAULT_CHARSET;
1912 lFont.lfOutPrecision = OUT_TT_PRECIS;
1913 lFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1914 lFont.lfQuality = quality;
1915 lFont.lfPitchAndFamily = DEFAULT_PITCH;
1917 strncpy(lFont.lfFaceName, fontName, LF_FACESIZE);
1919 auto enumProc = [](
const LOGFONT* pLFont,
const TEXTMETRIC* pTextMetric, DWORD FontType, LPARAM lParam)
1924 if ((!enumerate || EnumFontFamiliesEx(hdc, &lFont, enumProc, NULL, 0) == -1))
1925 font = CreateFontIndirect(&lFont);
1929 char selectedFontName[64];
1931 SelectFont(hdc, font);
1932 GetTextFace(hdc, 64, selectedFontName);
1933 if (strcmp(selectedFontName, fontName))
1940 ReleaseDC(NULL, hdc);
1945 PlatformFontPtr IGraphicsWin::LoadPlatformFont(
const char* fontID,
const char* fileNameOrResID)
1947 StaticStorage<InstalledFont>::Accessor fontStorage(sPlatformFontCache);
1949 void* pFontMem =
nullptr;
1951 WDL_String fullPath;
1953 const EResourceLocation fontLocation =
LocateResource(fileNameOrResID,
"ttf", fullPath, GetBundleID(), GetWinModuleHandle(),
nullptr);
1955 if (fontLocation == kNotFound)
1958 switch (fontLocation)
1962 HANDLE file = CreateFile(fullPath.Get(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1963 PlatformFontPtr ret =
nullptr;
1966 HANDLE mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
1969 resSize = (int)GetFileSize(file,
nullptr);
1970 pFontMem = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
1971 ret = LoadPlatformFont(fontID, pFontMem, resSize);
1972 UnmapViewOfFile(pFontMem);
1973 CloseHandle(mapping);
1982 pFontMem =
const_cast<void *
>(
LoadWinResource(fullPath.Get(),
"ttf", resSize, GetWinModuleHandle()));
1983 return LoadPlatformFont(fontID, pFontMem, resSize);
1991 PlatformFontPtr IGraphicsWin::LoadPlatformFont(
const char* fontID,
const char* fontName, ETextStyle style)
1993 int weight = style == ETextStyle::Bold ? FW_BOLD : FW_REGULAR;
1994 bool italic = style == ETextStyle::Italic;
1995 bool underline =
false;
1996 DWORD quality = DEFAULT_QUALITY;
1998 HFONT font = GetHFont(fontName, weight, italic, underline, quality,
true);
2000 return PlatformFontPtr(font ?
new Font(font,
TextStyleString(style),
true) :
nullptr);
2003 PlatformFontPtr IGraphicsWin::LoadPlatformFont(
const char* fontID,
void* pData,
int dataSize)
2005 StaticStorage<InstalledFont>::Accessor fontStorage(sPlatformFontCache);
2007 std::unique_ptr<InstalledFont> pFont;
2008 void* pFontMem = pData;
2009 int resSize = dataSize;
2011 pFont = std::make_unique<InstalledFont>(pFontMem, resSize);
2013 if (pFontMem && pFont && pFont->IsValid())
2015 IFontInfo fontInfo(pFontMem, resSize, 0);
2016 WDL_String family = fontInfo.GetFamily();
2017 int weight = fontInfo.IsBold() ? FW_BOLD : FW_REGULAR;
2018 bool italic = fontInfo.IsItalic();
2019 bool underline = fontInfo.IsUnderline();
2021 HFONT font = GetHFont(family.Get(), weight, italic, underline);
2025 fontStorage.Add(pFont.release(), fontID);
2026 return PlatformFontPtr(
new Font(font,
"",
false));
2033 void IGraphicsWin::CachePlatformFont(
const char* fontID,
const PlatformFontPtr& font)
2035 StaticStorage<HFontHolder>::Accessor hfontStorage(sHFontCache);
2037 HFONT hfont = font->GetDescriptor();
2039 if (!hfontStorage.Find(fontID))
2043 DWORD WINAPI VBlankRun(LPVOID lpParam)
2046 return pGraphics->OnVBlankRun();
2049 void IGraphicsWin::StartVBlankThread(HWND hWnd)
2051 mVBlankWindow = hWnd;
2052 mVBlankShutdown =
false;
2054 mVBlankThread = ::CreateThread(NULL, 0, VBlankRun,
this, 0, &threadId);
2057 void IGraphicsWin::StopVBlankThread()
2059 if (mVBlankThread != INVALID_HANDLE_VALUE)
2061 mVBlankShutdown =
true;
2062 ::WaitForSingleObject(mVBlankThread, 10000);
2063 mVBlankThread = INVALID_HANDLE_VALUE;
2079 typedef UINT32 D3DKMT_HANDLE;
2080 typedef UINT D3DDDI_VIDEO_PRESENT_SOURCE_ID;
2081 typedef struct _D3DKMT_OPENADAPTERFROMHDC {
2083 D3DKMT_HANDLE hAdapter;
2085 D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId;
2086 } D3DKMT_OPENADAPTERFROMHDC;
2087 typedef struct _D3DKMT_CLOSEADAPTER {
2088 D3DKMT_HANDLE hAdapter;
2089 } D3DKMT_CLOSEADAPTER;
2090 typedef struct _D3DKMT_WAITFORVERTICALBLANKEVENT {
2091 D3DKMT_HANDLE hAdapter;
2092 D3DKMT_HANDLE hDevice;
2093 D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId;
2094 } D3DKMT_WAITFORVERTICALBLANKEVENT;
2097 typedef NTSTATUS(WINAPI* D3DKMTOpenAdapterFromHdc)(D3DKMT_OPENADAPTERFROMHDC* Arg1);
2098 typedef NTSTATUS(WINAPI* D3DKMTCloseAdapter)(
const D3DKMT_CLOSEADAPTER* Arg1);
2099 typedef NTSTATUS(WINAPI* D3DKMTWaitForVerticalBlankEvent)(
const D3DKMT_WAITFORVERTICALBLANKEVENT* Arg1);
2101 DWORD IGraphicsWin::OnVBlankRun()
2103 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
2107 float rateFallback = 60.0f;
2108 int rateMS = (int)(1000.0f / rateFallback);
2116 D3DKMTOpenAdapterFromHdc pOpen =
nullptr;
2117 D3DKMTCloseAdapter pClose =
nullptr;
2118 D3DKMTWaitForVerticalBlankEvent pWait =
nullptr;
2119 HINSTANCE hInst = LoadLibrary(
"gdi32.dll");
2120 if (hInst !=
nullptr)
2122 pOpen = (D3DKMTOpenAdapterFromHdc)GetProcAddress((HMODULE)hInst,
"D3DKMTOpenAdapterFromHdc");
2123 pClose = (D3DKMTCloseAdapter)GetProcAddress((HMODULE)hInst,
"D3DKMTCloseAdapter");
2124 pWait = (D3DKMTWaitForVerticalBlankEvent)GetProcAddress((HMODULE)hInst,
"D3DKMTWaitForVerticalBlankEvent");
2131 if (!pOpen || !pClose || !pWait)
2133 while (mVBlankShutdown ==
false)
2143 bool adapterIsOpen =
false;
2144 DWORD adapterLastFailTime = 0;
2145 _D3DKMT_WAITFORVERTICALBLANKEVENT we = { 0 };
2147 while (mVBlankShutdown ==
false)
2152 if (adapterLastFailTime < ::GetTickCount() - 1000)
2155 D3DKMT_OPENADAPTERFROMHDC openAdapterData = { 0 };
2156 HDC hDC = GetDC(mVBlankWindow);
2157 openAdapterData.hDc = hDC;
2158 NTSTATUS status = (*pOpen)(&openAdapterData);
2162 adapterLastFailTime = 0;
2163 adapterIsOpen =
true;
2164 we.hAdapter = openAdapterData.hAdapter;
2166 we.VidPnSourceId = openAdapterData.VidPnSourceId;
2171 adapterLastFailTime = ::GetTickCount();
2180 NTSTATUS status = (*pWait)(&we);
2184 _D3DKMT_CLOSEADAPTER ca;
2185 ca.hAdapter = we.hAdapter;
2187 adapterIsOpen =
false;
2204 _D3DKMT_CLOSEADAPTER ca;
2205 ca.hAdapter = we.hAdapter;
2207 adapterIsOpen =
false;
2212 if (hInst !=
nullptr)
2214 FreeLibrary((HMODULE)hInst);
2221 void IGraphicsWin::VBlankNotify()
2224 ::PostMessage(mVBlankWindow, WM_VBLANK, mVBlankCount, 0);
2227 #ifndef NO_IGRAPHICS 2228 #if defined IGRAPHICS_SKIA 2229 #include "IGraphicsSkia.cpp" 2233 #elif defined IGRAPHICS_NANOVG 2234 #include "IGraphicsNanoVG.cpp" 2235 #ifdef IGRAPHICS_FREETYPE 2236 #define FONS_USE_FREETYPE 2237 #pragma comment(lib, "freetype.lib") void Scale(float scale)
Multiply each field of this IRECT by scale.
const IRECT & Get(int idx) const
Get an IRECT from the list (will crash if idx is invalid)
Used to manage a list of rectangular areas and optimize them for drawing to the screen.
Used to manage a rectangular area, independent of draw class/platform.
IGraphics platform class for Windows.
virtual ECursor SetMouseCursor(ECursor cursorType=ECursor::ARROW)
Sets the mouse cursor to one of ECursor (implementations should return the result of the base impleme...
Used to manage mouse modifiers i.e.
const void * LoadWinResource(const char *resID, const char *type, int &sizeInBytes, void *pHInstance)
Load a resource from the binary (windows only).
Common paths useful for plug-ins.
void PixelAlign()
Pixel aligns the rect in an inclusive manner (moves all points outwards)
Used to manage color data, independent of draw class/platform.
IPlug's parameter class.
float R
Right side of the rectangle (X + W)
IRECT GetScaled(float scale) const
Get a copy of this IRECT with all values multiplied by scale.
An editor delegate base class for a SOMETHING that uses IGraphics for it's UI.
IText is used to manage font and text/text entry style for a piece of text on the UI...
Used to group mouse coordinates with mouse modifier information.
EResourceLocation LocateResource(const char *fileNameOrResID, const char *type, WDL_String &result, const char *bundleID, void *pHInstance, const char *sharedResourcesSubPath)
Find the absolute path of a resource based on it's file name (e.g.
static const char * TextStyleString(ETextStyle style)
Helper to get a CString based on ETextStyle.
EParamType Type() const
Get the parameter's type.
float L
Left side of the rectangle (X)
Used for key press info, such as ASCII representation, virtual key (mapped to win32 codes) and modifi...
float T
Top of the rectangle (Y)
float B
Bottom of the rectangle (Y + H)