From: Patrick Schönberger Date: Mon, 10 Jan 2022 12:29:19 +0000 (+0100) Subject: Refactor into classes X-Git-Url: https://gitweb.ps.run/autorec/commitdiff_plain/3ec9dfbe56f54f699f2d5efb4e3a4be96e157bc0 Refactor into classes --- diff --git a/build.cmd b/build.cmd index d9e6d4f..c559480 100644 --- a/build.cmd +++ b/build.cmd @@ -1,6 +1,7 @@ +@echo off REM cl src/mongoose.c -c REM rc res/res.rc -cl /EHsc src/main.cpp mongoose.obj /link user32.lib gdi32.lib shell32.lib Shlwapi.lib ws2_32.lib res/res.res +cl /EHsc /Zi src/main.cpp mongoose.obj /link user32.lib gdi32.lib shell32.lib Shlwapi.lib ws2_32.lib res/res.res mt -manifest .\main.exe.manifest -outputresource:main.exe;1 \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index a590411..805932d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -87,60 +87,48 @@ checkForegroundProcess(std::string exeName) bool recording = false; HANDLE process = NULL; -int WINAPI -WinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nCmdShow) +// int WINAPI +// WinMain(HINSTANCE hInstance, +// HINSTANCE hPrevInstance, +// LPSTR lpCmdLine, +// int nCmdShow) +int main(int argc, char **argv) { - HWND window = win::Window("Title", "MyWindowClass", hInstance); - - lay_id row1 = lay_item(&win::_::ctx); - lay_insert(&win::_::ctx, win::_::root, row1); - lay_set_size_xy(&win::_::ctx, row1, 0, 25); - lay_set_behave(&win::_::ctx, row1, LAY_LEFT); - lay_set_contain(&win::_::ctx, row1, LAY_ROW); - lay_set_margins_ltrb(&win::_::ctx, row1, 5, 5, 5, 5); - lay_id row2 = lay_item(&win::_::ctx); - lay_insert(&win::_::ctx, win::_::root, row2); - lay_set_size_xy(&win::_::ctx, row2, 0, 0); - lay_set_behave(&win::_::ctx, row2, LAY_FILL); - lay_set_contain(&win::_::ctx, row2, LAY_ROW); - lay_set_margins_ltrb(&win::_::ctx, row2, 5, 5, 5, 5); - lay_id col1 = lay_item(&win::_::ctx); - lay_set_size_xy(&win::_::ctx, col1, 80, 0); - lay_set_behave(&win::_::ctx, col1, LAY_VCENTER); - lay_set_contain(&win::_::ctx, col1, LAY_COLUMN); - lay_set_margins_ltrb(&win::_::ctx, col1, 5, 0, 5, 0); - - HWND cbWindowTitle = win::CheckBox(window, "Window Title", row1, 100, 25, 0, 0); - HWND cbFullscreenWindow = win::CheckBox(window, "Any Fullscreen Application", row1, 200, 25, 0, 0); - - HWND btnConnect = win::Button(window, "Connect", row1, 100, 25, 0, 0); - win::Callback(btnConnect, BN_CLICKED, [&]() { - ws::connect("ws://127.0.0.1:4444"); - }); + //win::Window window("Title", "MyWindowClass", hInstance); + win::Window window("Title", "MyWindowClass", GetModuleHandle(0)); - win::Callback(cbWindowTitle, BN_CLICKED, [&]() { - SendMessageA(cbWindowTitle, BM_SETCHECK, SendMessageA(cbWindowTitle, BM_GETCHECK, 0, 0) ? BST_UNCHECKED : BST_CHECKED, 0); - }); - win::Callback(cbFullscreenWindow, BN_CLICKED, [&]() { - SendMessageA(cbFullscreenWindow, BM_SETCHECK, SendMessageA(cbFullscreenWindow, BM_GETCHECK, 0, 0) ? BST_UNCHECKED : BST_CHECKED, 0); + lay_context *ctx = &window.ctx; + lay_id root = window.lId; + + win::Hwnd row1(&window, &window, 0, 0, 0, 25, LAY_ROW, LAY_LEFT); + lay_set_margins_ltrb(ctx, row1.lId, 5, 5, 5, 5); + win::Hwnd row2(&window, &window, 0, 0, 0, 0, LAY_ROW, LAY_FILL); + lay_set_margins_ltrb(ctx, row2.lId, 5, 5, 5, 5); + + win::CheckBox cbWindowTitle(&window, &row1, "Window Title", 100, 25, 0, 0); + win::CheckBox cbFullscreenWindow(&window, &row1, "Any Fullscreen Application", 200, 25, 0, 0); + + win::Button btnConnect(&window, &row1, "Connect", 100, 25, 0, 0); + btnConnect.onClick([&]() { + ws::connect("ws://127.0.0.1:4444"); }); - HWND lstActiveProcesses = win::ListView(window, row2, 0, 0, 0, LAY_FILL); - lay_insert(&win::_::ctx, row2, col1); - HWND lstMonitoredProcesses = win::ListBox(window, row2, 0, 0, 0, LAY_FILL); - win::AddStyle(lstActiveProcesses, WS_VSCROLL); - win::AddStyle(lstMonitoredProcesses, WS_VSCROLL); - - HWND btnUpdateWindows = win::Button(window, "Update", col1, 85, 25, 0, 0); - HWND btnStartMonitoringName = win::Button(window, "Exe name >>", col1, 85, 25, 0, 0); - HWND btnStartMonitoringPath = win::Button(window, "Full path >>", col1, 85, 25, 0, 0); - HWND btnStopMonitoring = win::Button(window, "Remove", col1, 85, 25, 0, 0); - win::Callback(btnUpdateWindows, BN_CLICKED, [&]() { - win::ListClear(lstActiveProcesses); + win::ListBox lstActiveProcesses(&window, &row2, 0, 0, 0, LAY_FILL); + + win::Hwnd col1(&window, &row2, 0, 0, 80, 0, LAY_COLUMN, LAY_VCENTER); + lay_set_margins_ltrb(ctx, col1.lId, 5, 0, 5, 0); + + win::ListBox lstMonitoredProcesses(&window, &row2, 0, 0, 0, LAY_FILL); + lstActiveProcesses.addStyle(WS_VSCROLL); + lstMonitoredProcesses.addStyle(WS_VSCROLL); + + win::Button btnUpdateWindows(&window, &col1, "Update", 85, 25, 0, 0); + win::Button btnStartMonitoringName(&window, &col1, "Exe name >>", 85, 25, 0, 0); + win::Button btnStartMonitoringPath(&window, &col1, "Full path >>", 85, 25, 0, 0); + win::Button btnStopMonitoring(&window, &col1, "Remove", 85, 25, 0, 0); + btnUpdateWindows.onClick([&]() { + lstActiveProcesses.clear(); for (HWND hwnd = GetTopWindow(NULL); hwnd != nullptr; hwnd = GetNextWindow(hwnd, GW_HWNDNEXT)) { if (!IsWindowVisible(hwnd)) @@ -151,44 +139,44 @@ WinMain(HINSTANCE hInstance, char str[1024]; if (GetModuleFileNameExA(getHwndProcess(hwnd), 0, str, 1024) != 0 && - win::ListFindString(lstActiveProcesses, str) == LB_ERR) { - win::ListAddString(lstActiveProcesses, str); + lstActiveProcesses.findString(str) == LB_ERR) { + lstActiveProcesses.addString(str); } } }); - win::Callback(btnStartMonitoringName, BN_CLICKED, [&]() { - int sel = win::ListGetSelectedIndex(lstActiveProcesses); + btnStartMonitoringName.onClick([&]() { + int sel = lstActiveProcesses.getSelectedIndex(); if (sel < 0) return; - std::string selStr = win::ListGetText(lstActiveProcesses, sel); + std::string selStr = lstActiveProcesses.getText(sel); char *filename = new char[selStr.size()]; std::memcpy(filename, selStr.c_str(), selStr.size()); PathStripPathA(filename); - if (win::ListFindString(lstMonitoredProcesses, std::string(filename)) == LB_ERR) - win::ListAddString(lstMonitoredProcesses, std::string(filename)); + if (lstMonitoredProcesses.findString(std::string(filename)) == LB_ERR) + lstMonitoredProcesses.addString(std::string(filename)); delete[] filename; }); - win::Callback(btnStartMonitoringPath, BN_CLICKED, [&]() { - int sel = win::ListGetSelectedIndex(lstActiveProcesses); + btnStartMonitoringPath.onClick([&]() { + int sel = lstActiveProcesses.getSelectedIndex(); if (sel < 0) return; - std::string selStr = win::ListGetText(lstActiveProcesses, sel); - if (win::ListFindString(lstMonitoredProcesses, selStr) == LB_ERR) - win::ListAddString(lstMonitoredProcesses, selStr); + std::string selStr = lstActiveProcesses.getText(sel); + if (lstMonitoredProcesses.findString(selStr) == LB_ERR) + lstMonitoredProcesses.addString(selStr); }); - win::Callback(btnStopMonitoring, BN_CLICKED, [&]() { - int sel = win::ListGetSelectedIndex(lstMonitoredProcesses); + btnStopMonitoring.onClick([&]() { + int sel = lstMonitoredProcesses.getSelectedIndex(); if (sel < 0) return; - win::ListRemove(lstMonitoredProcesses, sel); + lstMonitoredProcesses.remove(sel); }); - win::ShowWindow(window); + window.show(); ws::init(); - SetTimer(window, 10123, 100, [](HWND, UINT, UINT_PTR, DWORD) { + SetTimer(window.hwnd, 10123, 100, [](HWND, UINT, UINT_PTR, DWORD) { if (!recording) { if (checkForegroundProcess("League of Legends.exe")) { recording = true; @@ -204,7 +192,7 @@ WinMain(HINSTANCE hInstance, } }); - while (win::UpdateWindow(window)) { + while (window.update()) { ws::update(); } } diff --git a/src/win.h b/src/win.h index 167e162..fe58ebe 100644 --- a/src/win.h +++ b/src/win.h @@ -10,320 +10,606 @@ processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") #include "layout.h" #include -#include +#include #include -using std::string; - -namespace win { -namespace _ { -using CallbackFn = std::function; -std::map> handlers; -std::map lIds; - -NOTIFYICONDATA niData = { 0 }; -void -ShowNotificationIcon() -{ - Shell_NotifyIconA(NIM_ADD, &_::niData); - Shell_NotifyIconA(NIM_SETVERSION, &_::niData); -} - -void -HideNotificationIcon() -{ - Shell_NotifyIconA(NIM_DELETE, &_::niData); -} - -lay_context ctx; -lay_id root; - -LRESULT CALLBACK -WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +// namespace wnin { +// namespace _ { +// using CallbackFn = std::function; +// std::map> handlers; +// std::map lIds; + +// NOTIFYICONDATA niData = { 0 }; +// void +// ShowNotificationIcon() +// { +// Shell_NotifyIconA(NIM_ADD, &_::niData); +// Shell_NotifyIconA(NIM_SETVERSION, &_::niData); +// } + +// void +// HideNotificationIcon() +// { +// Shell_NotifyIconA(NIM_DELETE, &_::niData); +// } + +// lay_context ctx; +// lay_id root; + +// LRESULT CALLBACK +// WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +// { +// switch (msg) { +// case WM_CLOSE: +// DestroyWindow(hwnd); +// break; +// case WM_DESTROY: +// Shell_NotifyIconA(NIM_DELETE, &niData); +// lay_destroy_context(&ctx); +// PostQuitMessage(0); +// break; +// case WM_SIZE: +// if (wParam == SIZE_MINIMIZED) { +// ShowNotificationIcon(); +// ShowWindow(hwnd, false); +// } +// else { +// lay_set_size_xy(&_::ctx, _::root, LOWORD(lParam), HIWORD(lParam)); +// lay_run_context(&_::ctx); + +// for (auto &lId : lIds) { +// lay_vec4 rect = lay_get_rect(&_::ctx, lId.second); +// SetWindowPos(lId.first, HWND_TOP, +// rect[0], +// rect[1], +// rect[2], +// rect[3], +// SWP_NOZORDER +// ); +// } +// RedrawWindow(hwnd, 0, 0, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN); +// } +// break; +// case WM_COMMAND: +// if (handlers.find((HWND)lParam) != handlers.end()) { +// auto handler = handlers[(HWND)lParam]; +// if (handler.find(HIWORD(wParam)) != handler.end()) { +// auto cb = handler[HIWORD(wParam)]; +// cb(); +// } +// } +// break; +// case WM_NOTIFY: +// break; +// case WM_APP + 1: +// if (LOWORD(lParam) == NIN_SELECT) { +// HideNotificationIcon(); +// ShowWindow(hwnd, true); +// SetForegroundWindow(hwnd); +// SetActiveWindow(hwnd); +// } +// break; +// case WM_CTLCOLORSTATIC: +// return (LONG)GetStockObject(WHITE_BRUSH); +// case WM_GETMINMAXINFO: { +// MINMAXINFO *mmInfo = (MINMAXINFO*)lParam; +// mmInfo->ptMinTrackSize.x = 400; +// mmInfo->ptMinTrackSize.y = 200; +// break; +// } +// default: +// return DefWindowProc(hwnd, msg, wParam, lParam); +// } +// return 0; +// } +// } + + +// void +// Callback(HWND hwnd, WORD ev, std::function cb) +// { +// _::handlers[hwnd][ev] = cb; +// } + +// HWND +// Window(string title, string className, HINSTANCE hInstance) +// { +// WNDCLASSEX wc; +// wc.cbSize = sizeof(WNDCLASSEX); +// wc.style = 0; +// wc.lpfnWndProc = _::WndProc; +// wc.cbClsExtra = 0; +// wc.cbWndExtra = 0; +// wc.hInstance = hInstance; +// wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION); +// wc.hCursor = LoadCursor(nullptr, IDC_ARROW); +// wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); +// wc.lpszMenuName = nullptr; +// wc.lpszClassName = className.c_str(); +// wc.hIconSm = LoadIcon(nullptr, IDI_APPLICATION); +// RegisterClassEx(&wc); + +// lay_init_context(&_::ctx); +// _::root = lay_item(&_::ctx); +// lay_set_contain(&_::ctx, _::root, LAY_COLUMN); + +// HWND result = CreateWindowA(className.c_str(), +// title.c_str(), +// WS_OVERLAPPEDWINDOW, +// CW_USEDEFAULT, +// CW_USEDEFAULT, +// CW_USEDEFAULT, +// CW_USEDEFAULT, +// nullptr, +// nullptr, +// hInstance, +// nullptr); + +// _::niData.cbSize = sizeof(_::niData); +// _::niData.uID = 12345; +// _::niData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; +// _::niData.hIcon = LoadIconA(hInstance, MAKEINTRESOURCEA(IDI_MY_ICON)); +// _::niData.hWnd = result; +// _::niData.uCallbackMessage = WM_APP+1; +// _::niData.uVersion = NOTIFYICON_VERSION_4; + +// return result; +// } + +// bool +// UpdateWindow(HWND hwnd) +// { +// MSG msg; +// if (GetMessage(&msg, nullptr, 0, 0) > 0) { +// TranslateMessage(&msg); +// DispatchMessage(&msg); +// return true; +// } +// return false; +// } + +// void +// ShowWindow(HWND hwnd) +// { +// ShowWindow(hwnd, true); + +// EnumChildWindows( +// hwnd, +// [](HWND hwnd, LPARAM lParam) -> BOOL { +// HFONT guiFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); +// SendMessage(hwnd, WM_SETFONT, (WPARAM)guiFont, MAKELPARAM(TRUE, 0)); +// return TRUE; +// }, +// 0); +// } + +// HWND +// Button(HWND hwnd, string title, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave) +// { +// lay_id lId = lay_item(&_::ctx); +// lay_insert(&_::ctx, parent, lId); +// lay_set_size_xy(&_::ctx, lId, w, h); +// lay_set_contain(&_::ctx, lId, contain); +// lay_set_behave(&_::ctx, lId, behave); + +// HWND result = CreateWindowExA(0, +// WC_BUTTONA, +// title.c_str(), +// WS_VISIBLE | WS_CHILD, +// 0, 0, 0, 0, +// hwnd, +// nullptr, +// nullptr, +// nullptr); +// _::lIds[result] = lId; +// return result; +// } + +// HWND +// ListBox(HWND hwnd, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave) +// { +// lay_id lId = lay_item(&_::ctx); +// lay_insert(&_::ctx, parent, lId); +// lay_set_size_xy(&_::ctx, lId, w, h); +// lay_set_contain(&_::ctx, lId, contain); +// lay_set_behave(&_::ctx, lId, behave); + +// HWND result = CreateWindowExA(0, +// WC_LISTBOXA, +// "", +// WS_VISIBLE | WS_CHILD | WS_BORDER | WS_VSCROLL, +// 0, 0, 0, 0, +// hwnd, +// nullptr, +// nullptr, +// nullptr); +// _::lIds[result] = lId; +// return result; +// } + +// void +// ListAddString(HWND hwnd, string str) +// { +// SendMessage(hwnd, LB_ADDSTRING, 0, (LPARAM)str.c_str()); +// } + +// int +// ListGetSelectedIndex(HWND hwnd) +// { +// int sel = SendMessage(hwnd, LB_GETCURSEL, 0, 0); +// return sel; +// } + +// int ListFindString(HWND hwnd, string str) +// { +// return SendMessageA(hwnd, LB_FINDSTRINGEXACT, -1, (LPARAM)str.c_str()); +// } + +// string +// ListGetText(HWND hwnd, int index) +// { +// char buffer[1024]; +// SendMessage(hwnd, LB_GETTEXT, index, (LPARAM)buffer); +// return string(buffer); +// } + +// void +// ListClear(HWND hwnd) +// { +// SendMessageA(hwnd, LB_RESETCONTENT, 0, 0); +// } + +// void ListRemove(HWND hwnd, int index) +// { +// SendMessageA(hwnd, LB_DELETESTRING, index, 0); +// } + +// HWND +// ListView(HWND hwnd, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave) +// { +// lay_id lId = lay_item(&_::ctx); +// lay_insert(&_::ctx, parent, lId); +// lay_set_size_xy(&_::ctx, lId, w, h); +// lay_set_contain(&_::ctx, lId, contain); +// lay_set_behave(&_::ctx, lId, behave); + +// HWND result = CreateWindowExA(0, +// WC_LISTVIEWA, +// "", +// WS_VISIBLE | WS_CHILD | WS_BORDER | WS_VSCROLL, +// 0, 0, 0, 0, +// hwnd, +// nullptr, +// nullptr, +// nullptr); +// _::lIds[result] = lId; +// return result; +// } + +// HWND +// CheckBox(HWND hwnd, string title, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave) +// { +// lay_id lId = lay_item(&_::ctx); +// lay_insert(&_::ctx, parent, lId); +// lay_set_size_xy(&_::ctx, lId, w, h); +// lay_set_contain(&_::ctx, lId, contain); +// lay_set_behave(&_::ctx, lId, behave); + +// HWND result = CreateWindowExA(0, +// WC_BUTTONA, +// title.c_str(), +// WS_VISIBLE | WS_CHILD | BS_CHECKBOX, +// 0, 0, 0, 0, +// hwnd, +// nullptr, +// nullptr, +// nullptr); +// _::lIds[result] = lId; +// return result; +// } + +// void SetStyle(HWND hwnd, DWORD style) +// { +// SetWindowLongPtrA(hwnd, GWL_STYLE, style); +// } +// DWORD GetStyle(HWND hwnd) +// { +// return GetWindowLongPtrA(hwnd, GWL_STYLE); +// } +// void AddStyle(HWND hwnd, DWORD style) +// { +// SetWindowLongPtrA(hwnd, GWL_STYLE, GetStyle(hwnd) | style); +// } +// void RemoveStyle(HWND hwnd, DWORD style) +// { +// SetWindowLongPtrA(hwnd, GWL_STYLE, GetStyle(hwnd) & (~style)); +// } +// } + + + + +namespace win { - switch (msg) { - case WM_CLOSE: - DestroyWindow(hwnd); - break; - case WM_DESTROY: - Shell_NotifyIconA(NIM_DELETE, &niData); - lay_destroy_context(&ctx); - PostQuitMessage(0); - break; - case WM_SIZE: - if (wParam == SIZE_MINIMIZED) { - ShowNotificationIcon(); - ShowWindow(hwnd, false); - } - else { - lay_set_size_xy(&_::ctx, _::root, LOWORD(lParam), HIWORD(lParam)); - lay_run_context(&_::ctx); - - for (auto &lId : lIds) { - lay_vec4 rect = lay_get_rect(&_::ctx, lId.second); - SetWindowPos(lId.first, HWND_TOP, - rect[0], - rect[1], - rect[2], - rect[3], - SWP_NOZORDER - ); - } - RedrawWindow(hwnd, 0, 0, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN); - } - break; - case WM_COMMAND: - if (handlers.find((HWND)lParam) != handlers.end()) { - auto handler = handlers[(HWND)lParam]; - if (handler.find(HIWORD(wParam)) != handler.end()) { - auto cb = handler[HIWORD(wParam)]; - cb(); + struct Window; + struct Hwnd + { + HWND hwnd; + lay_id lId; + Window *window; + + Hwnd() {} + Hwnd(Window *window, Hwnd *parent, LPCSTR className, LPCSTR windowName, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave); + + void setStyle(DWORD style) + { + SetWindowLongPtrA(hwnd, GWL_STYLE, style); + } + DWORD getStyle() + { + return GetWindowLongPtrA(hwnd, GWL_STYLE); + } + void addStyle(DWORD style) + { + SetWindowLongPtrA(hwnd, GWL_STYLE, getStyle() | style); + } + void removeStyle(DWORD style) + { + SetWindowLongPtrA(hwnd, GWL_STYLE, getStyle() & (~style)); + } + }; + struct Window : Hwnd + { + private: + NOTIFYICONDATAA niData = { 0 }; + + static LRESULT CALLBACK + WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) + { + Window *window = (Window*)GetWindowLongPtrA(hwnd, 0); + if (window == nullptr) + return DefWindowProc(hwnd, msg, wParam, lParam); + + bool defaultHandler = false; + + switch (msg) { + case WM_CLOSE: + DestroyWindow(hwnd); + break; + case WM_DESTROY: + Shell_NotifyIconA(NIM_DELETE, &window->niData); + lay_destroy_context(&window->ctx); + PostQuitMessage(0); + break; + case WM_SIZE: + if (wParam == SIZE_MINIMIZED) { + //TODO: auslagen + //ShowNotificationIcon(); + ShowWindow(hwnd, false); + } + else { + lay_set_size_xy(&window->ctx, window->lId, LOWORD(lParam), HIWORD(lParam)); + lay_run_context(&window->ctx); + + //RedrawWindow(hwnd, 0, 0, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN); + } + break; + case WM_NOTIFY: + break; + case WM_APP + 1: + if (LOWORD(lParam) == NIN_SELECT) { + //TODO: auslagern + //HideNotificationIcon(); + ShowWindow(hwnd, true); + SetForegroundWindow(hwnd); + SetActiveWindow(hwnd); + } + break; + case WM_CTLCOLORSTATIC: + return (LONG)GetStockObject(WHITE_BRUSH); + case WM_GETMINMAXINFO: { + MINMAXINFO *mmInfo = (MINMAXINFO*)lParam; + mmInfo->ptMinTrackSize.x = 400; + mmInfo->ptMinTrackSize.y = 200; + break; } + default: + defaultHandler = true; + break; } - break; - case WM_NOTIFY: - break; - case WM_APP + 1: - if (LOWORD(lParam) == NIN_SELECT) { - HideNotificationIcon(); - ShowWindow(hwnd, true); - SetForegroundWindow(hwnd); - SetActiveWindow(hwnd); + + for (auto handler : window->handlers[msg]) + handler(hwnd, msg, wParam, lParam); + + if (defaultHandler) + return DefWindowProc(hwnd, msg, wParam, lParam); + else + return 0; + } + public: + lay_context ctx; + std::unordered_map>> handlers; + + Window(std::string title, std::string className, HINSTANCE hInstance) + { + WNDCLASSEXA wc; + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = 0; + wc.lpfnWndProc = WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = sizeof(Window*); + wc.hInstance = hInstance; + wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION); + wc.hCursor = LoadCursor(nullptr, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wc.lpszMenuName = nullptr; + wc.lpszClassName = className.c_str(); + wc.hIconSm = LoadIcon(nullptr, IDI_APPLICATION); + RegisterClassExA(&wc); + + lay_init_context(&ctx); + lId = lay_item(&ctx); + lay_set_contain(&ctx, lId, LAY_COLUMN); + + hwnd = CreateWindowA(className.c_str(), + title.c_str(), + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + nullptr, + nullptr, + hInstance, + nullptr); + + SetWindowLongPtrA(hwnd, 0, (LONG_PTR)this); + + + niData.cbSize = sizeof(niData); + niData.uID = 12345; + niData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; + niData.hIcon = LoadIconA(hInstance, MAKEINTRESOURCEA(IDI_MY_ICON)); + niData.hWnd = hwnd; + niData.uCallbackMessage = WM_APP+1; + niData.uVersion = NOTIFYICON_VERSION_4; + } + bool update() + { + MSG msg; + if (GetMessage(&msg, nullptr, 0, 0) > 0) { + TranslateMessage(&msg); + DispatchMessage(&msg); + return true; } - break; - case WM_CTLCOLORSTATIC: - return (LONG)GetStockObject(WHITE_BRUSH); - case WM_GETMINMAXINFO: { - MINMAXINFO *mmInfo = (MINMAXINFO*)lParam; - mmInfo->ptMinTrackSize.x = 400; - mmInfo->ptMinTrackSize.y = 200; - break; + return false; + } + void show() + { + ShowWindow(hwnd, true); + + EnumChildWindows( + hwnd, + [](HWND hwnd, LPARAM lParam) -> BOOL { + HFONT guiFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); + SendMessage(hwnd, WM_SETFONT, (WPARAM)guiFont, MAKELPARAM(TRUE, 0)); + return TRUE; + }, + 0); + } + }; + + struct Button : Hwnd + { + Button(Window *window, Hwnd *parent, std::string title, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave) + : Hwnd(window, parent, WC_BUTTONA, title.c_str(), w, h, contain, behave) + { + window->handlers[WM_COMMAND].push_back([&](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + if ((HWND)lParam == this->hwnd && HIWORD(wParam) == BN_CLICKED) + for (auto handler : this->onClickHandlers) + handler(); + }); } - default: - return DefWindowProc(hwnd, msg, wParam, lParam); - } - return 0; -} -} - - -void -Callback(HWND hwnd, WORD ev, std::function cb) -{ - _::handlers[hwnd][ev] = cb; -} - -HWND -Window(string title, string className, HINSTANCE hInstance) -{ - WNDCLASSEX wc; - wc.cbSize = sizeof(WNDCLASSEX); - wc.style = 0; - wc.lpfnWndProc = _::WndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = hInstance; - wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION); - wc.hCursor = LoadCursor(nullptr, IDC_ARROW); - wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wc.lpszMenuName = nullptr; - wc.lpszClassName = className.c_str(); - wc.hIconSm = LoadIcon(nullptr, IDI_APPLICATION); - RegisterClassEx(&wc); - - lay_init_context(&_::ctx); - _::root = lay_item(&_::ctx); - lay_set_contain(&_::ctx, _::root, LAY_COLUMN); - - HWND result = CreateWindowA(className.c_str(), - title.c_str(), - WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, - CW_USEDEFAULT, - CW_USEDEFAULT, - CW_USEDEFAULT, - nullptr, - nullptr, - hInstance, - nullptr); - - _::niData.cbSize = sizeof(_::niData); - _::niData.uID = 12345; - _::niData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; - _::niData.hIcon = LoadIconA(hInstance, MAKEINTRESOURCEA(IDI_MY_ICON)); - _::niData.hWnd = result; - _::niData.uCallbackMessage = WM_APP+1; - _::niData.uVersion = NOTIFYICON_VERSION_4; - - return result; -} - -bool -UpdateWindow(HWND hwnd) -{ - MSG msg; - if (GetMessage(&msg, nullptr, 0, 0) > 0) { - TranslateMessage(&msg); - DispatchMessage(&msg); - return true; - } - return false; -} - -void -ShowWindow(HWND hwnd) -{ - ShowWindow(hwnd, true); - - EnumChildWindows( - hwnd, - [](HWND hwnd, LPARAM lParam) -> BOOL { - HFONT guiFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); - SendMessage(hwnd, WM_SETFONT, (WPARAM)guiFont, MAKELPARAM(TRUE, 0)); - return TRUE; - }, - 0); -} - -HWND -Button(HWND hwnd, string title, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave) -{ - lay_id lId = lay_item(&_::ctx); - lay_insert(&_::ctx, parent, lId); - lay_set_size_xy(&_::ctx, lId, w, h); - lay_set_contain(&_::ctx, lId, contain); - lay_set_behave(&_::ctx, lId, behave); - - HWND result = CreateWindowExA(0, - WC_BUTTONA, - title.c_str(), - WS_VISIBLE | WS_CHILD, - 0, 0, 0, 0, - hwnd, - nullptr, - nullptr, - nullptr); - _::lIds[result] = lId; - return result; -} - -HWND -ListBox(HWND hwnd, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave) -{ - lay_id lId = lay_item(&_::ctx); - lay_insert(&_::ctx, parent, lId); - lay_set_size_xy(&_::ctx, lId, w, h); - lay_set_contain(&_::ctx, lId, contain); - lay_set_behave(&_::ctx, lId, behave); - - HWND result = CreateWindowExA(0, - WC_LISTBOXA, - "", - WS_VISIBLE | WS_CHILD | WS_BORDER | WS_VSCROLL, - 0, 0, 0, 0, - hwnd, - nullptr, - nullptr, - nullptr); - _::lIds[result] = lId; - return result; -} - -void -ListAddString(HWND hwnd, string str) -{ - SendMessage(hwnd, LB_ADDSTRING, 0, (LPARAM)str.c_str()); -} -int -ListGetSelectedIndex(HWND hwnd) -{ - int sel = SendMessage(hwnd, LB_GETCURSEL, 0, 0); - return sel; -} + void onClick(std::function cb) + { + onClickHandlers.push_back(cb); + } + private: + std::vector> onClickHandlers; + }; + + struct CheckBox : Hwnd + { + CheckBox(Window *window, Hwnd *parent, std::string title, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave) + : Hwnd(window, parent, WC_BUTTONA, title.c_str(), w, h, contain, behave) + { + addStyle(BS_CHECKBOX); + window->handlers[WM_COMMAND].push_back([&](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + if ((HWND)lParam == this->hwnd && HIWORD(wParam) == BN_CLICKED) + SendMessageA(this->hwnd, BM_SETCHECK, SendMessageA(this->hwnd, BM_GETCHECK, 0, 0) ? BST_UNCHECKED : BST_CHECKED, 0); + }); + } + }; + + struct ListBox : Hwnd + { + ListBox(Window *window, Hwnd *parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave) + : Hwnd(window, parent, WC_LISTBOXA, "", w, h, contain, behave) + { + addStyle(WS_BORDER); + addStyle(WS_VSCROLL); + } -int ListFindString(HWND hwnd, string str) -{ - return SendMessageA(hwnd, LB_FINDSTRINGEXACT, -1, (LPARAM)str.c_str()); -} + void addString(std::string str) + { + SendMessage(hwnd, LB_ADDSTRING, 0, (LPARAM)str.c_str()); + } -string -ListGetText(HWND hwnd, int index) -{ - char buffer[1024]; - SendMessage(hwnd, LB_GETTEXT, index, (LPARAM)buffer); - return string(buffer); -} + int getSelectedIndex() + { + return SendMessage(hwnd, LB_GETCURSEL, 0, 0); + } -void -ListClear(HWND hwnd) -{ - SendMessageA(hwnd, LB_RESETCONTENT, 0, 0); -} + int findString(std::string str) + { + return SendMessageA(hwnd, LB_FINDSTRINGEXACT, -1, (LPARAM)str.c_str()); + } -void ListRemove(HWND hwnd, int index) -{ - SendMessageA(hwnd, LB_DELETESTRING, index, 0); -} + std::string getText(int index) + { + int len = SendMessageA(hwnd, LB_GETTEXTLEN, index, 0); + std::string result; + result.reserve(len); + SendMessage(hwnd, LB_GETTEXT, index, (LPARAM)result.data()); + return result; + } -HWND -ListView(HWND hwnd, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave) -{ - lay_id lId = lay_item(&_::ctx); - lay_insert(&_::ctx, parent, lId); - lay_set_size_xy(&_::ctx, lId, w, h); - lay_set_contain(&_::ctx, lId, contain); - lay_set_behave(&_::ctx, lId, behave); - - HWND result = CreateWindowExA(0, - WC_LISTVIEWA, - "", - WS_VISIBLE | WS_CHILD | WS_BORDER | WS_VSCROLL, - 0, 0, 0, 0, - hwnd, - nullptr, - nullptr, - nullptr); - _::lIds[result] = lId; - return result; -} + void clear() + { + SendMessageA(hwnd, LB_RESETCONTENT, 0, 0); + } -HWND -CheckBox(HWND hwnd, string title, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave) -{ - lay_id lId = lay_item(&_::ctx); - lay_insert(&_::ctx, parent, lId); - lay_set_size_xy(&_::ctx, lId, w, h); - lay_set_contain(&_::ctx, lId, contain); - lay_set_behave(&_::ctx, lId, behave); - - HWND result = CreateWindowExA(0, - WC_BUTTONA, - title.c_str(), - WS_VISIBLE | WS_CHILD | BS_CHECKBOX, - 0, 0, 0, 0, - hwnd, - nullptr, - nullptr, - nullptr); - _::lIds[result] = lId; - return result; + void remove(int index) + { + SendMessageA(hwnd, LB_DELETESTRING, index, 0); + } + }; } -void SetStyle(HWND hwnd, DWORD style) +win::Hwnd::Hwnd(Window *window, Hwnd *parent, LPCSTR className, LPCSTR windowName, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave) { - SetWindowLongPtrA(hwnd, GWL_STYLE, style); -} -DWORD GetStyle(HWND hwnd) -{ - return GetWindowLongPtrA(hwnd, GWL_STYLE); -} -void AddStyle(HWND hwnd, DWORD style) -{ - SetWindowLongPtrA(hwnd, GWL_STYLE, GetStyle(hwnd) | style); -} -void RemoveStyle(HWND hwnd, DWORD style) -{ - SetWindowLongPtrA(hwnd, GWL_STYLE, GetStyle(hwnd) & (~style)); -} + this->window = window; + + lId = lay_item(&window->ctx); + lay_insert(&window->ctx, parent->lId, lId); + lay_set_size_xy(&window->ctx, lId, w, h); + lay_set_contain(&window->ctx, lId, contain); + lay_set_behave(&window->ctx, lId, behave); + + hwnd = CreateWindowExA(0, + className, + windowName, + WS_VISIBLE | WS_CHILD, + 0, + 0, + 0, + 0, + window->hwnd, + nullptr, + nullptr, + nullptr); + + window->handlers[WM_SIZE].push_back([this](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + lay_vec4 rect = lay_get_rect(&this->window->ctx, this->lId); + SetWindowPos(this->hwnd, HWND_TOP, + rect[0], + rect[1], + rect[2], + rect[3], + SWP_NOZORDER + ); + }); } \ No newline at end of file