Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
TGUI 1.13 (TBD)
----------------

- Implemented support for themes in forms ([Issue #325](https://github.com/texus/TGUI/issues/325)):
- `loadWidgetsFromStream` now clears and restores the default theme during load, matching `loadWidgetsFromFile`
- `FormLoadOptions::applyDefaultTheme` keeps the global default theme active during form load so widgets without a `Renderer` property match programmatic construction
- Form files may declare top-level `Theme.<Alias>` sections with per-section renderer fallbacks (`Button = &1;`, etc.)
- `Renderer = @Alias` / `@Alias.Section` bind to runtime themes (`FormLoadOptions::themesByAlias`) or form fallbacks
- Form loading calls non-virtual `Widget::load(node, WidgetLoadResources)`, which sets a short-lived load context then dispatches to virtual `load(node, LoadingRenderersMap)` so custom widget subclasses keep a single override; `load(map)` builds a full `WidgetLoadResources` (including themes) and calls `Widget::loadUsingResources`
- Added Emscripten support
- Each tab in Tabs and VerticalTabs widgets can now be assigned a unique id
- Position and size layout expressions weren't saved when the result equaled (0,0)
Expand Down
15 changes: 15 additions & 0 deletions include/TGUI/Backend/Window/BackendGui.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,11 @@ namespace tgui
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loadWidgetsFromFile(const String& filename, bool replaceExisting = true);

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Loads the child widgets from a text file with load options
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loadWidgetsFromFile(const String& filename, bool replaceExisting, const FormLoadOptions& options);

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Saves the child widgets to a text file
///
Expand All @@ -495,6 +500,16 @@ namespace tgui
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loadWidgetsFromStream(std::stringstream&& stream, bool replaceExisting = true);

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Loads the child widgets from a string stream with load options
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loadWidgetsFromStream(std::stringstream& stream, bool replaceExisting, const FormLoadOptions& options);

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Loads the child widgets from a string stream with load options
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loadWidgetsFromStream(std::stringstream&& stream, bool replaceExisting, const FormLoadOptions& options);

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Saves this the child widgets to a text file
///
Expand Down
25 changes: 24 additions & 1 deletion include/TGUI/Container.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#ifndef TGUI_CONTAINER_HPP
#define TGUI_CONTAINER_HPP

#include <TGUI/FormLoadOptions.hpp>
#include <TGUI/Widget.hpp>

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -196,6 +197,11 @@ namespace tgui
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loadWidgetsFromFile(const String& filename, bool replaceExisting = true);

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Loads the child widgets from a text file with load options
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loadWidgetsFromFile(const String& filename, bool replaceExisting, const FormLoadOptions& options);

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Saves the child widgets to a text file
///
Expand All @@ -221,6 +227,16 @@ namespace tgui
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loadWidgetsFromStream(std::stringstream&& stream, bool replaceExisting = true);

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Loads the child widgets from a string stream with load options
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loadWidgetsFromStream(std::stringstream& stream, bool replaceExisting, const FormLoadOptions& options);

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Loads the child widgets from a string stream with load options
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loadWidgetsFromStream(std::stringstream&& stream, bool replaceExisting, const FormLoadOptions& options);

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Saves the child widgets to a text file
///
Expand Down Expand Up @@ -615,7 +631,9 @@ namespace tgui
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Mutual code in loadWidgetsFromFile and loadWidgetsFromStream
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loadWidgetsImpl(const std::unique_ptr<DataIO::Node>& rootNode, bool replaceExisting);
void loadWidgetsImpl(const std::unique_ptr<DataIO::Node>& rootNode, bool replaceExisting, const FormLoadOptions& options);

void loadWidgetsFromNodeTree(const std::unique_ptr<DataIO::Node>& rootNode, bool replaceExisting, const FormLoadOptions& options);

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Expand All @@ -635,6 +653,11 @@ namespace tgui

friend class SubwidgetContainer; // Needs access to save and load functions

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @internal
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loadContainedWidgetsFromNodes(const std::unique_ptr<DataIO::Node>& node, const WidgetLoadResources& resources);

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
};

Expand Down
50 changes: 50 additions & 0 deletions include/TGUI/FormLoadOptions.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// TGUI - Texus' Graphical User Interface
// Copyright (C) 2012-2026 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_FORM_LOAD_OPTIONS_HPP
#define TGUI_FORM_LOAD_OPTIONS_HPP

#include <TGUI/Loading/Theme.hpp>
#include <TGUI/String.hpp>

#include <map>
#include <memory>

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace tgui
{
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Options for loading widget forms
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct TGUI_API FormLoadOptions
{
std::map<String, Theme::Ptr> themesByAlias;
bool applyDefaultTheme = false;
};
} // namespace tgui

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#endif // TGUI_FORM_LOAD_OPTIONS_HPP
90 changes: 90 additions & 0 deletions include/TGUI/ScopeExit.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// TGUI - Texus' Graphical User Interface
// Copyright (C) 2012-2026 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_SCOPE_EXIT_HPP
#define TGUI_SCOPE_EXIT_HPP

#include <TGUI/Config.hpp>

#include <type_traits>
#include <utility>

namespace tgui
{
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Invokes a function when leaving scope (return or exception). Not included from TGUI.hpp; include explicitly if needed.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename F>
class ScopeExit
{
public:
template <typename G, typename = typename std::enable_if<!std::is_same<typename std::decay<G>::type, ScopeExit>::value>::type>
explicit ScopeExit(G&& func) :
m_func(std::forward<G>(func)),
m_active(true)
{
}

ScopeExit(const ScopeExit&) = delete;

ScopeExit& operator=(const ScopeExit&) = delete;
ScopeExit& operator=(ScopeExit&&) = delete;

ScopeExit(ScopeExit&& other) noexcept(std::is_nothrow_move_constructible<F>::value) :
m_func(std::move(other.m_func)),
m_active(other.m_active)
{
other.m_active = false;
}

~ScopeExit()
{
if (m_active)
m_func();
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Skip invoking the function when the guard is destroyed
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void release() noexcept
{
m_active = false;
}

private:
F m_func;
bool m_active;
};

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Helper to create a ScopeExit without naming the lambda's type
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename F>
TGUI_NODISCARD ScopeExit<typename std::decay<F>::type> makeScopeExit(F&& func)
{
return ScopeExit<typename std::decay<F>::type>(std::forward<F>(func));
}
} // namespace tgui

#endif // TGUI_SCOPE_EXIT_HPP
14 changes: 14 additions & 0 deletions include/TGUI/Widget.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include <TGUI/Sprite.hpp>
#include <TGUI/String.hpp>
#include <TGUI/Vector2.hpp>
#include <TGUI/WidgetLoadResources.hpp>

#include <unordered_set>

Expand Down Expand Up @@ -111,6 +112,11 @@ namespace tgui
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual ~Widget();

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Loads the widget from a form node (with theme resources)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void load(const std::unique_ptr<DataIO::Node>& node, const WidgetLoadResources& resources);

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Overload of copy assignment operator
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -1159,6 +1165,11 @@ namespace tgui
using SavingRenderersMap = std::map<const Widget*, std::pair<std::unique_ptr<DataIO::Node>, String>>;
using LoadingRenderersMap = std::map<String, std::shared_ptr<RendererData>>;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Loads widget fields from a form node using the given resources
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loadUsingResources(const std::unique_ptr<DataIO::Node>& node, const WidgetLoadResources& resources);

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Function called when one of the properties of the renderer is changed
///
Expand Down Expand Up @@ -1313,6 +1324,9 @@ namespace tgui
bool m_transparentTextureCached = false;
unsigned int m_textSizeCached = 0;

const std::map<String, std::shared_ptr<Theme>>* m_loadRuntimeThemesByAlias = nullptr;
const ThemeFallbackMap* m_loadThemeFallbacks = nullptr;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

friend class Container; // Container accesses save and load functions
Expand Down
62 changes: 62 additions & 0 deletions include/TGUI/WidgetLoadResources.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// TGUI - Texus' Graphical User Interface
// Copyright (C) 2012-2026 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_WIDGET_LOAD_RESOURCES_HPP
#define TGUI_WIDGET_LOAD_RESOURCES_HPP

#include <TGUI/Renderers/WidgetRenderer.hpp>
#include <TGUI/String.hpp>

#include <map>
#include <memory>

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace tgui
{
class Theme;

/// Fallback renderers from Theme.\<Alias\> sections in the form file
using ThemeFallbackMap = std::map<String, std::map<String, std::shared_ptr<RendererData>>>;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @internal
/// @brief Resources used when loading widgets from a form file
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct TGUI_API WidgetLoadResources
{
const std::map<String, std::shared_ptr<RendererData>>& renderers;
const std::map<String, std::shared_ptr<Theme>>* runtimeThemesByAlias = nullptr;
const ThemeFallbackMap* themeFallbacks = nullptr;

explicit WidgetLoadResources(const std::map<String, std::shared_ptr<RendererData>>& r) :
renderers(r)
{
}
};
} // namespace tgui

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#endif // TGUI_WIDGET_LOAD_RESOURCES_HPP
Loading
Loading