// Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.0 OR LicenseRef-Slint-commercial #pragma once #include #include #include "appview.h" #include #include namespace slint_platform = slint::experimental::platform; struct Geometry { int x = 0; int y = 0; uint32_t width = 0; uint32_t height = 0; }; struct MyWindowAdapter : public slint_platform::WindowAdapter { HWND hwnd; Geometry geometry = { 0, 0, 600, 300 }; std::optional m_renderer; MyWindowAdapter(HWND winId) { HINSTANCE hInstance = GetModuleHandleW(nullptr); // Register the window class. const wchar_t CLASS_NAME[] = L"Sample Window Class"; WNDCLASS wc = {}; wc.lpfnWndProc = MyWindowAdapter::windowProc; wc.hInstance = hInstance; wc.lpszClassName = CLASS_NAME; RegisterClass(&wc); // Create the window. hwnd = CreateWindowEx(0, // Optional window styles. CLASS_NAME, // Window class L"Learn to Program Windows", // Window text WS_CHILDWINDOW, // Window style // Size and position 0, 0, 600, 300, winId, NULL, // Menu hInstance, // Instance handle NULL // Additional application data ); m_renderer.emplace(slint_platform::NativeWindowHandle::from_win32(hwnd, hInstance), slint::PhysicalSize({ 600, 300 })); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this); } slint_platform::AbstractRenderer &renderer() override { return m_renderer.value(); } slint::PhysicalSize physical_size() const override { RECT r; GetWindowRect(hwnd, &r); return slint::PhysicalSize({ uint32_t(r.right - r.left), uint32_t(r.bottom - r.top) }); } void show() const override { ShowWindow(hwnd, SW_SHOWNORMAL); m_renderer->show(); } void hide() const override { // TODO: destroy window m_renderer->hide(); } void request_redraw() const override { InvalidateRect(hwnd, nullptr, false); } void render() { m_renderer->render(window()); if (has_active_animations()) request_redraw(); } void resize(uint32_t width, uint32_t height) { slint::PhysicalSize windowSize({ width, height }); m_renderer->resize(windowSize); dispatch_resize_event(slint::LogicalSize({ (float)width, (float)height })); } void setGeometry(int x, int y, int width, int height) { SetWindowPos(hwnd, nullptr, x, y, width, height, 0); } std::optional mouseEventForMessage(UINT uMsg, LPARAM lParam) { float x = float(LOWORD(lParam)); float y = float(HIWORD(lParam)); auto makePressEvent = [=](UINT uMsg) { slint::cbindgen_private::PointerEventButton button; switch (uMsg) { case WM_LBUTTONDOWN: button = slint::cbindgen_private::PointerEventButton::Left; break; case WM_MBUTTONDOWN: button = slint::cbindgen_private::PointerEventButton::Middle; break; case WM_RBUTTONDOWN: button = slint::cbindgen_private::PointerEventButton::Right; break; default: assert(!"not implemented"); } return slint::cbindgen_private::MouseEvent { .tag = slint::cbindgen_private::MouseEvent::Tag::Pressed, .pressed = slint::cbindgen_private::MouseEvent::Pressed_Body { .position = { x, y }, .button = button, } }; }; auto makeReleaseEvent = [=](UINT uMsg) { slint::cbindgen_private::PointerEventButton button; switch (uMsg) { case WM_LBUTTONUP: button = slint::cbindgen_private::PointerEventButton::Left; break; case WM_MBUTTONUP: button = slint::cbindgen_private::PointerEventButton::Middle; break; case WM_RBUTTONUP: button = slint::cbindgen_private::PointerEventButton::Right; break; default: assert(!"not implemented"); } return slint::cbindgen_private::MouseEvent { .tag = slint::cbindgen_private::MouseEvent::Tag::Released, .released = slint::cbindgen_private::MouseEvent::Released_Body { .position = { x, y }, .button = button, } }; }; switch (uMsg) { case WM_LBUTTONUP: case WM_MBUTTONUP: case WM_RBUTTONUP: return makeReleaseEvent(uMsg); case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: return makePressEvent(uMsg); case WM_MOUSEMOVE: return slint::cbindgen_private::MouseEvent { .tag = slint::cbindgen_private::MouseEvent::Tag::Moved, .moved = slint::cbindgen_private::MouseEvent::Moved_Body { .position = { x, y }, } }; default: break; } return std::nullopt; } void mouse_event(UINT uMsg, LPARAM lParam) { if (auto event = mouseEventForMessage(uMsg, lParam)) { dispatch_pointer_event(*event); } } static LRESULT CALLBACK windowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { MyWindowAdapter *self = reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); if (self == nullptr) { return DefWindowProc(hwnd, uMsg, wParam, lParam); } switch (uMsg) { case WM_DESTROY: PostQuitMessage(0); return 0; case WM_PAINT: { PAINTSTRUCT ps; BeginPaint(hwnd, &ps); slint_platform::update_timers_and_animations(); self->render(); EndPaint(hwnd, &ps); return 0; } case WM_SIZE: self->resize(LOWORD(lParam), HIWORD(lParam)); return 0; case WM_LBUTTONUP: case WM_LBUTTONDOWN: case WM_MBUTTONUP: case WM_MBUTTONDOWN: case WM_RBUTTONUP: case WM_RBUTTONDOWN: case WM_MOUSEMOVE: slint_platform::update_timers_and_animations(); self->mouse_event(uMsg, lParam); return 0; } return DefWindowProc(hwnd, uMsg, wParam, lParam); } private: };