]> gitweb.ps.run Git - autorec/blob - src/win.h
Merge branch 'main' of ps.run:autorec
[autorec] / src / win.h
1 #include <windows.h>\r
2 #include <CommCtrl.h>\r
3 \r
4 #include "../res/resource.h"\r
5 \r
6 #include "layout.h"\r
7 \r
8 #include <functional>\r
9 #include <unordered_map>\r
10 #include <string>\r
11 \r
12 \r
13 namespace win\r
14 {\r
15   struct Window;\r
16   struct Hwnd\r
17   {\r
18     HWND hwnd;\r
19     lay_id lId;\r
20     Window *window;\r
21 \r
22     Hwnd() {}\r
23     Hwnd(Window *window, LPCSTR className, LPCSTR windowName, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave);\r
24 \r
25     void setStyle(DWORD style)\r
26     {\r
27       SetWindowLongPtrA(hwnd, GWL_STYLE, style);\r
28     }\r
29     DWORD getStyle()\r
30     {\r
31       return GetWindowLongPtrA(hwnd, GWL_STYLE);\r
32     }\r
33     void addStyle(DWORD style)\r
34     {\r
35       SetWindowLongPtrA(hwnd, GWL_STYLE, getStyle() | style);\r
36     }\r
37     void removeStyle(DWORD style)\r
38     {\r
39       SetWindowLongPtrA(hwnd, GWL_STYLE, getStyle() & (~style));\r
40     }\r
41     void setActive(bool active)\r
42     {\r
43       EnableWindow(hwnd, active);\r
44     }\r
45   };\r
46   struct Window : Hwnd\r
47   {\r
48   private:\r
49 \r
50     static LRESULT CALLBACK\r
51     WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
52     {\r
53       Window *window = (Window*)GetWindowLongPtrA(hwnd, 0);\r
54       if (window == nullptr)\r
55         return DefWindowProc(hwnd, msg, wParam, lParam);\r
56 \r
57       bool defaultHandler = false;\r
58 \r
59       switch (msg) {\r
60         case WM_CLOSE:\r
61           DestroyWindow(hwnd);\r
62           break;\r
63         case WM_DESTROY:\r
64           lay_destroy_context(&window->ctx);\r
65           PostQuitMessage(0);\r
66           break;\r
67         case WM_SIZE:\r
68           if (wParam != SIZE_MINIMIZED) {\r
69             lay_set_size_xy(&window->ctx, window->lId, LOWORD(lParam), HIWORD(lParam));\r
70             lay_run_context(&window->ctx);\r
71 \r
72             //RedrawWindow(hwnd, 0, 0, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);\r
73           }\r
74           break;\r
75         case WM_NOTIFY:\r
76           break;\r
77         case WM_CTLCOLORSTATIC:\r
78           return (LONG_PTR)GetStockObject(WHITE_BRUSH);\r
79         default:\r
80           defaultHandler = true;\r
81           break;\r
82       }\r
83       \r
84       for (auto handler : window->handlers[msg])\r
85         handler(hwnd, msg, wParam, lParam);\r
86 \r
87       if (defaultHandler)\r
88         return DefWindowProc(hwnd, msg, wParam, lParam);\r
89       else\r
90         return 0;\r
91     }\r
92   public:\r
93     lay_context ctx;\r
94     std::unordered_map<UINT,\r
95       std::vector<\r
96         std::function<void(HWND, UINT, WPARAM, LPARAM)>>> handlers;\r
97 \r
98     struct Timer {\r
99       bool active = true;\r
100       std::function<void()> f;\r
101     };\r
102     std::vector<Timer> timers;\r
103 \r
104     Window(std::string title, std::string className, HINSTANCE hInstance)\r
105     {\r
106       WNDCLASSEXA wc;\r
107       wc.cbSize = sizeof(WNDCLASSEX);\r
108       wc.style = 0;\r
109       wc.lpfnWndProc = WndProc;\r
110       wc.cbClsExtra = 0;\r
111       wc.cbWndExtra = sizeof(Window*);\r
112       wc.hInstance = hInstance;\r
113       wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON_WHITE));\r
114       wc.hCursor = LoadCursor(hInstance, IDC_ARROW);\r
115       wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);\r
116       wc.lpszMenuName = nullptr;\r
117       wc.lpszClassName = className.c_str();\r
118       wc.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON_WHITE));\r
119       RegisterClassExA(&wc);\r
120 \r
121       lay_init_context(&ctx);\r
122       lId = lay_item(&ctx);\r
123       lay_set_contain(&ctx, lId, LAY_COLUMN);\r
124 \r
125       hwnd = CreateWindowA(className.c_str(),\r
126                           title.c_str(),\r
127                           WS_OVERLAPPEDWINDOW,\r
128                           CW_USEDEFAULT,\r
129                           CW_USEDEFAULT,\r
130                           CW_USEDEFAULT,\r
131                           CW_USEDEFAULT,\r
132                           nullptr,\r
133                           nullptr,\r
134                           hInstance,\r
135                           nullptr);\r
136 \r
137       SetWindowLongPtrA(hwnd, 0, (LONG_PTR)this);\r
138     }\r
139     bool update()\r
140     {\r
141       MSG msg;\r
142       if (GetMessage(&msg, nullptr, 0, 0) > 0) {\r
143         TranslateMessage(&msg);\r
144         DispatchMessage(&msg);\r
145         return true;\r
146       }\r
147       return false;\r
148     }\r
149     void show()\r
150     {\r
151       ShowWindow(hwnd, true);\r
152     }\r
153     void setDefaultFont()\r
154     {\r
155       EnumChildWindows(\r
156         hwnd,\r
157         [](HWND hwnd, LPARAM lParam) -> BOOL {\r
158           HFONT guiFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);\r
159           SendMessage(hwnd, WM_SETFONT, (WPARAM)guiFont, MAKELPARAM(TRUE, 0));\r
160           return TRUE;\r
161         },\r
162         0);\r
163     }\r
164     void setTimer(UINT interval, std::function<void()> cb)\r
165     {\r
166       SetTimer(this->hwnd, timers.size() + 1000, interval, [](HWND hwnd, UINT uMsg, UINT_PTR uIdEvent, DWORD dwTime) {\r
167         Window *window = (Window*)GetWindowLongPtrA(hwnd, 0);\r
168         if (window == nullptr)\r
169           return;\r
170 \r
171         window->timers[uIdEvent-1000].f();\r
172       });\r
173       Timer t;\r
174       t.f = cb;\r
175       timers.push_back(t);\r
176     }\r
177   };\r
178 \r
179   struct Button : Hwnd\r
180   {\r
181     Button(Window *window, std::string title, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)\r
182       : Hwnd(window, WC_BUTTONA, title.c_str(), parent, w, h, contain, behave)\r
183     {\r
184       window->handlers[WM_COMMAND].push_back([&](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {\r
185         if ((HWND)lParam == this->hwnd && HIWORD(wParam) == BN_CLICKED)\r
186           for (auto handler : this->onClickHandlers)\r
187             handler();\r
188       });\r
189     }\r
190 \r
191     void onClick(std::function<void()> cb)\r
192     {\r
193       onClickHandlers.push_back(cb);\r
194     }\r
195   private:\r
196     std::vector<std::function<void()>> onClickHandlers;\r
197   };\r
198   \r
199   struct CheckBox : Hwnd\r
200   {\r
201     CheckBox(Window *window, std::string title, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)\r
202       : Hwnd(window, WC_BUTTONA, title.c_str(), parent, w, h, contain, behave)\r
203     {\r
204       addStyle(BS_CHECKBOX);\r
205       window->handlers[WM_COMMAND].push_back([&](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {\r
206         if ((HWND)lParam == this->hwnd && HIWORD(wParam) == BN_CLICKED)\r
207           SendMessageA(this->hwnd, BM_SETCHECK, SendMessageA(this->hwnd, BM_GETCHECK, 0, 0) ? BST_UNCHECKED : BST_CHECKED, 0);\r
208       });\r
209     }\r
210   };\r
211 \r
212   struct ListBox : Hwnd\r
213   {\r
214     ListBox(Window *window, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)\r
215       : Hwnd(window, WC_LISTBOXA, "", parent, w, h, contain, behave)\r
216     {\r
217       addStyle(WS_BORDER);\r
218       //addStyle(WS_VSCROLL);\r
219     }\r
220 \r
221     void addString(std::string str)\r
222     {\r
223       SendMessage(hwnd, LB_ADDSTRING, 0, (LPARAM)str.c_str());\r
224     }\r
225 \r
226     int getSelectedIndex()\r
227     {\r
228       return SendMessage(hwnd, LB_GETCURSEL, 0, 0);\r
229     }\r
230 \r
231     int findString(std::string str)\r
232     {\r
233       return SendMessageA(hwnd, LB_FINDSTRINGEXACT, -1, (LPARAM)str.c_str());\r
234     }\r
235 \r
236     std::string getText(int index)\r
237     {\r
238       int len = SendMessageA(hwnd, LB_GETTEXTLEN, index, 0);\r
239       std::string result(len, 0);\r
240       SendMessage(hwnd, LB_GETTEXT, index, (LPARAM)result.data());\r
241       return result;\r
242     }\r
243 \r
244     void clear()\r
245     {\r
246       SendMessageA(hwnd, LB_RESETCONTENT, 0, 0);\r
247     }\r
248 \r
249     void remove(int index)\r
250     {\r
251       SendMessageA(hwnd, LB_DELETESTRING, index, 0);\r
252     }\r
253   };\r
254 \r
255   lay_id createLayId(lay_context *ctx, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)\r
256   {\r
257     lay_id lId = lay_item(ctx);\r
258     lay_insert(ctx, parent, lId);\r
259     lay_set_size_xy(ctx, lId, w, h);\r
260     lay_set_contain(ctx, lId, contain);\r
261     lay_set_behave(ctx, lId, behave);\r
262     return lId;\r
263   }\r
264 }\r
265 \r
266 \r
267 \r
268 \r
269 win::Hwnd::Hwnd(Window *window, LPCSTR className, LPCSTR windowName, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)\r
270 {\r
271   this->window = window;\r
272   \r
273   lId = createLayId(&window->ctx, parent, w, h, contain, behave);\r
274   \r
275   hwnd = CreateWindowExA(0,\r
276                           className,\r
277                           windowName,\r
278                           WS_VISIBLE | WS_CHILD,\r
279                           0,\r
280                           0,\r
281                           0,\r
282                           0,\r
283                           window->hwnd,\r
284                           nullptr,\r
285                           nullptr,\r
286                           nullptr);\r
287 \r
288   window->handlers[WM_SIZE].push_back([this](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {\r
289     lay_vec4 rect = lay_get_rect(&this->window->ctx, this->lId);\r
290     SetWindowPos(this->hwnd, HWND_TOP,\r
291       rect[0],\r
292       rect[1],\r
293       rect[2],\r
294       rect[3],\r
295       SWP_NOZORDER\r
296     );\r
297   });\r
298 }