blizzget/src/frameui/window.cpp
2016-03-09 11:42:26 +03:00

336 lines
10 KiB
C++

#include "window.h"
#include "frameui/fontsys.h"
#include <stdio.h>
#include <windowsx.h>
struct Window::TTData {
HWND hTip;
RECT tipRect;
int hitCode;
HFONT hFont;
std::string fixedTip;
};
static LRESULT CALLBACK TooltipWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (uMsg == WM_PAINT) {
std::string text = Window::getWindowText(hWnd);
RECT rc;
GetClientRect(hWnd, &rc);
PAINTSTRUCT ps;
HDC hDC = BeginPaint(hWnd, &ps);
HFONT hFont = (HFONT)GetWindowLongPtr(hWnd, GWLP_USERDATA);
SelectObject(hDC, hFont);
SetBkColor(hDC, 0xE1FFFF);
SetTextColor(hDC, 0x000000);
HPEN hPen = CreatePen(PS_SOLID, 0, 0x000000);
HPEN hPrev = (HPEN)SelectObject(hDC, hPen);
Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
rc.left += 5;
rc.top += 2;
rc.bottom -= 2;
rc.right -= 5;
DrawText(hDC, text.c_str(), text.length(), &rc, DT_LEFT | DT_TOP);
SelectObject(hDC, hPrev);
DeleteObject(hPen);
EndPaint(hWnd, &ps);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);;
}
ATOM Window::windowClass = NULL;
std::map<HWND, Window*> Window::handleMap;
Window* Window::fromHandle(HWND hWnd) {
auto it = handleMap.find(hWnd);
return (it == handleMap.end() ? nullptr : it->second);
}
WNDCLASSEX* Window::createclass(std::string const& wndClass) {
regClass = wndClass;
WNDCLASSEX* wcx = new WNDCLASSEX;
HINSTANCE hInstance = GetModuleHandle(NULL);
if (!GetClassInfoEx(hInstance, regClass.c_str(), wcx)) {
memset(wcx, 0, sizeof(WNDCLASSEX));
wcx->cbSize = sizeof(WNDCLASSEX);
wcx->lpfnWndProc = WindowProc;
wcx->hInstance = hInstance;
wcx->lpszClassName = regClass.c_str();
wcx->hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
return wcx;
}
delete wcx;
return NULL;
}
void Window::create(int x, int y, int width, int height, std::string const& text, uint32 style, uint32 exStyle,
HWND parent)
{
if (!windowClass && regClass.empty()) {
WNDCLASSEX wcex;
memset(&wcex, 0, sizeof wcex);
wcex.cbSize = sizeof wcex;
wcex.lpfnWndProc = WindowProc;
wcex.hInstance = GetModuleHandle(NULL);
wcex.lpszClassName = "WUTILSWINDOW";
wcex.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
windowClass = RegisterClassEx(&wcex);
}
hWnd = CreateWindowEx(exStyle, regClass.empty() ? "WUTILSWINDOW" : regClass.c_str(), text.c_str(), style,
x, y, width, height, parent, NULL, GetModuleHandle(NULL), this);
handleMap[hWnd] = this;
}
void Window::create(std::string const& wndClass, int x, int y, int width, int height, std::string const& text, uint32 style,
uint32 exStyle, HWND parent) {
hWnd = CreateWindowEx(exStyle, wndClass.c_str(), text.c_str(), style, x, y, width, height,
parent, NULL, GetModuleHandle(NULL), NULL);
handleMap[hWnd] = this;
}
void Window::subclass(std::string const& wndClass, int x, int y, int width, int height, std::string const& text, uint32 style,
uint32 exStyle, HWND parent) {
hWnd = CreateWindowEx(exStyle, wndClass.c_str(), text.c_str(), style, x, y, width, height,
parent, NULL, GetModuleHandle(NULL), NULL);
handleMap[hWnd] = this;
origProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR) WindowProc);
}
LRESULT CALLBACK Window::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
Window* wnd = fromHandle(hWnd);
if (wnd == NULL && uMsg == WM_CREATE) {
CREATESTRUCT* cs = (CREATESTRUCT*)lParam;
wnd = (Window*)cs->lpCreateParams;
if (wnd) wnd->hWnd = hWnd;
}
if (wnd) {
bool send = true;
if (wnd->ttData) {
TRACKMOUSEEVENT tme;
memset(&tme, 0, sizeof tme);
tme.cbSize = sizeof tme;
tme.hwndTrack = wnd->hWnd;
if (uMsg == WM_MOUSEMOVE) {
POINT pt;
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
if (wnd->ttData->hitCode >= 0) {
if (pt.x < wnd->ttData->tipRect.left || pt.x >= wnd->ttData->tipRect.right ||
pt.y < wnd->ttData->tipRect.top || pt.y >= wnd->ttData->tipRect.bottom) {
wnd->ttData->hitCode = -1;
}
}
if (wnd->ttData->hitCode < 0) {
ToolInfo ti;
wnd->ttData->hitCode = wnd->toolHitTest(pt, &ti);
if (wnd->ttData->hitCode >= 0) {
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.dwHoverTime = HOVER_DEFAULT;
TrackMouseEvent(&tme);
wnd->ttData->tipRect = ti.rc;
SetWindowText(wnd->ttData->hTip, ti.text.c_str());
HDC hDC = GetDC(wnd->ttData->hTip);
SelectObject(hDC, wnd->ttData->hFont);
RECT rc = { 0, 0, 1024, 1024 };
int ht = DrawText(hDC, ti.text.c_str(), ti.text.length(), &rc, DT_LEFT | DT_TOP | DT_CALCRECT);
ReleaseDC(wnd->ttData->hTip, hDC);
POINT ptTL;
ptTL.x = wnd->ttData->tipRect.left;
ptTL.y = wnd->ttData->tipRect.bottom + 5;
ClientToScreen(wnd->hWnd, &ptTL);
SetWindowLongPtr(wnd->ttData->hTip, GWLP_USERDATA, (LONG_PTR)wnd->ttData->hFont);
InvalidateRect(wnd->ttData->hTip, NULL, TRUE);
SetWindowPos(wnd->ttData->hTip, HWND_TOPMOST,
ptTL.x, ptTL.y, rc.right + 10, ht + 5,
SWP_NOACTIVATE);
} else {
tme.dwFlags = TME_CANCEL;
TrackMouseEvent(&tme);
ShowWindow(wnd->ttData->hTip, SW_HIDE);
}
}
} else if (uMsg == WM_MOUSELEAVE) {
ShowWindow(wnd->ttData->hTip, SW_HIDE);
wnd->ttData->hitCode = -1;
send = false;
} else if (uMsg == WM_MOUSEHOVER) {
tme.dwFlags = TME_CANCEL;
TrackMouseEvent(&tme);
if (wnd->ttData->hitCode >= 0) ShowWindow(wnd->ttData->hTip, SW_SHOWNA);
send = false;
} else if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || uMsg == WM_MBUTTONDOWN ||
uMsg == WM_MOUSEWHEEL || uMsg == WM_MOUSEHWHEEL || uMsg == WM_KEYDOWN) {
ShowWindow(wnd->ttData->hTip, SW_HIDE);
wnd->ttData->hitCode = -1;
}
}
if (send) {
if (uMsg == WM_CLOSE || uMsg == WM_DESTROY) wnd->endModal();
uint32 result = wnd->onWndMessage(uMsg, wParam, lParam);
if (uMsg == WM_DESTROY) wnd->hWnd = NULL;
return result;
} else {
return 0;
}
} else {
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
}
LRESULT Window::onWndMessage(uint32 message, WPARAM wParam, LPARAM lParam) {
if (origProc) return CallWindowProc(origProc, hWnd, message, wParam, lParam);
else return DefWindowProc(hWnd, message, wParam, lParam);
}
Window::Window() {
hWnd = NULL;
origProc = NULL;
ttData = NULL;
}
Window::~Window() {
if (hWnd) {
if (origProc) SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)origProc);
handleMap.erase(hWnd);
DestroyWindow(hWnd);
}
if (ttData) delete ttData;
}
void Window::setText(std::string const& text)
{
SetWindowText(hWnd, text.c_str());
}
std::string Window::getText() const {
return getWindowText(hWnd);
}
std::string Window::getWindowText(HWND hWnd) {
size_t length = GetWindowTextLength(hWnd);
std::string str;
str.resize(length + 1);
GetWindowText(hWnd, &str[0], str.length());
str.resize(length);
return str;
}
void Window::setFont(HFONT hFont) {
SendMessage(hWnd, WM_SETFONT, (WPARAM)hFont, TRUE);
}
HFONT Window::getFont() const {
return (HFONT)SendMessage(hWnd, WM_GETFONT, NULL, NULL);
}
void Window::enable(bool e) {
EnableWindow(hWnd, e);
}
void Window::showWindow(bool s) {
ShowWindow(hWnd, s ? SW_SHOW : SW_HIDE);
}
int Window::id() const {
return GetWindowLong(hWnd, GWL_ID);
}
void Window::setId(int id) {
SetWindowLong(hWnd, GWL_ID, id);
}
void Window::invalidate(bool erase) {
InvalidateRect(hWnd, NULL, erase ? TRUE : FALSE);
}
void Window::setRedraw(bool r) {
SendMessage(hWnd, WM_SETREDRAW, r ? TRUE : FALSE, 0);
if (r) RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE);
}
int Window::toolHitTest(POINT pt, ToolInfo* ti) {
if (ttData && ttData->fixedTip.length()) {
GetClientRect(hWnd, &ti->rc);
ti->text = ttData->fixedTip;
return 0;
}
return -1;
}
void Window::enableTooltips(bool enable) {
if (hWnd == NULL) return;
if (enable && ttData == NULL) {
ttData = new TTData;
ttData->hFont = FontSys::getSysFont();
WNDCLASSEX wcx;
HINSTANCE hInstance = GetModuleHandle(NULL);
if (!GetClassInfoEx(hInstance, "DRTooltip", &wcx)) {
memset(&wcx, 0, sizeof wcx);
wcx.cbSize = sizeof wcx;
wcx.lpfnWndProc = TooltipWindowProc;
wcx.hInstance = hInstance;
wcx.lpszClassName = "DRTooltip";
wcx.hbrBackground = CreateSolidBrush(0xE1FFFF);
RegisterClassEx(&wcx);
}
ttData->hTip = CreateWindowEx(WS_EX_TOPMOST, "DRTooltip",
NULL, WS_POPUP, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, hWnd, NULL,
hInstance, NULL);
ttData->hitCode = -1;
} else if (!enable && ttData != NULL) {
DestroyWindow(ttData->hTip);
delete ttData;
ttData = NULL;
}
}
void Window::setTooltipFont(HFONT hFont) {
if (ttData) ttData->hFont = hFont;
}
HFONT Window::getTooltipFont() {
return (ttData ? ttData->hFont : NULL);
}
void Window::endModal() {
if (continueModal) {
continueModal = false;
SetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOACTIVATE |
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
HWND hParent = GetWindow(hWnd, GW_OWNER);
if (hParent) {
EnableWindow(hParent, TRUE);
if (GetActiveWindow() == hWnd) SetActiveWindow(hParent);
}
PostMessage(hWnd, WM_CLOSE, 0, 0);
}
}
int Window::doModal() {
if (hWnd == NULL) return 0;
ShowWindow(hWnd, SW_SHOW);
HWND hParent = GetWindow(hWnd, GW_OWNER);
if (hParent) EnableWindow(hParent, FALSE);
MSG msg;
continueModal = true;
while (continueModal) {
if (!GetMessage(&msg, NULL, 0, 0)) {
PostQuitMessage(msg.wParam);
return 0;
}
if (!IsDialogMessage(hWnd, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
void Window::setTooltip(char const* tip) {
if (tip && *tip) {
enableTooltips(true);
ttData->fixedTip = tip;
} else {
enableTooltips(false);
}
}