280 lines
8.4 KiB
C++
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; }
|