From 5db158a98820cc5880396e9c418b620dc419f5e6 Mon Sep 17 00:00:00 2001 From: Michal_Marszalek <1aam2am1@gmail.com> Date: Sun, 12 Jan 2020 13:48:41 +0100 Subject: [PATCH] Changed method of storing names of widgets Fixed adding the same widget to multiple containers Added possibility to connect signals before creating widget Update .gitignore Now UserData property will be saved as string if possible --- .gitignore | 3 + .../WidgetProperties/WidgetProperties.hpp | 11 + gui-builder/src/Form.cpp | 5 +- gui-builder/src/GuiBuilder.cpp | 2 +- include/TGUI/Container.hpp | 25 +- include/TGUI/Gui.hpp | 14 +- include/TGUI/SignalManager.hpp | 208 ++++++++++++++++ include/TGUI/SignalManagerImpl.hpp | 121 ++++++++++ include/TGUI/String.hpp | 2 +- include/TGUI/TGUI.hpp | 1 + include/TGUI/Widget.hpp | 21 +- src/TGUI/CMakeLists.txt | 1 + src/TGUI/Container.cpp | 33 ++- src/TGUI/Gui.cpp | 19 +- src/TGUI/Layout.cpp | 6 +- src/TGUI/SignalManager.cpp | 223 ++++++++++++++++++ src/TGUI/String.cpp | 2 +- src/TGUI/Widget.cpp | 122 +++++++++- src/TGUI/Widgets/BoxLayout.cpp | 2 - src/TGUI/Widgets/MessageBox.cpp | 2 +- tests/CMakeLists.txt | 1 + tests/Container.cpp | 58 ++--- tests/SignalManager.cpp | 115 +++++++++ tests/Widget.cpp | 9 + tests/Widgets/ComboBox.cpp | 8 + tests/Widgets/HorizontalLayout.cpp | 16 +- tests/Widgets/Label.cpp | 4 + tests/Widgets/VerticalLayout.cpp | 16 +- 28 files changed, 934 insertions(+), 116 deletions(-) create mode 100644 include/TGUI/SignalManager.hpp create mode 100644 include/TGUI/SignalManagerImpl.hpp create mode 100644 src/TGUI/SignalManager.cpp create mode 100644 tests/SignalManager.cpp diff --git a/.gitignore b/.gitignore index f39d4a064..d51a71ddd 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,6 @@ CmakeSettings.json CombinedSources*.cpp .DS_Store *~ +/cmake-build-debug +/cmake-build-release +/.idea \ No newline at end of file diff --git a/gui-builder/include/WidgetProperties/WidgetProperties.hpp b/gui-builder/include/WidgetProperties/WidgetProperties.hpp index 4b3b6ebf5..a415b5b26 100644 --- a/gui-builder/include/WidgetProperties/WidgetProperties.hpp +++ b/gui-builder/include/WidgetProperties/WidgetProperties.hpp @@ -54,6 +54,8 @@ struct WidgetProperties widget->setVisible(parseBoolean(value, true)); else if (property == "Enabled") widget->setEnabled(parseBoolean(value, true)); + else if (property == "UserData") + widget->setUserData(value.toAnsiString()); else // Renderer property widget->getRenderer()->setProperty(property, value); } @@ -67,6 +69,15 @@ struct WidgetProperties pairs["Height"] = {"String", widget->getSizeLayout().y.toString()}; pairs["Visible"] = {"Bool", tgui::Serializer::serialize(widget->isVisible())}; pairs["Enabled"] = {"Bool", tgui::Serializer::serialize(widget->isEnabled())}; + try + { + pairs["UserData"] = {"String", widget->getUserData()}; + } + catch(const std::bad_cast&) + { + pairs["UserData"] = {"String", ""}; + } + PropertyValueMap rendererPairs; const auto renderer = widget->getSharedRenderer(); diff --git a/gui-builder/src/Form.cpp b/gui-builder/src/Form.cpp index a552a27a5..7637598b7 100644 --- a/gui-builder/src/Form.cpp +++ b/gui-builder/src/Form.cpp @@ -220,7 +220,7 @@ bool Form::setSelectedWidgetName(const std::string& name) } } - m_selectedWidget->ptr->getParent()->setWidgetName(m_selectedWidget->ptr, name); + m_selectedWidget->ptr->Widget::setWidgetName(name); m_selectedWidget->name = name; return true; } @@ -575,12 +575,11 @@ void Form::drawExtra(sf::RenderWindow& window) const void Form::importLoadedWidgets(tgui::Container::Ptr parent) { const auto& widgets = parent->getWidgets(); - const auto& widgetNames = parent->getWidgetNames(); for (std::size_t i = 0; i < widgets.size(); ++i) { const std::string id = tgui::to_string(widgets[i].get()); m_widgets[id] = std::make_shared(widgets[i]); - m_widgets[id]->name = widgetNames[i]; + m_widgets[id]->name = widgets[i]->getWidgetName(); m_widgets[id]->theme = "Custom"; if (widgets[i]->isContainer()) diff --git a/gui-builder/src/GuiBuilder.cpp b/gui-builder/src/GuiBuilder.cpp index 8f2cd4b98..b949bd9f0 100644 --- a/gui-builder/src/GuiBuilder.cpp +++ b/gui-builder/src/GuiBuilder.cpp @@ -2218,7 +2218,7 @@ void GuiBuilder::fillWidgetHierarchyTreeRecursively(std::vector& hie const size_t widgetCount = asContainer->getWidgets().size(); for (size_t i = 0; i < widgetCount; ++i) { - hierarchy.push_back(asContainer->getWidgetNames()[i]); + hierarchy.push_back(asContainer->getWidgets()[i]->getWidgetName()); fillWidgetHierarchyTreeRecursively(hierarchy, asContainer->getWidgets()[i]); hierarchy.pop_back(); } diff --git a/include/TGUI/Container.hpp b/include/TGUI/Container.hpp index a3686dd80..99cb048a9 100644 --- a/include/TGUI/Container.hpp +++ b/include/TGUI/Container.hpp @@ -107,18 +107,26 @@ namespace tgui return m_widgets; } - +#ifndef TGUI_REMOVE_DEPRECATED_CODE ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Returns a list of the names of all the widgets in this container /// /// @return Vector of all widget names /// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - const std::vector& getWidgetNames() const + TGUI_DEPRECATED("Use getWidgets() and Widget::getWidgetName instead") const std::vector getWidgetNames() const { + std::vector m_widgetNames; + m_widgetNames.reserve(m_widgets.size()); + + for (std::size_t i = 0; i < m_widgets.size(); ++i) + { + m_widgetNames.emplace_back(m_widgets[i]->getWidgetName()); + } + return m_widgetNames; } - +#endif ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Adds a widget to the container @@ -186,7 +194,7 @@ namespace tgui ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// virtual void removeAllWidgets(); - +#ifndef TGUI_REMOVE_DEPRECATED_CODE ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Changes the name of a widget /// @@ -196,7 +204,7 @@ namespace tgui /// @return True when the name was changed, false when the widget wasn't part of this container. /// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool setWidgetName(const Widget::Ptr& widget, const std::string& name); + TGUI_DEPRECATED("Use Widget::setWidgetName instead") bool setWidgetName(const Widget::Ptr& widget, const std::string& name); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -204,11 +212,11 @@ namespace tgui /// /// @param widget Widget of which the name should be retrieved /// - /// @return Name of the widget or an empty string when the widget didn't exist or wasn't given a name + /// @return Name of the widget or an empty string when the widget wasn't part of this container or wasn't given a name /// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::string getWidgetName(const Widget::ConstPtr& widget) const; - + TGUI_DEPRECATED("Use Widget::getWidgetName instead") std::string getWidgetName(const Widget::ConstPtr& widget) const; +#endif ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Unchecks all the radio buttons @@ -465,7 +473,6 @@ namespace tgui protected: std::vector m_widgets; - std::vector m_widgetNames; Widget::Ptr m_widgetBelowMouse; Widget::Ptr m_focusedWidget; diff --git a/include/TGUI/Gui.hpp b/include/TGUI/Gui.hpp index b8af8c0f7..cd0ed677d 100644 --- a/include/TGUI/Gui.hpp +++ b/include/TGUI/Gui.hpp @@ -217,15 +217,15 @@ namespace tgui ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// const std::vector& getWidgets() const; - +#ifndef TGUI_REMOVE_DEPRECATED_CODE ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Returns a list of the names of all the widgets /// /// @return Vector of all widget names /// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - const std::vector& getWidgetNames() const; - + TGUI_DEPRECATED("Use getWidgets() and Widget::getWidgetName instead") const std::vector getWidgetNames() const; +#endif ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Adds a widget to the container @@ -291,7 +291,7 @@ namespace tgui ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void removeAllWidgets(); - +#ifndef TGUI_REMOVE_DEPRECATED_CODE ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Changes the name of a widget /// @@ -301,7 +301,7 @@ namespace tgui /// @return True when the name was changed, false when the widget wasn't part of this container /// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - bool setWidgetName(const Widget::Ptr& widget, const std::string& name); + TGUI_DEPRECATED("Use Widget::setWidgetName instead") bool setWidgetName(const Widget::Ptr& widget, const std::string& name); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -312,8 +312,8 @@ namespace tgui /// @return Name of the widget or an empty string when the widget didn't exist or wasn't given a name /// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - std::string getWidgetName(const Widget::Ptr& widget) const; - + TGUI_DEPRECATED("Use Widget::getWidgetName instead") std::string getWidgetName(const Widget::Ptr& widget) const; +#endif ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Focuses the next widget diff --git a/include/TGUI/SignalManager.hpp b/include/TGUI/SignalManager.hpp new file mode 100644 index 000000000..35354bba6 --- /dev/null +++ b/include/TGUI/SignalManager.hpp @@ -0,0 +1,208 @@ +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// TGUI - Texus' Graphical User Interface +// Copyright (C) 2012-2019 Bruno Van de Velde (vdv_b@tgui.eu) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +#ifndef TGUI_SIGNAL_MANAGER_HPP +#define TGUI_SIGNAL_MANAGER_HPP + + +#include +#include + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace tgui { + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + class TGUI_API SignalManager { + public: + + typedef std::shared_ptr Ptr; ///< Shared widget pointer + typedef std::shared_ptr ConstPtr; ///< Shared constant widget pointer + + using Delegate = std::function; + using DelegateEx = std::function, const std::string&)>; + + typedef std::weak_ptr Weak; + typedef unsigned int SignalID; + typedef struct{std::string m_widgetName; std::string m_signalName; std::pair m_func;} SignalTuple; + typedef struct{SignalID m_signalId; Weak m_widget; unsigned int m_signalWidgetID;} ConnectedSignalTuple; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Default constructor + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + SignalManager(); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Destructor + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual ~SignalManager(); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Sets Signal Manager that will be used to operate a signal + /// + /// @param manager Manager that will be used to operate ours signals connected by loadWidgetsFromFile + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + static void setDefaultSignalManager(const SignalManager::Ptr& manager); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Retrieves Signal Manager that will be used to operate a signal + /// + /// @return Signal Manager used to operate the signals + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + static SignalManager::Ptr getSignalManager(); + +#if defined(__cpp_if_constexpr) && (__cpp_if_constexpr >= 201606L) + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Connects a signal handler that will be called when this signal is emitted + /// + /// @param widgetName Name of the widget to connect to + /// @param signalName Name of the signal + /// @param handler Callback function that is given the extra arguments provided to this function as arguments + /// @param args Optional extra arguments to pass to the signal handler when the signal is emitted + /// + /// @return Unique id of the connection + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + template + unsigned int connect(std::string widgetName, std::string signalName, Func&& handler, const BoundArgs&... args); + +#else + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Connects a signal handler that will be called when this signal is emitted + /// + /// @param widgetName Name of the widget to connect to + /// @param signalName Name of the signal + /// @param handler Callback function that is given the extra arguments provided to this function as arguments + /// @param args Optional extra arguments to pass to the signal handler when the signal is emitted + /// + /// @return Unique id of the connection + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + template >::value>::type* = nullptr> + unsigned int connect(std::string widgetName, std::string signalName, Func&& handler, const Args&... args); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Connects a signal handler that will be called when this signal is emitted + /// + /// @param widgetName Name of the widget to connect to + /// @param signalName Name of the signal + /// @param handler Callback function that is given a pointer to the widget, the name of the signal and the extra + /// arguments provided to this function as arguments + /// @param args Optional extra arguments to pass to the signal handler when the signal is emitted + /// + /// @return Unique id of the connection + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + template >::value // Ambigious otherwise when passing bind expression + && std::is_convertible, const std::string&)>>::value>::type* = nullptr> + unsigned int connect(std::string widgetName, std::string signalName, Func&& handler, BoundArgs&&... args); +#endif + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Connect a signal handler to multiple signals + /// + /// @param widgetName Name of the widget to connect to + /// @param signalNames List of signal names that will trigger the signal handler + /// @param handler Callback function + /// @param args Optional extra arguments to pass to the signal handler when the signal is emitted + /// + /// @return Unique id of the last connection. When passing e.g. 2 signal names, the first signal will correspond to id-1. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + template + unsigned int connect(std::string widgetName, std::initializer_list signalNames, Func&& handler, BoundArgs&&... args); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Disconnect a signal handler + /// + /// @param id Unique id of the connection returned by the connect function + /// + /// @return True when a connection with this id existed and was removed + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual bool disconnect(unsigned int id); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Disconnect all signal handler + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void disconnectAll(); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @internal + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void add(const Widget::Ptr& widgetPtr); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @internal + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void remove(Widget* widget); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + private: + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @internal + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + unsigned int generateUniqueId(); + + unsigned int m_lastId; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + protected: + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @internal + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + std::pair makeSignal(const Delegate&); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @internal + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + std::pair makeSignal(const DelegateEx&); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Function that is called each time new signal is created with it id + /// + /// @param id Id of new signal + /// + /// @internal + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void connect(SignalID id); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + static SignalManager::Ptr m_manager; + + std::vector m_widgets; + std::map m_signals; + std::vector m_connectedSignals; + }; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#endif //TGUI_SIGNAL_MANAGER_HPP diff --git a/include/TGUI/SignalManagerImpl.hpp b/include/TGUI/SignalManagerImpl.hpp new file mode 100644 index 000000000..533b3b50e --- /dev/null +++ b/include/TGUI/SignalManagerImpl.hpp @@ -0,0 +1,121 @@ +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// TGUI - Texus' Graphical User Interface +// Copyright (C) 2012-2019 Bruno Van de Velde (vdv_b@tgui.eu) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +#ifndef TGUI_SIGNALMANAGERIMPL_HPP +#define TGUI_SIGNALMANAGERIMPL_HPP + +#include +#include + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace tgui{ + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if defined(__cpp_if_constexpr) && (__cpp_if_constexpr >= 201606L) + template + unsigned int SignalManager::connect(std::string widgetName, std::string signalName, Func&& handler, const BoundArgs&... args) + { + const unsigned int id = generateUniqueId(); + + if constexpr (std::is_convertible_v> + && std::is_invocable_v + && !std::is_function_v) + { + // Reference to function, all parameters bound + m_signals[id] = {widgetName, signalName, makeSignal([=, f=std::function(handler)]{ std::invoke(f, args...); })}; + } + else if constexpr (std::is_convertible_v>) + { + // Function with all parameters bound + m_signals[id] = {widgetName, signalName, makeSignal([=]{ std::invoke(handler, args...); })}; + } + else if constexpr (std::is_convertible_v&, const std::string&)>> + && std::is_invocable_v&, const std::string&> + && !std::is_function_v) + { + // Reference to function with caller arguments, all parameters bound + m_signals[id] = {widgetName, signalName, makeSignal([=, f=std::function& w, const std::string& s)>(handler)](const std::shared_ptr& w, const std::string& s){ std::invoke(f, args..., w, s); })}; + } + else if constexpr (std::is_convertible_v&, const std::string&)>>) + { + // Function with caller arguments, all parameters bound + m_signals[id] = {widgetName, signalName, makeSignal([=](const std::shared_ptr& w, const std::string& s){ std::invoke(handler, args..., w, s); })}; + } + else + { + // Function with unbound arguments + using binder = internal_signal::func_traits, BoundArgs...>; + m_signals[id] = {widgetName, signalName, makeSignal(binder::bind(signal, std::forward(handler), args...))}; + } + + connect(id); + return id; + } + +#else + template >::value>::type*> + unsigned int SignalManager::connect(std::string widgetName, std::string signalName, Func&& handler, const Args&... args) + { + const unsigned int id = generateUniqueId(); + m_signals[id] = {widgetName, signalName, makeSignal([f=std::function(handler),args...](){ f(args...); })}; + + connect(id); + return id; + } + + template >::value // Ambigious otherwise when passing bind expression + && std::is_convertible, const std::string&)>>::value>::type*> + unsigned int SignalManager::connect(std::string widgetName, std::string signalName, Func&& handler, BoundArgs&&... args) + { + const unsigned int id = generateUniqueId(); + m_signals[id] = {widgetName, signalName, makeSignal( + [f=std::function&, const std::string&)>(handler), args...] + (const std::shared_ptr& w, const std::string& s) + { f(args..., w, s); } + )}; + + connect(id); + return id; + } +#endif + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + template + unsigned int SignalManager::connect(std::string widgetName, std::initializer_list signalNames, Func&& handler, BoundArgs&&... args) + { + unsigned int lastId = 0; + for (auto& signalName : signalNames) + lastId = connect(widgetName, signalName, handler, args...); + + return lastId; + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#endif //TGUI_SIGNALMANAGERIMPL_HPP diff --git a/include/TGUI/String.hpp b/include/TGUI/String.hpp index ec3ca0c6a..a803ede19 100644 --- a/include/TGUI/String.hpp +++ b/include/TGUI/String.hpp @@ -47,7 +47,7 @@ namespace tgui /// @brief Checks if a character is a whitespace character (space, tab, carriage return or line feed) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #ifdef TGUI_NEXT - TGUI_API bool isWhitespace(char32_t character); + TGUI_API bool isWhitespace(uint32_t character); #else TGUI_API bool isWhitespace(sf::Uint32 character); #endif diff --git a/include/TGUI/TGUI.hpp b/include/TGUI/TGUI.hpp index 768a6ff56..3bdb5c1f3 100644 --- a/include/TGUI/TGUI.hpp +++ b/include/TGUI/TGUI.hpp @@ -74,6 +74,7 @@ #include #include +#include #include #ifdef SFML_SYSTEM_IOS diff --git a/include/TGUI/Widget.hpp b/include/TGUI/Widget.hpp index 70bb00511..db123ca39 100644 --- a/include/TGUI/Widget.hpp +++ b/include/TGUI/Widget.hpp @@ -428,7 +428,7 @@ namespace tgui /// /// Examples: /// @code - /// widget->setUserData("Data"); + /// widget->setUserData("Data"); // Note: type to retrieve with getUserData is 'const char*' here /// widget->setUserData(5); /// @endcode ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -505,6 +505,24 @@ namespace tgui Widget::Ptr getToolTip() const; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Changes the name of a widget + /// + /// @param name New name for the widget + /// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void setWidgetName(const std::string& name); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Returns the name of a widget + /// + /// @return Name of the widget or an empty string when wasn't given a name + /// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + std::string getWidgetName() const; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Changes whether a widget could be focused /// @@ -829,6 +847,7 @@ namespace tgui protected: std::string m_type; + std::string m_name; Layout2d m_position; Layout2d m_size; diff --git a/src/TGUI/CMakeLists.txt b/src/TGUI/CMakeLists.txt index ed845e84e..88a8f4a06 100644 --- a/src/TGUI/CMakeLists.txt +++ b/src/TGUI/CMakeLists.txt @@ -13,6 +13,7 @@ set(TGUI_SRC Sprite.cpp Signal.cpp String.cpp + SignalManager.cpp SvgImage.cpp TextStyle.cpp Text.cpp diff --git a/src/TGUI/Container.cpp b/src/TGUI/Container.cpp index 148bdf9f3..65c1ba380 100644 --- a/src/TGUI/Container.cpp +++ b/src/TGUI/Container.cpp @@ -112,7 +112,7 @@ namespace tgui { // Copy all the widgets for (std::size_t i = 0; i < other.m_widgets.size(); ++i) - add(other.m_widgets[i]->clone(), other.m_widgetNames[i]); + add(other.m_widgets[i]->clone(), other.m_widgets[i]->getWidgetName()); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -120,7 +120,6 @@ namespace tgui Container::Container(Container&& other) : Widget {std::move(other)}, m_widgets {std::move(other.m_widgets)}, - m_widgetNames {std::move(other.m_widgetNames)}, m_widgetBelowMouse {std::move(other.m_widgetBelowMouse)}, m_focusedWidget {std::move(other.m_focusedWidget)}, m_handingMouseReleased{std::move(other.m_handingMouseReleased)} @@ -161,7 +160,7 @@ namespace tgui for (std::size_t i = 0; i < right.m_widgets.size(); ++i) { // Don't allow the 'add' function of a derived class to be called, since its members are not copied yet - Container::add(right.m_widgets[i]->clone(), right.m_widgetNames[i]); + Container::add(right.m_widgets[i]->clone(), right.m_widgets[i]->getWidgetName()); } } @@ -177,7 +176,6 @@ namespace tgui { Widget::operator=(std::move(right)); m_widgets = std::move(right.m_widgets); - m_widgetNames = std::move(right.m_widgetNames); m_widgetBelowMouse = std::move(right.m_widgetBelowMouse); m_focusedWidget = std::move(right.m_focusedWidget); m_handingMouseReleased = std::move(right.m_handingMouseReleased); @@ -218,9 +216,13 @@ namespace tgui { assert(widgetPtr != nullptr); + if(widgetPtr->getParent()) + { + widgetPtr->getParent()->remove(widgetPtr); + } widgetPtr->setParent(this); m_widgets.push_back(widgetPtr); - m_widgetNames.push_back(widgetName); + widgetPtr->setWidgetName(widgetName); if (m_fontCached != getGlobalFont()) widgetPtr->setInheritedFont(m_fontCached); @@ -233,13 +235,13 @@ namespace tgui Widget::Ptr Container::get(const sf::String& widgetName) const { - for (std::size_t i = 0; i < m_widgetNames.size(); ++i) + for (std::size_t i = 0; i < m_widgets.size(); ++i) { - if (m_widgetNames[i] == widgetName) + if (m_widgets[i]->getWidgetName() == widgetName) return m_widgets[i]; } - for (std::size_t i = 0; i < m_widgetNames.size(); ++i) + for (std::size_t i = 0; i < m_widgets.size(); ++i) { if (m_widgets[i]->isContainer()) { @@ -277,7 +279,6 @@ namespace tgui // Remove the widget widget->setParent(nullptr); m_widgets.erase(m_widgets.begin() + i); - m_widgetNames.erase(m_widgetNames.begin() + i); return true; } } @@ -293,21 +294,20 @@ namespace tgui widget->setParent(nullptr); m_widgets.clear(); - m_widgetNames.clear(); m_widgetBelowMouse = nullptr; m_focusedWidget = nullptr; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - +#ifndef TGUI_REMOVE_DEPRECATED_CODE bool Container::setWidgetName(const Widget::Ptr& widget, const std::string& name) { for (std::size_t i = 0; i < m_widgets.size(); ++i) { if (m_widgets[i] == widget) { - m_widgetNames[i] = name; + m_widgets[i]->setWidgetName(name); return true; } } @@ -322,12 +322,12 @@ namespace tgui for (std::size_t i = 0; i < m_widgets.size(); ++i) { if (m_widgets[i] == widget) - return m_widgetNames[i]; + return m_widgets[i]->getWidgetName(); } return ""; } - +#endif ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Container::uncheckRadioButtons() @@ -470,11 +470,9 @@ namespace tgui // Copy the widget m_widgets.push_back(m_widgets[i]); - m_widgetNames.push_back(m_widgetNames[i]); // Remove the old widget m_widgets.erase(m_widgets.begin() + i); - m_widgetNames.erase(m_widgetNames.begin() + i); break; } } @@ -491,13 +489,10 @@ namespace tgui // Copy the widget const Widget::Ptr obj = m_widgets[i]; - const std::string name = m_widgetNames[i]; m_widgets.insert(m_widgets.begin(), obj); - m_widgetNames.insert(m_widgetNames.begin(), name); // Remove the old widget m_widgets.erase(m_widgets.begin() + i + 1); - m_widgetNames.erase(m_widgetNames.begin() + i + 1); break; } } diff --git a/src/TGUI/Gui.cpp b/src/TGUI/Gui.cpp index e947bc4bd..5d4e876d7 100644 --- a/src/TGUI/Gui.cpp +++ b/src/TGUI/Gui.cpp @@ -330,12 +330,15 @@ namespace tgui } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - const std::vector& Gui::getWidgetNames() const +#ifndef TGUI_REMOVE_DEPRECATED_CODE + const std::vector Gui::getWidgetNames() const { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" return m_container->getWidgetNames(); +#pragma GCC diagnostic pop } - +#endif ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Gui::add(const Widget::Ptr& widgetPtr, const sf::String& widgetName) @@ -365,19 +368,25 @@ namespace tgui } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - +#ifndef TGUI_REMOVE_DEPRECATED_CODE bool Gui::setWidgetName(const Widget::Ptr& widget, const std::string& name) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" return m_container->setWidgetName(widget, name); +#pragma GCC diagnostic pop } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// std::string Gui::getWidgetName(const Widget::Ptr& widget) const { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" return m_container->getWidgetName(widget); +#pragma GCC diagnostic pop } - +#endif ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Gui::focusNextWidget() diff --git a/src/TGUI/Layout.cpp b/src/TGUI/Layout.cpp index 1410699c2..3b7c3f9e5 100644 --- a/src/TGUI/Layout.cpp +++ b/src/TGUI/Layout.cpp @@ -733,10 +733,9 @@ namespace tgui if (container != nullptr) { const auto& widgets = container->getWidgets(); - const auto& widgetNames = container->getWidgetNames(); for (std::size_t i = 0; i < widgets.size(); ++i) { - if (toLower(widgetNames[i]) == widgetName) + if (toLower(widgets[i]->getWidgetName()) == widgetName) return parseBindingString(expression.substr(dotPos+1), widgets[i].get(), xAxis); } } @@ -745,10 +744,9 @@ namespace tgui if (widget->getParent()) { const auto& widgets = widget->getParent()->getWidgets(); - const auto& widgetNames = widget->getParent()->getWidgetNames(); for (std::size_t i = 0; i < widgets.size(); ++i) { - if (toLower(widgetNames[i]) == widgetName) + if (toLower(widgets[i]->getWidgetName()) == widgetName) return parseBindingString(expression.substr(dotPos+1), widgets[i].get(), xAxis); } } diff --git a/src/TGUI/SignalManager.cpp b/src/TGUI/SignalManager.cpp new file mode 100644 index 000000000..edce27c61 --- /dev/null +++ b/src/TGUI/SignalManager.cpp @@ -0,0 +1,223 @@ +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// TGUI - Texus' Graphical User Interface +// Copyright (C) 2012-2019 Bruno Van de Velde (vdv_b@tgui.eu) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +#include +#include + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace tgui +{ + SignalManager::Ptr SignalManager::m_manager = std::make_shared(); + + SignalManager::SignalManager() + { + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + SignalManager::~SignalManager() + { + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void SignalManager::setDefaultSignalManager(const SignalManager::Ptr &manager) + { + m_manager = manager; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + SignalManager::Ptr SignalManager::getSignalManager() + { + return m_manager; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool SignalManager::disconnect(unsigned int id) + { + auto it = m_signals.find(id); + if (it != m_signals.end()) + { + m_signals.erase(it); + + for (auto it2 = m_connectedSignals.begin(); it2 != m_connectedSignals.end();) + { + if (it2->m_signalId != id) + { + ++it2; + continue; + } + + if (auto widget = it2->m_widget.lock()) + { + widget->disconnect(it2->m_signalWidgetID); + } + + it2 = m_connectedSignals.erase(it2); + } + + return true; + } + else + { + return false; + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void SignalManager::disconnectAll() + { + for (auto &it : m_connectedSignals) + { + if (auto widget = it.m_widget.lock()) + { + widget->disconnect(it.m_signalWidgetID); + } + } + + m_signals.clear(); + m_connectedSignals.clear(); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void SignalManager::add(const Widget::Ptr &widgetPtr) + { + m_widgets.emplace_back(widgetPtr); + + for (auto &it : m_signals) + { + if (it.second.m_widgetName == widgetPtr->getWidgetName()) + { + unsigned int id; + if (it.second.m_func.first) + { + id = widgetPtr->connect(it.second.m_signalName, it.second.m_func.first); + } + else + { + id = widgetPtr->connect(it.second.m_signalName, it.second.m_func.second); + } + + m_connectedSignals.push_back({it.first, widgetPtr, id}); + } + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void SignalManager::remove(Widget *widget) + { + for (auto it = m_widgets.begin(); it != m_widgets.end();) + { + if (it->expired() || it->lock().get() == widget) + { + it = m_widgets.erase(it); + } + else + { + ++it; + } + } + for (auto it = m_connectedSignals.begin(); it != m_connectedSignals.end();) + { + if (it->m_widget.expired()) + { + it = m_connectedSignals.erase(it); + } + else if(it->m_widget.lock().get() == widget) + { + widget->disconnect(it->m_signalWidgetID); + it = m_connectedSignals.erase(it); + } + else + { + ++it; + } + } + } + + void SignalManager::connect(SignalID sid) + { + auto signalIt = m_signals.find(sid); + if (signalIt == m_signals.end()) + { return; } + auto &handle = signalIt->second; + + for (auto &it : m_widgets) + { + if (auto widget = it.lock()) + { + if (widget->getWidgetName() == handle.m_widgetName) + { + unsigned int id; + if (handle.m_func.first) + { + id = widget->connect(handle.m_signalName, handle.m_func.first); + } + else + { + id = widget->connect(handle.m_signalName, handle.m_func.second); + } + + m_connectedSignals.push_back({sid, it, id}); + } + } + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + std::pair + SignalManager::makeSignal(const SignalManager::Delegate &handle) + { + return std::make_pair(handle, SignalManager::DelegateEx{}); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + std::pair + SignalManager::makeSignal(const SignalManager::DelegateEx &handle) + { + return std::make_pair(SignalManager::Delegate{}, handle); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + unsigned int SignalManager::generateUniqueId() + { + return ++m_lastId; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/src/TGUI/String.cpp b/src/TGUI/String.cpp index 1059e3525..39ca233fd 100644 --- a/src/TGUI/String.cpp +++ b/src/TGUI/String.cpp @@ -46,7 +46,7 @@ namespace tgui ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #ifdef TGUI_NEXT - bool isWhitespace(char32_t character) + bool isWhitespace(uint32_t character) #else bool isWhitespace(sf::Uint32 character) #endif diff --git a/src/TGUI/Widget.cpp b/src/TGUI/Widget.cpp index 2daae6007..2cde4b0a3 100644 --- a/src/TGUI/Widget.cpp +++ b/src/TGUI/Widget.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -131,6 +132,8 @@ namespace tgui for (auto& layout : m_boundSizeLayouts) layout->unbindWidget(); + + SignalManager::getSignalManager()->remove(this); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -139,6 +142,7 @@ namespace tgui SignalWidgetBase {other}, enable_shared_from_this{other}, m_type {other.m_type}, + m_name {other.m_name}, m_position {other.m_position}, m_size {other.m_size}, m_boundPositionLayouts {}, @@ -174,6 +178,7 @@ namespace tgui onMouseEnter {std::move(other.onMouseEnter)}, onMouseLeave {std::move(other.onMouseLeave)}, m_type {std::move(other.m_type)}, + m_name {std::move(other.m_name)}, m_position {std::move(other.m_position)}, m_size {std::move(other.m_size)}, m_boundPositionLayouts {std::move(other.m_boundPositionLayouts)}, @@ -202,6 +207,11 @@ namespace tgui m_renderer->subscribe(this, m_rendererChangedCallback); other.m_renderer = nullptr; + + if(other.m_parent) + { + m_parent->remove(other.shared_from_this()); + } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -223,13 +233,13 @@ namespace tgui onMouseLeave.disconnectAll(); m_type = other.m_type; + m_name = other.m_name; m_position = other.m_position; m_size = other.m_size; m_boundPositionLayouts = {}; m_boundSizeLayouts = {}; m_enabled = other.m_enabled; m_visible = other.m_visible; - m_parent = nullptr; m_mouseHover = false; m_mouseDown = false; m_focused = false; @@ -248,6 +258,12 @@ namespace tgui m_size.y.connectWidget(this, false, [this]{ setSize(getSizeLayout()); }); m_renderer->subscribe(this, m_rendererChangedCallback); + + if(m_parent) + { + SignalManager::getSignalManager()->remove(this); + SignalManager::getSignalManager()->add(shared_from_this()); + } } return *this; @@ -272,13 +288,13 @@ namespace tgui onMouseEnter = std::move(other.onMouseEnter); onMouseLeave = std::move(other.onMouseLeave); m_type = std::move(other.m_type); + m_name = std::move(other.m_name); m_position = std::move(other.m_position); m_size = std::move(other.m_size); m_boundPositionLayouts = std::move(other.m_boundPositionLayouts); m_boundSizeLayouts = std::move(other.m_boundSizeLayouts); m_enabled = std::move(other.m_enabled); m_visible = std::move(other.m_visible); - m_parent = nullptr; m_mouseHover = std::move(other.m_mouseHover); m_mouseDown = std::move(other.m_mouseDown); m_focused = std::move(other.m_focused); @@ -299,6 +315,12 @@ namespace tgui m_renderer->subscribe(this, m_rendererChangedCallback); other.m_renderer = nullptr; + + if(m_parent) + { + SignalManager::getSignalManager()->remove(&other); + SignalManager::getSignalManager()->add(shared_from_this()); + } } return *this; @@ -617,7 +639,7 @@ namespace tgui TGUI_LAMBDA_CAPTURE_EQ_THIS{ setVisible(false); setPosition(position); onAnimationFinished.emit(this, type, false); })); } else - { + { TGUI_PRINT_WARNING("hideWithEffect(SlideToBottom) does not work before widget has a parent."); } @@ -763,6 +785,29 @@ namespace tgui ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void Widget::setWidgetName(const std::string& name) + { + if(m_name != name) + { + m_name = name; + + if(m_parent) + { + SignalManager::getSignalManager()->remove(this); + SignalManager::getSignalManager()->add(shared_from_this()); + } + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + std::string Widget::getWidgetName() const + { + return m_name; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void Widget::setFocusable(bool focusable) { m_focusable = focusable; @@ -793,6 +838,15 @@ namespace tgui void Widget::setParent(Container* parent) { + if(!parent) + { + SignalManager::getSignalManager()->remove(this); + } + else if(!m_parent) + { + SignalManager::getSignalManager()->add(shared_from_this()); + } + m_parent = parent; // Give the layouts another chance to find widgets to which it refers @@ -987,7 +1041,7 @@ namespace tgui if (!m_enabled && (getSharedRenderer()->getOpacityDisabled() != -1)) m_opacityCached = getSharedRenderer()->getOpacityDisabled() * m_inheritedOpacity; else - m_opacityCached = getSharedRenderer()->getOpacity() * m_inheritedOpacity; + m_opacityCached = getSharedRenderer()->getOpacity() * m_inheritedOpacity; } else if (property == "font") { @@ -1011,8 +1065,7 @@ namespace tgui std::unique_ptr Widget::save(SavingRenderersMap& renderers) const { sf::String widgetName; - if (getParent()) - widgetName = getParent()->getWidgetName(shared_from_this()); + widgetName = m_name; auto node = std::make_unique(); if (widgetName.isEmpty()) @@ -1028,6 +1081,55 @@ namespace tgui node->propertyValuePairs["Position"] = std::make_unique(m_position.toString()); if (getSize() != Vector2f{}) node->propertyValuePairs["Size"] = std::make_unique(m_size.toString()); +#if TGUI_COMPILED_WITH_CPP_VER >= 17 + if(m_userData.has_value()) + { + try + { + sf::String string = std::any_cast(m_userData); + + node->propertyValuePairs["UserData"] = std::make_unique(Serializer::serialize(string.toAnsiString())); + } + catch (const std::bad_any_cast&) + { + try + { + std::string string = std::any_cast(m_userData); + + node->propertyValuePairs["UserData"] = std::make_unique(Serializer::serialize(string)); + } + catch (const std::bad_any_cast&) + { + try + { + std::string string = std::any_cast(m_userData); + + node->propertyValuePairs["UserData"] = std::make_unique(Serializer::serialize(string)); + } + catch (const std::bad_any_cast&) + { + + } + } + } + } +#else + if(m_userData.not_null()) + { + if(m_userData.is()) + { + node->propertyValuePairs["UserData"] = std::make_unique(Serializer::serialize(m_userData.as().toAnsiString())); + } + else if(m_userData.is()) + { + node->propertyValuePairs["UserData"] = std::make_unique(Serializer::serialize(m_userData.as())); + } + else if(m_userData.is()) + { + node->propertyValuePairs["UserData"] = std::make_unique(Serializer::serialize(m_userData.as())); + } + } +#endif if (getToolTip() != nullptr) { @@ -1063,6 +1165,14 @@ namespace tgui setPosition(parseLayout(node->propertyValuePairs["position"]->value)); if (node->propertyValuePairs["size"]) setSize(parseLayout(node->propertyValuePairs["size"]->value)); + if(node->propertyValuePairs["userdata"]) + { +#if TGUI_COMPILED_WITH_CPP_VER >= 17 + m_userData = std::make_any(Deserializer::deserialize(ObjectConverter::Type::String, node->propertyValuePairs["userdata"]->value).getString().toAnsiString()); +#else + m_userData = tgui::Any(Deserializer::deserialize(ObjectConverter::Type::String, node->propertyValuePairs["userdata"]->value).getString().toAnsiString()); +#endif + } if (node->propertyValuePairs["renderer"]) { diff --git a/src/TGUI/Widgets/BoxLayout.cpp b/src/TGUI/Widgets/BoxLayout.cpp index 09e76505d..bc9cbf0e1 100644 --- a/src/TGUI/Widgets/BoxLayout.cpp +++ b/src/TGUI/Widgets/BoxLayout.cpp @@ -91,10 +91,8 @@ namespace tgui Group::add(widget, widgetName); m_widgets.pop_back(); - m_widgetNames.pop_back(); m_widgets.insert(m_widgets.begin() + index, widget); - m_widgetNames.insert(m_widgetNames.begin() + index, widgetName); } else // Just add the widget to the back Group::add(widget, widgetName); diff --git a/src/TGUI/Widgets/MessageBox.cpp b/src/TGUI/Widgets/MessageBox.cpp index 874862ab8..dbe2e09c8 100644 --- a/src/TGUI/Widgets/MessageBox.cpp +++ b/src/TGUI/Widgets/MessageBox.cpp @@ -363,7 +363,7 @@ namespace tgui for (unsigned int i = 0; i < m_widgets.size(); ++i) { - if ((m_widgetNames[i].getSize() >= 32) && (m_widgetNames[i].substring(0, 32) == "#TGUI_INTERNAL$MessageBoxButton:")) + if ((m_widgets[i]->getWidgetName().length() >= 32) && (m_widgets[i]->getWidgetName().substr(0, 32) == "#TGUI_INTERNAL$MessageBoxButton:")) { auto button = std::dynamic_pointer_cast