Files
2026-08-16 18:24:52 +07:00

224 lines
5.9 KiB
C++

// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#pragma once
#include "../lib/vstguibase.h"
#include "../lib/iexternalview.h"
#include <windows.h>
#include <cassert>
#include <functional>
#include <cstdint>
#include <string>
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ExternalView {
//------------------------------------------------------------------------
inline void setWindowSize (HWND window, IntRect r)
{
SetWindowPos (window, HWND_TOP, static_cast<int> (r.origin.x), static_cast<int> (r.origin.y),
static_cast<int> (r.size.width), static_cast<int> (r.size.height),
SWP_NOZORDER | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_DEFERERASE);
}
//------------------------------------------------------------------------
struct HWNDWindow final
{
using WindowProcFunc =
std::function<LONG_PTR (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)>;
HWNDWindow (HINSTANCE instance) : instance (instance) {}
~HWNDWindow () noexcept
{
if (window)
{
SetWindowLongPtr (window, GWLP_USERDATA, (__int3264)(LONG_PTR) nullptr);
DestroyWindow (window);
}
destroyWindowClass ();
}
bool create (const TCHAR* title, const IntRect& frame, HWND parent, DWORD exStyle = 0,
DWORD style = WS_CHILD)
{
if (!initWindowClass ())
return false;
window = CreateWindowEx (
exStyle, MAKEINTATOM (windowClassAtom), title, style, static_cast<int> (frame.origin.x),
static_cast<int> (frame.origin.y), static_cast<int> (frame.size.width),
static_cast<int> (frame.size.height), parent, nullptr, instance, nullptr);
if (!window)
return false;
SetWindowLongPtr (window, GWLP_USERDATA, (__int3264)(LONG_PTR)this);
return true;
}
void setWindowProc (WindowProcFunc&& func) { windowProc = std::move (func); }
void setSize (const IntRect& r)
{
if (!window)
return;
setWindowSize (window, r);
}
void show (bool state) { ShowWindow (window, state ? SW_SHOW : SW_HIDE); }
void setEnabled (bool state) { EnableWindow (window, state); }
HWND getHWND () const { return window; }
HINSTANCE getInstance () const { return instance; }
private:
bool initWindowClass ()
{
assert (instance != nullptr);
if (windowClassAtom != 0)
return true;
std::wstring windowClassName;
windowClassName = TEXT ("VSTGUI ExternalView Container ");
windowClassName += std::to_wstring (reinterpret_cast<uint64_t> (this));
WNDCLASS windowClass;
windowClass.style = CS_GLOBALCLASS;
windowClass.lpfnWndProc = WindowProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = instance;
windowClass.hIcon = 0;
windowClass.hCursor = LoadCursor (NULL, IDC_ARROW);
windowClass.hbrBackground = 0;
windowClass.lpszMenuName = 0;
windowClass.lpszClassName = windowClassName.data ();
windowClassAtom = RegisterClass (&windowClass);
return windowClassAtom != 0;
}
void destroyWindowClass ()
{
if (windowClassAtom == 0)
return;
UnregisterClass (MAKEINTATOM (windowClassAtom), instance);
windowClassAtom = 0;
}
static LONG_PTR WINAPI WindowProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_ERASEBKGND)
return 1;
auto instance = reinterpret_cast<HWNDWindow*> (GetWindowLongPtr (hwnd, GWLP_USERDATA));
if (instance && instance->windowProc)
return instance->windowProc (hwnd, message, wParam, lParam);
return DefWindowProc (hwnd, message, wParam, lParam);
}
WindowProcFunc windowProc;
HWND window {nullptr};
HINSTANCE instance {nullptr};
ATOM windowClassAtom {0};
};
//------------------------------------------------------------------------
struct NonClientMetrics
{
static const NONCLIENTMETRICS& get ()
{
static NonClientMetrics gInstance;
return gInstance.nonClientMetrics;
}
private:
NonClientMetrics ()
{
nonClientMetrics.cbSize = sizeof (nonClientMetrics);
SystemParametersInfoForDpi (SPI_GETNONCLIENTMETRICS, nonClientMetrics.cbSize,
&nonClientMetrics, 0, 96);
}
NONCLIENTMETRICS nonClientMetrics {};
};
//------------------------------------------------------------------------
struct ExternalHWNDBase : ViewAdapter
{
using Base = ExternalHWNDBase;
using PlatformViewType = ExternalView::PlatformViewType;
using IntRect = ExternalView::IntRect;
HWNDWindow container;
HWND child {nullptr};
ExternalHWNDBase (HINSTANCE hInst) : container (hInst)
{
container.create (nullptr, {{0, 0}, {1, 1}}, HWND_MESSAGE,
WS_EX_NOPARENTNOTIFY | WS_EX_COMPOSITED, WS_CHILD | WS_VISIBLE);
}
virtual ~ExternalHWNDBase () noexcept
{
if (child)
DestroyWindow (child);
}
bool platformViewTypeSupported (PlatformViewType type) override
{
return type == PlatformViewType::HWND;
}
bool attach (void* parent, PlatformViewType parentViewType) override
{
assert (container.getHWND ());
if (parent == nullptr || parentViewType != PlatformViewType::HWND)
return false;
auto parentHWND = reinterpret_cast<HWND> (parent);
SetParent (container.getHWND (), parentHWND);
return true;
}
bool remove () override
{
assert (container.getHWND ());
SetParent (container.getHWND (), HWND_MESSAGE);
return true;
}
void setViewSize (IntRect frame, IntRect visible) override
{
assert (container.getHWND ());
container.setSize (visible);
if (child)
{
frame.origin.x -= visible.origin.x;
frame.origin.y -= visible.origin.y;
setWindowSize (child, frame);
}
}
void setContentScaleFactor (double scaleFactor) override {}
void setMouseEnabled (bool state) override { EnableWindow (container.getHWND (), state); }
void takeFocus () override { SetFocus (child); }
void looseFocus () override
{
if (GetFocus () == child)
{
SetFocus (GetParent (container.getHWND ()));
}
}
};
//------------------------------------------------------------------------
} // ExternalView
} // VSTGUI