mirror of
https://github.com/CDAGaming/blizzget
synced 2025-11-09 19:15:58 +03:00
336 lines
10 KiB
C++
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);
|
|
}
|
|
}
|