1
0
Fork 0
spectre/source/Platform/Win32/Win32Display.cpp

264 lines
No EOL
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, width, 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