1 #pragma comment(linker, "\"/manifestdependency:type='win32' \
\r
2 name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
\r
3 processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
\r
6 #include <CommCtrl.h>
\r
8 #include "../res/resource.h"
\r
12 #include <functional>
\r
13 #include <unordered_map>
\r
18 // using CallbackFn = std::function<void()>;
\r
19 // std::map<HWND, std::map<WORD, CallbackFn>> handlers;
\r
20 // std::map<HWND, lay_id> lIds;
\r
22 // NOTIFYICONDATA niData = { 0 };
\r
24 // ShowNotificationIcon()
\r
26 // Shell_NotifyIconA(NIM_ADD, &_::niData);
\r
27 // Shell_NotifyIconA(NIM_SETVERSION, &_::niData);
\r
31 // HideNotificationIcon()
\r
33 // Shell_NotifyIconA(NIM_DELETE, &_::niData);
\r
40 // WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
\r
44 // DestroyWindow(hwnd);
\r
47 // Shell_NotifyIconA(NIM_DELETE, &niData);
\r
48 // lay_destroy_context(&ctx);
\r
49 // PostQuitMessage(0);
\r
52 // if (wParam == SIZE_MINIMIZED) {
\r
53 // ShowNotificationIcon();
\r
54 // ShowWindow(hwnd, false);
\r
57 // lay_set_size_xy(&_::ctx, _::root, LOWORD(lParam), HIWORD(lParam));
\r
58 // lay_run_context(&_::ctx);
\r
60 // for (auto &lId : lIds) {
\r
61 // lay_vec4 rect = lay_get_rect(&_::ctx, lId.second);
\r
62 // SetWindowPos(lId.first, HWND_TOP,
\r
70 // RedrawWindow(hwnd, 0, 0, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);
\r
74 // if (handlers.find((HWND)lParam) != handlers.end()) {
\r
75 // auto handler = handlers[(HWND)lParam];
\r
76 // if (handler.find(HIWORD(wParam)) != handler.end()) {
\r
77 // auto cb = handler[HIWORD(wParam)];
\r
85 // if (LOWORD(lParam) == NIN_SELECT) {
\r
86 // HideNotificationIcon();
\r
87 // ShowWindow(hwnd, true);
\r
88 // SetForegroundWindow(hwnd);
\r
89 // SetActiveWindow(hwnd);
\r
92 // case WM_CTLCOLORSTATIC:
\r
93 // return (LONG)GetStockObject(WHITE_BRUSH);
\r
94 // case WM_GETMINMAXINFO: {
\r
95 // MINMAXINFO *mmInfo = (MINMAXINFO*)lParam;
\r
96 // mmInfo->ptMinTrackSize.x = 400;
\r
97 // mmInfo->ptMinTrackSize.y = 200;
\r
101 // return DefWindowProc(hwnd, msg, wParam, lParam);
\r
109 // Callback(HWND hwnd, WORD ev, std::function<void()> cb)
\r
111 // _::handlers[hwnd][ev] = cb;
\r
115 // Window(string title, string className, HINSTANCE hInstance)
\r
118 // wc.cbSize = sizeof(WNDCLASSEX);
\r
120 // wc.lpfnWndProc = _::WndProc;
\r
121 // wc.cbClsExtra = 0;
\r
122 // wc.cbWndExtra = 0;
\r
123 // wc.hInstance = hInstance;
\r
124 // wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
\r
125 // wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
\r
126 // wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
\r
127 // wc.lpszMenuName = nullptr;
\r
128 // wc.lpszClassName = className.c_str();
\r
129 // wc.hIconSm = LoadIcon(nullptr, IDI_APPLICATION);
\r
130 // RegisterClassEx(&wc);
\r
132 // lay_init_context(&_::ctx);
\r
133 // _::root = lay_item(&_::ctx);
\r
134 // lay_set_contain(&_::ctx, _::root, LAY_COLUMN);
\r
136 // HWND result = CreateWindowA(className.c_str(),
\r
138 // WS_OVERLAPPEDWINDOW,
\r
148 // _::niData.cbSize = sizeof(_::niData);
\r
149 // _::niData.uID = 12345;
\r
150 // _::niData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
\r
151 // _::niData.hIcon = LoadIconA(hInstance, MAKEINTRESOURCEA(IDI_MY_ICON));
\r
152 // _::niData.hWnd = result;
\r
153 // _::niData.uCallbackMessage = WM_APP+1;
\r
154 // _::niData.uVersion = NOTIFYICON_VERSION_4;
\r
160 // UpdateWindow(HWND hwnd)
\r
163 // if (GetMessage(&msg, nullptr, 0, 0) > 0) {
\r
164 // TranslateMessage(&msg);
\r
165 // DispatchMessage(&msg);
\r
172 // ShowWindow(HWND hwnd)
\r
174 // ShowWindow(hwnd, true);
\r
176 // EnumChildWindows(
\r
178 // [](HWND hwnd, LPARAM lParam) -> BOOL {
\r
179 // HFONT guiFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
\r
180 // SendMessage(hwnd, WM_SETFONT, (WPARAM)guiFont, MAKELPARAM(TRUE, 0));
\r
187 // Button(HWND hwnd, string title, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)
\r
189 // lay_id lId = lay_item(&_::ctx);
\r
190 // lay_insert(&_::ctx, parent, lId);
\r
191 // lay_set_size_xy(&_::ctx, lId, w, h);
\r
192 // lay_set_contain(&_::ctx, lId, contain);
\r
193 // lay_set_behave(&_::ctx, lId, behave);
\r
195 // HWND result = CreateWindowExA(0,
\r
198 // WS_VISIBLE | WS_CHILD,
\r
204 // _::lIds[result] = lId;
\r
209 // ListBox(HWND hwnd, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)
\r
211 // lay_id lId = lay_item(&_::ctx);
\r
212 // lay_insert(&_::ctx, parent, lId);
\r
213 // lay_set_size_xy(&_::ctx, lId, w, h);
\r
214 // lay_set_contain(&_::ctx, lId, contain);
\r
215 // lay_set_behave(&_::ctx, lId, behave);
\r
217 // HWND result = CreateWindowExA(0,
\r
220 // WS_VISIBLE | WS_CHILD | WS_BORDER | WS_VSCROLL,
\r
226 // _::lIds[result] = lId;
\r
231 // ListAddString(HWND hwnd, string str)
\r
233 // SendMessage(hwnd, LB_ADDSTRING, 0, (LPARAM)str.c_str());
\r
237 // ListGetSelectedIndex(HWND hwnd)
\r
239 // int sel = SendMessage(hwnd, LB_GETCURSEL, 0, 0);
\r
243 // int ListFindString(HWND hwnd, string str)
\r
245 // return SendMessageA(hwnd, LB_FINDSTRINGEXACT, -1, (LPARAM)str.c_str());
\r
249 // ListGetText(HWND hwnd, int index)
\r
251 // char buffer[1024];
\r
252 // SendMessage(hwnd, LB_GETTEXT, index, (LPARAM)buffer);
\r
253 // return string(buffer);
\r
257 // ListClear(HWND hwnd)
\r
259 // SendMessageA(hwnd, LB_RESETCONTENT, 0, 0);
\r
262 // void ListRemove(HWND hwnd, int index)
\r
264 // SendMessageA(hwnd, LB_DELETESTRING, index, 0);
\r
268 // ListView(HWND hwnd, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)
\r
270 // lay_id lId = lay_item(&_::ctx);
\r
271 // lay_insert(&_::ctx, parent, lId);
\r
272 // lay_set_size_xy(&_::ctx, lId, w, h);
\r
273 // lay_set_contain(&_::ctx, lId, contain);
\r
274 // lay_set_behave(&_::ctx, lId, behave);
\r
276 // HWND result = CreateWindowExA(0,
\r
279 // WS_VISIBLE | WS_CHILD | WS_BORDER | WS_VSCROLL,
\r
285 // _::lIds[result] = lId;
\r
290 // CheckBox(HWND hwnd, string title, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)
\r
292 // lay_id lId = lay_item(&_::ctx);
\r
293 // lay_insert(&_::ctx, parent, lId);
\r
294 // lay_set_size_xy(&_::ctx, lId, w, h);
\r
295 // lay_set_contain(&_::ctx, lId, contain);
\r
296 // lay_set_behave(&_::ctx, lId, behave);
\r
298 // HWND result = CreateWindowExA(0,
\r
301 // WS_VISIBLE | WS_CHILD | BS_CHECKBOX,
\r
307 // _::lIds[result] = lId;
\r
311 // void SetStyle(HWND hwnd, DWORD style)
\r
313 // SetWindowLongPtrA(hwnd, GWL_STYLE, style);
\r
315 // DWORD GetStyle(HWND hwnd)
\r
317 // return GetWindowLongPtrA(hwnd, GWL_STYLE);
\r
319 // void AddStyle(HWND hwnd, DWORD style)
\r
321 // SetWindowLongPtrA(hwnd, GWL_STYLE, GetStyle(hwnd) | style);
\r
323 // void RemoveStyle(HWND hwnd, DWORD style)
\r
325 // SetWindowLongPtrA(hwnd, GWL_STYLE, GetStyle(hwnd) & (~style));
\r
342 Hwnd(Window *window, Hwnd *parent, LPCSTR className, LPCSTR windowName, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave);
\r
344 void setStyle(DWORD style)
\r
346 SetWindowLongPtrA(hwnd, GWL_STYLE, style);
\r
350 return GetWindowLongPtrA(hwnd, GWL_STYLE);
\r
352 void addStyle(DWORD style)
\r
354 SetWindowLongPtrA(hwnd, GWL_STYLE, getStyle() | style);
\r
356 void removeStyle(DWORD style)
\r
358 SetWindowLongPtrA(hwnd, GWL_STYLE, getStyle() & (~style));
\r
361 struct Window : Hwnd
\r
364 NOTIFYICONDATAA niData = { 0 };
\r
366 static LRESULT CALLBACK
\r
367 WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
\r
369 Window *window = (Window*)GetWindowLongPtrA(hwnd, 0);
\r
370 if (window == nullptr)
\r
371 return DefWindowProc(hwnd, msg, wParam, lParam);
\r
373 bool defaultHandler = false;
\r
377 DestroyWindow(hwnd);
\r
380 Shell_NotifyIconA(NIM_DELETE, &window->niData);
\r
381 lay_destroy_context(&window->ctx);
\r
382 PostQuitMessage(0);
\r
385 if (wParam == SIZE_MINIMIZED) {
\r
387 //ShowNotificationIcon();
\r
388 ShowWindow(hwnd, false);
\r
391 lay_set_size_xy(&window->ctx, window->lId, LOWORD(lParam), HIWORD(lParam));
\r
392 lay_run_context(&window->ctx);
\r
394 //RedrawWindow(hwnd, 0, 0, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);
\r
400 if (LOWORD(lParam) == NIN_SELECT) {
\r
402 //HideNotificationIcon();
\r
403 ShowWindow(hwnd, true);
\r
404 SetForegroundWindow(hwnd);
\r
405 SetActiveWindow(hwnd);
\r
408 case WM_CTLCOLORSTATIC:
\r
409 return (LONG)GetStockObject(WHITE_BRUSH);
\r
410 case WM_GETMINMAXINFO: {
\r
411 MINMAXINFO *mmInfo = (MINMAXINFO*)lParam;
\r
412 mmInfo->ptMinTrackSize.x = 400;
\r
413 mmInfo->ptMinTrackSize.y = 200;
\r
417 defaultHandler = true;
\r
421 for (auto handler : window->handlers[msg])
\r
422 handler(hwnd, msg, wParam, lParam);
\r
424 if (defaultHandler)
\r
425 return DefWindowProc(hwnd, msg, wParam, lParam);
\r
431 std::unordered_map<UINT,
\r
433 std::function<void(HWND, UINT, WPARAM, LPARAM)>>> handlers;
\r
435 Window(std::string title, std::string className, HINSTANCE hInstance)
\r
438 wc.cbSize = sizeof(WNDCLASSEX);
\r
440 wc.lpfnWndProc = WndProc;
\r
442 wc.cbWndExtra = sizeof(Window*);
\r
443 wc.hInstance = hInstance;
\r
444 wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
\r
445 wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
\r
446 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
\r
447 wc.lpszMenuName = nullptr;
\r
448 wc.lpszClassName = className.c_str();
\r
449 wc.hIconSm = LoadIcon(nullptr, IDI_APPLICATION);
\r
450 RegisterClassExA(&wc);
\r
452 lay_init_context(&ctx);
\r
453 lId = lay_item(&ctx);
\r
454 lay_set_contain(&ctx, lId, LAY_COLUMN);
\r
456 hwnd = CreateWindowA(className.c_str(),
\r
458 WS_OVERLAPPEDWINDOW,
\r
468 SetWindowLongPtrA(hwnd, 0, (LONG_PTR)this);
\r
471 niData.cbSize = sizeof(niData);
\r
472 niData.uID = 12345;
\r
473 niData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
\r
474 niData.hIcon = LoadIconA(hInstance, MAKEINTRESOURCEA(IDI_MY_ICON));
\r
475 niData.hWnd = hwnd;
\r
476 niData.uCallbackMessage = WM_APP+1;
\r
477 niData.uVersion = NOTIFYICON_VERSION_4;
\r
482 if (GetMessage(&msg, nullptr, 0, 0) > 0) {
\r
483 TranslateMessage(&msg);
\r
484 DispatchMessage(&msg);
\r
491 ShowWindow(hwnd, true);
\r
495 [](HWND hwnd, LPARAM lParam) -> BOOL {
\r
496 HFONT guiFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
\r
497 SendMessage(hwnd, WM_SETFONT, (WPARAM)guiFont, MAKELPARAM(TRUE, 0));
\r
504 struct Button : Hwnd
\r
506 Button(Window *window, Hwnd *parent, std::string title, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)
\r
507 : Hwnd(window, parent, WC_BUTTONA, title.c_str(), w, h, contain, behave)
\r
509 window->handlers[WM_COMMAND].push_back([&](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
\r
510 if ((HWND)lParam == this->hwnd && HIWORD(wParam) == BN_CLICKED)
\r
511 for (auto handler : this->onClickHandlers)
\r
516 void onClick(std::function<void()> cb)
\r
518 onClickHandlers.push_back(cb);
\r
521 std::vector<std::function<void()>> onClickHandlers;
\r
524 struct CheckBox : Hwnd
\r
526 CheckBox(Window *window, Hwnd *parent, std::string title, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)
\r
527 : Hwnd(window, parent, WC_BUTTONA, title.c_str(), w, h, contain, behave)
\r
529 addStyle(BS_CHECKBOX);
\r
530 window->handlers[WM_COMMAND].push_back([&](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
\r
531 if ((HWND)lParam == this->hwnd && HIWORD(wParam) == BN_CLICKED)
\r
532 SendMessageA(this->hwnd, BM_SETCHECK, SendMessageA(this->hwnd, BM_GETCHECK, 0, 0) ? BST_UNCHECKED : BST_CHECKED, 0);
\r
537 struct ListBox : Hwnd
\r
539 ListBox(Window *window, Hwnd *parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)
\r
540 : Hwnd(window, parent, WC_LISTBOXA, "", w, h, contain, behave)
\r
542 addStyle(WS_BORDER);
\r
543 addStyle(WS_VSCROLL);
\r
546 void addString(std::string str)
\r
548 SendMessage(hwnd, LB_ADDSTRING, 0, (LPARAM)str.c_str());
\r
551 int getSelectedIndex()
\r
553 return SendMessage(hwnd, LB_GETCURSEL, 0, 0);
\r
556 int findString(std::string str)
\r
558 return SendMessageA(hwnd, LB_FINDSTRINGEXACT, -1, (LPARAM)str.c_str());
\r
561 std::string getText(int index)
\r
563 int len = SendMessageA(hwnd, LB_GETTEXTLEN, index, 0);
\r
564 std::string result;
\r
565 result.reserve(len);
\r
566 SendMessage(hwnd, LB_GETTEXT, index, (LPARAM)result.data());
\r
572 SendMessageA(hwnd, LB_RESETCONTENT, 0, 0);
\r
575 void remove(int index)
\r
577 SendMessageA(hwnd, LB_DELETESTRING, index, 0);
\r
582 win::Hwnd::Hwnd(Window *window, Hwnd *parent, LPCSTR className, LPCSTR windowName, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)
\r
584 this->window = window;
\r
586 lId = lay_item(&window->ctx);
\r
587 lay_insert(&window->ctx, parent->lId, lId);
\r
588 lay_set_size_xy(&window->ctx, lId, w, h);
\r
589 lay_set_contain(&window->ctx, lId, contain);
\r
590 lay_set_behave(&window->ctx, lId, behave);
\r
592 hwnd = CreateWindowExA(0,
\r
595 WS_VISIBLE | WS_CHILD,
\r
605 window->handlers[WM_SIZE].push_back([this](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
\r
606 lay_vec4 rect = lay_get_rect(&this->window->ctx, this->lId);
\r
607 SetWindowPos(this->hwnd, HWND_TOP,
\r