107#pragma warning(disable: 6335)
112struct hash<set<uint32_t>>
114 size_t operator () (
const set<uint32_t>& data);
120 bool operator()(
const FILETIME& left,
const FILETIME& right)
const
122 return CompareFileTime(&left, &right) == -1;
126static set<uint32_t> makeHotkey(uint32_t key,
const vector<gui_framework::hotkeys::additionalKeys>& additionalKeys);
130 unique_ptr<GUIFramework> GUIFramework::instance =
nullptr;
133 key(static_cast<uint32_t>(-1))
140 hotkeyEvent(hotkeyEvent),
141 additionalKeys(additionalKeys)
148 functionName(functionName),
149 moduleName(moduleName),
150 additionalKeys(additionalKeys)
155 void GUIFramework::initCreators()
157 creators.reserve(25);
179#pragma region ProgressBars
185#pragma region ComboBoxes
193#pragma region ListBoxes
199#pragma region ListViews
213#pragma region Trackbars
220 void GUIFramework::initDeserializers()
222 deserializers.reserve(25);
244#pragma region ProgressBars
250#pragma region ComboBoxes
258#pragma region ListBoxes
264#pragma region ListViews
278#pragma region Trackbars
287 unique_lock<recursive_mutex> lock(componentsMutex);
289 components.push_back(component);
294 unique_lock<recursive_mutex> lock(componentsMutex);
296 erase(components, component);
299 uint32_t GUIFramework::generateId(wstring_view windowName)
301 unique_lock<mutex> lock(idMutex);
305 if (availableIds.size())
307 id = availableIds.front();
316 generatedIds.insert(make_pair(windowName,
id));
321 uint32_t GUIFramework::generateTrayId()
326 void GUIFramework::removeIds(
const wstring& windowName)
328 unique_lock<mutex> lock(idMutex);
330 if (!generatedIds.contains(windowName))
335 auto it = generatedIds.equal_range(windowName);
337 for_each(it.first, it.second, [
this](
const pair<wstring, uint32_t>& data) { availableIds.push(generatedIds.extract(data.first).mapped()); });
340 void GUIFramework::removeId(
const wstring& windowName, uint32_t
id)
342 unique_lock<mutex> lock(idMutex);
344 if (!generatedIds.contains(windowName))
349 auto it = generatedIds.equal_range(windowName);
351 for (; it.first != it.second; ++it.first)
353 if (it.first->second ==
id)
355 availableIds.push(generatedIds.extract(it.first).mapped());
362 vector<uint32_t> GUIFramework::getIds(
const wstring& windowName)
364 unique_lock<mutex> lock(idMutex);
366 auto resultIterator = generatedIds.equal_range(windowName);
367 vector<uint32_t> result;
369 if (resultIterator.first != generatedIds.end())
371 result.reserve(distance(resultIterator.first, resultIterator.second));
373 for_each(resultIterator.first, resultIterator.second, [&result](
const pair<wstring, uint32_t>& data) { result.push_back(data.second); });
379 void GUIFramework::processHotkeys()
const
381 static set<const set<uint32_t>*> possibleHotkeys;
382 static constexpr int keyDownBit = 1 << 16;
384 possibleHotkeys.clear();
386 ranges::for_each(allHotkeys, [](
const set<uint32_t>& keys) { possibleHotkeys.insert(&keys); });
388 for (
const auto& i : allHotkeys)
390 for (
const auto& j : i)
392 if (!(GetAsyncKeyState(j) & keyDownBit))
394 possibleHotkeys.erase(&i);
401 if (possibleHotkeys.size())
403 const set<uint32_t>& hotkey = **possibleHotkeys.begin();
405 hotkeys.at(hash<set<uint32_t>>()(hotkey))();
409 void GUIFramework::initUIThreadId()
411 HANDLE handle = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, NULL);
412 DWORD currentProcessId = GetCurrentProcessId();
413 map<FILETIME, DWORD> threadsCreationTime;
414 THREADENTRY32 threadEntry = {};
416 threadEntry.dwSize =
sizeof(threadEntry);
418 if (Thread32First(handle, &threadEntry))
422 if (threadEntry.th32OwnerProcessID == currentProcessId)
424 if (HANDLE threadHandle = OpenThread(THREAD_QUERY_INFORMATION,
false, threadEntry.th32ThreadID))
426 FILETIME creationTime;
431 if (GetThreadTimes(threadHandle, &creationTime, &exiteTime, &kernelTime, &userTime))
433 threadsCreationTime.emplace(move(creationTime), threadEntry.th32ThreadID);
437 }
while (Thread32Next(handle, &threadEntry));
442 if (threadsCreationTime.empty())
444 throw exceptions::CantGetUIThreadId(__FILE__, __FUNCTION__, __LINE__);
447 uiThreadId = threadsCreationTime.begin()->second;
450 void GUIFramework::loadModule(
const string& modulePath,
const string& moduleName)
454 if (modulePath.empty())
456 if (!filesystem::exists(moduleName))
458 throw exceptions::FileDoesNotExist(moduleName, __FILE__, __FUNCTION__, __LINE__);
463 if (!filesystem::exists(modulePath))
465 throw exceptions::FileDoesNotExist(modulePath, __FILE__, __FUNCTION__, __LINE__);
469 catch (
const exceptions::FileDoesNotExist& e)
471 unique_lock<mutex> lock(loadModulesMutex);
473 cantLoadedModules.push_back(e.what());
478 HMODULE module = LoadLibraryA
485 unique_lock<mutex> lock(loadModulesMutex);
491 if (modulePath.empty())
493 throw exceptions::CantLoadModuleException(moduleName, __FILE__, __FUNCTION__, __LINE__);
497 throw exceptions::CantLoadModuleException(modulePath, __FILE__, __FUNCTION__, __LINE__);
500 catch (
const exceptions::CantLoadModuleException& e)
502 cantLoadedModules.push_back(e.what());
507 modules[moduleName] =
module;
509 modulesPaths[moduleName] = modulePath.empty() ? moduleName : modulePath;
513 void GUIFramework::loadModulesFromSettings(
const json::utility::jsonObject& settingsObject)
517 modules.reserve(jsonModules.size());
519 for (
const json::utility::jsonObject& jsonModule : jsonModules)
521 const json::utility::jsonObject& moduleObject = std::get<json::utility::jsonObject>(jsonModule.data.front().second);
523 const string& modulePath = std::get<string>(ranges::find_if
526 [](
const pair<string, json::utility::jsonObject::variantType>& value) { return value.first == json_settings::pathToModuleSettings; }
530 unique_lock<mutex> lock(loadModulesMutex);
532 modules.emplace(moduleName,
nullptr);
534 modulesPaths.emplace(moduleName,
"");
537 asyncModulesHandles.push_back
541 bind(
static_cast<void(GUIFramework::*)(
const string&,
const string&)
>(&GUIFramework::loadModule),
this, modulePath, moduleName)
547 GUIFramework::GUIFramework() :
558 this->initUIThreadId();
564 if (threadsCount != -1)
568 threadPool = make_unique<threading::ThreadPool>(
static_cast<uint32_t
>(threadsCount));
572 threadPool = make_unique<threading::ThreadPool>();
576 catch (
const json::exceptions::CantFindValueException&)
581 InitCommonControlsEx(&comm);
584 modules.emplace(
"", GetModuleHandleW(
nullptr));
592 this->initCreators();
595 catch (
const json::exceptions::CantFindValueException&)
604 this->initDeserializers();
607 catch (
const json::exceptions::CantFindValueException&)
614 this->loadModulesFromSettings(settingsObject);
616 catch (
const json::exceptions::CantFindValueException&)
622 GUIFramework::~GUIFramework()
624 for (
auto& [name, module] : modules)
630 GUIFramework& GUIFramework::GUIFramework::get()
632 static mutex getInstanceMutex;
636 unique_lock<mutex> lock(getInstanceMutex);
638 instance.reset(
new GUIFramework());
647 unique_lock<recursive_mutex> runOnUIThreadLock(instance.runOnUIThreadMutex);
649 instance.runOnUIFunctions.push(function);
655 unique_lock<recursive_mutex> runOnUIThreadLock(instance.runOnUIThreadMutex);
657 instance.runOnUIFunctions.push(move(function));
663 wchar_t** argv =
nullptr;
664 wstring_view commandLine = GetCommandLineW();
665 STARTUPINFO startInfo = {};
666 PROCESS_INFORMATION processInfo = {};
668 startInfo.cb =
sizeof(startInfo);
670 argv = CommandLineToArgvW(commandLine.data(), &argc);
675 const_cast<wchar_t*
>(commandLine.data()),
699 string version =
"1.1.0";
704 unique_ptr<threading::Future>
GUIFramework::addTask(
const function<
void()>& task,
const function<
void()>& callback)
708 throw runtime_error(
"Can't find threadsCount setting in gui_framework.json");
711 return threadPool->addTask(task, callback);
714 unique_ptr<threading::Future>
GUIFramework::addTask(
const function<
void()>& task, function<
void()>&& callback)
718 throw runtime_error(
"Can't find threadsCount setting in gui_framework.json");
721 return threadPool->addTask(task, move(callback));
724 unique_ptr<threading::Future>
GUIFramework::addTask(function<
void()>&& task,
const function<
void()>& callback)
728 throw runtime_error(
"Can't find threadsCount setting in gui_framework.json");
731 return threadPool->addTask(move(task), callback);
734 unique_ptr<threading::Future>
GUIFramework::addTask(function<
void()>&& task, function<
void()>&& callback)
738 throw runtime_error(
"Can't find threadsCount setting in gui_framework.json");
741 return threadPool->addTask(move(task), move(callback));
746 set<uint32_t> hotkey = makeHotkey(key, additionalKeys);
747 size_t id = hash<set<uint32_t>>()(hotkey);
749 unique_lock<mutex> lock(hotkeyIdMutex);
751 hotkeys[id] = onClick;
753 allHotkeys.push_back(move(hotkey));
755 serializableHotkeysData[id] = hotkeyData(key, onClick, additionalKeys);
765 unique_lock<mutex> lock(loadModulesMutex);
767 const HMODULE& module = this->
getModules().at(moduleName);
769 tem =
reinterpret_cast<onClickSignature>(GetProcAddress(module, functionName.data()));
773 throw exceptions::CantFindFunctionFromModuleException(functionName, moduleName, __FILE__, __FUNCTION__, __LINE__);
780 unique_lock<mutex> lock(hotkeyIdMutex);
782 serializableHotkeysData[id].functionName = functionName;
783 serializableHotkeysData[id].moduleName = moduleName;
791 unique_lock<mutex> lock(hotkeyIdMutex);
793 auto it = hotkeys.find(hotkeyId);
795 if (it != hotkeys.end())
797 set<uint32_t> hotkey = makeHotkey(serializableHotkeysData[hotkeyId].key, serializableHotkeysData[hotkeyId].additionalKeys);
801 erase(allHotkeys, hotkey);
803 serializableHotkeysData.erase(hotkeyId);
813 unique_lock<mutex> lock(hotkeyIdMutex);
815 set<uint32_t> hotkey = makeHotkey(key, additionalKeys);
816 size_t hotkeyId = hash<set<uint32_t>>()(hotkey);
817 auto it = hotkeys.find(hotkeyId);
819 if (it != hotkeys.end())
823 erase(allHotkeys, hotkey);
825 serializableHotkeysData.erase(hotkeyId);
835 vector<hotkeyData> result;
837 result.reserve(serializableHotkeysData.size());
839 unique_lock<mutex> lock(hotkeyIdMutex);
841 for (
const auto& [key, value] : serializableHotkeysData)
843 result.emplace_back(value);
849 void GUIFramework::loadModule(
const string& moduleName,
const filesystem::path& pathToModule)
851 if (!filesystem::exists(pathToModule))
856 HMODULE module = LoadLibraryA(pathToModule.string().data());
860 throw exceptions::CantLoadModuleException(moduleName, __FILE__, __FUNCTION__, __LINE__);
863 modules.emplace(moduleName, module);
868 auto it = modules.find(moduleName);
870 if (it == modules.end())
875 FreeLibrary(it->second);
882 return ranges::find(components, component) != components.end();
887 using json::utility::jsonObject;
889 unique_lock<mutex> lock(hotkeyIdMutex);
890 vector<jsonObject> result;
892 for (
const auto& [key, value] : serializableHotkeysData)
894 if (value.functionName.size())
898 object.data.push_back({
"key"s,
static_cast<uint64_t
>(value.key) });
899 object.data.push_back({
"functionName"s, value.functionName });
900 object.data.push_back({
"moduleName"s, value.moduleName });
901 object.data.push_back({
"pathToModule"s, modulesPaths.at(value.moduleName) });
903 if (value.additionalKeys.size())
905 vector<jsonObject> additionalKeys;
907 additionalKeys.reserve(value.additionalKeys.size());
909 ranges::for_each(value.additionalKeys, [&additionalKeys](
const hotkeys::additionalKeys& key) { json::utility::appendArray(static_cast<int64_t>(key), additionalKeys); });
911 object.data.push_back({
"additionalKeys"s, move(additionalKeys) });
914 json::utility::appendArray(move(
object), result);
923 using json::utility::jsonObject;
925 const auto& jsonHotkeys = description.getArray(
"hotkeys");
927 for (
const auto& i : jsonHotkeys)
929 const jsonObject& hotkey = std::get<jsonObject>(i.data.front().second);
932 const string& functionName = hotkey.getString(
"functionName");
933 const string& moduleName = hotkey.getString(
"moduleName");
934 vector<uint64_t> tem = json::utility::JSONArrayWrapper(hotkey.getArray(
"additionalKeys")).getAsUInt64_tArray();
935 vector<hotkeys::additionalKeys> additionalKeys;
937 ranges::for_each(tem, [&additionalKeys](uint64_t additionalKey) { additionalKeys.push_back(
static_cast<hotkeys::additionalKeys>(additionalKey)); });
939 this->
registerHotkey(key, functionName, moduleName, additionalKeys);
952 localization::TextLocalization::get().changeLanguage(language);
953 localization::WTextLocalization::get().changeLanguage(language);
955 for (
const auto& component : components)
959 localizable->updateLocalizationEvent();
971 return deserializers;
979 const unordered_map<string, HMODULE, localization::utility::StringViewHash, localization::utility::StringViewEqual>&
GUIFramework::getModules()
const
991 unique_lock<mutex> lock(loadModulesMutex);
993 return cantLoadedModules;
998 return modules.at(moduleName);
1002size_t hash<set<uint32_t>>::operator () (
const set<uint32_t>& data)
1011 for (
const auto& i : data)
1013 result = 31 * result + i;
1019set<uint32_t> makeHotkey(uint32_t key,
const vector<gui_framework::hotkeys::additionalKeys>& additionalKeys)
1021 set<uint32_t> hotkey;
Base class for all windows, controls, etc.
const std::unordered_map< std::string, std::string > & getModulesPaths() const
Get all loaded modules paths.
std::vector< std::string > getCantLoadedModules()
List of all exceptions in load modules process.
void changeLocalization(const std::string &language) const
Change localization for all components.
void unloadModule(const std::string &moduleName)
Unload module.
size_t registerHotkey(hotkeys::keys key, const std::function< void()> &onClick, const std::vector< hotkeys::additionalKeys > &additionalKeys={})
Only works in thread, that call runMainLoop from WindowHolder. Thread safe register hotkey.
std::vector< json::utility::jsonObject > serializeHotkeys()
Serialize hotkeys.
void deserializeHotkeys(const json::utility::jsonObject &description)
Deserialize hotkeys.
const std::unordered_map< std::string, HMODULE, localization::utility::StringViewHash, localization::utility::StringViewEqual > & getModules() const
Get all loaded modules.
void addCreator(Args &&... args)
Add derived from BaseComponentCreator creator.
std::vector< hotkeyData > getRegisteredHotkeys()
Thread safe get hotkeys.
static void runOnUIThread(const std::function< void()> &function)
Run function in UI thread. Functions processed only when window in main UI thread has focus.
bool isExist(BaseComponent *component)
Check if component created. If component destroyed after you call findComponent, you may have not val...
const std::unordered_map< size_t, smartPointerType< utility::BaseComponentCreator > > & getCreators() const
Get all current registered creators.
HMODULE operator[](const std::string &moduleName) const
Get handle to specific module.
const json::JSONParser & getJSONSettings() const
Get settings from gui_framework.json.
const std::unordered_map< size_t, smartPointerType< interfaces::IDeserializer > > & getDeserializers() const
Get all current registered deserializers.
static DWORD getUIThreadId()
Getter for UI thread id.
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 std::string getGUIFrameworkVersion()
Get current GUIFramework version.
static GUIFramework & get()
Singleton instance access.
friend class BaseComponent
static void restartApplication(int exitCode=0)
Restart application with given exit code.
bool unregisterHotkey(size_t hotkeyId)
Thread safe unregister hotkey.
void addDeserializer(Args &&... args)
Add derived from IDeserializer deserializer.
bool isModulesLoaded() const
Check if modules are loaded. You can call getCantLoadedModules() to check if loaded modules have fail...
Throws by asset finding methods.
Exception that receive error code from GetLastError function.
Provides changing localization in component by calling GUIFramework::changeLocalization.
virtual bool getAutoUpdate() const final
constexpr uint32_t startTrayId
Used by GUIFramework and BaseMainWindow internally.
const std::string modulesSetting
const std::string usingDeserializersSetting
const std::string settingsObject
const std::string moduleNameSetting
constexpr std::string_view settingsJSONFile
const std::string usingCreatorsSetting
const std::string threadsCountSetting
constexpr std::wstring_view msftEditLibrary
void(*)() onClickSignature
Default on click signature.
bool operator()(const FILETIME &left, const FILETIME &right) const