-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathWindow.hpp.backup
More file actions
396 lines (350 loc) · 14.6 KB
/
Window.hpp.backup
File metadata and controls
396 lines (350 loc) · 14.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
#ifndef WPP_WINDOW_HPP
#define WPP_WINDOW_HPP
#include "winplusplus.hpp"
#include "message_loop.hpp"
constexpr auto WINDOW_TIMER_OFFSET_START = 0x2374;
namespace wpp
{
/**
* @struct window_class
* @brief Encapsulates window class information.
*/
struct window_class {
friend class window;
/**
* @brief Default constructor.
*/
window_class() = default;
/**
* @brief Parameterized constructor.
* @param name Class name.
* @param instance Instance handle.
* @param icon Icon handle.
* @param cursor Cursor handle.
* @param background Background brush.
* @param menu Menu name.
* @param style Class style.
* @param extra Extra bytes.
*/
window_class(const tstring& name, HINSTANCE instance = NULL, HICON icon = NULL, HCURSOR cursor = NULL,
HBRUSH background = (HBRUSH)(COLOR_WINDOW), LPCTSTR menu = NULL, UINT style = 0, int extra = 0) {
ZeroMemory(&m_window_class, sizeof(WNDCLASSEX));
m_window_class.cbSize = sizeof(WNDCLASSEX);
m_window_class.style = style;
m_window_class.cbClsExtra = 0;
m_window_class.cbWndExtra = extra;
m_window_class.hInstance = instance;
m_window_class.hIcon = icon;
m_window_class.hCursor = cursor;
m_window_class.hbrBackground = background;
m_window_class.lpszMenuName = menu;
m_window_class.lpszClassName = name.c_str();
m_window_class.hIconSm = icon;
m_window_class.lpfnWndProc = nullptr; // Will be set by the window class when registering
}
window_class(WNDCLASS window_class) {
ZeroMemory(&m_window_class, sizeof(WNDCLASSEX));
std::memcpy(&m_window_class, &window_class, sizeof(WNDCLASS));
}
protected:
/**
* @brief Gets the instance handle.
* @return Instance handle.
*/
HINSTANCE instance() const { return m_window_class.hInstance; }
/**
* @brief Gets the class name.
* @return Class name.
*/
LPCTSTR class_name() const { return m_window_class.lpszClassName; }
/**
* @brief Gets the class style.
* @return Class style.
*/
UINT style() const { return m_window_class.style; }
/**
* @brief Registers the window class.
*/
void Register() {
m_class_atom = RegisterClassEx(&m_window_class);
}
/**
* @brief Unregisters the window class.
*/
void Unregister() {
UnregisterClass(m_window_class.lpszClassName, m_window_class.hInstance);
m_class_atom = NULL;
}
/**
* @brief Gets the class atom.
* @return Class atom.
*/
ATOM& atom() { return m_class_atom; }
/**
* @brief Gets the window class structure.
* @return Window class structure.
*/
WNDCLASSEX& get() { return m_window_class; }
private:
WNDCLASSEX m_window_class; ///< Window class structure.
ATOM m_class_atom = NULL; ///< Class atom.
};
class window : public hwnd {
public:
using menu_callback = std::function<void(WPARAM, LPARAM)>;
using timer_callback = std::function<void()>;
using window_message_callback = std::function<LRESULT(HWND, WPARAM, LPARAM)>;
using message_handler = LRESULT(HWND hWnd, WPARAM wParam, LPARAM lParam);
/**
* @class RadioButtonGroup
* @brief Manages a group of radio buttons within a window.
*/
class radio_button_group {
friend class window;
public:
/**
* @brief Constructor.
* @param parent Pointer to the parent window.
*/
radio_button_group(window* parent)
: m_parent(parent) {
}
virtual ~radio_button_group() = default;
/**
* @brief Creates a radio button.
* @param control_id Control ID.
* @param text Button text.
* @param x X position.
* @param y Y position.
* @param width Button width.
* @param height Button height.
* @param initial_state Initial state of the button.
* @return Pointer to the created radio button.
*/
control_ptr<radio_button> create_button(const tstring& text, int x, int y, int width, int height, BOOL initial_state = FALSE);
/**
* @brief Gets the index of the selected radio button.
* @return Index of the selected radio button.
*/
int selected_index();
private:
std::vector<control_ptr<radio_button>> m_radio_buttons; ///< Vector of radio buttons.
window* m_parent; ///< Pointer to the parent window.
};
/**
* @brief Constructor.
* @param wnd_class Window class.
* @param window_name Window name.
* @param x_pos X position.
* @param y_pos Y position.
* @param width Width.
* @param height Height.
* @param style Window style.
* @param menu_id Menu ID.
* @param menu Menu handle.
* @param param Additional parameters.
* @param style_ex Extended window style.
*/
window(window_class wnd_class, const tstring& window_name, int x_pos, int y_pos, int width, int height, DWORD style = WS_OVERLAPPEDWINDOW,
int menu_id = -1, HMENU menu = NULL, HFONT font = NULL, DWORD style_ex = 0);
/**
* @brief Destructor.
*/
virtual ~window() noexcept;
virtual message_handler on_create;
virtual message_handler on_close;
virtual message_handler on_quit;
virtual message_handler on_timer;
virtual message_handler on_notify;
virtual message_handler on_command;
virtual message_handler on_destroy;
virtual message_handler on_display_change;
virtual message_handler on_move;
virtual message_handler on_menu_command;
virtual message_handler on_paint;
virtual message_handler on_size;
virtual message_handler on_key_down;
virtual message_handler on_key_up;
virtual message_handler on_h_scroll;
virtual message_handler on_v_scroll;
virtual message_handler on_drop_files;
virtual message_handler on_dpi_changed;
virtual message_handler on_ctl_color_edit;
virtual message_handler on_ctl_color_static;
/**
* @brief Creates the window without running a message loop.
* @param parent_window Parent window handle.
* @param param Additional parameters.
* @return True if window was created successfully, false otherwise.
*/
virtual bool create_window(HWND parent_window = HWND_DESKTOP, LPVOID param = NULL);
/**
* @brief Runs the window with its own message loop.
* @param parent_window Parent window handle.
* @param param Additional parameters.
* @return True if window was created and ran, false otherwise.
*/
virtual bool run_window(HWND parent_window = HWND_DESKTOP, LPVOID param = NULL);
/**
* @brief Window procedure.
* @param hWnd Window handle.
* @param Msg Message.
* @param wParam WPARAM.
* @param lParam LPARAM.
* @return Result of message processing.
*/
virtual LRESULT window_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
int message_box(const tstring& message, const tstring& title, UINT type) {
return ::MessageBox(m_handle, message.c_str(), title.c_str(), type);
}
template<typename... Args>
int message_box_info(const tstring& title, tstring_view format_str, Args&&... args) {
return message_box(format_tstring(format_str, std::forward<Args>(args)...), title, MB_OK | MB_ICONINFORMATION);
}
template<typename... Args>
int message_box_warn(const tstring& title, tstring_view format_str, Args&&... args) {
return message_box(format_string(format_str, std::forward<Args>(args)...), title, MB_OK | MB_ICONWARNING);
}
template<typename... Args>
int message_box_error(const tstring& title, tstring_view format_str, Args&&... args) {
return message_box(format_string(format_str, std::forward<Args>(args)...), title, MB_OK | MB_ICONERROR);
}
/**
* @brief Shows the window.
*/
void show_window();
/**
* @brief Hides the window.
*/
void hide_window();
/**
* @brief Closes the window.
*/
void close_window();
/**
* @brief Quits the window.
* @param exit_code Exit code.
*/
void quit_window(INT exit_code = 0);
/**
* @brief Creates a radio button group.
* @return Pointer to the created radio button group.
*/
control_ptr<window::radio_button_group> create_radio_button_group();
// Create window controls with customizable styles
control_ptr<button> create_button(const tstring& text, int x, int y, int width, int height, DWORD style = BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_OVERLAPPED, DWORD style_ex = 0);
control_ptr<check_box> create_check_box(const tstring& text, int x, int y, int width, int height, BOOL initial_state = false, DWORD style = BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_OVERLAPPED, DWORD style_ex = 0);
control_ptr<group_box> create_group_box(const tstring& text, int x, int y, int width, int height, DWORD style = BS_GROUPBOX | WS_CHILD | WS_VISIBLE | WS_OVERLAPPED, DWORD style_ex = 0);
control_ptr<static_control> create_static_control(const tstring& text, int x, int y, int width, int height, DWORD style = SS_LEFT | WS_CHILD | WS_VISIBLE, DWORD style_ex = 0);
control_ptr<combo_box> create_combo_box(int x, int y, int width, int height, DWORD style = CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE | WS_VSCROLL, DWORD style_ex = 0);
control_ptr<edit_text> create_edit_text(int x, int y, int width, int height, const tstring& initial_text = _T(""), DWORD style = ES_LEFT | WS_CHILD | WS_VISIBLE, DWORD style_ex = WS_EX_CLIENTEDGE);
control_ptr<list_box> create_list_box(int x, int y, int width, int height, DWORD style = LBS_STANDARD | WS_CHILD | WS_BORDER | WS_VISIBLE, DWORD style_ex = 0);
control_ptr<list_view> create_list_view(int x, int y, int width, int height, DWORD style = LVS_REPORT | WS_CHILD | WS_VISIBLE, DWORD style_ex = WS_EX_CLIENTEDGE);
control_ptr<tree_view> create_tree_view(int x, int y, int width, int height, DWORD style = TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | WS_CHILD | WS_VISIBLE, DWORD style_ex = WS_EX_CLIENTEDGE);
control_ptr<tab_control> create_tab_control(int x, int y, int width, int height, DWORD style = TCS_MULTILINE | WS_CHILD | WS_VISIBLE, DWORD style_ex = 0);
control_ptr<progress_bar> create_progress_bar(int x, int y, int width, int height, DWORD style = PBS_SMOOTH | WS_CHILD | WS_BORDER | WS_VISIBLE, DWORD style_ex = 0);
control_ptr<up_down_control> create_spin_control(int x, int y, int width, int height, DWORD style = UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS | WS_CHILD | WS_BORDER | WS_VISIBLE, DWORD style_ex = 0);
control_ptr<rich_edit_text> create_rich_edit(int x, int y, int width, int height, const tstring& initial_text = _T(""), DWORD style = ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE, DWORD style_ex = WS_EX_CLIENTEDGE);
control_ptr<sys_link> create_link_control(const tstring& text, int x, int y, int width, int height, DWORD style = WS_CHILD | WS_VISIBLE, DWORD style_ex = 0);
control_ptr<scroll_bar> create_scroll_bar(scroll_orientation orientation, int x, int y, int width, int height, DWORD style = WS_CHILD | WS_VISIBLE, DWORD style_ex = 0);
control_ptr<track_bar> create_track_bar(int x, int y, int width, int height, DWORD style = WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS, DWORD style_ex = 0);
control_ptr<up_down_control> create_updown_control(int x, int y, int width, int height, DWORD style = UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS | WS_CHILD | WS_BORDER | WS_VISIBLE, DWORD style_ex = 0);
/**
* @brief Registers a menu control callback.
* @param control_id Control ID.
* @param callback Callback for the menu item.
*/
void register_menu_command(UINT_PTR menu_id, menu_callback callback) {
if (callback)
m_menu_command_events[menu_id] = std::move(callback);
else
m_menu_command_events.erase(menu_id);
}
/**
* @brief Adds a timer event.
* @tparam DC Callback type.
* @param timer_elapse Timer interval in milliseconds.
* @param callback Callback function.
*/
template<typename DC>
void add_timer(INT timer_elapse, DC callback) {
const UINT_PTR timer_id = ++m_internal_timer_id + WINDOW_TIMER_OFFSET_START;
if (::SetTimer(m_handle, timer_id, timer_elapse, NULL) != 0)
m_timer_events[timer_id] = callback;
}
/**
* @brief Gets a control by ID.
* @tparam CtrlType Control type.
* @param control_id Control ID.
* @return Pointer to the control.
*/
template<typename CtrlType = control>
inline control_ptr<CtrlType> get_control(UINT control_id) {
auto it = std::find_if(m_controls.begin(), m_controls.end(), [control_id](const control_ptr<control>& control) {
return control && control->get_id() == control_id;
});
if (it != m_controls.end() && *it) {
return std::dynamic_pointer_cast<CtrlType>(*it);
}
return nullptr;
}
/**
* @brief Gets a control by its handle.
* @param handle The handle of the control.
* @return The control object.
*/
template<typename CtrlType = control>
inline control_ptr<CtrlType> get_control_by_handle(HWND handle) {
auto it = std::find_if(m_controls.begin(), m_controls.end(), [handle](const control_ptr<control>& control) {
return control && control->get_handle() == handle;
});
if (it != m_controls.end() && *it) {
return std::dynamic_pointer_cast<CtrlType>(*it);
}
return nullptr;
}
/**
* @brief Sets the layout panel for automatic control arrangement.
* @param layout Shared pointer to the layout panel.
*/
void set_layout(std::shared_ptr<layout::panel> layout) {
m_layout_panel = std::move(layout);
if (m_layout_panel && m_handle) {
m_layout_panel->set_parent_window(m_handle);
// Do initial layout
RECT rc = get_rect();
m_layout_panel->measure(rc.right, rc.bottom);
m_layout_panel->arrange(0, 0, rc.right, rc.bottom);
}
}
/**
* @brief Gets the current layout panel.
* @return Shared pointer to the layout panel (may be nullptr).
*/
std::shared_ptr<layout::panel> get_layout() const {
return m_layout_panel;
}
private:
void init_message_events();
void cleanup();
BOOL handle_scroll_message(scroll_orientation orientation, WPARAM wParam, LPARAM lParam);
protected:
std::unique_ptr<void, void(*)(void*)> m_thunk_storage{ nullptr, +[](void* p) {} }; ///< Thunk storage for window procedure.
window_class m_window_class; ///< Window class.
int m_x_pos, m_y_pos, m_width, m_height; ///< Window position and size.
tstring m_window_name; ///< Window name.
HMENU m_menu_handle; ///< Menu handle.
HFONT m_font; ///< Font handle.
int m_menu_id; ///< Menu ID.
DWORD m_style, m_style_ex; ///< Window styles.
UINT m_control_id = WM_USER + 1; ///< Control ID index.
UINT_PTR m_internal_timer_id = 0; ///< Internal timer ID.
std::atomic_bool m_window_running = false; ///< Window running flag.
std::map<INT, window_message_callback> m_message_events; ///< Message events.
std::map<UINT_PTR, timer_callback> m_timer_events; ///< Timer events.
std::map<UINT_PTR, menu_callback> m_menu_command_events; ///< Menu command events.
std::shared_ptr<layout::panel> m_layout_panel; ///< Layout panel for automatic control arrangement.
std::vector<control_ptr<>> m_controls; ///< Controls container.
};
}
#endif // WPP_WINDOW_HPP