]> gitweb.ps.run Git - autorec/blob - src/win.h
Refactor into classes
[autorec] / src / win.h
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
4 \r
5 #include <windows.h>\r
6 #include <CommCtrl.h>\r
7 \r
8 #include "../res/resource.h"\r
9 \r
10 #include "layout.h"\r
11 \r
12 #include <functional>\r
13 #include <unordered_map>\r
14 #include <string>\r
15 \r
16 // namespace wnin {\r
17 // namespace _ {\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
21 \r
22 // NOTIFYICONDATA niData = { 0 };\r
23 // void\r
24 // ShowNotificationIcon()\r
25 // {\r
26 //   Shell_NotifyIconA(NIM_ADD, &_::niData);\r
27 //   Shell_NotifyIconA(NIM_SETVERSION, &_::niData);\r
28 // }\r
29 \r
30 // void\r
31 // HideNotificationIcon()\r
32 // {\r
33 //   Shell_NotifyIconA(NIM_DELETE, &_::niData);\r
34 // }\r
35 \r
36 // lay_context ctx;\r
37 // lay_id root;\r
38 \r
39 // LRESULT CALLBACK\r
40 // WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
41 // {\r
42 //   switch (msg) {\r
43 //     case WM_CLOSE:\r
44 //       DestroyWindow(hwnd);\r
45 //       break;\r
46 //     case WM_DESTROY:\r
47 //       Shell_NotifyIconA(NIM_DELETE, &niData);\r
48 //       lay_destroy_context(&ctx);\r
49 //       PostQuitMessage(0);\r
50 //       break;\r
51 //     case WM_SIZE:\r
52 //       if (wParam == SIZE_MINIMIZED) {\r
53 //         ShowNotificationIcon();\r
54 //         ShowWindow(hwnd, false);\r
55 //       }\r
56 //       else {\r
57 //         lay_set_size_xy(&_::ctx, _::root, LOWORD(lParam), HIWORD(lParam));\r
58 //         lay_run_context(&_::ctx);\r
59 \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
63 //             rect[0],\r
64 //             rect[1],\r
65 //             rect[2],\r
66 //             rect[3],\r
67 //             SWP_NOZORDER\r
68 //           );\r
69 //         }\r
70 //         RedrawWindow(hwnd, 0, 0, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);\r
71 //       }\r
72 //       break;\r
73 //     case WM_COMMAND:\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
78 //           cb();\r
79 //         }\r
80 //       }\r
81 //       break;\r
82 //     case WM_NOTIFY:\r
83 //       break;\r
84 //     case WM_APP + 1:\r
85 //       if (LOWORD(lParam) == NIN_SELECT) {\r
86 //         HideNotificationIcon();\r
87 //         ShowWindow(hwnd, true);\r
88 //         SetForegroundWindow(hwnd);\r
89 //         SetActiveWindow(hwnd);\r
90 //       }\r
91 //       break;\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
98 //       break;\r
99 //     }\r
100 //     default:\r
101 //       return DefWindowProc(hwnd, msg, wParam, lParam);\r
102 //   }\r
103 //   return 0;\r
104 // }\r
105 // }\r
106 \r
107 \r
108 // void\r
109 // Callback(HWND hwnd, WORD ev, std::function<void()> cb)\r
110 // {\r
111 //   _::handlers[hwnd][ev] = cb;\r
112 // }\r
113 \r
114 // HWND\r
115 // Window(string title, string className, HINSTANCE hInstance)\r
116 // {\r
117 //   WNDCLASSEX wc;\r
118 //   wc.cbSize = sizeof(WNDCLASSEX);\r
119 //   wc.style = 0;\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
131 \r
132 //   lay_init_context(&_::ctx);\r
133 //   _::root = lay_item(&_::ctx);\r
134 //   lay_set_contain(&_::ctx, _::root, LAY_COLUMN);\r
135 \r
136 //   HWND result = CreateWindowA(className.c_str(),\r
137 //                        title.c_str(),\r
138 //                        WS_OVERLAPPEDWINDOW,\r
139 //                        CW_USEDEFAULT,\r
140 //                        CW_USEDEFAULT,\r
141 //                        CW_USEDEFAULT,\r
142 //                        CW_USEDEFAULT,\r
143 //                        nullptr,\r
144 //                        nullptr,\r
145 //                        hInstance,\r
146 //                        nullptr);\r
147                        \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
155 \r
156 //   return result;\r
157 // }\r
158 \r
159 // bool\r
160 // UpdateWindow(HWND hwnd)\r
161 // {\r
162 //   MSG msg;\r
163 //   if (GetMessage(&msg, nullptr, 0, 0) > 0) {\r
164 //     TranslateMessage(&msg);\r
165 //     DispatchMessage(&msg);\r
166 //     return true;\r
167 //   }\r
168 //   return false;\r
169 // }\r
170 \r
171 // void\r
172 // ShowWindow(HWND hwnd)\r
173 // {\r
174 //   ShowWindow(hwnd, true);\r
175 \r
176 //   EnumChildWindows(\r
177 //     hwnd,\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
181 //       return TRUE;\r
182 //     },\r
183 //     0);\r
184 // }\r
185 \r
186 // HWND\r
187 // Button(HWND hwnd, string title, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)\r
188 // {\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
194 \r
195 //   HWND result = CreateWindowExA(0,\r
196 //                                 WC_BUTTONA,\r
197 //                                 title.c_str(),\r
198 //                                 WS_VISIBLE | WS_CHILD,\r
199 //                                 0, 0, 0, 0,\r
200 //                                 hwnd,\r
201 //                                 nullptr,\r
202 //                                 nullptr,\r
203 //                                 nullptr);\r
204 //   _::lIds[result] = lId;\r
205 //   return result;\r
206 // }\r
207 \r
208 // HWND\r
209 // ListBox(HWND hwnd, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)\r
210 // {\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
216 \r
217 //   HWND result = CreateWindowExA(0,\r
218 //                          WC_LISTBOXA,\r
219 //                          "",\r
220 //                          WS_VISIBLE | WS_CHILD | WS_BORDER | WS_VSCROLL,\r
221 //                          0, 0, 0, 0,\r
222 //                          hwnd,\r
223 //                          nullptr,\r
224 //                          nullptr,\r
225 //                          nullptr);\r
226 //   _::lIds[result] = lId;\r
227 //   return result;\r
228 // }\r
229 \r
230 // void\r
231 // ListAddString(HWND hwnd, string str)\r
232 // {\r
233 //   SendMessage(hwnd, LB_ADDSTRING, 0, (LPARAM)str.c_str());\r
234 // }\r
235 \r
236 // int\r
237 // ListGetSelectedIndex(HWND hwnd)\r
238 // {\r
239 //   int sel = SendMessage(hwnd, LB_GETCURSEL, 0, 0);\r
240 //   return sel;\r
241 // }\r
242 \r
243 // int ListFindString(HWND hwnd, string str)\r
244 // {\r
245 //   return SendMessageA(hwnd, LB_FINDSTRINGEXACT, -1, (LPARAM)str.c_str());\r
246 // }\r
247 \r
248 // string\r
249 // ListGetText(HWND hwnd, int index)\r
250 // {\r
251 //   char buffer[1024];\r
252 //   SendMessage(hwnd, LB_GETTEXT, index, (LPARAM)buffer);\r
253 //   return string(buffer);\r
254 // }\r
255 \r
256 // void\r
257 // ListClear(HWND hwnd)\r
258 // {\r
259 //   SendMessageA(hwnd, LB_RESETCONTENT, 0, 0);\r
260 // }\r
261 \r
262 // void ListRemove(HWND hwnd, int index)\r
263 // {\r
264 //   SendMessageA(hwnd, LB_DELETESTRING, index, 0);\r
265 // }\r
266 \r
267 // HWND\r
268 // ListView(HWND hwnd, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)\r
269 // {\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
275 \r
276 //   HWND result = CreateWindowExA(0,\r
277 //                          WC_LISTVIEWA,\r
278 //                          "",\r
279 //                          WS_VISIBLE | WS_CHILD | WS_BORDER | WS_VSCROLL,\r
280 //                          0, 0, 0, 0,\r
281 //                          hwnd,\r
282 //                          nullptr,\r
283 //                          nullptr,\r
284 //                          nullptr);\r
285 //   _::lIds[result] = lId;\r
286 //   return result;\r
287 // }\r
288 \r
289 // HWND\r
290 // CheckBox(HWND hwnd, string title, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)\r
291 // {\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
297 \r
298 //   HWND result = CreateWindowExA(0,\r
299 //                          WC_BUTTONA,\r
300 //                          title.c_str(),\r
301 //                          WS_VISIBLE | WS_CHILD | BS_CHECKBOX,\r
302 //                          0, 0, 0, 0,\r
303 //                          hwnd,\r
304 //                          nullptr,\r
305 //                          nullptr,\r
306 //                          nullptr);\r
307 //   _::lIds[result] = lId;\r
308 //   return result;\r
309 // }\r
310 \r
311 // void SetStyle(HWND hwnd, DWORD style)\r
312 // {\r
313 //   SetWindowLongPtrA(hwnd, GWL_STYLE, style);\r
314 // }\r
315 // DWORD GetStyle(HWND hwnd)\r
316 // {\r
317 //   return GetWindowLongPtrA(hwnd, GWL_STYLE);\r
318 // }\r
319 // void AddStyle(HWND hwnd, DWORD style)\r
320 // {\r
321 //   SetWindowLongPtrA(hwnd, GWL_STYLE, GetStyle(hwnd) | style);\r
322 // }\r
323 // void RemoveStyle(HWND hwnd, DWORD style)\r
324 // {\r
325 //   SetWindowLongPtrA(hwnd, GWL_STYLE, GetStyle(hwnd) & (~style));\r
326 // }\r
327 // }\r
328 \r
329 \r
330 \r
331 \r
332 namespace win\r
333 {\r
334   struct Window;\r
335   struct Hwnd\r
336   {\r
337     HWND hwnd;\r
338     lay_id lId;\r
339     Window *window;\r
340 \r
341     Hwnd() {}\r
342     Hwnd(Window *window, Hwnd *parent, LPCSTR className, LPCSTR windowName, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave);\r
343 \r
344     void setStyle(DWORD style)\r
345     {\r
346       SetWindowLongPtrA(hwnd, GWL_STYLE, style);\r
347     }\r
348     DWORD getStyle()\r
349     {\r
350       return GetWindowLongPtrA(hwnd, GWL_STYLE);\r
351     }\r
352     void addStyle(DWORD style)\r
353     {\r
354       SetWindowLongPtrA(hwnd, GWL_STYLE, getStyle() | style);\r
355     }\r
356     void removeStyle(DWORD style)\r
357     {\r
358       SetWindowLongPtrA(hwnd, GWL_STYLE, getStyle() & (~style));\r
359     }\r
360   };\r
361   struct Window : Hwnd\r
362   {\r
363   private:\r
364     NOTIFYICONDATAA niData = { 0 };\r
365 \r
366     static LRESULT CALLBACK\r
367     WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
368     {\r
369       Window *window = (Window*)GetWindowLongPtrA(hwnd, 0);\r
370       if (window == nullptr)\r
371         return DefWindowProc(hwnd, msg, wParam, lParam);\r
372 \r
373       bool defaultHandler = false;\r
374 \r
375       switch (msg) {\r
376         case WM_CLOSE:\r
377           DestroyWindow(hwnd);\r
378           break;\r
379         case WM_DESTROY:\r
380           Shell_NotifyIconA(NIM_DELETE, &window->niData);\r
381           lay_destroy_context(&window->ctx);\r
382           PostQuitMessage(0);\r
383           break;\r
384         case WM_SIZE:\r
385           if (wParam == SIZE_MINIMIZED) {\r
386             //TODO: auslagen\r
387             //ShowNotificationIcon();\r
388             ShowWindow(hwnd, false);\r
389           }\r
390           else {\r
391             lay_set_size_xy(&window->ctx, window->lId, LOWORD(lParam), HIWORD(lParam));\r
392             lay_run_context(&window->ctx);\r
393 \r
394             //RedrawWindow(hwnd, 0, 0, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);\r
395           }\r
396           break;\r
397         case WM_NOTIFY:\r
398           break;\r
399         case WM_APP + 1:\r
400           if (LOWORD(lParam) == NIN_SELECT) {\r
401             //TODO: auslagern\r
402             //HideNotificationIcon();\r
403             ShowWindow(hwnd, true);\r
404             SetForegroundWindow(hwnd);\r
405             SetActiveWindow(hwnd);\r
406           }\r
407           break;\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
414           break;\r
415         }\r
416         default:\r
417           defaultHandler = true;\r
418           break;\r
419       }\r
420       \r
421       for (auto handler : window->handlers[msg])\r
422         handler(hwnd, msg, wParam, lParam);\r
423 \r
424       if (defaultHandler)\r
425         return DefWindowProc(hwnd, msg, wParam, lParam);\r
426       else\r
427         return 0;\r
428     }\r
429   public:\r
430     lay_context ctx;\r
431     std::unordered_map<UINT,\r
432       std::vector<\r
433         std::function<void(HWND, UINT, WPARAM, LPARAM)>>> handlers;\r
434 \r
435     Window(std::string title, std::string className, HINSTANCE hInstance)\r
436     {\r
437       WNDCLASSEXA wc;\r
438       wc.cbSize = sizeof(WNDCLASSEX);\r
439       wc.style = 0;\r
440       wc.lpfnWndProc = WndProc;\r
441       wc.cbClsExtra = 0;\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
451 \r
452       lay_init_context(&ctx);\r
453       lId = lay_item(&ctx);\r
454       lay_set_contain(&ctx, lId, LAY_COLUMN);\r
455 \r
456       hwnd = CreateWindowA(className.c_str(),\r
457                           title.c_str(),\r
458                           WS_OVERLAPPEDWINDOW,\r
459                           CW_USEDEFAULT,\r
460                           CW_USEDEFAULT,\r
461                           CW_USEDEFAULT,\r
462                           CW_USEDEFAULT,\r
463                           nullptr,\r
464                           nullptr,\r
465                           hInstance,\r
466                           nullptr);\r
467 \r
468       SetWindowLongPtrA(hwnd, 0, (LONG_PTR)this);\r
469       \r
470                           \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
478     }\r
479     bool update()\r
480     {\r
481       MSG msg;\r
482       if (GetMessage(&msg, nullptr, 0, 0) > 0) {\r
483         TranslateMessage(&msg);\r
484         DispatchMessage(&msg);\r
485         return true;\r
486       }\r
487       return false;\r
488     }\r
489     void show()\r
490     {\r
491       ShowWindow(hwnd, true);\r
492 \r
493       EnumChildWindows(\r
494         hwnd,\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
498           return TRUE;\r
499         },\r
500         0);\r
501     }\r
502   };\r
503 \r
504   struct Button : Hwnd\r
505   {\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
508     {\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
512             handler();\r
513       });\r
514     }\r
515 \r
516     void onClick(std::function<void()> cb)\r
517     {\r
518       onClickHandlers.push_back(cb);\r
519     }\r
520   private:\r
521     std::vector<std::function<void()>> onClickHandlers;\r
522   };\r
523   \r
524   struct CheckBox : Hwnd\r
525   {\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
528     {\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
533       });\r
534     }\r
535   };\r
536 \r
537   struct ListBox : Hwnd\r
538   {\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
541     {\r
542       addStyle(WS_BORDER);\r
543       addStyle(WS_VSCROLL);\r
544     }\r
545 \r
546     void addString(std::string str)\r
547     {\r
548       SendMessage(hwnd, LB_ADDSTRING, 0, (LPARAM)str.c_str());\r
549     }\r
550 \r
551     int getSelectedIndex()\r
552     {\r
553       return SendMessage(hwnd, LB_GETCURSEL, 0, 0);\r
554     }\r
555 \r
556     int findString(std::string str)\r
557     {\r
558       return SendMessageA(hwnd, LB_FINDSTRINGEXACT, -1, (LPARAM)str.c_str());\r
559     }\r
560 \r
561     std::string getText(int index)\r
562     {\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
567       return result;\r
568     }\r
569 \r
570     void clear()\r
571     {\r
572       SendMessageA(hwnd, LB_RESETCONTENT, 0, 0);\r
573     }\r
574 \r
575     void remove(int index)\r
576     {\r
577       SendMessageA(hwnd, LB_DELETESTRING, index, 0);\r
578     }\r
579   };\r
580 }\r
581 \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
583 {\r
584   this->window = window;\r
585   \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
591   \r
592   hwnd = CreateWindowExA(0,\r
593                           className,\r
594                           windowName,\r
595                           WS_VISIBLE | WS_CHILD,\r
596                           0,\r
597                           0,\r
598                           0,\r
599                           0,\r
600                           window->hwnd,\r
601                           nullptr,\r
602                           nullptr,\r
603                           nullptr);\r
604 \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
608       rect[0],\r
609       rect[1],\r
610       rect[2],\r
611       rect[3],\r
612       SWP_NOZORDER\r
613     );\r
614   });\r
615 }