]> gitweb.ps.run Git - autorec/blob - src/win.h
MVP
[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 "layout.h"\r
9 \r
10 #include <functional>\r
11 #include <map>\r
12 #include <string>\r
13 \r
14 using std::string;\r
15 \r
16 namespace win {\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(nullptr, IDI_WINLOGO);\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 }