Skip to content
Merged
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
4 changes: 4 additions & 0 deletions Client/core/CGUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ void CLocalGUI::ChangeLocale(const char* szName)

m_LastLocaleName = strCanonicalLocale;

// Attempt CEGUI cleanup
if (CGUI* pGUI = CCore::GetSingleton().GetGUI())
pGUI->Cleanup();

if (guiWasLoaded)
{
CreateWindows(guiWasLoaded);
Expand Down
50 changes: 25 additions & 25 deletions Client/core/CLocalization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,7 @@ CLocalization::CLocalization(const SString& strLocale, const SString& strLocaleP

CLocalization::~CLocalization()
{
for (auto iter : m_LanguageMap)
{
delete iter.second;
}
m_pCurrentLang = nullptr;
}

//
Expand Down Expand Up @@ -99,29 +96,32 @@ void CLocalization::SetCurrentLanguage(SString strLocale)
CLanguage* CLocalization::GetLanguage(SString strLocale)
{
strLocale = ValidateLocale(strLocale);
CLanguage* pLanguage = MapFindRef(m_LanguageMap, strLocale);
if (!pLanguage)
auto iter = m_LanguageMap.find(strLocale);
if (iter != m_LanguageMap.end())
{
return iter->second.get();
}

Language Lang = Language::from_name(strLocale);
Lang = Lang ? Lang : Language::from_name("en_US");

try
{
std::unique_ptr<CLanguage> pLanguage = std::make_unique<CLanguage>(m_DictManager.get_dictionary(Lang, MTA_LOCALE_TEXTDOMAIN), Lang.str(), Lang.get_name());
CLanguage* pLanguagePtr = pLanguage.get();
m_LanguageMap.emplace(strLocale, std::move(pLanguage));
return pLanguagePtr;
}
catch (const std::exception& ex)
{
WriteDebugEvent(SString("Localization failed to load dictionary for '%s': %s", strLocale.c_str(), ex.what()));
return (strLocale != "en_US") ? GetLanguage("en_US") : nullptr;
}
catch (...)
{
Language Lang = Language::from_name(strLocale);
Lang = Lang ? Lang : Language::from_name("en_US");

try
{
pLanguage = new CLanguage(m_DictManager.get_dictionary(Lang, MTA_LOCALE_TEXTDOMAIN), Lang.str(), Lang.get_name());
MapSet(m_LanguageMap, strLocale, pLanguage);
}
catch (const std::exception& ex)
{
WriteDebugEvent(SString("Localization failed to load dictionary for '%s': %s", strLocale.c_str(), ex.what()));
return (strLocale != "en_US") ? GetLanguage("en_US") : nullptr;
}
catch (...)
{
WriteDebugEvent(SString("Localization failed to load dictionary for '%s': unknown error", strLocale.c_str()));
return (strLocale != "en_US") ? GetLanguage("en_US") : nullptr;
}
WriteDebugEvent(SString("Localization failed to load dictionary for '%s': unknown error", strLocale.c_str()));
return (strLocale != "en_US") ? GetLanguage("en_US") : nullptr;
}
return pLanguage;
}

//
Expand Down
9 changes: 5 additions & 4 deletions Client/core/CLocalization.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ using namespace tinygettext;

#include <core/CLocalizationInterface.h>
#include "CLanguage.h"
#define MTA_LOCALE_DIR "MTA/locale/"
#include <memory>
#define MTA_LOCALE_DIR "MTA/locale/"

#pragma once

Expand Down Expand Up @@ -42,7 +43,7 @@ class CLocalization : public CLocalizationInterface
static void LogCallback(const std::string& str);

private:
DictionaryManager m_DictManager;
std::map<SString, CLanguage*> m_LanguageMap;
CLanguage* m_pCurrentLang{};
DictionaryManager m_DictManager;
std::map<SString, std::unique_ptr<CLanguage>> m_LanguageMap;
CLanguage* m_pCurrentLang{};
};
107 changes: 76 additions & 31 deletions Client/gui/CGUI_Impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ CGUI_Impl::~CGUI_Impl()
// DO NOT delete m_pRenderer - it's already deleted by System destructor
}

void CGUI_Impl::CreateRootWindow()
{
if (!m_pWindowManager || !m_pSystem)
return;

// Create dummy GUI root
m_pTop = reinterpret_cast<CEGUI::DefaultWindow*>(m_pWindowManager->createWindow("DefaultWindow", "guiroot"));
m_pSystem->setGUISheet(m_pTop);
}

void CGUI_Impl::SetSkin(const char* szName)
{
if (m_HasSchemeLoaded)
Expand All @@ -162,12 +172,8 @@ void CGUI_Impl::SetSkin(const char* szName)

CEGUI::System::getSingleton().setDefaultMouseCursor("CGUI-Images", "MouseArrow");

// Destroy any windows we already have
CEGUI::WindowManager::getSingleton().destroyAllWindows();

// Create dummy GUI root
m_pTop = reinterpret_cast<CEGUI::DefaultWindow*>(m_pWindowManager->createWindow("DefaultWindow", "guiroot"));
m_pSystem->setGUISheet(m_pTop);
// Clean up CEGUI - this also re-creates the root window
Cleanup();

// Disable single click timeouts
m_pSystem->setSingleClickTimeout(100000000.0f);
Expand Down Expand Up @@ -327,28 +333,31 @@ bool CGUI_Impl::GetGUIInputEnabled()
break;
case INPUTMODE_NO_BINDS_ON_EDIT:
{
CEGUI::Window* pActiveWindow = m_pTop->getActiveChild();
if (!pActiveWindow || pActiveWindow == m_pTop || !pActiveWindow->isVisible())
{
return false;
}
if (pActiveWindow->getType() == "CGUI/Editbox")
{
CEGUI::Editbox* pEditBox = reinterpret_cast<CEGUI::Editbox*>(pActiveWindow);
return (!pEditBox->isReadOnly() && pEditBox->hasInputFocus());
}
else if (pActiveWindow->getType() == "CGUI/MultiLineEditbox")
{
CEGUI::MultiLineEditbox* pMultiLineEditBox = reinterpret_cast<CEGUI::MultiLineEditbox*>(pActiveWindow);
return (!pMultiLineEditBox->isReadOnly() && pMultiLineEditBox->hasInputFocus());
}
else if (pActiveWindow->getType() == CGUIWEBBROWSER_NAME)
if (m_pTop)
{
auto pElement = reinterpret_cast<CGUIElement_Impl*>(pActiveWindow->getUserData());
if (pElement->GetType() == CGUI_WEBBROWSER)
CEGUI::Window* pActiveWindow = m_pTop->getActiveChild();
if (!pActiveWindow || pActiveWindow == m_pTop || !pActiveWindow->isVisible())
{
return false;
}
if (pActiveWindow->getType() == "CGUI/Editbox")
{
CEGUI::Editbox* pEditBox = reinterpret_cast<CEGUI::Editbox*>(pActiveWindow);
return (!pEditBox->isReadOnly() && pEditBox->hasInputFocus());
}
else if (pActiveWindow->getType() == "CGUI/MultiLineEditbox")
{
CEGUI::MultiLineEditbox* pMultiLineEditBox = reinterpret_cast<CEGUI::MultiLineEditbox*>(pActiveWindow);
return (!pMultiLineEditBox->isReadOnly() && pMultiLineEditBox->hasInputFocus());
}
else if (pActiveWindow->getType() == CGUIWEBBROWSER_NAME)
{
auto pWebBrowser = reinterpret_cast<CGUIWebBrowser_Impl*>(pElement);
return pWebBrowser->HasInputFocus();
auto pElement = reinterpret_cast<CGUIElement_Impl*>(pActiveWindow->getUserData());
if (pElement->GetType() == CGUI_WEBBROWSER)
{
auto pWebBrowser = reinterpret_cast<CGUIWebBrowser_Impl*>(pElement);
return pWebBrowser->HasInputFocus();
}
}
}
return false;
Expand Down Expand Up @@ -580,6 +589,9 @@ eCursorType CGUI_Impl::GetCursorType()

void CGUI_Impl::AddChild(CGUIElement_Impl* pChild)
{
if (!m_pTop)
return;

m_pTop->addChildWindow(pChild->GetWindow());
}

Expand Down Expand Up @@ -1153,12 +1165,15 @@ bool CGUI_Impl::Event_MouseButtonDown(const CEGUI::EventArgs& Args)
pElement->Event_OnMouseButtonDown();
else
{
// If there's no element, we're probably dealing with the root element
CEGUI::Window* pActiveWindow = m_pTop->getActiveChild();
if (m_pTop == wnd && pActiveWindow)
if (m_pTop)
{
// Deactivate active window to trigger onClientGUIBlur
pActiveWindow->deactivate();
// If there's no element, we're probably dealing with the root element
CEGUI::Window* pActiveWindow = m_pTop->getActiveChild();
if (m_pTop == wnd && pActiveWindow)
{
// Deactivate active window to trigger onClientGUIBlur
pActiveWindow->deactivate();
}
}
}

Expand Down Expand Up @@ -1797,3 +1812,33 @@ CEGUI::Window* CGUI_Impl::GetMasterWindow(CEGUI::Window* wnd)
}
return wnd;
}

void CGUI_Impl::Cleanup()
{
try
{
CleanDeadPool();

m_pTop = nullptr;

if (m_pWindowManager)
m_pWindowManager->destroyAllWindows();

// Clear redraw structures that may reference old elements
m_RedrawQueue.clear();
m_RedrawRegistry.clear();

// Recreate the root window (destroyed above via destroyAllWindows)
CreateRootWindow();
}
catch (const std::exception& e)
{
WriteDebugEvent(SString("CGUI_Impl::Cleanup - Exception: %s", e.what()));
m_pTop = nullptr;
}
catch (...)
{
WriteDebugEvent("CGUI_Impl::Cleanup() failed with unknown exception");
m_pTop = nullptr;
}
}
5 changes: 5 additions & 0 deletions Client/gui/CGUI_Impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,9 @@ class CGUI_Impl : public CGUI, public CGUITabList
CGUIWindow* LoadLayout(CGUIElement* pParent, const SString& strFilename);
bool LoadImageset(const SString& strFilename);

// Cleanup CEGUI active resources (dead pool)
void Cleanup();

private:
friend class CGUIElement_Impl;
CGUIButton* _CreateButton(CGUIElement_Impl* pParent = NULL, const char* szCaption = "");
Expand Down Expand Up @@ -361,4 +364,6 @@ class CGUI_Impl : public CGUI, public CGUITabList
bool m_HasSchemeLoaded;
SString m_CurrentSchemeName;
CElapsedTime m_RenderOkTimer;

void CreateRootWindow();
};
2 changes: 2 additions & 0 deletions Client/sdk/gui/CGUI.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,6 @@ class CGUI

virtual CGUIWindow* LoadLayout(CGUIElement* pParent, const SString& strFilename) = 0;
virtual bool LoadImageset(const SString& strFilename) = 0;

virtual void Cleanup() = 0;
};
Loading