GUIFramework 1.1.0
Framework for desktop GUI applications in C++.
Loading...
Searching...
No Matches
BaseComponent.cpp
Go to the documentation of this file.
1#include "BaseComponent.h"
2
4#include "GUIFramework.h"
9
12
13#pragma warning(disable: 6387)
14#pragma warning(disable: 4312)
15
16#define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
17
18using namespace std;
19
21{
22 void BaseComponent::runFunctionAsync(const function<void()>& callable, const function<void()>& callback) noexcept
23 {
24 GUIFramework::get().addTask(callable, callback);
25 }
26
27 void BaseComponent::runFunctionAsync(function<void()>&& callable, const function<void()>& callback) noexcept
28 {
29 GUIFramework::get().addTask(move(callable), callback);
30 }
31
32 LRESULT BaseComponent::preWindowMessagesHandle(HWND handle, UINT message, WPARAM wparam, LPARAM lparam, bool& isUsed)
33 {
34 isUsed = false;
35
36 if (message == WM_SIZE)
37 {
38 interfaces::IResizableComponent* resizableComponent = dynamic_cast<interfaces::IResizableComponent*>(this);
39
40 if (resizableComponent && !resizableComponent->getBlockResize())
41 {
42 isUsed = true;
43
44 resizableComponent->resize(LOWORD(lparam), HIWORD(lparam));
45
46 return 0;
47 }
48 }
49
50 return -1;
51 }
52
53 LRESULT BaseComponent::windowMessagesHandle(HWND handle, UINT message, WPARAM wparam, LPARAM lparam, bool& isUsed)
54 {
55 isUsed = false;
56
57 return -1;
58 }
59
60 void BaseComponent::setLocalizationKeys(interfaces::ITextLocalized* localized, const vector<string>& localizationKeys)
61 {
62 if (interfaces::ISingleTextLocalized* single = dynamic_cast<interfaces::ISingleTextLocalized*>(localized); single && localizationKeys.size())
63 {
64 single->setLocalizationKey(localizationKeys.front());
65 }
66 else if (interfaces::IMultipleTextLocalized* multi = dynamic_cast<interfaces::IMultipleTextLocalized*>(localized))
67 {
68 for (string_view localizationKey : localizationKeys)
69 {
70 multi->addLocalizationKey(localizationKey);
71 }
72 }
73 }
74
75 BaseComponent::BaseComponent(wstring_view className, wstring_view windowName, const utility::ComponentSettings& settings, const interfaces::IStyles& styles, BaseComposite* parent, string_view windowFunctionName, string_view moduleName, uint16_t smallIconResource, uint16_t largeIconResources) :
76 parent(parent),
77 className(className),
78 windowName(windowName),
79 handle(nullptr),
80 desiredWidth(settings.width),
81 desiredHeight(settings.height),
82 desiredX(settings.x),
83 desiredY(settings.y),
84 id(parent ? GUIFramework::get().generateId(windowName) : NULL),
85 backgroundColor(RGB(255, 255, 255)),
86 textColor(RGB(0, 0, 0))
87 {
88 WNDCLASSEXW classStruct = {};
89 interfaces::ITextLocalized* localized = dynamic_cast<interfaces::ITextLocalized*>(this);
90 const unordered_map<string, HMODULE, localization::utility::StringViewHash, localization::utility::StringViewEqual>& modules = GUIFramework::get().getModules();
91 const HMODULE* findedModule = nullptr;
92
93 for (const auto& [moduleName, module] : modules)
94 {
95 if (GetClassInfoExW(module, className.data(), &classStruct))
96 {
97 findedModule = &module;
98
99 break;
100 }
101 }
102
103 if (!findedModule)
104 {
105 if (windowFunctionName.size())
106 {
107 WNDPROC windowFunction = reinterpret_cast<WNDPROC>(GetProcAddress(nullptr, format("{}WindowFunction", windowFunctionName).data()));
108
109 if (!windowFunction)
110 {
111 throw exceptions::CantFindCompositeFunctionException(format("{}WindowFunction", windowFunctionName), __FILE__, __FUNCTION__, __LINE__);
112 }
113
114 classStruct.cbSize = sizeof(WNDCLASSEXW);
115 classStruct.lpszClassName = className.data();
116 classStruct.hInstance = utility::getCurrentModule();
117 classStruct.hCursor = LoadCursorW(nullptr, IDC_ARROW);
118 classStruct.lpfnWndProc = windowFunction;
119 classStruct.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW);
120
121 if (smallIconResource)
122 {
123 if (moduleName.size())
124 {
125 if (auto it = modules.find(moduleName); it != modules.end())
126 {
127 classStruct.hIconSm = static_cast<HICON>(LoadImageW(it->second, MAKEINTRESOURCEW(largeIconResources), IMAGE_ICON, standard_sizes::smallIconWidth, standard_sizes::smallIconHeight, NULL));
128 }
129 else
130 {
131 throw runtime_error(format("Can't load small icon resource for {}", moduleName));
132 }
133 }
134 else
135 {
136 classStruct.hIconSm = static_cast<HICON>(LoadImageW(classStruct.hInstance, MAKEINTRESOURCEW(largeIconResources), IMAGE_ICON, standard_sizes::smallIconWidth, standard_sizes::smallIconHeight, NULL));
137 }
138 }
139
140 if (largeIconResources)
141 {
142 if (moduleName.size())
143 {
144 if (auto it = modules.find(moduleName); it != modules.end())
145 {
146 classStruct.hIcon = static_cast<HICON>(LoadImageW(it->second, MAKEINTRESOURCEW(largeIconResources), IMAGE_ICON, standard_sizes::largeIconWidth, standard_sizes::largeIconHeight, NULL));
147 }
148 else
149 {
150 throw runtime_error(format("Can't load large icon resource for {}", moduleName));
151 }
152 }
153 else
154 {
155 classStruct.hIcon = static_cast<HICON>(LoadImageW(classStruct.hInstance, MAKEINTRESOURCEW(largeIconResources), IMAGE_ICON, standard_sizes::largeIconWidth, standard_sizes::largeIconHeight, NULL));
156 }
157 }
158
159 RegisterClassExW(&classStruct);
160 }
161 }
162
163 handle = CreateWindowExW
164 (
165 static_cast<DWORD>(styles.getExtendedStyles() | settings.styles.getExtendedStyles()),
166 classStruct.lpszClassName,
167 windowName.data(),
168 static_cast<DWORD>(styles.getStyles()) | static_cast<DWORD>(settings.styles.getStyles()) | (parent ? WS_CHILDWINDOW | WS_BORDER : WS_OVERLAPPEDWINDOW),
169 settings.x,
170 settings.y,
171 settings.width,
172 settings.height,
173 parent ? parent->getHandle() : nullptr,
174 reinterpret_cast<HMENU>(id),
175 findedModule ? *findedModule : utility::getCurrentModule(),
176 nullptr
177 );
178
179 GUIFramework::get().addComponent(this);
180
182
183 if (!parent)
184 {
185 SendMessageW(handle, custom_window_messages::initTopLevelWindowPointer, reinterpret_cast<WPARAM>(this), NULL);
186 }
187 else
188 {
189 BaseComponent* topLevelWindow = parent;
190
191 parent->addChild(this);
192
193 while (topLevelWindow->getParent())
194 {
195 topLevelWindow = topLevelWindow->getParent();
196 }
197
198 SendMessageW(handle, custom_window_messages::initTopLevelWindowPointer, reinterpret_cast<WPARAM>(topLevelWindow), NULL);
199 }
200
201 ShowWindow(handle, SW_SHOW);
202
203 if (localized)
204 {
205 this->setLocalizationKeys(localized, settings.localizationKeys);
206
207 localized->updateLocalizationEvent();
208 }
209 }
210
211 LRESULT BaseComponent::handleMessages(HWND handle, UINT message, WPARAM wparam, LPARAM lparam, bool& isUsed)
212 {
213 LRESULT result = this->preWindowMessagesHandle(handle, message, wparam, lparam, isUsed);
214
215 if (isUsed)
216 {
217 return result;
218 }
219
220 return this->windowMessagesHandle(handle, message, wparam, lparam, isUsed);
221 }
222
224 {
225 bool result = DestroyWindow(handle);
226
227 if (result && parent)
228 {
229 if (BaseComposite* parentComposite = dynamic_cast<BaseComposite*>(parent))
230 {
231 parentComposite->removeChild(this);
232 }
233 }
234
235 return result;
236 }
237
239 {
240 bool result = PostMessageW(handle, WM_CLOSE, NULL, NULL);
241
242 if (result && parent)
243 {
244 if (BaseComposite* parentComposite = dynamic_cast<BaseComposite*>(parent))
245 {
246 parentComposite->removeChild(this);
247 }
248 }
249
250 return result;
251 }
252
254 {
255 EnableWindow(handle, true);
256 }
257
259 {
260 EnableWindow(handle, false);
261 }
262
264 {
265 return IsWindowEnabled(handle);
266 }
267
269 {
270 return !this->isEnabled();
271 }
272
273 LRESULT BaseComponent::sendRawMessage(UINT message, WPARAM wparam, LPARAM lparam)
274 {
275 return SendMessageW(handle, message, wparam, lparam);
276 }
277
278 void BaseComponent::setDesiredWidth(uint16_t desiredWidth)
279 {
280 this->desiredWidth = desiredWidth;
281 }
282
283 void BaseComponent::setDesiredHeight(uint16_t desiredHeight)
284 {
285 this->desiredHeight = desiredHeight;
286 }
287
288 void BaseComponent::setDesiredX(int desiredX)
289 {
290 this->desiredX = desiredX;
291 }
292
293 void BaseComponent::setDesiredY(int desiredY)
294 {
295 this->desiredY = desiredY;
296 }
297
298 void BaseComponent::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue)
299 {
300 backgroundColor = RGB(red, green, blue);
301
302 InvalidateRect(handle, nullptr, true);
303 }
304
305 void BaseComponent::setTextColor(uint8_t red, uint8_t green, uint8_t blue)
306 {
307 textColor = RGB(red, green, blue);
308
309 InvalidateRect(handle, nullptr, true);
310 }
311
313 {
314 return parent;
315 }
316
318 {
319 return handle;
320 }
321
322 wstring_view BaseComponent::getWindowName() const
323 {
324 return windowName;
325 }
326
327 wstring_view BaseComponent::getClassName() const
328 {
329 return className;
330 }
331
333 {
334 return desiredWidth;
335 }
336
338 {
339 return desiredHeight;
340 }
341
343 {
344 RECT sizes;
345
346 GetClientRect(handle, &sizes);
347
348 return static_cast<uint16_t>(sizes.right - sizes.left);
349 }
350
352 {
353 RECT sizes;
354
355 GetClientRect(handle, &sizes);
356
357 return static_cast<uint16_t>(sizes.bottom - sizes.top);
358 }
359
361 {
362 RECT coordinates;
363
364 GetWindowRect(handle, &coordinates);
365
366 MapWindowPoints(HWND_DESKTOP, parent ? parent->getHandle() : HWND_DESKTOP, reinterpret_cast<POINT*>(&coordinates), 2);
367
368 return coordinates;
369 }
370
372 {
373 return desiredX;
374 }
375
377 {
378 return desiredY;
379 }
380
381 uint32_t BaseComponent::getId() const
382 {
383 return id;
384 }
385
387 {
388 return backgroundColor;
389 }
390
392 {
393 return textColor;
394 }
395
400
401 json::JSONBuilder BaseComponent::getStructure() const
402 {
403 using json::utility::jsonObject;
404 using json::utility::appendArray;
405
406 uint32_t codepage = ISerializable::getCodepage();
407 json::JSONBuilder builder(codepage);
408
409 jsonObject structure;
410 vector<jsonObject> backgroundColorJSON;
411 vector<jsonObject> textColorJSON;
412 vector<jsonObject> localizationKeys;
413 const interfaces::ITextOperations* textOperations = dynamic_cast<const interfaces::ITextOperations*>(this);
414
415 appendArray(static_cast<int64_t>(GetRValue(backgroundColor)), backgroundColorJSON);
416 appendArray(static_cast<int64_t>(GetGValue(backgroundColor)), backgroundColorJSON);
417 appendArray(static_cast<int64_t>(GetBValue(backgroundColor)), backgroundColorJSON);
418
419 appendArray(static_cast<int64_t>(GetRValue(textColor)), textColorJSON);
420 appendArray(static_cast<int64_t>(GetGValue(textColor)), textColorJSON);
421 appendArray(static_cast<int64_t>(GetBValue(textColor)), textColorJSON);
422
423 structure.data.push_back({ "className"s, utility::to_string(className, codepage) });
424
425 structure.data.push_back({ "hash"s, this->getHash() });
426
427 structure.data.push_back({ "desiredX"s, desiredX });
428 structure.data.push_back({ "desiredY"s, desiredY });
429
430 structure.data.push_back({ "desiredWidth"s, static_cast<uint64_t>(desiredWidth) });
431 structure.data.push_back({ "desiredHeight"s, static_cast<uint64_t>(desiredHeight) });
432
433 structure.data.push_back({ "backgroundColor"s, move(backgroundColorJSON) });
434 structure.data.push_back({ "textColor"s, move(textColorJSON) });
435
436 if (textOperations)
437 {
438 structure.data.push_back({ "text"s, utility::to_string(textOperations->getText(), codepage) });
439 }
440
441 structure.data.push_back({ "styles"s, styles->getStyles() });
442
443 structure.data.push_back({ "extendedStyles"s, styles->getExtendedStyles() });
444
445 if (const interfaces::ISingleTextLocalized* single = dynamic_cast<const interfaces::ISingleTextLocalized*>(this))
446 {
447 appendArray(single->getLocalizationKey(), localizationKeys);
448 }
449 else if (const interfaces::IMultipleTextLocalized* multiple = dynamic_cast<const interfaces::IMultipleTextLocalized*>(this))
450 {
451 for (const string& localizationKey : multiple->getLocalizationKeys())
452 {
453 appendArray(localizationKey, localizationKeys);
454 }
455 }
456
457 if (localizationKeys.size())
458 {
459 structure.data.push_back({ "localizationKeys"s, move(localizationKeys) });
460 }
461
462 builder.push_back(make_pair(utility::to_string(windowName, codepage), move(structure)));
463
464 return builder;
465 }
466
468 {
469 if (!this->destroyComponent())
470 {
471 this->asyncDestroyComponent();
472 }
473
474 try
475 {
476 GUIFramework::get().removeId(windowName, id);
477 }
478 catch (const exception&)
479 {
480
481 }
482
483 GUIFramework::get().removeComponent(this);
484 }
485}
std::unique_ptr< T > smartPointerType
Compatible smart pointer type.
Base class for all windows, controls, etc.
void setDesiredHeight(uint16_t desiredHeight)
std::wstring_view getWindowName() const
virtual void setLocalizationKeys(interfaces::ITextLocalized *localized, const std::vector< std::string > &localizationKeys)
Override for custom localization.
void setDesiredWidth(uint16_t desiredWidth)
virtual LRESULT windowMessagesHandle(HWND handle, UINT message, WPARAM wparam, LPARAM lparam, bool &isUsed)
const std::wstring className
virtual size_t getHash() const =0
Used as key in creators.
virtual json::JSONBuilder getStructure() const override
LRESULT handleMessages(HWND handle, UINT message, WPARAM wparam, LPARAM lparam, bool &isUsed)
virtual void setTextColor(uint8_t red, uint8_t green, uint8_t blue)
virtual LRESULT preWindowMessagesHandle(HWND handle, UINT message, WPARAM wparam, LPARAM lparam, bool &isUsed)
const std::wstring windowName
const smartPointerType< interfaces::IStyles > & getStyles() const
BaseComponent(std::wstring_view className, std::wstring_view windowName, const utility::ComponentSettings &settings, const interfaces::IStyles &styles, BaseComposite *parent=nullptr, std::string_view windowFunctionName="", std::string_view moduleName="", uint16_t smallIconResource=NULL, uint16_t largeIconResource=NULL)
static void runFunctionAsync(const std::function< void()> &callable, const std::function< void()> &callback=nullptr) noexcept
Add task to thread pool.
BaseComponent * getParent() const
COLORREF getBackgroundColor() const
virtual void setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue)
smartPointerType< interfaces::IStyles > styles
LRESULT sendRawMessage(UINT message, WPARAM wparam, LPARAM lparam)
SendMessage WinAPI wrapper.
std::wstring_view getClassName() const
Base class for all windows that has children windows.
Singleton with GUIFramework settings and some functionality.
const std::unordered_map< std::string, HMODULE, localization::utility::StringViewHash, localization::utility::StringViewEqual > & getModules() const
Get all loaded modules.
std::unique_ptr< threading::Future > addTask(const std::function< void()> &task, const std::function< void()> &callback=nullptr)
Add task to thread pool. Thread safe method.
static GUIFramework & get()
Singleton instance access.
Can't find CREATE_DEFAULT_WINDOW_FUNCTION macro for specific window.
Change localization of combo boxes, list views, tab controls, etc.
Provides resize, setBlockResize, getBlockResize methods.
virtual void resize(uint16_t width, uint16_t height)
Resize component.
Change localization of buttons, edit controls, etc.
Provides styles for other classes.
Definition IStyles.h:11
virtual LONG_PTR getStyles() const final
Definition IStyles.cpp:33
virtual LONG_PTR getExtendedStyles() const final
Definition IStyles.cpp:38
Provides changing localization in component by calling GUIFramework::changeLocalization.
Provides setText and getText methods.
virtual std::wstring getText() const final
Get text from control.
constexpr uint32_t initTopLevelWindowPointer
WPARAM contains BaseComposite*.
HMODULE getCurrentModule()
Get handle to current executable.
Definition Utility.cpp:119
smartPointerType< T > make_smart_pointer(Args &&... args)
Make function with current build configuration compatibility.
Definition Utility.h:96
string to_string(wstring_view stringToConvert, uint32_t codepage)
Definition Utility.cpp:41
std::vector< std::string > localizationKeys