]> gitweb.ps.run Git - autorec/blob - src/win.h
167e162d9b6858c7979eaaafa077f05210d0d54d
[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 <map>\r
14 #include <string>\r
15 \r
16 using std::string;\r
17 \r
18 namespace win {\r
19 namespace _ {\r
20 using CallbackFn = std::function<void()>;\r
21 std::map<HWND, std::map<WORD, CallbackFn>> handlers;\r
22 std::map<HWND, lay_id> lIds;\r
23 \r
24 NOTIFYICONDATA niData = { 0 };\r
25 void\r
26 ShowNotificationIcon()\r
27 {\r
28   Shell_NotifyIconA(NIM_ADD, &_::niData);\r
29   Shell_NotifyIconA(NIM_SETVERSION, &_::niData);\r
30 }\r
31 \r
32 void\r
33 HideNotificationIcon()\r
34 {\r
35   Shell_NotifyIconA(NIM_DELETE, &_::niData);\r
36 }\r
37 \r
38 lay_context ctx;\r
39 lay_id root;\r
40 \r
41 LRESULT CALLBACK\r
42 WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
43 {\r
44   switch (msg) {\r
45     case WM_CLOSE:\r
46       DestroyWindow(hwnd);\r
47       break;\r
48     case WM_DESTROY:\r
49       Shell_NotifyIconA(NIM_DELETE, &niData);\r
50       lay_destroy_context(&ctx);\r
51       PostQuitMessage(0);\r
52       break;\r
53     case WM_SIZE:\r
54       if (wParam == SIZE_MINIMIZED) {\r
55         ShowNotificationIcon();\r
56         ShowWindow(hwnd, false);\r
57       }\r
58       else {\r
59         lay_set_size_xy(&_::ctx, _::root, LOWORD(lParam), HIWORD(lParam));\r
60         lay_run_context(&_::ctx);\r
61 \r
62         for (auto &lId : lIds) {\r
63           lay_vec4 rect = lay_get_rect(&_::ctx, lId.second);\r
64           SetWindowPos(lId.first, HWND_TOP,\r
65             rect[0],\r
66             rect[1],\r
67             rect[2],\r
68             rect[3],\r
69             SWP_NOZORDER\r
70           );\r
71         }\r
72         RedrawWindow(hwnd, 0, 0, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);\r
73       }\r
74       break;\r
75     case WM_COMMAND:\r
76       if (handlers.find((HWND)lParam) != handlers.end()) {\r
77         auto handler = handlers[(HWND)lParam];\r
78         if (handler.find(HIWORD(wParam)) != handler.end()) {\r
79           auto cb = handler[HIWORD(wParam)];\r
80           cb();\r
81         }\r
82       }\r
83       break;\r
84     case WM_NOTIFY:\r
85       break;\r
86     case WM_APP + 1:\r
87       if (LOWORD(lParam) == NIN_SELECT) {\r
88         HideNotificationIcon();\r
89         ShowWindow(hwnd, true);\r
90         SetForegroundWindow(hwnd);\r
91         SetActiveWindow(hwnd);\r
92       }\r
93       break;\r
94     case WM_CTLCOLORSTATIC:\r
95       return (LONG)GetStockObject(WHITE_BRUSH);\r
96     case WM_GETMINMAXINFO: {\r
97       MINMAXINFO *mmInfo = (MINMAXINFO*)lParam;\r
98       mmInfo->ptMinTrackSize.x = 400;\r
99       mmInfo->ptMinTrackSize.y = 200;\r
100       break;\r
101     }\r
102     default:\r
103       return DefWindowProc(hwnd, msg, wParam, lParam);\r
104   }\r
105   return 0;\r
106 }\r
107 }\r
108 \r
109 \r
110 void\r
111 Callback(HWND hwnd, WORD ev, std::function<void()> cb)\r
112 {\r
113   _::handlers[hwnd][ev] = cb;\r
114 }\r
115 \r
116 HWND\r
117 Window(string title, string className, HINSTANCE hInstance)\r
118 {\r
119   WNDCLASSEX wc;\r
120   wc.cbSize = sizeof(WNDCLASSEX);\r
121   wc.style = 0;\r
122   wc.lpfnWndProc = _::WndProc;\r
123   wc.cbClsExtra = 0;\r
124   wc.cbWndExtra = 0;\r
125   wc.hInstance = hInstance;\r
126   wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION);\r
127   wc.hCursor = LoadCursor(nullptr, IDC_ARROW);\r
128   wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);\r
129   wc.lpszMenuName = nullptr;\r
130   wc.lpszClassName = className.c_str();\r
131   wc.hIconSm = LoadIcon(nullptr, IDI_APPLICATION);\r
132   RegisterClassEx(&wc);\r
133 \r
134   lay_init_context(&_::ctx);\r
135   _::root = lay_item(&_::ctx);\r
136   lay_set_contain(&_::ctx, _::root, LAY_COLUMN);\r
137 \r
138   HWND result = CreateWindowA(className.c_str(),\r
139                        title.c_str(),\r
140                        WS_OVERLAPPEDWINDOW,\r
141                        CW_USEDEFAULT,\r
142                        CW_USEDEFAULT,\r
143                        CW_USEDEFAULT,\r
144                        CW_USEDEFAULT,\r
145                        nullptr,\r
146                        nullptr,\r
147                        hInstance,\r
148                        nullptr);\r
149                        \r
150   _::niData.cbSize = sizeof(_::niData);\r
151   _::niData.uID = 12345;\r
152   _::niData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;\r
153   _::niData.hIcon = LoadIconA(hInstance, MAKEINTRESOURCEA(IDI_MY_ICON));\r
154   _::niData.hWnd = result;\r
155   _::niData.uCallbackMessage = WM_APP+1;\r
156   _::niData.uVersion = NOTIFYICON_VERSION_4;\r
157 \r
158   return result;\r
159 }\r
160 \r
161 bool\r
162 UpdateWindow(HWND hwnd)\r
163 {\r
164   MSG msg;\r
165   if (GetMessage(&msg, nullptr, 0, 0) > 0) {\r
166     TranslateMessage(&msg);\r
167     DispatchMessage(&msg);\r
168     return true;\r
169   }\r
170   return false;\r
171 }\r
172 \r
173 void\r
174 ShowWindow(HWND hwnd)\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 HWND\r
189 Button(HWND hwnd, string title, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)\r
190 {\r
191   lay_id lId = lay_item(&_::ctx);\r
192   lay_insert(&_::ctx, parent, lId);\r
193   lay_set_size_xy(&_::ctx, lId, w, h);\r
194   lay_set_contain(&_::ctx, lId, contain);\r
195   lay_set_behave(&_::ctx, lId, behave);\r
196 \r
197   HWND result = CreateWindowExA(0,\r
198                                 WC_BUTTONA,\r
199                                 title.c_str(),\r
200                                 WS_VISIBLE | WS_CHILD,\r
201                                 0, 0, 0, 0,\r
202                                 hwnd,\r
203                                 nullptr,\r
204                                 nullptr,\r
205                                 nullptr);\r
206   _::lIds[result] = lId;\r
207   return result;\r
208 }\r
209 \r
210 HWND\r
211 ListBox(HWND hwnd, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)\r
212 {\r
213   lay_id lId = lay_item(&_::ctx);\r
214   lay_insert(&_::ctx, parent, lId);\r
215   lay_set_size_xy(&_::ctx, lId, w, h);\r
216   lay_set_contain(&_::ctx, lId, contain);\r
217   lay_set_behave(&_::ctx, lId, behave);\r
218 \r
219   HWND result = CreateWindowExA(0,\r
220                          WC_LISTBOXA,\r
221                          "",\r
222                          WS_VISIBLE | WS_CHILD | WS_BORDER | WS_VSCROLL,\r
223                          0, 0, 0, 0,\r
224                          hwnd,\r
225                          nullptr,\r
226                          nullptr,\r
227                          nullptr);\r
228   _::lIds[result] = lId;\r
229   return result;\r
230 }\r
231 \r
232 void\r
233 ListAddString(HWND hwnd, string str)\r
234 {\r
235   SendMessage(hwnd, LB_ADDSTRING, 0, (LPARAM)str.c_str());\r
236 }\r
237 \r
238 int\r
239 ListGetSelectedIndex(HWND hwnd)\r
240 {\r
241   int sel = SendMessage(hwnd, LB_GETCURSEL, 0, 0);\r
242   return sel;\r
243 }\r
244 \r
245 int ListFindString(HWND hwnd, string str)\r
246 {\r
247   return SendMessageA(hwnd, LB_FINDSTRINGEXACT, -1, (LPARAM)str.c_str());\r
248 }\r
249 \r
250 string\r
251 ListGetText(HWND hwnd, int index)\r
252 {\r
253   char buffer[1024];\r
254   SendMessage(hwnd, LB_GETTEXT, index, (LPARAM)buffer);\r
255   return string(buffer);\r
256 }\r
257 \r
258 void\r
259 ListClear(HWND hwnd)\r
260 {\r
261   SendMessageA(hwnd, LB_RESETCONTENT, 0, 0);\r
262 }\r
263 \r
264 void ListRemove(HWND hwnd, int index)\r
265 {\r
266   SendMessageA(hwnd, LB_DELETESTRING, index, 0);\r
267 }\r
268 \r
269 HWND\r
270 ListView(HWND hwnd, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)\r
271 {\r
272   lay_id lId = lay_item(&_::ctx);\r
273   lay_insert(&_::ctx, parent, lId);\r
274   lay_set_size_xy(&_::ctx, lId, w, h);\r
275   lay_set_contain(&_::ctx, lId, contain);\r
276   lay_set_behave(&_::ctx, lId, behave);\r
277 \r
278   HWND result = CreateWindowExA(0,\r
279                          WC_LISTVIEWA,\r
280                          "",\r
281                          WS_VISIBLE | WS_CHILD | WS_BORDER | WS_VSCROLL,\r
282                          0, 0, 0, 0,\r
283                          hwnd,\r
284                          nullptr,\r
285                          nullptr,\r
286                          nullptr);\r
287   _::lIds[result] = lId;\r
288   return result;\r
289 }\r
290 \r
291 HWND\r
292 CheckBox(HWND hwnd, string title, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)\r
293 {\r
294   lay_id lId = lay_item(&_::ctx);\r
295   lay_insert(&_::ctx, parent, lId);\r
296   lay_set_size_xy(&_::ctx, lId, w, h);\r
297   lay_set_contain(&_::ctx, lId, contain);\r
298   lay_set_behave(&_::ctx, lId, behave);\r
299 \r
300   HWND result = CreateWindowExA(0,\r
301                          WC_BUTTONA,\r
302                          title.c_str(),\r
303                          WS_VISIBLE | WS_CHILD | BS_CHECKBOX,\r
304                          0, 0, 0, 0,\r
305                          hwnd,\r
306                          nullptr,\r
307                          nullptr,\r
308                          nullptr);\r
309   _::lIds[result] = lId;\r
310   return result;\r
311 }\r
312 \r
313 void SetStyle(HWND hwnd, DWORD style)\r
314 {\r
315   SetWindowLongPtrA(hwnd, GWL_STYLE, style);\r
316 }\r
317 DWORD GetStyle(HWND hwnd)\r
318 {\r
319   return GetWindowLongPtrA(hwnd, GWL_STYLE);\r
320 }\r
321 void AddStyle(HWND hwnd, DWORD style)\r
322 {\r
323   SetWindowLongPtrA(hwnd, GWL_STYLE, GetStyle(hwnd) | style);\r
324 }\r
325 void RemoveStyle(HWND hwnd, DWORD style)\r
326 {\r
327   SetWindowLongPtrA(hwnd, GWL_STYLE, GetStyle(hwnd) & (~style));\r
328 }\r
329 }