Magic_Game/core/Base/Window.cpp

500 lines
9.7 KiB
C++
Raw Normal View History

2018-04-21 21:24:46 +08:00
#include "..\e2dbase.h"
#include "..\e2dmanager.h"
2018-01-30 16:45:38 +08:00
#include <imm.h>
#pragma comment (lib ,"imm32.lib")
e2d::Window * e2d::Window::_instance = nullptr;
2018-01-30 16:45:38 +08:00
e2d::Window::Window()
: _hWnd(nullptr)
2018-07-03 23:39:00 +08:00
, _size(640, 480)
, _title(L"Easy2D Game")
, _iconID(0)
{
}
e2d::Window::~Window()
{
// <20>رտ<D8B1><D5BF><EFBFBD>̨
if (::GetConsoleWindow())
{
::FreeConsole();
}
// <20>رմ<D8B1><D5B4><EFBFBD>
if (_hWnd)
{
::DestroyWindow(_hWnd);
_hWnd = nullptr;
}
}
e2d::Window * e2d::Window::getInstance()
{
if (!_instance)
_instance = new (std::nothrow) Window;
return _instance;
}
void e2d::Window::destroyInstance()
{
if (_instance)
{
delete _instance;
_instance = nullptr;
}
}
bool e2d::Window::createMutex(const String & mutex)
{
if (mutex.isEmpty())
return false;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̻<EFBFBD><CCBB><EFBFBD><EFBFBD><EFBFBD>
String fullMutexName = L"Easy2DApp-" + mutex;
HANDLE hMutex = ::CreateMutex(nullptr, TRUE, (LPCWSTR)fullMutexName);
if (hMutex == nullptr)
{
WARN("CreateMutex Failed!");
return false;
}
else if (::GetLastError() == ERROR_ALREADY_EXISTS)
{
// <20>رս<D8B1><D5BD>̻<EFBFBD><CCBB><EFBFBD><EFBFBD><EFBFBD>
::CloseHandle(hMutex);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϸ<EFBFBD><CFB7><EFBFBD><EFBFBD>
if (!this->_title.isEmpty())
{
// <20><>ȡ<EFBFBD><C8A1><EFBFBD>ھ<EFBFBD><DABE><EFBFBD>
HWND hProgramWnd = ::FindWindow(L"Easy2DApp", (LPCTSTR)this->_title);
if (hProgramWnd)
{
// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ״̬
WINDOWPLACEMENT wpm;
::GetWindowPlacement(hProgramWnd, &wpm);
// <20><><EFBFBD><EFBFBD><EFBFBD>еij<D0B5><C4B3>򴰿ڻ<F2B4B0BF>ԭ<EFBFBD><D4AD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬
wpm.showCmd = SW_SHOW;
::SetWindowPlacement(hProgramWnd, &wpm);
::SetWindowPos(hProgramWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
}
}
return false;
}
return true;
}
2018-07-03 23:39:00 +08:00
HWND e2d::Window::__create()
2018-01-30 16:45:38 +08:00
{
// ע<><EFBFBD><E1B4B0><EFBFBD><EFBFBD>
2018-03-01 00:19:09 +08:00
WNDCLASSEX wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpszClassName = L"Easy2DApp";
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wcex.lpfnWndProc = Window::WndProc;
2018-01-30 16:45:38 +08:00
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = HINST_THISCOMPONENT;
wcex.hbrBackground = nullptr;
wcex.lpszMenuName = nullptr;
wcex.hCursor = ::LoadCursor(nullptr, IDC_ARROW);
2018-01-30 16:45:38 +08:00
2018-07-03 23:39:00 +08:00
if (this->_iconID != 0)
{
wcex.hIcon = (HICON)::LoadImage(
HINST_THISCOMPONENT,
MAKEINTRESOURCE(this->_iconID),
IMAGE_ICON,
0,
0,
LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE
);
}
else
{
wcex.hIcon = nullptr;
}
2018-01-30 16:45:38 +08:00
RegisterClassEx(&wcex);
// <20><>Ϊ CreateWindow <20><><EFBFBD><EFBFBD>ʹ<EFBFBD>õ<EFBFBD><C3B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ش<EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD>ȡϵͳ<CFB5><CDB3> DPI <20><>ʹ<EFBFBD><CAB9>
// <20><>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
float dpiScaleX = 0.f, dpiScaleY = 0.f;
Renderer::getFactory()->GetDesktopDpi(&dpiScaleX, &dpiScaleY);
2018-01-30 16:45:38 +08:00
2018-07-03 23:39:00 +08:00
int nWidth = static_cast<int>(ceil(this->_size.width * dpiScaleX / 96.f));
int nHeight = static_cast<int>(ceil(this->_size.height * dpiScaleY / 96.f));
2018-01-30 16:45:38 +08:00
// <20><><EFBFBD><EFBFBD>ڴ<EFBFBD>С
2018-07-03 23:39:00 +08:00
DWORD dwStyle = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX &~WS_THICKFRAME;
RECT wr = { 0, 0, static_cast<LONG>(nWidth), static_cast<LONG>(nHeight) };
::AdjustWindowRectEx(&wr, dwStyle, FALSE, NULL);
// <20><>ȡ<EFBFBD>µĿ<C2B5><C4BF><EFBFBD>
nWidth = static_cast<int>(wr.right - wr.left);
nHeight = static_cast<int>(wr.bottom - wr.top);
// <20><>ȡ<EFBFBD><C8A1>Ļ<EFBFBD>ֱ<EFBFBD><D6B1><EFBFBD>
int screenWidth = ::GetSystemMetrics(SM_CXSCREEN);
int screenHeight = ::GetSystemMetrics(SM_CYSCREEN);
2018-01-30 16:45:38 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
2018-07-03 23:39:00 +08:00
HWND hWnd = ::CreateWindowEx(
NULL,
2018-01-30 16:45:38 +08:00
L"Easy2DApp",
2018-07-03 23:39:00 +08:00
(LPCTSTR)this->_title,
dwStyle,
2018-07-03 23:39:00 +08:00
(screenWidth - nWidth) / 2, (screenHeight - nHeight) / 2,
nWidth, nHeight,
nullptr,
nullptr,
2018-01-30 16:45:38 +08:00
HINST_THISCOMPONENT,
nullptr
2018-01-30 16:45:38 +08:00
);
2018-07-03 23:39:00 +08:00
HRESULT hr = hWnd ? S_OK : E_FAIL;
2018-01-30 16:45:38 +08:00
if (SUCCEEDED(hr))
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
2018-07-04 17:00:21 +08:00
this->setTypewritingEnabled(false);
// <20><><EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD>̨<EFBFBD>رհ<D8B1>ť
HWND consoleHWnd = ::GetConsoleWindow();
if (consoleHWnd)
2018-01-30 16:45:38 +08:00
{
HMENU hmenu = ::GetSystemMenu(consoleHWnd, FALSE);
2018-01-30 16:45:38 +08:00
::RemoveMenu(hmenu, SC_CLOSE, MF_BYCOMMAND);
}
}
else
{
::UnregisterClass(L"Easy2DApp", HINST_THISCOMPONENT);
}
2018-07-03 23:39:00 +08:00
return hWnd;
2018-01-30 16:45:38 +08:00
}
void e2d::Window::poll()
2018-01-30 16:45:38 +08:00
{
while (::PeekMessage(&_msg, nullptr, 0, 0, PM_REMOVE))
2018-01-30 16:45:38 +08:00
{
::TranslateMessage(&_msg);
::DispatchMessage(&_msg);
2018-01-30 16:45:38 +08:00
}
}
2018-02-27 21:07:43 +08:00
double e2d::Window::getWidth()
2018-01-30 16:45:38 +08:00
{
return _size.width;
2018-01-30 16:45:38 +08:00
}
2018-02-27 21:07:43 +08:00
double e2d::Window::getHeight()
2018-01-30 16:45:38 +08:00
{
return _size.height;
2018-01-30 16:45:38 +08:00
}
e2d::Size e2d::Window::getSize()
2018-01-30 16:45:38 +08:00
{
return _size;
}
e2d::String e2d::Window::getTitle()
{
return _title;
2018-01-30 16:45:38 +08:00
}
HWND e2d::Window::getHWnd()
2018-01-30 16:45:38 +08:00
{
2018-07-03 23:39:00 +08:00
if (!_hWnd)
{
_hWnd = this->__create();
if (_hWnd == nullptr)
{
throw SystemException(L"ע<EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><EFBFBD>");
}
}
return _hWnd;
2018-01-30 16:45:38 +08:00
}
void e2d::Window::setSize(int width, int height)
2018-01-30 16:45:38 +08:00
{
2018-07-03 23:39:00 +08:00
this->_size = Size(width, height);
if (_hWnd)
{
// <20><><EFBFBD><EFBFBD>ڴ<EFBFBD>С
DWORD dwStyle = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX &~WS_THICKFRAME;
RECT wr = { 0, 0, static_cast<LONG>(width), static_cast<LONG>(height) };
::AdjustWindowRectEx(&wr, dwStyle, FALSE, NULL);
// <20><>ȡ<EFBFBD>µĿ<C2B5><C4BF><EFBFBD>
width = static_cast<int>(wr.right - wr.left);
height = static_cast<int>(wr.bottom - wr.top);
// <20><>ȡ<EFBFBD><C8A1>Ļ<EFBFBD>ֱ<EFBFBD><D6B1><EFBFBD>
int screenWidth = ::GetSystemMetrics(SM_CXSCREEN);
int screenHeight = ::GetSystemMetrics(SM_CYSCREEN);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><C4B4>ڴ<EFBFBD>С<EFBFBD>ȷֱ<C8B7><D6B1>ʴ<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
WARN_IF(screenWidth < width || screenHeight < height, "The window is larger than screen!");
// ȡ<><C8A1>Сֵ
2018-07-04 12:49:05 +08:00
width = std::min(width, screenWidth);
height = std::min(height, screenHeight);
2018-07-03 23:39:00 +08:00
// <20>޸Ĵ<DEB8><C4B4>ڴ<EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ô<EFBFBD><C3B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ļ<EFBFBD><C4BB><EFBFBD><EFBFBD>
::MoveWindow(_hWnd, (screenWidth - width) / 2, (screenHeight - height) / 2, width, height, TRUE);
}
2018-01-30 16:45:38 +08:00
}
void e2d::Window::setTitle(const String& title)
2018-01-30 16:45:38 +08:00
{
2018-07-03 23:39:00 +08:00
this->_title = title;
if (_hWnd)
{
::SetWindowText(_hWnd, (LPCWSTR)title);
}
2018-01-30 16:45:38 +08:00
}
void e2d::Window::setIcon(int iconID)
{
2018-07-03 23:39:00 +08:00
this->_iconID = iconID;
if (_hWnd)
{
HICON hIcon = (HICON)::LoadImage(HINST_THISCOMPONENT, MAKEINTRESOURCE(iconID), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
// <20><><EFBFBD>ô<EFBFBD><C3B4>ڵ<EFBFBD>ͼ<EFBFBD><CDBC>
::SendMessage(_hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
::SendMessage(_hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
}
}
void e2d::Window::setCursor(Cursor cursor)
{
LPCWSTR pCursorName = nullptr;
switch (cursor)
{
2018-05-24 20:37:34 +08:00
case Cursor::Normal:
pCursorName = IDC_ARROW;
break;
2018-05-24 20:37:34 +08:00
case Cursor::Hand:
pCursorName = IDC_HAND;
break;
2018-05-24 20:37:34 +08:00
case Cursor::No:
pCursorName = IDC_NO;
break;
2018-05-24 20:37:34 +08:00
case Cursor::Wait:
pCursorName = IDC_WAIT;
break;
2018-05-24 20:37:34 +08:00
case Cursor::ArrowWait:
pCursorName = IDC_APPSTARTING;
break;
default:
break;
}
HCURSOR hCursor = ::LoadCursor(nullptr, pCursorName);
::SetCursor(hCursor);
}
2018-07-13 01:33:53 +08:00
void e2d::Window::setConsoleEnabled(bool enabled)
2018-01-30 16:45:38 +08:00
{
// <20><><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD><D1B4>ڵĿ<DAB5><C4BF><EFBFBD>̨<EFBFBD><CCA8><EFBFBD><EFBFBD>
HWND hwnd = ::GetConsoleWindow();
// <20>رտ<D8B1><D5BF><EFBFBD>̨
2018-07-13 01:33:53 +08:00
if (enabled)
2018-01-30 16:45:38 +08:00
{
if (hwnd)
{
::ShowWindow(hwnd, SW_SHOWNORMAL);
}
else
{
// <20><>ʾһ<CABE><D2BB><EFBFBD>¿<EFBFBD><C2BF><EFBFBD>̨
if (::AllocConsole())
{
hwnd = ::GetConsoleWindow();
// <20>ض<EFBFBD><D8B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
FILE * stdoutStream, * stdinStream, * stderrStream;
freopen_s(&stdoutStream, "conout$", "w+t", stdout);
freopen_s(&stdinStream, "conin$", "r+t", stdin);
2018-02-01 22:07:44 +08:00
freopen_s(&stderrStream, "conout$", "w+t", stderr);
2018-01-30 16:45:38 +08:00
// <20><><EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD>̨<EFBFBD>رհ<D8B1>ť
HMENU hmenu = ::GetSystemMenu(hwnd, FALSE);
::RemoveMenu(hmenu, SC_CLOSE, MF_BYCOMMAND);
}
}
}
else
{
if (hwnd)
{
::ShowWindow(hwnd, SW_HIDE);
}
}
}
2018-07-04 17:00:21 +08:00
void e2d::Window::setTypewritingEnabled(bool enabled)
2018-01-30 16:45:38 +08:00
{
static HIMC hImc = nullptr;
2018-07-04 17:00:21 +08:00
if (enabled)
2018-01-30 16:45:38 +08:00
{
if (hImc != nullptr)
{
::ImmAssociateContext(_hWnd, hImc);
2018-01-30 16:45:38 +08:00
hImc = nullptr;
}
}
else
{
if (hImc == nullptr)
{
hImc = ::ImmAssociateContext(_hWnd, nullptr);
2018-01-30 16:45:38 +08:00
}
}
}
bool e2d::Window::popup(const String & text, const String & title, Popup style, bool hasCancel)
{
2018-07-17 00:35:27 +08:00
UINT type = 0;
switch (style)
{
case e2d::Window::Popup::Information:
2018-07-17 00:35:27 +08:00
type = MB_ICONINFORMATION;
break;
case e2d::Window::Popup::Warning:
2018-07-17 00:35:27 +08:00
type = MB_ICONWARNING;
break;
case e2d::Window::Popup::Error:
2018-07-17 00:35:27 +08:00
type = MB_ICONERROR;
break;
default:
break;
}
2018-07-17 00:35:27 +08:00
if (hasCancel)
{
type |= MB_OKCANCEL;
}
2018-07-05 16:44:47 +08:00
Game::getInstance()->pause();
2018-07-17 00:35:27 +08:00
int ret = ::MessageBox(_hWnd, (LPCWSTR)text, (LPCWSTR)title, type);
2018-07-05 16:44:47 +08:00
Game::getInstance()->resume();
2018-07-17 00:35:27 +08:00
return ret == IDOK;
}
2018-01-30 16:45:38 +08:00
LRESULT e2d::Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
2018-01-30 16:45:38 +08:00
{
LRESULT result = 0;
bool hasHandled = false;
2018-01-30 16:45:38 +08:00
switch (message)
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
case WM_LBUTTONUP:
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_MBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MBUTTONDBLCLK:
case WM_RBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK:
case WM_MOUSEMOVE:
case WM_MOUSEWHEEL:
{
SceneManager::getInstance()->dispatch(MouseEvent(message, wParam, lParam));
}
result = 0;
hasHandled = true;
break;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
case WM_KEYDOWN:
case WM_KEYUP:
{
SceneManager::getInstance()->dispatch(KeyEvent(message, wParam, lParam));
}
result = 0;
hasHandled = true;
break;
2018-01-30 16:45:38 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>С<EFBFBD><EFBFBD><E4BBAF>Ϣ
case WM_SIZE:
{
UINT width = LOWORD(lParam);
UINT height = HIWORD(lParam);
if (wParam == SIZE_RESTORED)
{
Window::getInstance()->_size = Size(width, height);
}
2018-01-30 16:45:38 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>յ<EFBFBD>һ<EFBFBD><D2BB> WM_SIZE <20><>Ϣ<EFBFBD><CFA2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ⱦ
// Ŀ<><C4BF><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܻ<EFBFBD><DCBB><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD>ܣ<EFBFBD><DCA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ժ<EFBFBD><D4BA><EFBFBD><EFBFBD>п<EFBFBD><D0BF>ܵ<EFBFBD>
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>ε<EFBFBD><CEB5><EFBFBD> EndDraw ʱ<><CAB1><EFBFBD><EFBFBD>
auto pRT = Renderer::getInstance()->getRenderTarget();
if (pRT)
{
pRT->Resize(D2D1::SizeU(width, height));
}
}
break;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڱ<EFBFBD><DAB1><EFBFBD><EFBFBD><EFBFBD><E4BBAF>Ϣ
case WM_SETTEXT:
{
2018-07-03 18:42:00 +08:00
Window::getInstance()->_title = (const wchar_t*)lParam;
2018-01-30 16:45:38 +08:00
}
break;
// <20><><EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD><D6B1>ʱ仯<CAB1><E4BBAF>Ϣ
case WM_DISPLAYCHANGE:
{
// <20>ػ<EFBFBD><D8BB>ͻ<EFBFBD><CDBB><EFBFBD>
InvalidateRect(hWnd, nullptr, FALSE);
2018-01-30 16:45:38 +08:00
}
result = 0;
hasHandled = true;
2018-01-30 16:45:38 +08:00
break;
// <20>ػ洰<D8BB><E6B4B0>
case WM_PAINT:
{
e2d::Renderer::getInstance()->render();
ValidateRect(hWnd, nullptr);
2018-01-30 16:45:38 +08:00
}
result = 0;
hasHandled = true;
2018-01-30 16:45:38 +08:00
break;
// <20><><EFBFBD>ڹر<DAB9><D8B1><EFBFBD>Ϣ
case WM_CLOSE:
{
e2d::Scene * pCurrentScene = e2d::SceneManager::getInstance()->getCurrentScene();
2018-01-30 16:45:38 +08:00
if (!pCurrentScene || pCurrentScene->onCloseWindow())
{
2018-07-03 01:49:20 +08:00
e2d::Game::getInstance()->quit();
2018-01-30 16:45:38 +08:00
}
}
result = 0;
hasHandled = true;
2018-01-30 16:45:38 +08:00
break;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
2018-01-30 16:45:38 +08:00
case WM_DESTROY:
{
PostQuitMessage(0);
}
result = 1;
hasHandled = true;
2018-01-30 16:45:38 +08:00
break;
}
if (!hasHandled)
{
result = DefWindowProc(hWnd, message, wParam, lParam);
2018-01-30 16:45:38 +08:00
}
return result;
}