You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
391 lines
12 KiB
C++
391 lines
12 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
|
|
#include "StdAfx.h"
|
|
#include "Win32GUI.h"
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <string>
|
|
#include <map>
|
|
#include "commctrl.h"
|
|
#include "StringHelpers.h"
|
|
|
|
namespace Win32GUI
|
|
{
|
|
const int WM_REFLECT_BASE = WM_USER + 0x1c00;
|
|
const int WM_COMMAND_REFLECT = WM_REFLECT_BASE + WM_COMMAND;
|
|
const int WM_NOTIFY_REFLECT = WM_REFLECT_BASE + WM_NOTIFY;
|
|
|
|
class Window
|
|
{
|
|
public:
|
|
typedef LRESULT (Window::* WindowProcMethod)(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
Window(WindowProcMethod windowProc);
|
|
~Window();
|
|
static LRESULT CALLBACK StaticWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
LRESULT WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
LRESULT FrameWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
void Subclass(HWND window);
|
|
void Unsubclass(HWND window);
|
|
|
|
WNDPROC m_oldWndProc;
|
|
WindowProcMethod m_windowProc;
|
|
typedef std::multimap<unsigned, EventCallbacks::ICallback*> CallbackMap;
|
|
CallbackMap m_callbackMap;
|
|
};
|
|
}
|
|
|
|
void Win32GUI::Initialize()
|
|
{
|
|
InitCommonControls();
|
|
LoadLibrary(_T("riched20.dll"));
|
|
}
|
|
|
|
void Win32GUI::RegisterFrameClass(const TCHAR* name)
|
|
{
|
|
WNDCLASS cls;
|
|
std::memset(&cls, 0, sizeof(cls));
|
|
cls.style = 0;
|
|
cls.lpfnWndProc = &Window::StaticWindowProc;
|
|
cls.cbClsExtra = 0;
|
|
cls.cbWndExtra = 0;
|
|
cls.hInstance = GetModuleHandle(0);
|
|
cls.hIcon = 0;
|
|
cls.hCursor = LoadCursor(0, IDC_ARROW);
|
|
cls.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
|
|
cls.lpszMenuName = 0;
|
|
cls.lpszClassName = name;
|
|
|
|
RegisterClass(&cls);
|
|
}
|
|
|
|
HWND Win32GUI::CreateFrame(const TCHAR* className, unsigned style, int width, int height)
|
|
{
|
|
Window* window = new Window(&Window::FrameWindowProc);
|
|
|
|
HWND hwnd = CreateWindow(
|
|
className, // LPCTSTR lpClassName,
|
|
TEXT(""), // LPCTSTR lpWindowName,
|
|
style, // DWORD dwStyle,
|
|
CW_USEDEFAULT, // int x,
|
|
CW_USEDEFAULT, // int y,
|
|
width, // int nWidth,
|
|
height, // int nHeight,
|
|
0, // HWND hWndParent,
|
|
0, // HMENU hMenu,
|
|
GetModuleHandle(0), // HINSTANCE hInstance,
|
|
window); // LPVOID lpParam
|
|
|
|
return hwnd;
|
|
}
|
|
|
|
HWND Win32GUI::CreateControl(const TCHAR* className, unsigned style, HWND parent, int left, int top, int width, int height)
|
|
{
|
|
Window* window = new Window(&Window::WindowProc);
|
|
|
|
HWND hwnd = CreateWindow(
|
|
className, // LPCTSTR lpClassName,
|
|
0, // LPCTSTR lpWindowName,
|
|
style | WS_CHILD | WS_VISIBLE, // DWORD dwStyle,
|
|
left, // int x,
|
|
top, // int y,
|
|
width, // int nWidth,
|
|
height, // int nHeight,
|
|
parent, // HWND hWndParent,
|
|
0, // HMENU hMenu,
|
|
GetModuleHandle(0), // HINSTANCE hInstance,
|
|
0); // LPVOID lpParam
|
|
|
|
window->Subclass(hwnd);
|
|
|
|
return hwnd;
|
|
}
|
|
|
|
int Win32GUI::Run()
|
|
{
|
|
MSG msg;
|
|
BOOL status;
|
|
while ((status = GetMessage(&msg, HWND(0), UINT(0), UINT(0))) != 0)
|
|
{
|
|
if (status == -1)
|
|
{
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
return (int)msg.wParam;
|
|
}
|
|
|
|
Win32GUI::Window::Window(WindowProcMethod windowProc)
|
|
: m_windowProc(windowProc)
|
|
, m_oldWndProc(0)
|
|
{
|
|
}
|
|
|
|
Win32GUI::Window::~Window()
|
|
{
|
|
for (CallbackMap::iterator callbackPos = m_callbackMap.begin(); callbackPos != m_callbackMap.end(); ++callbackPos)
|
|
{
|
|
(*callbackPos).second->Release();
|
|
}
|
|
}
|
|
|
|
LRESULT CALLBACK Win32GUI::Window::StaticWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
Window* window = 0;
|
|
{
|
|
if (uMsg == WM_CREATE)
|
|
{
|
|
CREATESTRUCT* create_struct = (CREATESTRUCT*)lParam;
|
|
window = (Window*)create_struct->lpCreateParams;
|
|
#if defined(_WIN64)
|
|
SetWindowLongPtr(hwnd, GWLP_USERDATA, LONG_PTR(window));
|
|
#else //defined(_WIN64)
|
|
SetWindowLong(hwnd, GWL_USERDATA, PtrToLong(window));
|
|
#endif //defined(_WIN64)
|
|
}
|
|
else
|
|
{
|
|
#if defined(_WIN64)
|
|
window = (Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
#else //defined(_WIN64)
|
|
window = (Window*)LongToPtr(GetWindowLong(hwnd, GWL_USERDATA));
|
|
#endif //defined(_WIN64)
|
|
}
|
|
}
|
|
|
|
LRESULT result = 0;
|
|
if (window)
|
|
{
|
|
result = (window->*(window->m_windowProc))(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
else
|
|
{
|
|
result = DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
if (uMsg == WM_DESTROY)
|
|
{
|
|
delete window;
|
|
#if defined(_WIN64)
|
|
SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
|
|
#else //defined(_WIN64)
|
|
SetWindowLong(hwnd, GWL_USERDATA, 0);
|
|
#endif //defined(_WIN64)
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
LRESULT Win32GUI::Window::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_COMMAND:
|
|
{
|
|
HWND control = (HWND)lParam;
|
|
if (control)
|
|
{
|
|
SendMessage(control, WM_COMMAND_REFLECT, wParam, lParam);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
{
|
|
NMHDR* notify_header = reinterpret_cast<NMHDR*>(lParam);
|
|
if (notify_header->hwndFrom)
|
|
{
|
|
SendMessage(notify_header->hwndFrom, WM_NOTIFY_REFLECT, wParam, lParam);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_COMMAND_REFLECT:
|
|
switch (HIWORD(wParam))
|
|
{
|
|
case EN_CHANGE:
|
|
{
|
|
std::string text = GetWindowString(hwnd);
|
|
|
|
std::pair<CallbackMap::iterator, CallbackMap::iterator> range = m_callbackMap.equal_range(EventCallbacks::TextChanged::ID);
|
|
for (CallbackMap::iterator callbackPos = range.first; callbackPos != range.second; ++callbackPos)
|
|
{
|
|
EventCallbacks::IStringCallback* callback = static_cast<EventCallbacks::IStringCallback*>((*callbackPos).second);
|
|
callback->Call(text);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case BN_CLICKED:
|
|
{
|
|
if (GetWindowLong(hwnd, GWL_STYLE) & BS_CHECKBOX)
|
|
{
|
|
bool checked = (0 != SendMessage(hwnd, BM_GETCHECK, 0, 0));
|
|
std::pair<CallbackMap::iterator, CallbackMap::iterator> range = m_callbackMap.equal_range(EventCallbacks::Checked::ID);
|
|
for (CallbackMap::iterator callbackPos = range.first; callbackPos != range.second; ++callbackPos)
|
|
{
|
|
EventCallbacks::IBoolCallback* callback = static_cast<EventCallbacks::IBoolCallback*>((*callbackPos).second);
|
|
callback->Call(checked);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::pair<CallbackMap::iterator, CallbackMap::iterator> range = m_callbackMap.equal_range(EventCallbacks::Pushed::ID);
|
|
for (CallbackMap::iterator callbackPos = range.first; callbackPos != range.second; ++callbackPos)
|
|
{
|
|
EventCallbacks::IVoidCallback* callback = static_cast<EventCallbacks::IVoidCallback*>((*callbackPos).second);
|
|
callback->Call();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_GETMINMAXINFO:
|
|
{
|
|
int minW = 0, maxW = 0, minH = 100000, maxH = 100000;
|
|
|
|
std::pair<CallbackMap::iterator, CallbackMap::iterator> range = m_callbackMap.equal_range(EventCallbacks::GetDimensions::ID);
|
|
for (CallbackMap::iterator callbackPos = range.first; callbackPos != range.second; ++callbackPos)
|
|
{
|
|
EventCallbacks::IGetDimensionsCallback* callback = static_cast<EventCallbacks::IGetDimensionsCallback*>((*callbackPos).second);
|
|
callback->Call(minW, maxW, minH, maxH);
|
|
}
|
|
|
|
MINMAXINFO* minMaxInfo = (MINMAXINFO*)lParam;
|
|
minMaxInfo->ptMinTrackSize.x = minW;
|
|
minMaxInfo->ptMaxTrackSize.x = maxW;
|
|
minMaxInfo->ptMinTrackSize.y = minH;
|
|
minMaxInfo->ptMaxTrackSize.y = maxH;
|
|
}
|
|
break;
|
|
|
|
case WM_SIZE:
|
|
{
|
|
int width = LOWORD(lParam);
|
|
int height = HIWORD(lParam);
|
|
std::pair<CallbackMap::iterator, CallbackMap::iterator> range = m_callbackMap.equal_range(EventCallbacks::SizeChanged::ID);
|
|
for (CallbackMap::iterator callbackPos = range.first; callbackPos != range.second; ++callbackPos)
|
|
{
|
|
EventCallbacks::ISizeCallback* callback = static_cast<EventCallbacks::ISizeCallback*>((*callbackPos).second);
|
|
callback->Call(width, height);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_NOTIFY_REFLECT:
|
|
break;
|
|
}
|
|
|
|
LRESULT result = 0;
|
|
if (m_oldWndProc)
|
|
{
|
|
result = CallWindowProc(m_oldWndProc, hwnd, uMsg, wParam, lParam);
|
|
}
|
|
else
|
|
{
|
|
result = DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
LRESULT Win32GUI::Window::FrameWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_CLOSE:
|
|
PostQuitMessage(0);
|
|
break;
|
|
}
|
|
|
|
return WindowProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
void Win32GUI::Window::Subclass(HWND window)
|
|
{
|
|
#if defined(_WIN64)
|
|
SetWindowLongPtr(window, GWLP_USERDATA, LONG_PTR(this));
|
|
m_oldWndProc = (WNDPROC)GetWindowLongPtr(window, GWLP_WNDPROC);
|
|
SetWindowLongPtr(window, GWLP_WNDPROC, LONG_PTR(&Window::StaticWindowProc));
|
|
#else //defined(_WIN64)
|
|
SetWindowLong(window, GWL_USERDATA, PtrToLong(this));
|
|
m_oldWndProc = (WNDPROC)LongToPtr(GetWindowLong(window, GWL_WNDPROC));
|
|
SetWindowLong(window, GWL_WNDPROC, PtrToLong(&Window::StaticWindowProc));
|
|
#endif //defined(_WIN64)
|
|
}
|
|
|
|
void Win32GUI::Window::Unsubclass(HWND window)
|
|
{
|
|
#if defined(_WIN64)
|
|
SetWindowLongPtr(window, GWLP_USERDATA, 0);
|
|
SetWindowLongPtr(window, GWLP_WNDPROC, LONG_PTR(m_oldWndProc));
|
|
#else //defined(_WIN64)
|
|
SetWindowLongPtr(window, GWL_USERDATA, 0);
|
|
SetWindowLong(window, GWLP_WNDPROC, PtrToLong(m_oldWndProc));
|
|
#endif //defined(_WIN64)
|
|
m_oldWndProc = 0;
|
|
}
|
|
|
|
std::string Win32GUI::GetWindowString(HWND hwnd)
|
|
{
|
|
LRESULT length = SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0);
|
|
std::wstring wtext(length, 0);
|
|
SendMessageW(hwnd, WM_GETTEXT, length + 1, (LPARAM)&wtext[0]);
|
|
return StringHelpers::ConvertUtf16ToAnsi(wtext.c_str(), '?');
|
|
}
|
|
|
|
void Win32GUI::SetWindowString(HWND hwnd, const std::string& text)
|
|
{
|
|
std::wstring wtext = StringHelpers::ConvertAnsiToUtf16(text.c_str());
|
|
SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)&wtext[0]);
|
|
}
|
|
|
|
HFONT Win32GUI::CreateFont()
|
|
{
|
|
HFONT hFont = 0;
|
|
HFONT hGuiFont = static_cast<HFONT>(::GetStockObject(DEFAULT_GUI_FONT));
|
|
|
|
LOGFONT lfGuiFont = { 0 };
|
|
if (::GetObject(hGuiFont, sizeof(LOGFONT), &lfGuiFont) == sizeof(LOGFONT))
|
|
{
|
|
_tcsncpy(lfGuiFont.lfFaceName, _T("MS Shell Dlg 2"), sizeof(lfGuiFont.lfFaceName) / sizeof(TCHAR));
|
|
lfGuiFont.lfFaceName[(sizeof(lfGuiFont.lfFaceName) / sizeof(TCHAR)) - 1] = '\0';
|
|
|
|
hFont = ::CreateFontIndirect(&lfGuiFont);
|
|
|
|
return hFont;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void Win32GUI::SetCallbackObject(HWND hwnd, unsigned eventID, EventCallbacks::ICallback* callback)
|
|
{
|
|
#if defined(_WIN64)
|
|
Window* window = (Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
#else //defined(_WIN64)
|
|
Window* window = (Window*)LongToPtr(GetWindowLong(hwnd, GWL_USERDATA));
|
|
#endif //defined(_WIN64)
|
|
|
|
window->m_callbackMap.insert(std::make_pair(eventID, callback));
|
|
}
|