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