Files
mirage/src/mirage_render/platform_window/windows/windows_window.cpp
2025-03-26 17:25:55 +08:00

280 lines
8.4 KiB
C++

#include <iostream>
#include "platform_window/platform_window.h"
#include <windows.h>
#define WINDOW_HANDLE static_cast<HWND>(window_handle_)
bool mouse_tracking_ = FALSE;
std::vector<platform_window*> windows;
platform_window* get_window_from_hwnd(const HWND hwnd) {
for (const auto& window: windows) {
if (window->get_window_handle() == hwnd) {
return window;
}
}
return nullptr;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
bool processed = false;
// 窗口关闭事件
if (uMsg == WM_CLOSE) {
std::erase_if(windows, [hwnd](platform_window* window) {
if (window->get_window_handle() == hwnd) {
window->close();
return true;
}
return false;
});
processed = true;
}
// 窗口销毁事件
if (uMsg == WM_DESTROY) {
PostQuitMessage(0);
processed = true;
}
// 窗口移动事件
if (uMsg == WM_MOVE) {
if (const auto window = get_window_from_hwnd(hwnd)) { window->on_move(LOWORD(lParam), HIWORD(lParam)); }
processed = true;
}
// 窗口大小改变事件
if (uMsg == WM_SIZE) {
if (const auto window = get_window_from_hwnd(hwnd)) {
window->on_resize(LOWORD(lParam), HIWORD(lParam));
}
processed = true;
}
// 鼠标移动事件
if (uMsg == WM_MOUSEMOVE) {
if (const auto window = get_window_from_hwnd(hwnd)) {
const int x = LOWORD(lParam);
const int y = HIWORD(lParam);
const Eigen::Vector2f pos(static_cast<float>(x), static_cast<float>(y));
window->handle_mouse_move(pos);
}
if (!mouse_tracking_) {
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hwnd;
tme.dwHoverTime = HOVER_DEFAULT;
TrackMouseEvent(&tme);
mouse_tracking_ = TRUE;
}
processed = true;
}
// 鼠标按键事件
const auto lmr_button = uMsg >= WM_LBUTTONDOWN && uMsg <= WM_MBUTTONDBLCLK;
const auto x_button = uMsg >= WM_XBUTTONDOWN && uMsg <= WM_XBUTTONDBLCLK;
if (lmr_button || x_button) {
if (const auto window = get_window_from_hwnd(hwnd)) {
const int x = LOWORD(lParam);
const int y = HIWORD(lParam);
const Eigen::Vector2f pos(static_cast<float>(x), static_cast<float>(y));
const auto action = platform_event_to_mouse_action(uMsg, wParam);
const auto button = platform_event_to_mouse_button(uMsg, wParam);
if (action == mouse_action::press)
window->handle_mouse_button_down(pos, button);
else if (action == mouse_action::release)
window->handle_mouse_button_up(pos, button);
else if (action == mouse_action::dbl_click)
window->handle_mouse_dbl_click(pos, button);
}
processed = true;
}
// 鼠标滚轮事件
if (uMsg == WM_MOUSEWHEEL || uMsg == WM_MOUSEHWHEEL) {
if (const auto window = get_window_from_hwnd(hwnd)) {
const int x = LOWORD(lParam);
const int y = HIWORD(lParam);
const Eigen::Vector2f pos(static_cast<float>(x), static_cast<float>(y));
const auto delta = platform_event_to_wheel_event(uMsg, wParam, lParam);
window->handle_mouse_wheel(pos, delta);
}
processed = true;
}
if (uMsg == WM_MOUSELEAVE) {
mouse_tracking_ = FALSE;
if (const auto window = get_window_from_hwnd(hwnd)) {
window->handle_mouse_leave();
}
processed = true;
}
if (processed) { return 0; }
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
platform_window::platform_window(int32_t in_width, int32_t in_height, const wchar_t* in_title) {
WNDCLASS wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = GetModuleHandle(nullptr);
wc.lpszClassName = L"mirage_window_class";
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
RegisterClass(&wc);
RECT rect = { 0, 0, in_width, in_height };
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
window_handle_ = (void*)CreateWindowW(
L"mirage_window_class", in_title,
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT,
rect.right - rect.left, rect.bottom - rect.top,
NULL, NULL, GetModuleHandleW(NULL), NULL
);
if (!window_handle_) {
std::cerr << "Failed to create window" << std::endl;
return;
}
windows.push_back(this);
}
void platform_window::show() { ShowWindow(WINDOW_HANDLE, SW_SHOW); }
void platform_window::hide() { ShowWindow(WINDOW_HANDLE, SW_HIDE); }
void platform_window::close() {
if (!window_handle_) { return; }
on_close_delegate.broadcast(this);
DestroyWindow(WINDOW_HANDLE);
window_handle_ = nullptr;
}
void platform_window::maximize() { ShowWindow(WINDOW_HANDLE, SW_MAXIMIZE); }
void platform_window::minimize() { ShowWindow(WINDOW_HANDLE, SW_MINIMIZE); }
bool platform_window::is_visible() const {
// 判断最小化和隐藏状态
return IsWindowVisible(WINDOW_HANDLE) && !IsIconic(WINDOW_HANDLE);
}
void platform_window::move(int x, int y) {
RECT rect;
GetWindowRect(WINDOW_HANDLE, &rect);
MoveWindow(WINDOW_HANDLE, x, y, rect.right - rect.left, rect.bottom - rect.top, TRUE);
on_move(x, y);
}
void platform_window::resize(int width, int height) {
RECT rect;
GetWindowRect(WINDOW_HANDLE, &rect);
MoveWindow(WINDOW_HANDLE, rect.left, rect.top, width, height, TRUE);
}
Eigen::Vector2i platform_window::get_window_size() const {
// 获取窗口大小, 包括边框和标题栏
RECT rect;
if (GetWindowRect(WINDOW_HANDLE, &rect)) {
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
return Eigen::Vector2i(width, height);
}
return Eigen::Vector2i(0, 0);
}
Eigen::Vector2i platform_window::get_window_frame_size() const {
// 获取窗口大小, 不包括边框和标题栏 (客户区大小)
RECT rect;
if (GetClientRect(WINDOW_HANDLE, &rect)) {
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
return Eigen::Vector2i(width, height);
}
return Eigen::Vector2i(0, 0);
}
float platform_window::get_window_dpi_scale() const {
return 1.f;
}
Eigen::Vector2i platform_window::get_window_position() const {
RECT rect;
if (!GetWindowRect(WINDOW_HANDLE, &rect)) { return {}; }
return { rect.left, rect.top };
}
void* platform_window::get_window_handle() const { return window_handle_; }
platform_window& platform_window::set_title(const wchar_t* title) {
SetWindowText(WINDOW_HANDLE, title);
return *this;
}
platform_window& platform_window::set_has_minimize_button(bool has_minimize_button) {
auto style = GetWindowLong(WINDOW_HANDLE, GWL_STYLE);
if (has_minimize_button) { style |= WS_MINIMIZEBOX; } else { style &= ~WS_MINIMIZEBOX; }
SetWindowLong(WINDOW_HANDLE, GWL_STYLE, style);
return *this;
}
platform_window& platform_window::set_has_maximize_button(bool has_maximize_button) {
auto style = GetWindowLong(WINDOW_HANDLE, GWL_STYLE);
if (has_maximize_button) { style |= WS_MAXIMIZEBOX; } else { style &= ~WS_MAXIMIZEBOX; }
SetWindowLong(WINDOW_HANDLE, GWL_STYLE, style);
return *this;
}
platform_window& platform_window::set_has_close_button(bool has_close_button) {
auto style = GetWindowLong(WINDOW_HANDLE, GWL_STYLE);
if (has_close_button) { style |= WS_SYSMENU; } else { style &= ~WS_SYSMENU; }
SetWindowLong(WINDOW_HANDLE, GWL_STYLE, style);
return *this;
}
platform_window& platform_window::set_has_border(bool has_border) {
auto style = GetWindowLong(WINDOW_HANDLE, GWL_STYLE);
if (has_border) { style |= WS_BORDER; } else { style &= ~WS_BORDER; }
SetWindowLong(WINDOW_HANDLE, GWL_STYLE, style);
return *this;
}
platform_window& platform_window::set_has_caption(bool has_caption) {
auto style = GetWindowLong(WINDOW_HANDLE, GWL_STYLE);
if (has_caption) { style |= WS_CAPTION; } else { style &= ~WS_CAPTION; }
SetWindowLong(WINDOW_HANDLE, GWL_STYLE, style);
return *this;
}
platform_window& platform_window::set_has_resizable_border(bool has_resizable_border) {
auto style = GetWindowLong(WINDOW_HANDLE, GWL_STYLE);
if (has_resizable_border) { style |= WS_THICKFRAME; } else { style &= ~WS_THICKFRAME; }
SetWindowLong(WINDOW_HANDLE, GWL_STYLE, style);
return *this;
}
platform_window& platform_window::set_topmost(bool is_topmost) {
auto style = GetWindowLong(WINDOW_HANDLE, GWL_EXSTYLE);
if (is_topmost) { style |= WS_EX_TOPMOST; } else { style &= ~WS_EX_TOPMOST; }
SetWindowLong(WINDOW_HANDLE, GWL_EXSTYLE, style);
return *this;
}
bool platform_window::poll_events() {
MSG msg;
bool has_messages = false;
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
has_messages = true;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return has_messages;
}
const std::vector<platform_window*>& platform_window::get_windows() { return windows; }