264 lines
5.3 KiB
C++
264 lines
5.3 KiB
C++
|
|
#include <Windows.h>
|
|
|
|
|
|
#include <Spectre/Display/Display.h>
|
|
#include <Spectre/System/SystemEvent.h>
|
|
#include <Spectre/System/Log.h>
|
|
#include "Win32Application.h"
|
|
#include "Win32Internal.h"
|
|
#include "Win32Display.h"
|
|
|
|
namespace sp {
|
|
|
|
#define WND_CLASSNAME "SPECTRE_WIN32_WNDCLASS"
|
|
|
|
static bool firstTime = true;
|
|
|
|
Win32Display::Win32Display() :
|
|
m_handle (NULL),
|
|
m_icon (0),
|
|
m_cursor (0),
|
|
m_inResizeModalLoop (false),
|
|
m_minSize (200, 200)
|
|
{
|
|
}
|
|
|
|
Win32Display::~Win32Display()
|
|
{
|
|
if (m_icon) {
|
|
DestroyIcon(m_icon);
|
|
}
|
|
|
|
if (m_handle) {
|
|
DestroyWindow(m_handle);
|
|
}
|
|
}
|
|
|
|
bool Win32Display::create(DisplayDescription description)
|
|
{
|
|
DWORD flags = getWin32Flags(description.decoration);
|
|
int x, y;
|
|
|
|
if (firstTime) {
|
|
registerClass();
|
|
firstTime = false;
|
|
}
|
|
|
|
centerWindow(x, y, description.mode.width, description.mode.height);
|
|
|
|
// Create window.
|
|
m_handle = CreateWindowExA(0, WND_CLASSNAME, "", flags,
|
|
x, y, description.mode.width, description.mode.height,
|
|
NULL, NULL, GetModuleHandle(NULL), (LPVOID) this);
|
|
|
|
if (!m_handle) {
|
|
Log::error("Win32 - Could not create window: %s", Win32GetMessage(GetLastError()));
|
|
return false;
|
|
}
|
|
|
|
setSize(description.mode.width, description.mode.height);
|
|
|
|
// Store the size for use later.
|
|
m_size = getSize();
|
|
|
|
return true;
|
|
}
|
|
|
|
void Win32Display::destroy()
|
|
{
|
|
if (m_handle) {
|
|
DestroyWindow(m_handle);
|
|
m_handle = NULL;
|
|
}
|
|
}
|
|
|
|
void* Win32Display::getHandle() const
|
|
{
|
|
return m_handle;
|
|
}
|
|
|
|
bool Win32Display::isValid()
|
|
{
|
|
return m_handle != NULL;
|
|
}
|
|
|
|
void Win32Display::setSize(unsigned int width, unsigned int height)
|
|
{
|
|
int w, h;
|
|
RECT rect = {0, 0, (LONG) width, (LONG) height};
|
|
AdjustWindowRect(&rect, GetWindowLong(m_handle, GWL_STYLE), false);
|
|
|
|
w = rect.right - rect.left;
|
|
h = rect.bottom - rect.top;
|
|
|
|
::SetWindowPos(m_handle, NULL, 0, 0, w, h, SWP_NOMOVE | SWP_NOZORDER);
|
|
}
|
|
|
|
Vector2u Win32Display::getSize() const
|
|
{
|
|
RECT rect;
|
|
Vector2u size;
|
|
|
|
if (GetClientRect(m_handle, &rect)) {
|
|
size.x = rect.right - rect.left;
|
|
size.y = rect.bottom - rect.top;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
void Win32Display::setPosition(unsigned int x, unsigned int y)
|
|
{
|
|
::SetWindowPos(m_handle, NULL, x, y, 0, 0, SWP_NOSIZE);
|
|
}
|
|
|
|
void Win32Display::setCaption(const std::string& caption)
|
|
{
|
|
::SetWindowText(m_handle, caption.c_str());
|
|
}
|
|
|
|
void Win32Display::showCursor(bool value)
|
|
{
|
|
if (value) {
|
|
m_cursor = ::LoadCursor(NULL, IDC_ARROW);
|
|
} else {
|
|
m_cursor = 0;
|
|
}
|
|
|
|
::SetCursor(m_cursor);
|
|
}
|
|
|
|
void Win32Display::setIcon(const std::string& icon)
|
|
{
|
|
HICON hIcon = (HICON) ::LoadImage(0, icon.c_str(), IMAGE_ICON,
|
|
0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE);
|
|
|
|
if (hIcon) {
|
|
|
|
if (m_icon) {
|
|
DestroyIcon(m_icon);
|
|
}
|
|
m_icon = hIcon;
|
|
|
|
::SendMessage(m_handle, WM_SETICON, ICON_SMALL, (LPARAM) hIcon);
|
|
::SendMessage(m_handle, WM_SETICON, ICON_BIG, (LPARAM) hIcon);
|
|
}
|
|
}
|
|
|
|
void Win32Display::registerClass()
|
|
{
|
|
WNDCLASSA wndcl;
|
|
|
|
ZeroMemory(&wndcl, sizeof(wndcl));
|
|
|
|
wndcl.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
|
|
wndcl.lpfnWndProc = Win32Display::staticWndProc;
|
|
wndcl.hInstance = ::GetModuleHandle(NULL);
|
|
wndcl.lpszClassName = WND_CLASSNAME;
|
|
|
|
::RegisterClass(&wndcl);
|
|
}
|
|
|
|
DWORD Win32Display::getWin32Flags(unsigned int flags)
|
|
{
|
|
DWORD win32_flags = WS_VISIBLE;
|
|
|
|
if (flags == DisplayDecorate::None) {
|
|
win32_flags |= WS_POPUP;
|
|
} else {
|
|
if (flags & DisplayDecorate::Menu) {
|
|
win32_flags |= WS_CAPTION | WS_MINIMIZEBOX;
|
|
}
|
|
|
|
if (flags & DisplayDecorate::Resize) {
|
|
win32_flags |= WS_THICKFRAME | WS_MAXIMIZEBOX;
|
|
}
|
|
|
|
if (flags & DisplayDecorate::Close) {
|
|
win32_flags |= WS_SYSMENU;
|
|
}
|
|
}
|
|
return win32_flags;
|
|
}
|
|
|
|
void Win32Display::centerWindow(int &x, int &y, int width, int height)
|
|
{
|
|
x = (::GetSystemMetrics(SM_CXSCREEN) - width) / 2;
|
|
y = (::GetSystemMetrics(SM_CYSCREEN) - height) / 2;
|
|
}
|
|
|
|
void Win32Display::processResizeMessage(const Vector2u& new_size)
|
|
{
|
|
// Check if the size has actually changed.
|
|
if (m_size != new_size) {
|
|
|
|
// Update the size and notify the higher layer.
|
|
m_size = new_size;
|
|
onReshape(m_size.x, m_size.y);
|
|
}
|
|
}
|
|
|
|
void Win32Display::processMessage(UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch(message) {
|
|
case WM_SETCURSOR :
|
|
if (LOWORD(lParam) == HTCLIENT) {
|
|
::SetCursor(m_cursor);
|
|
}
|
|
break;
|
|
case WM_DESTROY :
|
|
destroy();
|
|
PostQuitMessage(0);
|
|
break;
|
|
case WM_SETFOCUS :
|
|
OutputDebugString("WM_SETFOCUS\n");
|
|
break;
|
|
case WM_KILLFOCUS :
|
|
OutputDebugString("WM_KILLFOCUS\n");
|
|
break;
|
|
case WM_SIZE :
|
|
|
|
if (!m_inResizeModalLoop && (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED)) {
|
|
processResizeMessage(getSize());
|
|
}
|
|
break;
|
|
case WM_GETMINMAXINFO :
|
|
{
|
|
MINMAXINFO* info = (MINMAXINFO*)lParam;
|
|
info->ptMinTrackSize.x = m_minSize.x;
|
|
info->ptMinTrackSize.y = m_minSize.y;
|
|
info->ptMaxTrackSize.x = 99999;
|
|
info->ptMaxTrackSize.y = 99999;
|
|
break;
|
|
}
|
|
case WM_ENTERSIZEMOVE :
|
|
m_inResizeModalLoop = true;
|
|
break;
|
|
case WM_EXITSIZEMOVE :
|
|
m_inResizeModalLoop = false;
|
|
processResizeMessage(getSize());
|
|
break;
|
|
}
|
|
}
|
|
|
|
LRESULT CALLBACK Win32Display::staticWndProc(HWND handle, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
Win32Display *display;
|
|
|
|
if (message == WM_NCCREATE) {
|
|
|
|
LONG_PTR ptr = (LONG_PTR) ((LPCREATESTRUCT)lParam)->lpCreateParams;
|
|
::SetWindowLong(handle, GWL_USERDATA, ptr);
|
|
|
|
display = (Win32Display*) ptr;
|
|
} else {
|
|
display = (Win32Display*) ::GetWindowLong(handle, GWL_USERDATA);
|
|
}
|
|
|
|
if (display) {
|
|
display->processMessage(message, wParam, lParam);
|
|
}
|
|
return DefWindowProc(handle, message, wParam, lParam);
|
|
}
|
|
|
|
} // namespace sp
|