#include #include #include #pragma comment(lib, "d2d1") #include "basewin.h" template void SafeRelease(T **ppT) { if (*ppT) { (*ppT)->Release(); *ppT = NULL; } } class DPIScale { static float scaleX; static float scaleY; public: static void Initialize(ID2D1Factory *pFactory) { FLOAT dpiX, dpiY; pFactory->GetDesktopDpi(&dpiX, &dpiY); scaleX = dpiX/96.0f; scaleY = dpiY/96.0f; } template static D2D1_POINT_2F PixelsToDips(T x, T y) { return D2D1::Point2F(static_cast(x) / scaleX, static_cast(y) / scaleY); } }; float DPIScale::scaleX = 1.0f; float DPIScale::scaleY = 1.0f; class MainWindow : public BaseWindow { ID2D1Factory *pFactory; ID2D1HwndRenderTarget *pRenderTarget; ID2D1SolidColorBrush *pBrush; D2D1_ELLIPSE ellipse; D2D1_POINT_2F ptMouse; void CalculateLayout() { } HRESULT CreateGraphicsResources(); void DiscardGraphicsResources(); void OnPaint(); void Resize(); void OnLButtonDown(int pixelX, int pixelY, DWORD flags); void OnLButtonUp(); void OnMouseMove(int pixelX, int pixelY, DWORD flags); public: MainWindow() : pFactory(NULL), pRenderTarget(NULL), pBrush(NULL), ellipse(D2D1::Ellipse(D2D1::Point2F(), 0, 0)), ptMouse(D2D1::Point2F()) { } PCWSTR ClassName() const { return L"Circle Window Class"; } LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam); }; HRESULT MainWindow::CreateGraphicsResources() { HRESULT hr = S_OK; if (pRenderTarget == NULL) { RECT rc; GetClientRect(m_hwnd, &rc); D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom); hr = pFactory->CreateHwndRenderTarget( D2D1::RenderTargetProperties(), D2D1::HwndRenderTargetProperties(m_hwnd, size), &pRenderTarget); if (SUCCEEDED(hr)) { const D2D1_COLOR_F color = D2D1::ColorF(1.0f, 1.0f, 0); hr = pRenderTarget->CreateSolidColorBrush(color, &pBrush); if (SUCCEEDED(hr)) { CalculateLayout(); } } } return hr; } void MainWindow::DiscardGraphicsResources() { SafeRelease(&pRenderTarget); SafeRelease(&pBrush); } void MainWindow::OnPaint() { HRESULT hr = CreateGraphicsResources(); if (SUCCEEDED(hr)) { PAINTSTRUCT ps; BeginPaint(m_hwnd, &ps); pRenderTarget->BeginDraw(); pRenderTarget->Clear( D2D1::ColorF(D2D1::ColorF::SkyBlue) ); pRenderTarget->FillEllipse(ellipse, pBrush); hr = pRenderTarget->EndDraw(); if (FAILED(hr) || hr == D2DERR_RECREATE_TARGET) { DiscardGraphicsResources(); } EndPaint(m_hwnd, &ps); } } void MainWindow::Resize() { if (pRenderTarget != NULL) { RECT rc; GetClientRect(m_hwnd, &rc); D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom); pRenderTarget->Resize(size); CalculateLayout(); InvalidateRect(m_hwnd, NULL, FALSE); } } void MainWindow::OnLButtonDown(int pixelX, int pixelY, DWORD flags) { SetCapture(m_hwnd); ellipse.point = ptMouse = DPIScale::PixelsToDips(pixelX, pixelY); ellipse.radiusX = ellipse.radiusY = 1.0f; InvalidateRect(m_hwnd, NULL, FALSE); } void MainWindow::OnMouseMove(int pixelX, int pixelY, DWORD flags) { if (flags & MK_LBUTTON) { const D2D1_POINT_2F dips = DPIScale::PixelsToDips(pixelX, pixelY); const float width = (dips.x - ptMouse.x) / 2; const float height = (dips.y - ptMouse.y) / 2; const float x1 = ptMouse.x + width; const float y1 = ptMouse.y + height; ellipse = D2D1::Ellipse(D2D1::Point2F(x1, y1), width, height); InvalidateRect(m_hwnd, NULL, FALSE); } } void MainWindow::OnLButtonUp() { ReleaseCapture(); } int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR, int nCmdShow) { MainWindow win; if (!win.Create(L"Circle", WS_OVERLAPPEDWINDOW)) { return 0; } ShowWindow(win.Window(), nCmdShow); // Run the message loop. MSG msg = { }; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } LRESULT MainWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CREATE: if (FAILED(D2D1CreateFactory( D2D1_FACTORY_TYPE_SINGLE_THREADED, &pFactory))) { return -1; // Fail CreateWindowEx. } DPIScale::Initialize(pFactory); return 0; case WM_DESTROY: DiscardGraphicsResources(); SafeRelease(&pFactory); PostQuitMessage(0); return 0; case WM_PAINT: OnPaint(); return 0; case WM_SIZE: Resize(); return 0; case WM_LBUTTONDOWN: OnLButtonDown(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), (DWORD)wParam); return 0; case WM_LBUTTONUP: OnLButtonUp(); return 0; case WM_MOUSEMOVE: OnMouseMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), (DWORD)wParam); return 0; } return DefWindowProc(m_hwnd, uMsg, wParam, lParam); }