]> gitweb.ps.run Git - autorec/blob - src/win.h
ws connect works
[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 struct Length\r
18 {\r
19   int pixel;\r
20   float percent;\r
21 };\r
22 struct Size\r
23 {\r
24   Length x, y, w, h;\r
25   int getX(HWND hwnd)\r
26   {\r
27     RECT rect;\r
28     GetClientRect(hwnd, &rect);\r
29     return x.percent * (rect.right - rect.left) + x.pixel;\r
30   }\r
31   int getY(HWND hwnd)\r
32   {\r
33     RECT rect;\r
34     GetClientRect(hwnd, &rect);\r
35     return y.percent * (rect.bottom - rect.top) + y.pixel;\r
36   }\r
37   int getW(HWND hwnd)\r
38   {\r
39     RECT rect;\r
40     GetClientRect(hwnd, &rect);\r
41     return w.percent * (rect.right - rect.left) + w.pixel;\r
42   }\r
43   int getH(HWND hwnd, int _w, int _h)\r
44   {\r
45     RECT rect;\r
46     GetWindowRect(hwnd, &rect);\r
47     return h.percent * (rect.bottom - rect.top) + h.pixel;\r
48   }\r
49 };\r
50 \r
51 namespace _ {\r
52 using CallbackFn = std::function<void()>;\r
53 std::map<HWND, std::map<WORD, CallbackFn>> handlers;\r
54 std::map<HWND, lay_id> lIds;\r
55 \r
56 NOTIFYICONDATA niData = { 0 };\r
57 \r
58 lay_context ctx;\r
59 lay_id root;\r
60 \r
61 LRESULT CALLBACK\r
62 WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
63 {\r
64   switch (msg) {\r
65     case WM_CLOSE:\r
66       DestroyWindow(hwnd);\r
67       break;\r
68     case WM_DESTROY:\r
69       Shell_NotifyIconA(NIM_DELETE, &niData);\r
70       lay_destroy_context(&ctx);\r
71       PostQuitMessage(0);\r
72       break;\r
73     case WM_SIZE:\r
74       if (wParam == SIZE_MINIMIZED) {\r
75         ShowWindow(hwnd, false);\r
76         SetForegroundWindow(hwnd);\r
77         SetActiveWindow(hwnd);\r
78       }\r
79       else {\r
80         lay_set_size_xy(&_::ctx, _::root, LOWORD(lParam), HIWORD(lParam));\r
81         lay_run_context(&_::ctx);\r
82 \r
83         for (auto &lId : lIds) {\r
84           lay_vec4 rect = lay_get_rect(&_::ctx, lId.second);\r
85           SetWindowPos(lId.first, HWND_TOP,\r
86             rect[0],\r
87             rect[1],\r
88             rect[2],\r
89             rect[3],\r
90             SWP_NOZORDER\r
91           );\r
92         }\r
93         RedrawWindow(hwnd, 0, 0, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);\r
94       }\r
95       break;\r
96     case WM_COMMAND:\r
97       if (handlers.find((HWND)lParam) != handlers.end()) {\r
98         auto handler = handlers[(HWND)lParam];\r
99         if (handler.find(HIWORD(wParam)) != handler.end()) {\r
100           auto cb = handler[HIWORD(wParam)];\r
101           cb();\r
102         }\r
103       }\r
104       break;\r
105     case WM_NOTIFY:\r
106       break;\r
107     case WM_APP + 1:\r
108       if (LOWORD(lParam) == NIN_SELECT)\r
109         ShowWindow(hwnd, true);\r
110       break;\r
111     case WM_CTLCOLORSTATIC:\r
112       return (LONG)GetStockObject(WHITE_BRUSH);\r
113     case WM_GETMINMAXINFO: {\r
114       MINMAXINFO *mmInfo = (MINMAXINFO*)lParam;\r
115       mmInfo->ptMinTrackSize.x = 400;\r
116       mmInfo->ptMinTrackSize.y = 200;\r
117       break;\r
118     }\r
119     default:\r
120       return DefWindowProc(hwnd, msg, wParam, lParam);\r
121   }\r
122   return 0;\r
123 }\r
124 }\r
125 \r
126 void\r
127 ShowNotificationIcon(HINSTANCE hInstance, HWND hwnd)\r
128 {\r
129   _::niData.cbSize = sizeof(_::niData);\r
130   _::niData.uID = 12345;\r
131   _::niData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;\r
132   _::niData.hIcon = LoadIconA(nullptr, IDI_WINLOGO);\r
133   _::niData.hWnd = hwnd;\r
134   _::niData.uCallbackMessage = WM_APP+1;\r
135   _::niData.uVersion = NOTIFYICON_VERSION_4;\r
136 \r
137   Shell_NotifyIconA(NIM_ADD, &_::niData);\r
138   Shell_NotifyIconA(NIM_SETVERSION, &_::niData);\r
139 }\r
140 \r
141 void\r
142 Callback(HWND hwnd, WORD ev, std::function<void()> cb)\r
143 {\r
144   _::handlers[hwnd][ev] = cb;\r
145 }\r
146 \r
147 HWND\r
148 Window(string title, string className, HINSTANCE hInstance)\r
149 {\r
150   WNDCLASSEX wc;\r
151   wc.cbSize = sizeof(WNDCLASSEX);\r
152   wc.style = 0;\r
153   wc.lpfnWndProc = _::WndProc;\r
154   wc.cbClsExtra = 0;\r
155   wc.cbWndExtra = 0;\r
156   wc.hInstance = hInstance;\r
157   wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION);\r
158   wc.hCursor = LoadCursor(nullptr, IDC_ARROW);\r
159   wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);\r
160   wc.lpszMenuName = nullptr;\r
161   wc.lpszClassName = className.c_str();\r
162   wc.hIconSm = LoadIcon(nullptr, IDI_APPLICATION);\r
163   RegisterClassEx(&wc);\r
164 \r
165   lay_init_context(&_::ctx);\r
166   _::root = lay_item(&_::ctx);\r
167   lay_set_contain(&_::ctx, _::root, LAY_COLUMN);\r
168   lay_set_margins_ltrb(&_::ctx, _::root, 5, 5, 5, 5);\r
169 \r
170   return CreateWindowA(className.c_str(),\r
171                        title.c_str(),\r
172                        WS_OVERLAPPEDWINDOW,\r
173                        CW_USEDEFAULT,\r
174                        CW_USEDEFAULT,\r
175                        CW_USEDEFAULT,\r
176                        CW_USEDEFAULT,\r
177                        nullptr,\r
178                        nullptr,\r
179                        hInstance,\r
180                        nullptr);\r
181 }\r
182 \r
183 bool\r
184 UpdateWindow(HWND hwnd)\r
185 {\r
186   MSG msg;\r
187   if (GetMessage(&msg, nullptr, 0, 0) > 0) {\r
188     TranslateMessage(&msg);\r
189     DispatchMessage(&msg);\r
190     return true;\r
191   }\r
192   return false;\r
193 }\r
194 \r
195 void\r
196 ShowWindow(HWND hwnd)\r
197 {\r
198   ShowWindow(hwnd, true);\r
199 \r
200   EnumChildWindows(\r
201     hwnd,\r
202     [](HWND hwnd, LPARAM lParam) -> BOOL {\r
203       HFONT guiFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);\r
204       SendMessage(hwnd, WM_SETFONT, (WPARAM)guiFont, MAKELPARAM(TRUE, 0));\r
205       return TRUE;\r
206     },\r
207     0);\r
208 }\r
209 \r
210 HWND\r
211 Button(HWND hwnd, string title, 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_BUTTONA,\r
221                                 title.c_str(),\r
222                                 WS_VISIBLE | WS_CHILD,\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 HWND\r
233 ListBox(HWND hwnd, lay_id parent, lay_scalar w, lay_scalar h, uint32_t contain, uint32_t behave)\r
234 {\r
235   lay_id lId = lay_item(&_::ctx);\r
236   lay_insert(&_::ctx, parent, lId);\r
237   lay_set_size_xy(&_::ctx, lId, w, h);\r
238   lay_set_contain(&_::ctx, lId, contain);\r
239   lay_set_behave(&_::ctx, lId, behave);\r
240 \r
241   HWND result = CreateWindowExA(0,\r
242                          WC_LISTBOXA,\r
243                          "",\r
244                          WS_VISIBLE | WS_CHILD | WS_BORDER | WS_VSCROLL,\r
245                          0, 0, 0, 0,\r
246                          hwnd,\r
247                          nullptr,\r
248                          nullptr,\r
249                          nullptr);\r
250   _::lIds[result] = lId;\r
251   return result;\r
252 }\r
253 \r
254 void\r
255 ListAddString(HWND hwnd, string str)\r
256 {\r
257   SendMessage(hwnd, LB_ADDSTRING, 0, (LPARAM)str.c_str());\r
258 }\r
259 \r
260 int\r
261 ListGetSelectedIndex(HWND hwnd)\r
262 {\r
263   int sel = SendMessage(hwnd, LB_GETCURSEL, 0, 0);\r
264   return sel;\r
265 }\r
266 \r
267 int ListFindString(HWND hwnd, string str)\r
268 {\r
269   return SendMessageA(hwnd, LB_FINDSTRINGEXACT, -1, (LPARAM)str.c_str());\r
270 }\r
271 \r
272 string\r
273 ListGetText(HWND hwnd, int index)\r
274 {\r
275   char buffer[1024];\r
276   SendMessage(hwnd, LB_GETTEXT, index, (LPARAM)buffer);\r
277   return string(buffer);\r
278 }\r
279 \r
280 void\r
281 ListClear(HWND hwnd)\r
282 {\r
283   SendMessageA(hwnd, LB_RESETCONTENT, 0, 0);\r
284 }\r
285 \r
286 void ListRemove(HWND hwnd, int index)\r
287 {\r
288   SendMessageA(hwnd, LB_DELETESTRING, index, 0);\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 }