merge development

Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
This commit is contained in:
chcurran
2021-08-17 15:37:30 -07:00
322 changed files with 5753 additions and 7185 deletions
+4
View File
@@ -238,9 +238,13 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
3rdParty::Qt::Core
3rdParty::Qt::Gui
3rdParty::Qt::Widgets
3rdParty::Qt::Test
Legacy::CryCommon
AZ::AzToolsFramework
AZ::AzToolsFramework.Tests
AZ::AzToolsFrameworkTestCommon
Legacy::EditorLib
Gem::AtomToolsFramework.Static
RUNTIME_DEPENDENCIES
Gem::LmbrCentral
)
@@ -10,7 +10,6 @@
// Editor
#include "PropertyCtrl.h"
#include "PropertyAnimationCtrl.h"
#include "PropertyResourceCtrl.h"
#include "PropertyGenericCtrl.h"
#include "PropertyMiscCtrl.h"
@@ -22,9 +21,7 @@ void RegisterReflectedVarHandlers()
if (!registered)
{
registered = true;
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew AnimationPropertyWidgetHandler());
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew FileResourceSelectorWidgetHandler());
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew ReverbPresetPropertyHandler());
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew SequencePropertyHandler());
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew SequenceIdPropertyHandler());
EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew LocalStringPropertyHandler());
@@ -73,16 +73,6 @@ void GenericPopupPropertyEditor::SetPropertyType(PropertyType type)
m_propertyType = type;
}
void ReverbPresetPropertyEditor::onEditClicked()
{
CSelectEAXPresetDlg PresetDlg(this);
PresetDlg.SetCurrPreset(GetValue());
if (PresetDlg.exec() == QDialog::Accepted)
{
SetValue(PresetDlg.GetCurrPreset());
}
}
void SequencePropertyEditor::onEditClicked()
{
CSelectSequenceDialog gtDlg(this);
@@ -96,15 +96,6 @@ public:
}
};
class ReverbPresetPropertyEditor
: public GenericPopupPropertyEditor
{
public:
ReverbPresetPropertyEditor(QWidget* pParent = nullptr)
: GenericPopupPropertyEditor(pParent){}
void onEditClicked() override;
};
class MissionObjPropertyEditor
: public GenericPopupPropertyEditor
{
@@ -155,7 +146,6 @@ public:
// So we use our own
#define CONST_AZ_CRC(name, value) AZ::u32(value)
using ReverbPresetPropertyHandler = GenericPopupWidgetHandler<ReverbPresetPropertyEditor, CONST_AZ_CRC("ePropertyReverbPreset", 0x51469f38)>;
using MissionObjPropertyHandler = GenericPopupWidgetHandler<MissionObjPropertyEditor, CONST_AZ_CRC("ePropertyMissionObj", 0x4a2d0dc8)>;
using SequencePropertyHandler = GenericPopupWidgetHandler<SequencePropertyEditor, CONST_AZ_CRC("ePropertySequence", 0xdd1c7d44)>;
using SequenceIdPropertyHandler = GenericPopupWidgetHandler<SequenceIdPropertyEditor, CONST_AZ_CRC("ePropertySequenceId", 0x05983dcc)>;
@@ -17,9 +17,9 @@
// AzToolsFramework
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyAudioCtrl.h>
// Editor
#include "IResourceSelectorHost.h"
#include "Controls/QToolTipWidget.h"
#include "Controls/BitmapToolTip.h"
@@ -35,8 +35,8 @@ BrowseButton::BrowseButton(PropertyType type, QWidget* parent /*= nullptr*/)
void BrowseButton::SetPathAndEmit(const QString& path)
{
//only emit if path changes, except for ePropertyGeomCache. Old property control
if (path != m_path || m_propertyType == ePropertyGeomCache)
//only emit if path changes. Old property control
if (path != m_path)
{
m_path = path;
emit PathChanged(m_path);
@@ -78,21 +78,6 @@ private:
// Filters for texture.
selection = AssetSelectionModel::AssetGroupSelection("Texture");
}
else if (m_propertyType == ePropertyModel)
{
// Filters for models.
selection = AssetSelectionModel::AssetGroupSelection("Geometry");
}
else if (m_propertyType == ePropertyGeomCache)
{
// Filters for geom caches.
selection = AssetSelectionModel::AssetTypeSelection("Geom Cache");
}
else if (m_propertyType == ePropertyFile)
{
// Filters for files.
selection = AssetSelectionModel::AssetTypeSelection("File");
}
else
{
return;
@@ -106,14 +91,7 @@ private:
switch (m_propertyType)
{
case ePropertyTexture:
case ePropertyModel:
newPath.replace("\\\\", "/");
}
switch (m_propertyType)
{
case ePropertyTexture:
case ePropertyModel:
case ePropertyFile:
if (newPath.size() > MAX_PATH)
{
newPath.resize(MAX_PATH);
@@ -125,26 +103,51 @@ private:
}
};
class ResourceSelectorButton
class AudioControlSelectorButton
: public BrowseButton
{
public:
AZ_CLASS_ALLOCATOR(ResourceSelectorButton, AZ::SystemAllocator, 0);
AZ_CLASS_ALLOCATOR(AudioControlSelectorButton, AZ::SystemAllocator, 0);
ResourceSelectorButton(PropertyType type, QWidget* pParent = nullptr)
AudioControlSelectorButton(PropertyType type, QWidget* pParent = nullptr)
: BrowseButton(type, pParent)
{
setToolTip(tr("Select resource"));
setToolTip(tr("Select Audio Control"));
}
private:
void OnClicked() override
{
SResourceSelectorContext x;
x.parentWidget = this;
x.typeName = Prop::GetPropertyTypeToResourceType(m_propertyType);
QString newPath = GetIEditor()->GetResourceSelectorHost()->SelectResource(x, m_path);
SetPathAndEmit(newPath);
AZStd::string resourceResult;
auto ConvertLegacyAudioPropertyType = [](const PropertyType type) -> AzToolsFramework::AudioPropertyType
{
switch (type)
{
case ePropertyAudioTrigger:
return AzToolsFramework::AudioPropertyType::Trigger;
case ePropertyAudioRTPC:
return AzToolsFramework::AudioPropertyType::Rtpc;
case ePropertyAudioSwitch:
return AzToolsFramework::AudioPropertyType::Switch;
case ePropertyAudioSwitchState:
return AzToolsFramework::AudioPropertyType::SwitchState;
case ePropertyAudioEnvironment:
return AzToolsFramework::AudioPropertyType::Environment;
case ePropertyAudioPreloadRequest:
return AzToolsFramework::AudioPropertyType::Preload;
default:
return AzToolsFramework::AudioPropertyType::NumTypes;
}
};
auto propType = ConvertLegacyAudioPropertyType(m_propertyType);
if (propType != AzToolsFramework::AudioPropertyType::NumTypes)
{
AzToolsFramework::AudioControlSelectorRequestBus::EventResult(
resourceResult, propType, &AzToolsFramework::AudioControlSelectorRequestBus::Events::SelectResource,
AZStd::string_view{ m_path.toUtf8().constData() });
SetPathAndEmit(QString{ resourceResult.c_str() });
}
}
};
@@ -235,18 +238,13 @@ void FileResourceSelectorWidget::SetPropertyType(PropertyType type)
AddButton(new TextureEditButton);
m_previewToolTip.reset(new CBitmapToolTip);
break;
case ePropertyModel:
case ePropertyGeomCache:
case ePropertyAudioTrigger:
case ePropertyAudioSwitch:
case ePropertyAudioSwitchState:
case ePropertyAudioRTPC:
case ePropertyAudioEnvironment:
case ePropertyAudioPreloadRequest:
AddButton(new ResourceSelectorButton(type));
break;
case ePropertyFile:
AddButton(new FileBrowseButton(type));
AddButton(new AudioControlSelectorButton(type));
break;
default:
break;
@@ -1,93 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
// Description : implementation file
#include "EditorDefs.h"
#include "ReflectedPropertiesPanel.h"
/////////////////////////////////////////////////////////////////////////////
// ReflectedPropertiesPanel dialog
ReflectedPropertiesPanel::ReflectedPropertiesPanel(QWidget* pParent)
: ReflectedPropertyControl(pParent)
{
}
//////////////////////////////////////////////////////////////////////////
void ReflectedPropertiesPanel::DeleteVars()
{
ClearVarBlock();
m_updateCallbacks.clear();
m_varBlock = nullptr;
}
//////////////////////////////////////////////////////////////////////////
void ReflectedPropertiesPanel::SetVarBlock(class CVarBlock* vb, ReflectedPropertyControl::UpdateVarCallback* updCallback, const char* category)
{
assert(vb);
m_varBlock = vb;
RemoveAllItems();
m_varBlock = vb;
AddVarBlock(m_varBlock, category);
SetUpdateCallback(AZStd::bind(&ReflectedPropertiesPanel::OnPropertyChanged, this, AZStd::placeholders::_1));
// When new object set all previous callbacks freed.
m_updateCallbacks.clear();
if (updCallback)
{
stl::push_back_unique(m_updateCallbacks, updCallback);
}
}
//////////////////////////////////////////////////////////////////////////
void ReflectedPropertiesPanel::AddVars(CVarBlock* vb, ReflectedPropertyControl::UpdateVarCallback* updCallback, const char* category)
{
assert(vb);
bool bNewBlock = false;
// Make a clone of properties.
if (!m_varBlock)
{
RemoveAllItems();
m_varBlock = vb->Clone(true);
AddVarBlock(m_varBlock, category);
bNewBlock = true;
}
m_varBlock->Wire(vb);
if (bNewBlock)
{
SetUpdateCallback(AZStd::bind(&ReflectedPropertiesPanel::OnPropertyChanged, this, AZStd::placeholders::_1));
// When new object set all previous callbacks freed.
m_updateCallbacks.clear();
}
if (updCallback)
{
stl::push_back_unique(m_updateCallbacks, updCallback);
}
}
void ReflectedPropertiesPanel::OnPropertyChanged(IVariable* pVar)
{
std::list<ReflectedPropertyControl::UpdateVarCallback*>::iterator iter;
for (iter = m_updateCallbacks.begin(); iter != m_updateCallbacks.end(); ++iter)
{
(*iter)->operator()(pVar);
}
}
@@ -1,46 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_REFLECTEDPROPERTIESPANEL_H
#define CRYINCLUDE_EDITOR_REFLECTEDPROPERTIESPANEL_H
#pragma once
#include "Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.h"
#include "Util/Variable.h"
/////////////////////////////////////////////////////////////////////////////
// ReflectedPropertiesPanel dialog
AZ_PUSH_DISABLE_DLL_EXPORT_BASECLASS_WARNING
//This class is a port of ReflectedPropertiesPanel to use the ReflectedPropertyControl
class SANDBOX_API ReflectedPropertiesPanel
: public ReflectedPropertyControl
{
AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING
public:
ReflectedPropertiesPanel(QWidget* pParent = nullptr); // standard constructor
void DeleteVars();
void AddVars(class CVarBlock* vb, ReflectedPropertyControl::UpdateVarCallback* func = nullptr, const char* category = nullptr);
void SetVarBlock(class CVarBlock* vb, ReflectedPropertyControl::UpdateVarCallback* func = nullptr, const char* category = nullptr);
protected:
void OnPropertyChanged(IVariable* pVar);
protected:
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
TSmartPtr<CVarBlock> m_varBlock;
std::list<ReflectedPropertyControl::UpdateVarCallback*> m_updateCallbacks;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
#endif // CRYINCLUDE_EDITOR_REFLECTEDPROPERTIESPANEL_H
@@ -255,9 +255,6 @@ void ReflectedPropertyItem::SetVariable(IVariable *var)
case ePropertySelection:
m_reflectedVarAdapter = new ReflectedVarEnumAdapter;
break;
case ePropertyAnimation:
m_reflectedVarAdapter = new ReflectedVarAnimationAdapter;
break;
case ePropertyColor:
m_reflectedVarAdapter = new ReflectedVarColorAdapter;
break;
@@ -265,7 +262,6 @@ void ReflectedPropertyItem::SetVariable(IVariable *var)
m_reflectedVarAdapter = new ReflectedVarUserAdapter;
break;
case ePropertyEquip:
case ePropertyReverbPreset:
case ePropertyGameToken:
case ePropertyMissionObj:
case ePropertySequence:
@@ -276,15 +272,12 @@ void ReflectedPropertyItem::SetVariable(IVariable *var)
m_reflectedVarAdapter = new ReflectedVarGenericPropertyAdapter(desc.m_type);
break;
case ePropertyTexture:
case ePropertyModel:
case ePropertyGeomCache:
case ePropertyAudioTrigger:
case ePropertyAudioSwitch:
case ePropertyAudioSwitchState:
case ePropertyAudioRTPC:
case ePropertyAudioEnvironment:
case ePropertyAudioPreloadRequest:
case ePropertyFile:
m_reflectedVarAdapter = new ReflectedVarResourceAdapter;
break;
case ePropertyFloatCurve:
@@ -569,7 +562,6 @@ void ReflectedPropertyItem::SetValue(const QString& sValue, bool bRecordUndo, bo
break;
case ePropertyTexture:
case ePropertyModel:
value.replace('\\', '/');
break;
}
@@ -578,8 +570,6 @@ void ReflectedPropertyItem::SetValue(const QString& sValue, bool bRecordUndo, bo
switch (m_type)
{
case ePropertyTexture:
case ePropertyModel:
case ePropertyFile:
if (value.length() >= MAX_PATH)
{
value = value.left(MAX_PATH);
@@ -31,12 +31,6 @@ void ReflectedVarInit::setupReflection(AZ::SerializeContext* serializeContext)
->Field("description", &CReflectedVar::m_description)
->Field("varName", &CReflectedVar::m_varName);
serializeContext->Class <CReflectedVarAnimation, CReflectedVar >()
->Version(1)
->Field("animation", &CReflectedVarAnimation::m_animation)
->Field("entityID", &CReflectedVarAnimation::m_entityID)
;
serializeContext->Class <CReflectedVarResource, CReflectedVar >()
->Version(1)
->Field("path", &CReflectedVarResource::m_path)
@@ -76,12 +70,6 @@ void ReflectedVarInit::setupReflection(AZ::SerializeContext* serializeContext)
AZ::EditContext* ec = serializeContext->GetEditContext();
if (ec)
{
ec->Class< CReflectedVarAnimation >("VarAnimation", "Animation")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &CReflectedVarAnimation::varName)
->Attribute(AZ::Edit::Attributes::DescriptionTextOverride, &CReflectedVarAnimation::description)
;
ec->Class< CReflectedVarResource >("VarResource", "Resource")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::NameLabelOverride, &CReflectedVarResource::varName)
@@ -284,8 +272,6 @@ AZ::u32 CReflectedVarGenericProperty::handler()
return AZ_CRC("ePropertyShader", 0xc40932f1);
case ePropertyEquip:
return AZ_CRC("ePropertyEquip", 0x66ffd290);
case ePropertyReverbPreset:
return AZ_CRC("ePropertyReverbPreset", 0x51469f38);
case ePropertyDeprecated0:
return AZ_CRC("ePropertyCustomAction", 0x4ffa5ba5);
case ePropertyGameToken:
@@ -265,32 +265,8 @@ public:
AZ::Vector3 m_color;
};
//Class to hold ePropertyAnimation (IVariable::DT_ANIMATION )
class CReflectedVarAnimation
: public CReflectedVar
{
public:
AZ_RTTI(CReflectedVarAnimation, "{635D982E-23EC-463F-8F33-4FC2C19D5673}", CReflectedVar)
CReflectedVarAnimation(const AZStd::string& name)
: CReflectedVar(name)
, m_entityID(0)
{}
CReflectedVarAnimation()
: m_entityID(0){}
AZStd::string varName() const { return m_varName; }
AZStd::string description() const { return m_description; }
AZStd::string m_animation;
AZ::EntityId m_entityID;
};
//Class to hold:
// ePropertyTexture (IVariable::DT_TEXTURE)
// ePropertyMaterial (IVariable::DT_MATERIAL)
// ePropertyModel (IVariable::DT_OBJECT)
// ePropertyGeomCache (IVariable::DT_GEOM_CACHE)
// ePropertyAudioTrigger (IVariable::DT_AUDIO_TRIGGER)
// ePropertyAudioSwitch (IVariable::DT_AUDIO_SWITCH )
// ePropertyAudioSwitchState (IVariable::DT_AUDIO_SWITCH_STATE)
@@ -344,7 +320,6 @@ public:
AZStd::vector<AZStd::string> m_itemDescriptions;
};
//Class to hold ePropertyAnimation (IVariable::DT_ANIMATION )
class CReflectedVarSpline
: public CReflectedVar
{
@@ -392,25 +392,6 @@ void ReflectedVarColorAdapter::SyncIVarToReflectedVar(IVariable *pVariable)
void ReflectedVarAnimationAdapter::SetVariable(IVariable *pVariable)
{
m_reflectedVar.reset(new CReflectedVarAnimation(pVariable->GetHumanName().toUtf8().data()));
m_reflectedVar->m_description = pVariable->GetDescription().toUtf8().data();
}
void ReflectedVarAnimationAdapter::SyncReflectedVarToIVar(IVariable *pVariable)
{
m_reflectedVar->m_entityID = static_cast<AZ::EntityId>(pVariable->GetUserData().value<AZ::u64>());
m_reflectedVar->m_animation = pVariable->GetDisplayValue().toUtf8().data();
}
void ReflectedVarAnimationAdapter::SyncIVarToReflectedVar(IVariable *pVariable)
{
pVariable->SetUserData(static_cast<AZ::u64>(m_reflectedVar->m_entityID));
pVariable->SetDisplayValue(m_reflectedVar->m_animation.c_str());
}
void ReflectedVarResourceAdapter::SetVariable(IVariable *pVariable)
{
m_reflectedVar.reset(new CReflectedVarResource(pVariable->GetHumanName().toUtf8().data()));
@@ -429,7 +410,7 @@ void ReflectedVarResourceAdapter::SyncReflectedVarToIVar(IVariable *pVariable)
void ReflectedVarResourceAdapter::SyncIVarToReflectedVar(IVariable *pVariable)
{
const bool bForceModified = (m_reflectedVar->m_propertyType == ePropertyGeomCache);
const bool bForceModified = false;
pVariable->SetForceModified(bForceModified);
pVariable->SetDisplayValue(m_reflectedVar->m_path.c_str());
@@ -218,20 +218,6 @@ AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
class EDITOR_CORE_API ReflectedVarAnimationAdapter
: public ReflectedVarAdapter
{
public:
void SetVariable(IVariable* pVariable) override;
void SyncReflectedVarToIVar(IVariable* pVariable) override;
void SyncIVarToReflectedVar(IVariable* pVariable) override;
CReflectedVar* GetReflectedVar() override { return m_reflectedVar.data(); }
private:
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
QScopedPointer<CReflectedVarAnimation > m_reflectedVar;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
class EDITOR_CORE_API ReflectedVarResourceAdapter
: public ReflectedVarAdapter
{
+8 -11
View File
@@ -891,8 +891,7 @@ CCrySingleDocTemplate::Confidence CCrySingleDocTemplate::MatchDocType(const char
/////////////////////////////////////////////////////////////////////////////
namespace
{
CryMutex g_splashScreenStateLock;
CryConditionVariable g_splashScreenStateChange;
AZStd::mutex g_splashScreenStateLock;
enum ESplashScreenState
{
eSplashScreenState_Init, eSplashScreenState_Started, eSplashScreenState_Destroy
@@ -923,7 +922,7 @@ QString FormatRichTextCopyrightNotice()
/////////////////////////////////////////////////////////////////////////////
void CCryEditApp::ShowSplashScreen(CCryEditApp* app)
{
g_splashScreenStateLock.Lock();
g_splashScreenStateLock.lock();
CStartupLogoDialog* splashScreen = new CStartupLogoDialog(FormatVersion(app->m_pEditor->GetFileVersion()), FormatRichTextCopyrightNotice());
@@ -931,8 +930,7 @@ void CCryEditApp::ShowSplashScreen(CCryEditApp* app)
g_splashScreen = splashScreen;
g_splashScreenState = eSplashScreenState_Started;
g_splashScreenStateLock.Unlock();
g_splashScreenStateChange.Notify();
g_splashScreenStateLock.unlock();
splashScreen->show();
// Make sure the initial paint of the splash screen occurs so we dont get stuck with a blank window
@@ -940,10 +938,9 @@ void CCryEditApp::ShowSplashScreen(CCryEditApp* app)
QObject::connect(splashScreen, &QObject::destroyed, splashScreen, [=]
{
g_splashScreenStateLock.Lock();
AZStd::scoped_lock lock(g_splashScreenStateLock);
g_pInitializeUIInfo = nullptr;
g_splashScreen = nullptr;
g_splashScreenStateLock.Unlock();
});
}
@@ -973,9 +970,9 @@ void CCryEditApp::CloseSplashScreen()
if (CStartupLogoDialog::instance())
{
delete CStartupLogoDialog::instance();
g_splashScreenStateLock.Lock();
g_splashScreenStateLock.lock();
g_splashScreenState = eSplashScreenState_Destroy;
g_splashScreenStateLock.Unlock();
g_splashScreenStateLock.unlock();
}
GetIEditor()->Notify(eNotify_OnSplashScreenDestroyed);
@@ -984,12 +981,12 @@ void CCryEditApp::CloseSplashScreen()
/////////////////////////////////////////////////////////////////////////////
void CCryEditApp::OutputStartupMessage(QString str)
{
g_splashScreenStateLock.Lock();
g_splashScreenStateLock.lock();
if (g_pInitializeUIInfo)
{
g_pInitializeUIInfo->SetInfoText(str.toUtf8().data());
}
g_splashScreenStateLock.Unlock();
g_splashScreenStateLock.unlock();
}
//////////////////////////////////////////////////////////////////////////
+2 -2
View File
@@ -130,7 +130,7 @@ public:
HotKey_BuildDefaults();
for (QPair<QString, QString> key : keys)
{
for (unsigned int j = 0; j < hotkeys.count(); j++)
for (int j = 0; j < hotkeys.count(); j++)
{
if (hotkeys[j].path.compare(key.first, Qt::CaseInsensitive) == 0)
{
@@ -256,7 +256,7 @@ public:
hotkey.second = settings.value("keySequence").toString();
if (!hotkey.first.isEmpty())
{
for (unsigned int j = 0; j < hotkeys.count(); j++)
for (int j = 0; j < hotkeys.count(); j++)
{
if (hotkeys[j].path.compare(hotkey.first, Qt::CaseInsensitive) == 0)
{
+1 -2
View File
@@ -2697,8 +2697,7 @@ void EditorViewportWidget::RestoreViewportAfterGameMode()
QString(
tr("When leaving \" Game Mode \" the engine will automatically restore your camera position to the default position before you "
"had entered Game mode.<br/><br/><small>If you dislike this setting you can always change this anytime in the global "
"preferences.</small><br/><br/>"))
.arg(EditorPreferencesGeneralRestoreViewportCameraSettingName);
"preferences.</small><br/><br/>"));
QString restoreOnExitGameModePopupDisabledRegKey("Editor/AutoHide/ViewportCameraRestoreOnExitGameMode");
// Read the popup disabled registry value
+2 -3
View File
@@ -20,7 +20,6 @@
#include "LogFile.h"
#include "CryListenerSet.h"
#include "Util/ModalWindowDismisser.h"
#include <CryCommon/CryThread.h>
#endif
class CStartupLogoDialog;
@@ -117,11 +116,11 @@ public:
//! mutex used by other threads to lock up the PAK modification,
//! so only one thread can modify the PAK at once
static CryMutex& GetPakModifyMutex()
static AZStd::recursive_mutex& GetPakModifyMutex()
{
//! mutex used to halt copy process while the export to game
//! or other pak operation is done in the main thread
static CryMutex s_pakModifyMutex;
static AZStd::recursive_mutex s_pakModifyMutex;
return s_pakModifyMutex;
}
+1 -1
View File
@@ -136,7 +136,7 @@ bool CGameExporter::Export(unsigned int flags, [[maybe_unused]] EEndian eExportE
m_settings.SetHiQuality();
}
CryAutoLock<CryMutex> autoLock(CGameEngine::GetPakModifyMutex());
AZStd::scoped_lock autoLock(CGameEngine::GetPakModifyMutex());
// Close this pak file.
if (!CloseLevelPack(m_levelPak, true))
-2
View File
@@ -68,7 +68,6 @@ class CDisplaySettings;
struct SGizmoParameters;
class CLevelIndependentFileMan;
class CSelectionTreeManager;
struct IResourceSelectorHost;
struct SEditorSettings;
class CGameExporter;
class IAWSResourceManager;
@@ -714,7 +713,6 @@ struct IEditor
virtual ESystemConfigSpec GetEditorConfigSpec() const = 0;
virtual ESystemConfigPlatform GetEditorConfigPlatform() const = 0;
virtual void ReloadTemplates() = 0;
virtual IResourceSelectorHost* GetResourceSelectorHost() = 0;
virtual void ShowStatusText(bool bEnable) = 0;
// Provides a way to extend the context menu of an object. The function gets called every time the menu is opened.
+3 -5
View File
@@ -67,7 +67,6 @@ AZ_POP_DISABLE_WARNING
#include "EditorFileMonitor.h"
#include "MainStatusBar.h"
#include "ResourceSelectorHost.h"
#include "Util/FileUtil_impl.h"
#include "Util/ImageUtil_impl.h"
#include "LogFileImpl.h"
@@ -187,7 +186,6 @@ CEditorImpl::CEditorImpl()
m_pAnimationContext = new CAnimationContext;
m_pImageUtil = new CImageUtil_impl();
m_pResourceSelectorHost.reset(CreateResourceSelectorHost());
m_selectedRegion.min = Vec3(0, 0, 0);
m_selectedRegion.max = Vec3(0, 0, 0);
DetectVersion();
@@ -252,7 +250,7 @@ void CEditorImpl::Uninitialize()
void CEditorImpl::UnloadPlugins()
{
CryAutoLock<CryMutex> lock(m_pluginMutex);
AZStd::scoped_lock lock(m_pluginMutex);
// Flush core buses. We're about to unload DLLs and need to ensure we don't have module-owned functions left behind.
AZ::Data::AssetBus::ExecuteQueuedEvents();
@@ -273,7 +271,7 @@ void CEditorImpl::UnloadPlugins()
void CEditorImpl::LoadPlugins()
{
CryAutoLock<CryMutex> lock(m_pluginMutex);
AZStd::scoped_lock lock(m_pluginMutex);
static const QString editor_plugins_folder("EditorPlugins");
@@ -1460,7 +1458,7 @@ void CEditorImpl::UnregisterNotifyListener(IEditorNotifyListener* listener)
ISourceControl* CEditorImpl::GetSourceControl()
{
CryAutoLock<CryMutex> lock(m_pluginMutex);
AZStd::scoped_lock lock(m_pluginMutex);
if (m_pSourceControl)
{
+1 -3
View File
@@ -290,7 +290,6 @@ public:
ESystemConfigPlatform GetEditorConfigPlatform() const;
void ReloadTemplates();
void AddErrorMessage(const QString& text, const QString& caption);
IResourceSelectorHost* GetResourceSelectorHost() { return m_pResourceSelectorHost.get(); }
virtual void ShowStatusText(bool bEnable);
void OnObjectContextMenuOpened(QMenu* pMenu, const CBaseObject* pObject);
@@ -374,7 +373,6 @@ protected:
//! Export manager for exporting objects and a terrain from the game to DCC tools
CExportManager* m_pExportManager;
std::unique_ptr<CEditorFileMonitor> m_pEditorFileMonitor;
std::unique_ptr<IResourceSelectorHost> m_pResourceSelectorHost;
QString m_selectFileBuffer;
QString m_levelNameBuffer;
@@ -401,7 +399,7 @@ protected:
IImageUtil* m_pImageUtil; // Vladimir@conffx
ILogFile* m_pLogFile; // Vladimir@conffx
CryMutex m_pluginMutex; // protect any pointers that come from plugins, such as the source control cached pointer.
AZStd::mutex m_pluginMutex; // protect any pointers that come from plugins, such as the source control cached pointer.
static const char* m_crashLogFileName;
};
+1 -1
View File
@@ -65,7 +65,7 @@ struct HotKey
int size = (m_catSize < o_catSize) ? m_catSize : o_catSize;
//sort categories to keep them together
for (unsigned int i = 0; i < size; i++)
for (int i = 0; i < size; i++)
{
if (m_categories[i] < o_categories[i])
{
-135
View File
@@ -1,135 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
// The aim of IResourceSelectorHost is to unify resource selection dialogs in a one
// API that can be reused with plugins. It also makes possible to register new
// resource selectors dynamically, e.g. inside plugins.
//
// Here is how new selectors are created. In your implementation file you add handler function:
//
// #include "IResourceSelectorHost.h"
//
// QString SoundFileSelector(const SResourceSelectorContext& x, const QString& previousValue)
// {
// CMyModalDialog dialog(CWnd::FromHandle(x.parentWindow));
// ...
// return previousValue;
// }
// REGISTER_RESOURCE_SELECTOR("Sound", SoundFileSelector, "Icons/sound_16x16.png")
//
// Here is how it can be invoked directly:
//
// SResourceSelectorContext x;
// x.parentWindow = parent.GetSafeHwnd();
// x.typeName = "Sound";
// string newValue = GetIEditor()->GetResourceSelector()->SelectResource(x, previousValue).c_str();
//
// If you have your own resource selectors in the plugin you will need to run
//
// RegisterModuleResourceSelectors(GetIEditor()->GetResourceSelector())
//
// during plugin initialization.
//
// If you want to be able to pass some custom context to the selector (e.g. source of the information for the
// list of items or something similar) then you can add a poitner argument to your selector function, i.e.:
//
// QString SoundFileSelector(const SResourceSelectorContext& x, const QString& previousValue,
// SoundFileList* list) // your context argument
#include <QString>
class QWidget;
struct SResourceSelectorContext
{
const char* typeName;
// use either parentWidget or parentWindow (not both) until everything porting to QWidget.
QWidget* parentWidget;
unsigned int entityId;
void* contextObject;
SResourceSelectorContext()
: parentWidget(0)
, typeName(0)
, entityId(0)
, contextObject()
{
}
};
// TResourceSelecitonFunction is used to declare handlers for specific types.
//
// For canceled dialogs previousValue should be returned.
typedef QString (* TResourceSelectionFunction)(const SResourceSelectorContext& selectorContext, const QString& previousValue);
typedef QString (* TResourceSelectionFunctionWithContext)(const SResourceSelectorContext& selectorContext, const QString& previousValue, void* contextObject);
struct SStaticResourceSelectorEntry;
// See note at the beginning of the file.
struct IResourceSelectorHost
{
virtual ~IResourceSelectorHost() = default;
virtual QString SelectResource(const SResourceSelectorContext& context, const QString& previousValue) = 0;
virtual const char* ResourceIconPath(const char* typeName) const = 0;
virtual void RegisterResourceSelector(const SStaticResourceSelectorEntry* entry) = 0;
// secondary responsibility of this class is to store global selections
virtual void SetGlobalSelection(const char* resourceType, const char* value) = 0;
virtual const char* GetGlobalSelection(const char* resourceType) const = 0;
};
// ---------------------------------------------------------------------------
#define INTERNAL_RSH_COMBINE_UTIL(A, B) A##B
#define INTERNAL_RSH_COMBINE(A, B) INTERNAL_RSH_COMBINE_UTIL(A, B)
#define REGISTER_RESOURCE_SELECTOR(name, function, icon) \
static SStaticResourceSelectorEntry INTERNAL_RSH_COMBINE(selector_##function, __LINE__)((name), (function), (icon));
struct SStaticResourceSelectorEntry
{
const char* typeName;
TResourceSelectionFunction function;
TResourceSelectionFunctionWithContext functionWithContext;
const char* iconPath;
static SStaticResourceSelectorEntry*& GetFirst() { static SStaticResourceSelectorEntry* first; return first; }
SStaticResourceSelectorEntry* next;
SStaticResourceSelectorEntry(const char* typeName, TResourceSelectionFunction function, const char* icon)
: typeName(typeName)
, function(function)
, functionWithContext()
, iconPath(icon)
{
next = GetFirst();
GetFirst() = this;
}
template<class T>
SStaticResourceSelectorEntry(const char* typeName, QString (*function)(const SResourceSelectorContext&, const QString& previousValue, T * context), const char* icon)
: typeName(typeName)
, function()
, functionWithContext(TResourceSelectionFunctionWithContext(function))
, iconPath(icon)
{
next = GetFirst();
GetFirst() = this;
}
};
inline void RegisterModuleResourceSelectors(IResourceSelectorHost* editorResourceSelector)
{
for (SStaticResourceSelectorEntry* current = SStaticResourceSelectorEntry::GetFirst(); current != 0; current = current->next)
{
editorResourceSelector->RegisterResourceSelector(current);
}
}
-1
View File
@@ -178,7 +178,6 @@ public:
MOCK_CONST_METHOD0(GetEditorConfigSpec, ESystemConfigSpec());
MOCK_CONST_METHOD0(GetEditorConfigPlatform, ESystemConfigPlatform());
MOCK_METHOD0(ReloadTemplates, void());
MOCK_METHOD0(GetResourceSelectorHost, IResourceSelectorHost* ());
MOCK_METHOD1(ShowStatusText, void(bool ));
MOCK_METHOD1(RegisterObjectContextMenuExtension, void(TContextMenuExtensionFunc ));
MOCK_METHOD0(GetEnv, SSystemGlobalEnvironment* ());
@@ -0,0 +1,152 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzFramework/Viewport/CameraInput.h>
#include <AzFramework/Viewport/ViewportControllerList.h>
#include <AzToolsFramework/Input/QtEventToAzInputManager.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
#include <Editor/ViewportManipulatorController.h>
namespace UnitTest
{
using AzToolsFramework::ViewportInteraction::MouseInteractionEvent;
class EditorInteractionViewportSelectionFake : public AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus::Handler
{
public:
void Connect();
void Disconnect();
// EditorInteractionSystemViewportSelectionRequestBus overrides ...
void SetHandler(const AzToolsFramework::ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder);
void SetDefaultHandler();
bool InternalHandleMouseViewportInteraction(const MouseInteractionEvent& mouseInteraction);
bool InternalHandleMouseManipulatorInteraction(const MouseInteractionEvent& mouseInteraction);
AZStd::function<bool(const MouseInteractionEvent& mouseInteraction)> m_internalHandleMouseViewportInteraction;
AZStd::function<bool(const MouseInteractionEvent& mouseInteraction)> m_internalHandleMouseManipulatorInteraction;
};
void EditorInteractionViewportSelectionFake::Connect()
{
AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus::Handler::BusConnect(AzToolsFramework::GetEntityContextId());
}
void EditorInteractionViewportSelectionFake::Disconnect()
{
AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus::Handler::BusDisconnect();
}
void EditorInteractionViewportSelectionFake::SetHandler(
[[maybe_unused]] const AzToolsFramework::ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder)
{
// noop
}
void EditorInteractionViewportSelectionFake::SetDefaultHandler()
{
// noop
}
bool EditorInteractionViewportSelectionFake::InternalHandleMouseViewportInteraction(const MouseInteractionEvent& mouseInteraction)
{
if (m_internalHandleMouseViewportInteraction)
{
return m_internalHandleMouseViewportInteraction(mouseInteraction);
}
return false;
}
bool EditorInteractionViewportSelectionFake::InternalHandleMouseManipulatorInteraction(const MouseInteractionEvent& mouseInteraction)
{
if (m_internalHandleMouseManipulatorInteraction)
{
return m_internalHandleMouseManipulatorInteraction(mouseInteraction);
}
return false;
}
class ViewportManipulatorControllerFixture : public AllocatorsTestFixture
{
public:
static const AzFramework::ViewportId TestViewportId = AzFramework::ViewportId(0);
void SetUp() override
{
AllocatorsTestFixture::SetUp();
m_rootWidget = AZStd::make_unique<QWidget>();
m_rootWidget->setFixedSize(QSize(100, 100));
m_controllerList = AZStd::make_shared<AzFramework::ViewportControllerList>();
m_controllerList->RegisterViewportContext(TestViewportId);
m_inputChannelMapper = AZStd::make_unique<AzToolsFramework::QtEventToAzInputMapper>(m_rootWidget.get(), TestViewportId);
}
void TearDown()
{
m_inputChannelMapper.reset();
m_controllerList->UnregisterViewportContext(TestViewportId);
m_controllerList.reset();
m_rootWidget.reset();
AllocatorsTestFixture::TearDown();
}
AZStd::unique_ptr<QWidget> m_rootWidget;
AzFramework::ViewportControllerListPtr m_controllerList;
AZStd::unique_ptr<AzToolsFramework::QtEventToAzInputMapper> m_inputChannelMapper;
};
TEST_F(ViewportManipulatorControllerFixture, An_event_is_not_propagated_to_the_viewport_when_a_manipulator_handles_it_first)
{
// forward input events to our controller list
QObject::connect(
m_inputChannelMapper.get(), &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, m_rootWidget.get(),
[this](const AzFramework::InputChannel* inputChannel, [[maybe_unused]] QEvent* event)
{
m_controllerList->HandleInputChannelEvent(
AzFramework::ViewportControllerInputEvent{ TestViewportId, nullptr, *inputChannel });
});
EditorInteractionViewportSelectionFake editorInteractionViewportFake;
editorInteractionViewportFake.m_internalHandleMouseManipulatorInteraction = [](const MouseInteractionEvent&)
{
// report the event was handled (manipulator was interacted with)
return true;
};
bool viewportInteractionCalled = false;
editorInteractionViewportFake.m_internalHandleMouseViewportInteraction = [&viewportInteractionCalled](const MouseInteractionEvent&)
{
// we should not call this as the manipulator will have consumed this event
viewportInteractionCalled = true;
return true;
};
editorInteractionViewportFake.Connect();
m_controllerList->Add(AZStd::make_shared<SandboxEditor::ViewportManipulatorController>());
// simulate a press and move
MousePressAndMove(m_rootWidget.get(), QPoint(10, 10), QPoint(10, 10), Qt::MouseButton::LeftButton);
MouseMove(m_rootWidget.get(), QPoint(20, 20), QPoint(10, 10), Qt::MouseButton::LeftButton);
MouseMove(m_rootWidget.get(), QPoint(30, 30), QPoint(0, 0), Qt::MouseButton::LeftButton);
QTest::mouseRelease(m_rootWidget.get(), Qt::MouseButton::LeftButton, Qt::KeyboardModifier::NoModifier, QPoint(30, 30));
// ensure the viewport did not receive the event when it was intercepted first by the manipulator
EXPECT_FALSE(viewportInteractionCalled);
editorInteractionViewportFake.Disconnect();
}
} // namespace UnitTest
@@ -9,7 +9,6 @@
#include "ComponentEntityEditorPlugin.h"
#include <LyViewPaneNames.h>
#include "IResourceSelectorHost.h"
#include "UI/QComponentEntityEditorMainWindow.h"
#include "UI/QComponentEntityEditorOutlinerWindow.h"
@@ -180,8 +179,6 @@ ComponentEntityEditorPlugin::ComponentEntityEditorPlugin([[maybe_unused]] IEdito
RegisterViewPane<SliceRelationshipWidget>(LyViewPane::SliceRelationships, LyViewPane::CategoryTools, options);
}
RegisterModuleResourceSelectors(GetIEditor()->GetResourceSelectorHost());
ComponentEntityEditorPluginInternal::RegisterSandboxObjects();
// Check for common mistakes in component declarations
@@ -82,7 +82,6 @@
#include <Editor/QtViewPaneManager.h>
#include <Editor/EditorViewportSettings.h>
#include <Editor/Util/PathUtil.h>
#include <IResourceSelectorHost.h>
#include "CryEdit.h"
#include "Undo/Undo.h"
@@ -1387,16 +1386,6 @@ AZStd::string SandboxIntegrationManager::GetLevelName()
return AZStd::string(GetIEditor()->GetGameEngine()->GetLevelName().toUtf8().constData());
}
AZStd::string SandboxIntegrationManager::SelectResource(const AZStd::string& resourceType, const AZStd::string& previousValue)
{
SResourceSelectorContext context;
context.parentWidget = GetMainWindow();
context.typeName = resourceType.c_str();
QString resource = GetEditor()->GetResourceSelectorHost()->SelectResource(context, previousValue.c_str());
return AZStd::string(resource.toUtf8().constData());
}
void SandboxIntegrationManager::OnContextReset()
{
// Deselect everything.
@@ -1452,7 +1441,7 @@ void SandboxIntegrationManager::ContextMenu_NewEntity()
if (view)
{
const QPoint viewPoint(m_contextMenuViewPoint.GetX(), m_contextMenuViewPoint.GetY());
worldPosition = LYVec3ToAZVec3(view->SnapToGrid(view->ViewToWorld(viewPoint)));
worldPosition = view->GetHitLocation(viewPoint);
}
CreateNewEntityAtPosition(worldPosition);
@@ -158,7 +158,6 @@ private:
void LaunchLuaEditor(const char* files) override;
bool IsLevelDocumentOpen() override;
AZStd::string GetLevelName() override;
AZStd::string SelectResource(const AZStd::string& resourceType, const AZStd::string& previousValue) override;
void OpenPinnedInspector(const AzToolsFramework::EntityIdSet& entities) override;
void ClosePinnedInspector(AzToolsFramework::EntityPropertyEditor* editor) override;
void GoToSelectedOrHighlightedEntitiesInViewports() override;
@@ -13,6 +13,7 @@
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/SceneCore/Events/AssetImportRequest.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneSerializationHandler.h>
@@ -96,7 +97,7 @@ namespace AZ
}
AZStd::shared_ptr<SceneAPI::Containers::Scene> scene =
AssetImportRequest::LoadSceneFromVerifiedPath(cleanPath, sceneSourceGuid, AssetImportRequest::RequestingApplication::Editor);
AssetImportRequest::LoadSceneFromVerifiedPath(cleanPath, sceneSourceGuid, AssetImportRequest::RequestingApplication::Editor, SceneAPI::SceneCore::LoadingComponent::TYPEINFO_Uuid());
if (!scene)
{
AZ_TracePrintf(Utilities::ErrorWindow, "Failed to load the requested scene.");
@@ -9,7 +9,6 @@
#include "CryFile.h"
#include "PerforceSourceControl.h"
#include "PasswordDlg.h"
#include <CryCommon/CryThread.h>
#include <QSettings>
#include <QDir>
@@ -23,7 +22,7 @@
namespace
{
CryCriticalSection g_cPerforceValues;
AZStd::mutex g_cPerforceValues;
}
////////////////////////////////////////////////////////////
@@ -31,9 +30,9 @@ ULONG STDMETHODCALLTYPE CPerforceSourceControl::Release()
{
if ((--m_ref) == 0)
{
g_cPerforceValues.Lock();
g_cPerforceValues.lock();
delete this;
g_cPerforceValues.Unlock();
g_cPerforceValues.unlock();
return 0;
}
else
@@ -57,7 +56,7 @@ void CPerforceSourceControl::ShowSettings()
void CPerforceSourceControl::SetSourceControlState(SourceControlState state)
{
CryAutoLock<CryCriticalSection> lock(g_cPerforceValues);
AZStd::scoped_lock lock(g_cPerforceValues);
switch (state)
{
-163
View File
@@ -1,163 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "EditorDefs.h"
#include "ResourceSelectorHost.h"
// Qt
#include <QMessageBox>
#include <QString>
// AzToolsFramework
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/AssetBrowser/Search/Filter.h>
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
class CResourceSelectorHost
: public IResourceSelectorHost
{
public:
CResourceSelectorHost()
{
RegisterModuleResourceSelectors(this);
}
QString SelectResource(const SResourceSelectorContext& context, const QString& previousValue) override
{
if (!context.typeName)
{
assert(false && "SResourceSelectorContext::typeName is not specified");
return QString();
}
TTypeMap::iterator it = m_typeMap.find(context.typeName);
if (it == m_typeMap.end())
{
QMessageBox::critical(QApplication::activeWindow(), QString(), QObject::tr("No Resource Selector is registered for resource type \"%1\"").arg(context.typeName));
return previousValue;
}
QString result = previousValue;
if (it->second->function)
{
result = it->second->function(context, previousValue);
}
else if (it->second->functionWithContext)
{
result = it->second->functionWithContext(context, previousValue, context.contextObject);
}
return result;
}
const char* ResourceIconPath(const char* typeName) const override
{
TTypeMap::const_iterator it = m_typeMap.find(typeName);
if (it != m_typeMap.end())
{
return it->second->iconPath;
}
return "";
}
void RegisterResourceSelector(const SStaticResourceSelectorEntry* entry) override
{
m_typeMap[entry->typeName] = entry;
}
void SetGlobalSelection(const char* resourceType, const char* value) override
{
if (!resourceType || !value)
{
return;
}
m_globallySelectedResources[resourceType] = value;
}
const char* GetGlobalSelection(const char* resourceType) const override
{
if (!resourceType)
{
return "";
}
auto it = m_globallySelectedResources.find(resourceType);
if (it != m_globallySelectedResources.end())
{
return it->second.c_str();
}
return "";
}
private:
using TTypeMap = std::map<AZStd::string, const SStaticResourceSelectorEntry *, stl::less_stricmp<AZStd::string>>;
TTypeMap m_typeMap;
std::map<AZStd::string, AZStd::string> m_globallySelectedResources;
};
// ---------------------------------------------------------------------------
IResourceSelectorHost* CreateResourceSelectorHost()
{
return new CResourceSelectorHost();
}
// ---------------------------------------------------------------------------
QString SoundFileSelector([[maybe_unused]] const SResourceSelectorContext& x, const QString& previousValue)
{
AssetSelectionModel selection = AssetSelectionModel::AssetTypeSelection("Audio");
AzToolsFramework::EditorRequests::Bus::Broadcast(&AzToolsFramework::EditorRequests::BrowseForAssets, selection);
if (selection.IsValid())
{
return Path::FullPathToGamePath(QString(selection.GetResult()->GetFullPath().c_str()));
}
else
{
return Path::FullPathToGamePath(previousValue);
}
}
REGISTER_RESOURCE_SELECTOR("Sound", SoundFileSelector, "")
// ---------------------------------------------------------------------------
QString ModelFileSelector([[maybe_unused]] const SResourceSelectorContext& x, const QString& previousValue)
{
AssetSelectionModel selection = AssetSelectionModel::AssetGroupSelection("Geometry");
AzToolsFramework::EditorRequests::Bus::Broadcast(&AzToolsFramework::EditorRequests::BrowseForAssets, selection);
if (selection.IsValid())
{
return Path::FullPathToGamePath(QString(selection.GetResult()->GetFullPath().c_str()));
}
else
{
return Path::FullPathToGamePath(previousValue);
}
}
REGISTER_RESOURCE_SELECTOR("Model", ModelFileSelector, "")
// ---------------------------------------------------------------------------
QString GeomCacheFileSelector([[maybe_unused]] const SResourceSelectorContext& x, const QString& previousValue)
{
AssetSelectionModel selection = AssetSelectionModel::AssetTypeSelection("Geom Cache");
AzToolsFramework::EditorRequests::Bus::Broadcast(&AzToolsFramework::EditorRequests::BrowseForAssets, selection);
if (selection.IsValid())
{
return Path::FullPathToGamePath(QString(selection.GetResult()->GetFullPath().c_str()));
}
else
{
return Path::FullPathToGamePath(previousValue);
}
}
REGISTER_RESOURCE_SELECTOR("GeomCache", GeomCacheFileSelector, "")
-18
View File
@@ -1,18 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_RESOURCESELECTORHOST_H
#define CRYINCLUDE_EDITOR_RESOURCESELECTORHOST_H
#pragma once
#include "IResourceSelectorHost.h"
IResourceSelectorHost* CreateResourceSelectorHost();
#endif // CRYINCLUDE_EDITOR_RESOURCESELECTORHOST_H
-1
View File
@@ -9,7 +9,6 @@
#pragma once
#include "CryThread.h"
#include "../Include/SandboxAPI.h"
#include <QString>
#include <QFileInfo>
-2
View File
@@ -10,8 +10,6 @@
#include "StringHelpers.h"
#include "Util.h"
#include <AzCore/std/string/string.h>
int StringHelpers::CompareIgnoreCase(const AZStd::string& str0, const AZStd::string& str1)
{
const size_t minLength = Util::getMin(str0.length(), str1.length());
+1 -1
View File
@@ -12,7 +12,7 @@
#pragma once
#include <AzCore/std/string/string.h>
#include <AzCore/std/containers/vector.h>
#include <vector>
namespace StringHelpers
{
+1 -1
View File
@@ -351,7 +351,7 @@ void CVarBlock::EnableUpdateCallbacks(bool boEnable)
void CVarBlock::GatherUsedResourcesInVar(IVariable* pVar, CUsedResources& resources)
{
int type = pVar->GetDataType();
if (type == IVariable::DT_FILE || type == IVariable::DT_OBJECT || type == IVariable::DT_TEXTURE)
if (type == IVariable::DT_TEXTURE)
{
// this is file.
QString filename;
+2 -6
View File
@@ -22,6 +22,8 @@ AZ_PUSH_DISABLE_WARNING(4458, "-Wunknown-warning-option")
AZ_POP_DISABLE_WARNING
#include <QVariant>
#include <StlUtils.h>
inline const char* to_c_str(const char* str) { return str; }
#define MAX_VAR_STRING_LENGTH 4096
@@ -140,15 +142,10 @@ struct IVariable
DT_PERCENT, //!< Percent data type, (Same as simple but value is from 0-1 and UI will be from 0-100).
DT_COLOR,
DT_ANGLE,
DT_FILE,
DT_TEXTURE,
DT_ANIMATION,
DT_OBJECT,
DT_SHADER,
DT_LOCAL_STRING,
DT_EQUIP,
DT_REVERBPRESET,
DT_DEPRECATED0, // formerly DT_MATERIAL
DT_MATERIALLOOKUP,
DT_EXTARRAY, // Extendable Array
DT_SEQUENCE, // Movie Sequence (DEPRECATED, use DT_SEQUENCE_ID, instead.)
@@ -158,7 +155,6 @@ struct IVariable
DT_SEQUENCE_ID, // Movie Sequence
DT_LIGHT_ANIMATION, // Light Animation Node in the global Light Animation Set
DT_PARTICLE_EFFECT,
DT_GEOM_CACHE, // Geometry cache
DT_DEPRECATED, // formerly DT_FLARE
DT_AUDIO_TRIGGER,
DT_AUDIO_SWITCH,
-33
View File
@@ -37,17 +37,12 @@ namespace Prop
{ IVariable::DT_CURVE | IVariable::DT_PERCENT, "FloatCurve", ePropertyFloatCurve, 13 },
{ IVariable::DT_CURVE | IVariable::DT_COLOR, "ColorCurve", ePropertyColorCurve, 1 },
{ IVariable::DT_ANGLE, "Angle", ePropertyAngle, 0 },
{ IVariable::DT_FILE, "File", ePropertyFile, 7 },
{ IVariable::DT_TEXTURE, "Texture", ePropertyTexture, 4 },
{ IVariable::DT_ANIMATION, "Animation", ePropertyAnimation, -1 },
{ IVariable::DT_MOTION, "Motion", ePropertyMotion, -1 },
{ IVariable::DT_OBJECT, "Model", ePropertyModel, 5 },
{ IVariable::DT_SIMPLE, "Selection", ePropertySelection, -1 },
{ IVariable::DT_SIMPLE, "List", ePropertyList, -1 },
{ IVariable::DT_SHADER, "Shader", ePropertyShader, 9 },
{ IVariable::DT_DEPRECATED0, "DEPRECATED", ePropertyDeprecated2, -1 },
{ IVariable::DT_EQUIP, "Equip", ePropertyEquip, 11 },
{ IVariable::DT_REVERBPRESET, "ReverbPreset", ePropertyReverbPreset, 11 },
{ IVariable::DT_LOCAL_STRING, "LocalString", ePropertyLocalString, 3 },
{ IVariable::DT_SEQUENCE, "Sequence", ePropertySequence, -1 },
{ IVariable::DT_MISSIONOBJ, "Mission Objective", ePropertyMissionObj, -1 },
@@ -55,7 +50,6 @@ namespace Prop
{ IVariable::DT_SEQUENCE_ID, "SequenceId", ePropertySequenceId, -1 },
{ IVariable::DT_LIGHT_ANIMATION, "LightAnimation", ePropertyLightAnimation, -1 },
{ IVariable::DT_PARTICLE_EFFECT, "ParticleEffect", ePropertyParticleName, 3 },
{ IVariable::DT_GEOM_CACHE, "Geometry Cache", ePropertyGeomCache, 5 },
{ IVariable::DT_AUDIO_TRIGGER, "Audio Trigger", ePropertyAudioTrigger, 6 },
{ IVariable::DT_AUDIO_SWITCH, "Audio Switch", ePropertyAudioSwitch, 6 },
{ IVariable::DT_AUDIO_SWITCH_STATE, "Audio Switch", ePropertyAudioSwitchState, 6 },
@@ -301,31 +295,4 @@ namespace Prop
return -1;
}
const char* GetPropertyTypeToResourceType(PropertyType type)
{
// The strings below are names used together with
// REGISTER_RESOURCE_SELECTOR. See IResourceSelector.h.
switch (type)
{
case ePropertyModel:
return "Model";
case ePropertyGeomCache:
return "GeomCache";
case ePropertyAudioTrigger:
return "AudioTrigger";
case ePropertyAudioSwitch:
return "AudioSwitch";
case ePropertyAudioSwitchState:
return "AudioSwitchState";
case ePropertyAudioRTPC:
return "AudioRTPC";
case ePropertyAudioEnvironment:
return "AudioEnvironment";
case ePropertyAudioPreloadRequest:
return "AudioPreloadRequest";
default:
return nullptr;
}
}
}
-6
View File
@@ -28,16 +28,11 @@ enum PropertyType
ePropertyAngle,
ePropertyFloatCurve,
ePropertyColorCurve,
ePropertyFile,
ePropertyTexture,
ePropertyAnimation,
ePropertyModel,
ePropertySelection,
ePropertyList,
ePropertyShader,
ePropertyDeprecated2, // formerly ePropertyMaterial
ePropertyEquip,
ePropertyReverbPreset,
ePropertyLocalString,
ePropertyDeprecated0, // formerly ePropertyCustomAction
ePropertyGameToken,
@@ -48,7 +43,6 @@ enum PropertyType
ePropertyLightAnimation,
ePropertyDeprecated1, // formerly ePropertyFlare
ePropertyParticleName,
ePropertyGeomCache,
ePropertyAudioTrigger,
ePropertyAudioSwitch,
ePropertyAudioSwitchState,
+24 -18
View File
@@ -46,24 +46,7 @@ void QtViewport::BuildDragDropContext(AzQtComponents::ViewportDragContext& conte
PreWidgetRendering(); // required so that the current render cam is set.
Vec3 pos = Vec3(ZERO);
HitContext hit;
if (HitTest(pt, hit))
{
pos = hit.raySrc + hit.rayDir * hit.dist;
pos = SnapToGrid(pos);
}
else
{
bool hitTerrain;
pos = ViewToWorld(pt, &hitTerrain);
if (hitTerrain)
{
pos.z = GetIEditor()->GetTerrainElevation(pos.x, pos.y);
}
pos = SnapToGrid(pos);
}
context.m_hitLocation = AZ::Vector3(pos.x, pos.y, pos.z);
context.m_hitLocation = GetHitLocation(pt);
PostWidgetRendering();
}
@@ -1154,6 +1137,29 @@ bool QtViewport::HitTest(const QPoint& point, HitContext& hitInfo)
return false;
}
AZ::Vector3 QtViewport::GetHitLocation(const QPoint& point)
{
Vec3 pos = Vec3(ZERO);
HitContext hit;
if (HitTest(point, hit))
{
pos = hit.raySrc + hit.rayDir * hit.dist;
pos = SnapToGrid(pos);
}
else
{
bool hitTerrain;
pos = ViewToWorld(point, &hitTerrain);
if (hitTerrain)
{
pos.z = GetIEditor()->GetTerrainElevation(pos.x, pos.y);
}
pos = SnapToGrid(pos);
}
return AZ::Vector3(pos.x, pos.y, pos.z);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::SetZoomFactor(float fZoomFactor)
{
+2
View File
@@ -201,6 +201,7 @@ public:
//! Performs hit testing of 2d point in view to find which object hit.
virtual bool HitTest(const QPoint& point, HitContext& hitInfo) = 0;
virtual AZ::Vector3 GetHitLocation(const QPoint& point) = 0;
virtual void MakeConstructionPlane(int axis) = 0;
@@ -436,6 +437,7 @@ public:
//! Performs hit testing of 2d point in view to find which object hit.
bool HitTest(const QPoint& point, HitContext& hitInfo) override;
AZ::Vector3 GetHitLocation(const QPoint& point) override;
//! Do 2D hit testing of line in world space.
// pToCameraDistance is an optional output parameter in which distance from the camera to the line is returned.
+16 -7
View File
@@ -28,6 +28,8 @@ namespace SandboxEditor
{
}
ViewportManipulatorControllerInstance::~ViewportManipulatorControllerInstance() = default;
AzToolsFramework::ViewportInteraction::MouseButton ViewportManipulatorControllerInstance::GetMouseButton(
const AzFramework::InputChannel& inputChannel)
{
@@ -103,14 +105,21 @@ namespace SandboxEditor
// Cache the ray trace results when doing manipulator interaction checks, no need to recalculate after
if (event.m_priority == ManipulatorPriority)
{
AzFramework::ScreenPoint screenPosition = AzFramework::ScreenPoint(0, 0);
ViewportMouseCursorRequestBus::EventResult(
screenPosition, GetViewportId(), &ViewportMouseCursorRequestBus::Events::ViewportCursorScreenPosition);
const auto* position = event.m_inputChannel.GetCustomData<AzFramework::InputChannel::PositionData2D>();
AZ_Assert(position, "Expected PositionData2D but found nullptr");
m_mouseInteraction.m_mousePick.m_screenCoordinates = screenPosition;
AzFramework::WindowSize windowSize;
AzFramework::WindowRequestBus::EventResult(
windowSize, event.m_windowHandle, &AzFramework::WindowRequestBus::Events::GetClientAreaSize);
auto screenPoint = AzFramework::ScreenPoint(
position->m_normalizedPosition.GetX() * windowSize.m_width,
position->m_normalizedPosition.GetY() * windowSize.m_height);
m_mouseInteraction.m_mousePick.m_screenCoordinates = screenPoint;
AZStd::optional<ProjectedViewportRay> ray;
ViewportInteractionRequestBus::EventResult(
ray, GetViewportId(), &ViewportInteractionRequestBus::Events::ViewportScreenToWorldRay, screenPosition);
ray, GetViewportId(), &ViewportInteractionRequestBus::Events::ViewportScreenToWorldRay, screenPoint);
if (ray.has_value())
{
@@ -118,6 +127,7 @@ namespace SandboxEditor
m_mouseInteraction.m_mousePick.m_rayDirection = ray.value().direction;
}
}
eventType = MouseEvent::Move;
}
else if (auto mouseButton = GetMouseButton(event.m_inputChannel); mouseButton != MouseButton::None)
@@ -217,8 +227,7 @@ namespace SandboxEditor
interactionHandled, AzToolsFramework::GetEntityContextId(), targetInteractionEvent, mouseInteractionEvent);
}
// Only filter button/key press events, not release events
return interactionHandled && event.m_inputChannel.IsActive();
return interactionHandled;
}
void ViewportManipulatorControllerInstance::ResetInputChannels()
+12 -8
View File
@@ -8,25 +8,29 @@
#pragma once
#include <AzFramework/Viewport/ViewportId.h>
#include <AzFramework/Viewport/MultiViewportController.h>
#include <AzFramework/Input/Events/InputChannelEventListener.h>
#include <AzFramework/Viewport/MultiViewportController.h>
#include <AzFramework/Viewport/ViewportId.h>
#include <AzToolsFramework/Viewport/ViewportTypes.h>
#include <SandboxAPI.h>
namespace SandboxEditor
{
class ViewportManipulatorControllerInstance;
using ViewportManipulatorController = AzFramework::MultiViewportController<ViewportManipulatorControllerInstance, AzFramework::ViewportControllerPriority::DispatchToAllPriorities>;
using ViewportManipulatorController = AzFramework::
MultiViewportController<ViewportManipulatorControllerInstance, AzFramework::ViewportControllerPriority::DispatchToAllPriorities>;
class ViewportManipulatorControllerInstance final
: public AzFramework::MultiViewportControllerInstanceInterface<ViewportManipulatorController>
{
public:
explicit ViewportManipulatorControllerInstance(AzFramework::ViewportId viewport, ViewportManipulatorController* controller);
SANDBOX_API ViewportManipulatorControllerInstance(AzFramework::ViewportId viewport, ViewportManipulatorController* controller);
SANDBOX_API ~ViewportManipulatorControllerInstance();
bool HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) override;
void ResetInputChannels() override;
void UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) override;
SANDBOX_API bool HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) override;
SANDBOX_API void ResetInputChannels() override;
SANDBOX_API void UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) override;
private:
bool IsDoubleClick(AzToolsFramework::ViewportInteraction::MouseButton) const;
@@ -39,4 +43,4 @@ namespace SandboxEditor
AZStd::unordered_map<AzToolsFramework::ViewportInteraction::MouseButton, AZ::ScriptTimePoint> m_pendingDoubleClicks;
AZ::ScriptTimePoint m_curTime;
};
} //namespace SandboxEditor
} // namespace SandboxEditor
-8
View File
@@ -289,7 +289,6 @@ set(FILES
Include/IPlugin.h
Include/IPreferencesPage.h
Include/IRenderListener.h
Include/IResourceSelectorHost.h
Include/ISourceControl.h
Include/ISubObjectSelectionReferenceFrameCalculator.h
Include/ITextureDatabaseUpdater.h
@@ -360,8 +359,6 @@ set(FILES
Controls/TimelineCtrl.cpp
Controls/TimelineCtrl.h
Controls/WndGridHelper.h
Controls/ReflectedPropertyControl/PropertyAnimationCtrl.cpp
Controls/ReflectedPropertyControl/PropertyAnimationCtrl.h
Controls/ReflectedPropertyControl/PropertyGenericCtrl.cpp
Controls/ReflectedPropertyControl/PropertyGenericCtrl.h
Controls/ReflectedPropertyControl/PropertyMiscCtrl.cpp
@@ -372,8 +369,6 @@ set(FILES
Controls/ReflectedPropertyControl/PropertyResourceCtrl.h
Controls/ReflectedPropertyControl/PropertyCtrl.cpp
Controls/ReflectedPropertyControl/PropertyCtrl.h
Controls/ReflectedPropertyControl/ReflectedPropertiesPanel.cpp
Controls/ReflectedPropertyControl/ReflectedPropertiesPanel.h
MainStatusBar.cpp
MainStatusBar.h
MainStatusBarItems.h
@@ -590,8 +585,6 @@ set(FILES
FBXExporterDialog.ui
FileTypeUtils.cpp
LightmapCompiler/SimpleTriangleRasterizer.cpp
ResourceSelectorHost.cpp
ResourceSelectorHost.h
ToolBox.cpp
TrackViewNewSequenceDialog.cpp
TrackViewNewSequenceDialog.ui
@@ -668,7 +661,6 @@ set(FILES
TrackView/2DBezierKeyUIControls.cpp
TrackView/AssetBlendKeyUIControls.cpp
TrackView/CaptureKeyUIControls.cpp
TrackView/CharacterKeyUIControls.cpp
TrackView/ConsoleKeyUIControls.cpp
TrackView/EventKeyUIControls.cpp
TrackView/GotoKeyUIControls.cpp
+1
View File
@@ -20,6 +20,7 @@ set(FILES
Lib/Tests/test_ViewPanePythonBindings.cpp
Lib/Tests/test_ViewportTitleDlgPythonBindings.cpp
Lib/Tests/test_DisplaySettingsPythonBindings.cpp
Lib/Tests/test_ViewportManipulatorController.cpp
DisplaySettingsPythonFuncs.cpp
DisplaySettingsPythonFuncs.h
)
@@ -728,6 +728,7 @@ namespace AZ
DestroyReflectionManager();
static_cast<SettingsRegistryImpl*>(m_settingsRegistry.get())->ClearNotifiers();
static_cast<SettingsRegistryImpl*>(m_settingsRegistry.get())->ClearMergeEvents();
// Uninit and unload any dynamic modules.
m_moduleManager->UnloadModules();
@@ -58,6 +58,12 @@ namespace AZ
Event& operator=(Event&& rhs);
//! Take the handlers registered with the other event
//! and move them to this event. The other will event
//! will be cleared after call
//! @param other event to move handlers
Event& ClaimHandlers(Event&& other);
//! Returns true if at least one handler is connected to this event.
bool HasHandlerConnected() const;
@@ -207,6 +207,32 @@ namespace AZ
}
template <typename... Params>
auto Event<Params...>::ClaimHandlers(Event&& other) -> Event&
{
auto handlers = AZStd::move(other.m_handlers);
auto addList = AZStd::move(other.m_addList);
other.m_freeList = {};
other.m_updating = false;
AZStd::array handlerContainers{ &handlers, &addList };
for (AZStd::vector<Handler*>* handlerList : handlerContainers)
{
for (Handler* handler : *handlerList)
{
if (handler != nullptr)
{
handler->m_index = 0;
handler->m_event = this;
Connect(*handler);
}
}
}
return *this;
}
template <typename... Params>
bool Event<Params...>::HasHandlerConnected() const
{
@@ -123,6 +123,36 @@ namespace AZ
using NotifyEvent = AZ::Event<AZStd::string_view, Type>;
using NotifyEventHandler = typename NotifyEvent::Handler;
using PreMergeEventCallback = AZStd::function<void(AZStd::string_view path, AZStd::string_view rootKey)>;
using PostMergeEventCallback = AZStd::function<void(AZStd::string_view path, AZStd::string_view rootKey)>;
using PreMergeEvent = AZ::Event<AZStd::string_view, AZStd::string_view>;
using PostMergeEvent = AZ::Event<AZStd::string_view, AZStd::string_view>;
using PreMergeEventHandler = typename PreMergeEvent::Handler;
using PostMergeEventHandler = typename PostMergeEvent::Handler;
struct ScopedMergeEvent
{
ScopedMergeEvent(
PreMergeEvent& preMergeEvent, PostMergeEvent& postMergeEvent, AZStd::string_view filePath, AZStd::string_view rootKey)
: m_preMergeEvent{ preMergeEvent }
, m_postMergeEvent{ postMergeEvent }
, m_filePath{ filePath }
, m_rootKey{ rootKey }
{
preMergeEvent.Signal(m_filePath, m_rootKey);
}
~ScopedMergeEvent()
{
m_postMergeEvent.Signal(m_filePath, m_rootKey);
}
PreMergeEvent& m_preMergeEvent;
PostMergeEvent& m_postMergeEvent;
AZStd::string_view m_filePath;
AZStd::string_view m_rootKey;
};
using VisitorCallback =
AZStd::function<VisitResponse(AZStd::string_view path, AZStd::string_view valueName, VisitAction action, Type type)>;
//! Base class for the visitor class during traversal over the Settings Registry. The type-agnostic function is always
@@ -169,6 +199,20 @@ namespace AZ
//! @callback The function to call when an entry gets a new/updated value.
[[nodiscard]] virtual NotifyEventHandler RegisterNotifier(NotifyCallback&& callback) = 0;
//! Register a function that will be called before a file is merged.
//! @callback The function to call before a file is merged.
[[nodiscard]] virtual PreMergeEventHandler RegisterPreMergeEvent(const PreMergeEventCallback& callback) = 0;
//! Register a function that will be called before a file is merged.
//! @callback The function to call before a file is merged.
[[nodiscard]] virtual PreMergeEventHandler RegisterPreMergeEvent (PreMergeEventCallback&& callback) = 0;
//! Register a function that will be called after a file is merged.
//! @callback The function to call after a file is merged.
[[nodiscard]] virtual PostMergeEventHandler RegisterPostMergeEvent(const PostMergeEventCallback& callback) = 0;
//! Register a function that will be called after a file is merged.
//! @callback The function to call after a file is merged.
[[nodiscard]] virtual PostMergeEventHandler RegisterPostMergeEvent (PostMergeEventCallback&& callback) = 0;
//! Gets the boolean value at the provided path.
//! @param result The target to write the result to.
//! @param path The path to the value.
@@ -20,7 +20,7 @@
namespace AZ
{
template<typename T>
bool SettingsRegistryImpl::SetValueInternal(AZStd::string_view path, T value, SettingsRegistryInterface::Type type)
bool SettingsRegistryImpl::SetValueInternal(AZStd::string_view path, T value)
{
if (path.empty())
{
@@ -56,7 +56,6 @@ namespace AZ
static_assert(!AZStd::is_same_v<T, T>, "SettingsRegistryImpl::SetValueInternal called with unsupported type.");
}
m_notifiers.Signal(path, type);
return true;
}
return false;
@@ -157,11 +156,11 @@ namespace AZ
// Setting to empty string to prevent assert
path = "";
}
AZStd::scoped_lock lock(m_settingMutex);
rapidjson::Pointer pointer(path.data(), path.length());
if (pointer.IsValid())
{
AZStd::scoped_lock lock(m_settingMutex);
const rapidjson::Value* value = pointer.Get(m_settings);
if (value)
{
@@ -207,7 +206,7 @@ namespace AZ
{
NotifyEventHandler notifyHandler{ callback };
{
AZStd::scoped_lock lock(m_settingMutex);
AZStd::scoped_lock lock(m_notifierMutex);
notifyHandler.Connect(m_notifiers);
}
return notifyHandler;
@@ -217,7 +216,7 @@ namespace AZ
{
NotifyEventHandler notifyHandler{ AZStd::move(callback) };
{
AZStd::scoped_lock lock(m_settingMutex);
AZStd::scoped_lock lock(m_notifierMutex);
notifyHandler.Connect(m_notifiers);
}
return notifyHandler;
@@ -225,10 +224,82 @@ namespace AZ
void SettingsRegistryImpl::ClearNotifiers()
{
AZStd::scoped_lock lock(m_settingMutex);
AZStd::scoped_lock lock(m_notifierMutex);
m_notifiers.DisconnectAllHandlers();
}
auto SettingsRegistryImpl::RegisterPreMergeEvent(const PreMergeEventCallback& callback) -> PreMergeEventHandler
{
PreMergeEventHandler preMergeHandler{ callback };
{
AZStd::scoped_lock lock(m_settingMutex);
preMergeHandler.Connect(m_preMergeEvent);
}
return preMergeHandler;
}
auto SettingsRegistryImpl::RegisterPreMergeEvent(PreMergeEventCallback&& callback) -> PreMergeEventHandler
{
PreMergeEventHandler preMergeHandler{ AZStd::move(callback) };
{
AZStd::scoped_lock lock(m_settingMutex);
preMergeHandler.Connect(m_preMergeEvent);
}
return preMergeHandler;
}
auto SettingsRegistryImpl::RegisterPostMergeEvent(const PostMergeEventCallback& callback) -> PostMergeEventHandler
{
PostMergeEventHandler postMergeHandler{ callback };
{
AZStd::scoped_lock lock(m_settingMutex);
postMergeHandler.Connect(m_postMergeEvent);
}
return postMergeHandler;
}
auto SettingsRegistryImpl::RegisterPostMergeEvent(PostMergeEventCallback&& callback) -> PostMergeEventHandler
{
PostMergeEventHandler postMergeHandler{ AZStd::move(callback) };
{
AZStd::scoped_lock lock(m_settingMutex);
postMergeHandler.Connect(m_postMergeEvent);
}
return postMergeHandler;
}
void SettingsRegistryImpl::ClearMergeEvents()
{
AZStd::scoped_lock lock(m_settingMutex);
m_preMergeEvent.DisconnectAllHandlers();
m_postMergeEvent.DisconnectAllHandlers();
}
void SettingsRegistryImpl::SignalNotifier(AZStd::string_view jsonPath, Type type)
{
// Move the Notifier AZ::Event to a local AZ::Event in order to allow
// the notifier handlers to be signaled outside of the notifier mutex
// This allows other threads to register notifiers while this thread
// is invoking the handlers
decltype(m_notifiers) localNotifierEvent;
{
AZStd::scoped_lock lock(m_notifierMutex);
localNotifierEvent = AZStd::move(m_notifiers);
}
localNotifierEvent.Signal(jsonPath, type);
{
// Swap the local handlers with the current m_notifiers which
// will contain any handlers added during the signaling of the
// local event
AZStd::scoped_lock lock(m_notifierMutex);
AZStd::swap(m_notifiers, localNotifierEvent);
// Append any added handlers to the m_notifier structure
m_notifiers.ClaimHandlers(AZStd::move(localNotifierEvent));
}
}
SettingsRegistryInterface::Type SettingsRegistryImpl::GetType(AZStd::string_view path) const
{
if (path.empty())
@@ -239,11 +310,11 @@ namespace AZ
path = "";
}
AZStd::scoped_lock lock(m_settingMutex);
rapidjson::Pointer pointer(path.data(), path.length());
if (pointer.IsValid())
{
AZStd::scoped_lock lock(m_settingMutex);
const rapidjson::Value* value = pointer.Get(m_settings);
if (value)
{
@@ -316,11 +387,11 @@ namespace AZ
// Setting to empty string to prevent assert
path = "";
}
AZStd::scoped_lock lock(m_settingMutex);
rapidjson::Pointer pointer(path.data(), path.length());
if (pointer.IsValid())
{
AZStd::scoped_lock lock(m_settingMutex);
const rapidjson::Value* value = pointer.Get(m_settings);
if (value)
{
@@ -333,32 +404,52 @@ namespace AZ
bool SettingsRegistryImpl::Set(AZStd::string_view path, bool value)
{
AZStd::scoped_lock lock(m_settingMutex);
return SetValueInternal(path, value, Type::Boolean);
if (AZStd::scoped_lock lock(m_settingMutex); !SetValueInternal(path, value))
{
return false;
}
SignalNotifier(path, Type::Boolean);
return true;
}
bool SettingsRegistryImpl::Set(AZStd::string_view path, s64 value)
{
AZStd::scoped_lock lock(m_settingMutex);
return SetValueInternal(path, value, Type::Integer);
if (AZStd::scoped_lock lock(m_settingMutex); !SetValueInternal(path, value))
{
return false;
}
SignalNotifier(path, Type::Integer);
return true;
}
bool SettingsRegistryImpl::Set(AZStd::string_view path, u64 value)
{
AZStd::scoped_lock lock(m_settingMutex);
return SetValueInternal(path, value, Type::Integer);
if (AZStd::scoped_lock lock(m_settingMutex); !SetValueInternal(path, value))
{
return false;
}
SignalNotifier(path, Type::Integer);
return true;
}
bool SettingsRegistryImpl::Set(AZStd::string_view path, double value)
{
AZStd::scoped_lock lock(m_settingMutex);
return SetValueInternal(path, value, Type::FloatingPoint);
if (AZStd::scoped_lock lock(m_settingMutex); !SetValueInternal(path, value))
{
return false;
}
SignalNotifier(path, Type::FloatingPoint);
return true;
}
bool SettingsRegistryImpl::Set(AZStd::string_view path, AZStd::string_view value)
{
AZStd::scoped_lock lock(m_settingMutex);
return SetValueInternal(path, value, Type::String);
if (AZStd::scoped_lock lock(m_settingMutex); !SetValueInternal(path, value))
{
return false;
}
SignalNotifier(path, Type::String);
return true;
}
bool SettingsRegistryImpl::Set(AZStd::string_view path, const char* value)
@@ -376,7 +467,6 @@ namespace AZ
path = "";
}
AZStd::scoped_lock lock(m_settingMutex);
rapidjson::Pointer pointer(path.data(), path.length());
if (pointer.IsValid())
@@ -386,9 +476,10 @@ namespace AZ
value, nullptr, valueTypeID, m_serializationSettings);
if (jsonResult.GetProcessing() != JsonSerializationResult::Processing::Halted)
{
AZStd::scoped_lock lock(m_settingMutex);
rapidjson::Value& setting = pointer.Create(m_settings, m_settings.GetAllocator());
setting = AZStd::move(store);
m_notifiers.Signal(path, Type::Object);
SignalNotifier(path, Type::Object);
return true;
}
}
@@ -404,13 +495,13 @@ namespace AZ
// Setting to empty string to prevent assert
path = "";
}
AZStd::scoped_lock lock(m_settingMutex);
rapidjson::Pointer pointerPath(path.data(), path.size());
if (!pointerPath.IsValid())
{
return false;
}
AZStd::scoped_lock lock(m_settingMutex);
return pointerPath.Erase(m_settings);
}
@@ -540,7 +631,7 @@ namespace AZ
return false;
}
m_notifiers.Signal("", Type::Object);
SignalNotifier("", Type::Object);
return true;
}
@@ -562,8 +653,6 @@ namespace AZ
scratchBuffer = &buffer;
}
AZStd::scoped_lock lock(m_settingMutex);
bool result = false;
if (path[path.length()] == 0)
{
@@ -577,6 +666,8 @@ namespace AZ
R"(Path "%.*s" is too long. Either make sure that the provided path is terminated or use a shorter path.)",
static_cast<int>(path.length()), path.data());
Pointer pointer(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/-");
AZStd::scoped_lock lock(m_settingMutex);
Value pathValue(path.data(), aznumeric_caster(path.length()), m_settings.GetAllocator());
pointer.Create(m_settings, m_settings.GetAllocator()).SetObject()
.AddMember(StringRef("Error"), StringRef("Unable to read registry file."), m_settings.GetAllocator())
@@ -622,6 +713,7 @@ namespace AZ
{
AZ_Error("Settings Registry", false, "Folder path for the Setting Registry is too long: %.*s",
static_cast<int>(path.size()), path.data());
AZStd::scoped_lock lock(m_settingMutex);
pointer.Create(m_settings, m_settings.GetAllocator()).SetObject()
.AddMember(StringRef("Error"), StringRef("Folder path for the Setting Registry is too long."), m_settings.GetAllocator())
.AddMember(StringRef("Path"), Value(path.data(), aznumeric_caster(path.length()), m_settings.GetAllocator()), m_settings.GetAllocator());
@@ -659,6 +751,7 @@ namespace AZ
if (fileList.size() >= MaxRegistryFolderEntries)
{
AZ_Error("Settings Registry", false, "Too many files in registry folder.");
AZStd::scoped_lock lock(m_settingMutex);
pointer.Create(m_settings, m_settings.GetAllocator()).SetObject()
.AddMember(StringRef("Error"), StringRef("Too many files in registry folder."), m_settings.GetAllocator())
.AddMember(StringRef("Path"), Value(folderPath.c_str(), aznumeric_caster(folderPath.size()), m_settings.GetAllocator()), m_settings.GetAllocator())
@@ -678,7 +771,6 @@ namespace AZ
SystemFile::FindFiles(folderPath.c_str(), callback);
AZStd::scoped_lock lock(m_settingMutex);
if (!platform.empty())
{
// Move the folderPath prefix back to the supplied path before the wildcard
@@ -696,6 +788,7 @@ namespace AZ
if (fileList.size() >= MaxRegistryFolderEntries)
{
AZ_Error("Settings Registry", false, "Too many files in registry folder.");
AZStd::scoped_lock lock(m_settingMutex);
pointer.Create(m_settings, m_settings.GetAllocator()).SetObject()
.AddMember(StringRef("Error"), StringRef("Too many files in registry folder."), m_settings.GetAllocator())
.AddMember(StringRef("Path"), Value(folderPath.c_str(), aznumeric_caster(folderPath.size()), m_settings.GetAllocator()), m_settings.GetAllocator())
@@ -923,6 +1016,8 @@ namespace AZ
collisionFound = true;
AZ_Error("Settings Registry", false, R"(Two registry files in "%.*s" point to the same specialization: "%s" and "%s")",
AZ_STRING_ARG(folderPath), lhs.m_relativePath.c_str(), rhs.m_relativePath.c_str());
AZStd::scoped_lock lock(m_settingMutex);
historyPointer.Create(m_settings, m_settings.GetAllocator()).SetObject()
.AddMember(StringRef("Error"), StringRef("Too many files in registry folder."), m_settings.GetAllocator())
.AddMember(StringRef("Path"),
@@ -1077,6 +1172,7 @@ namespace AZ
}
}
AZStd::scoped_lock lock(m_settingMutex);
pointer.Create(m_settings, m_settings.GetAllocator()).SetObject()
.AddMember(StringRef("Error"), StringRef("Unable to parse registry file due to invalid json."), m_settings.GetAllocator())
.AddMember(StringRef("Path"), Value(path, m_settings.GetAllocator()), m_settings.GetAllocator())
@@ -1102,6 +1198,7 @@ namespace AZ
R"(To merge the supplied settings registry file, the settings within it must be placed within a JSON Object '{}')"
R"( in order to allow moving of its fields using the root-key as an anchor.)", path);
AZStd::scoped_lock lock(m_settingMutex);
pointer.Create(m_settings, m_settings.GetAllocator()).SetObject()
.AddMember(StringRef("Error"), StringRef("Cannot merge registry file with a root which is not a JSON Object,"
" an empty root key and a merge approach of JsonMergePatch. Otherwise the Settings Registry would be overridden."
@@ -1115,9 +1212,12 @@ namespace AZ
return false;
}
ScopedMergeEvent scopedMergeEvent(m_preMergeEvent, m_postMergeEvent, path, rootKey);
JsonSerializationResult::ResultCode mergeResult(JsonSerializationResult::Tasks::Merge);
if (rootKey.empty())
{
AZStd::scoped_lock lock(m_settingMutex);
mergeResult = JsonSerialization::ApplyPatch(m_settings, m_settings.GetAllocator(), jsonPatch, mergeApproach, m_applyPatchSettings);
}
else
@@ -1125,6 +1225,7 @@ namespace AZ
Pointer root(rootKey.data(), rootKey.length());
if (root.IsValid())
{
AZStd::scoped_lock lock(m_settingMutex);
Value& rootValue = root.Create(m_settings, m_settings.GetAllocator());
mergeResult = JsonSerialization::ApplyPatch(rootValue, m_settings.GetAllocator(), jsonPatch, mergeApproach, m_applyPatchSettings);
}
@@ -1132,6 +1233,7 @@ namespace AZ
{
AZ_Error("Settings Registry", false, R"(Failed to root path "%.*s" is invalid.)",
aznumeric_cast<int>(rootKey.length()), rootKey.data());
AZStd::scoped_lock lock(m_settingMutex);
pointer.Create(m_settings, m_settings.GetAllocator()).SetObject()
.AddMember(StringRef("Error"), StringRef("Invalid root key."), m_settings.GetAllocator())
.AddMember(StringRef("Path"), Value(path, m_settings.GetAllocator()), m_settings.GetAllocator());
@@ -1141,15 +1243,19 @@ namespace AZ
if (mergeResult.GetProcessing() != JsonSerializationResult::Processing::Completed)
{
AZ_Error("Settings Registry", false, R"(Failed to fully merge registry file "%s".)", path);
AZStd::scoped_lock lock(m_settingMutex);
pointer.Create(m_settings, m_settings.GetAllocator()).SetObject()
.AddMember(StringRef("Error"), StringRef("Failed to fully merge registry file."), m_settings.GetAllocator())
.AddMember(StringRef("Path"), Value(path, m_settings.GetAllocator()), m_settings.GetAllocator());
return false;
}
pointer.Create(m_settings, m_settings.GetAllocator()).SetString(path, m_settings.GetAllocator());
{
AZStd::scoped_lock lock(m_settingMutex);
pointer.Create(m_settings, m_settings.GetAllocator()).SetString(path, m_settings.GetAllocator());
}
m_notifiers.Signal("", Type::Object);
SignalNotifier("", Type::Object);
return true;
}
@@ -48,6 +48,12 @@ namespace AZ
[[nodiscard]] NotifyEventHandler RegisterNotifier(NotifyCallback&& callback) override;
void ClearNotifiers();
[[nodiscard]] PreMergeEventHandler RegisterPreMergeEvent(const PreMergeEventCallback& callback) override;
[[nodiscard]] PreMergeEventHandler RegisterPreMergeEvent(PreMergeEventCallback&& callback) override;
[[nodiscard]] PostMergeEventHandler RegisterPostMergeEvent(const PostMergeEventCallback& callback) override;
[[nodiscard]] PostMergeEventHandler RegisterPostMergeEvent(PostMergeEventCallback&& callback) override;
void ClearMergeEvents();
bool Get(bool& result, AZStd::string_view path) const override;
bool Get(s64& result, AZStd::string_view path) const override;
bool Get(u64& result, AZStd::string_view path) const override;
@@ -89,7 +95,7 @@ namespace AZ
using RegistryFileList = AZStd::fixed_vector<RegistryFile, MaxRegistryFolderEntries>;
template<typename T>
bool SetValueInternal(AZStd::string_view path, T value, SettingsRegistryInterface::Type type);
bool SetValueInternal(AZStd::string_view path, T value);
template<typename T>
bool GetValueInternal(T& result, AZStd::string_view path) const;
VisitResponse Visit(Visitor& visitor, StackedString& path, AZStd::string_view valueName,
@@ -100,9 +106,15 @@ namespace AZ
const rapidjson::Pointer& historyPointer, AZStd::string_view folderPath);
bool ExtractFileDescription(RegistryFile& output, const char* filename, const Specializations& specializations);
bool MergeSettingsFileInternal(const char* path, Format format, AZStd::string_view rootKey, AZStd::vector<char>& scratchBuffer);
void SignalNotifier(AZStd::string_view jsonPath, Type type);
mutable AZStd::recursive_mutex m_settingMutex;
mutable AZStd::recursive_mutex m_notifierMutex;
NotifyEvent m_notifiers;
PreMergeEvent m_preMergeEvent;
PostMergeEvent m_postMergeEvent;
rapidjson::Document m_settings;
JsonSerializerSettings m_serializationSettings;
JsonDeserializerSettings m_deserializationSettings;
@@ -25,6 +25,10 @@ namespace AZ
MOCK_CONST_METHOD2(Visit, bool(const VisitorCallback&, AZStd::string_view));
MOCK_METHOD1(RegisterNotifier, NotifyEventHandler(const NotifyCallback&));
MOCK_METHOD1(RegisterNotifier, NotifyEventHandler(NotifyCallback&&));
MOCK_METHOD1(RegisterPreMergeEvent, PreMergeEventHandler(const PreMergeEventCallback&));
MOCK_METHOD1(RegisterPreMergeEvent, PreMergeEventHandler(PreMergeEventCallback&&));
MOCK_METHOD1(RegisterPostMergeEvent, PostMergeEventHandler(const PostMergeEventCallback&));
MOCK_METHOD1(RegisterPostMergeEvent, PostMergeEventHandler(PostMergeEventCallback&&));
MOCK_CONST_METHOD2(Get, bool(bool&, AZStd::string_view));
MOCK_CONST_METHOD2(Get, bool(s64&, AZStd::string_view));
@@ -240,6 +240,37 @@ namespace UnitTest
static_assert(!AZStd::is_copy_assignable_v<AZ::Event<int32_t>>, "AZ Events should not be copy assignable");
}
TEST_F(EventTests, TestClaimHandlers_TakesAllSourceHandlers)
{
AZ::Event<> testEvent1;
AZ::Event<> testEvent2;
int32_t handlerInvokeCount{};
auto handlerCallback = [&handlerInvokeCount]()
{
++handlerInvokeCount;
};
AZ::Event<>::Handler testHandler1(handlerCallback);
AZ::Event<>::Handler testHandler2(handlerCallback);
testHandler1.Connect(testEvent1);
testHandler2.Connect(testEvent2);
EXPECT_TRUE(testEvent1.HasHandlerConnected());
EXPECT_TRUE(testEvent2.HasHandlerConnected());
testEvent1.ClaimHandlers(AZStd::move(testEvent2));
EXPECT_TRUE(testEvent1.HasHandlerConnected());
EXPECT_FALSE(testEvent2.HasHandlerConnected());
// testEvent1 should have both handlers
testEvent1.Signal();
EXPECT_EQ(2, handlerInvokeCount);
// testEvent2 should have neither of the handlers
testEvent2.Signal();
EXPECT_EQ(2, handlerInvokeCount);
}
TEST_F(EventTests, HandlerMoveAssignment_ProperlyDisconnectsFromOldEvent)
{
AZ::Event<> testEvent1;
@@ -34,7 +34,7 @@ namespace AzFramework
bool GetFullScreenState() const override;
void SetFullScreenState(bool fullScreenState) override;
bool CanToggleFullScreenState() const override { return true; }
uint32_t GetMainDisplayRefreshRate() const override;
uint32_t GetDisplayRefreshRate() const override;
private:
static NSWindowStyleMask ConvertToNSWindowStyleMask(const WindowStyleMasks& styleMasks);
@@ -142,7 +142,7 @@ namespace AzFramework
return nativeMask ? nativeMask : defaultMask;
}
uint32_t NativeWindowImpl_Darwin::GetMainDisplayRefreshRate() const
uint32_t NativeWindowImpl_Darwin::GetDisplayRefreshRate() const
{
return m_mainDisplayRefreshRate;
}
@@ -207,7 +207,10 @@ namespace AzFramework
// Handles Win32 Window Event callbacks
LRESULT CALLBACK NativeWindowImpl_Win32::WindowCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
NativeWindowImpl_Win32* nativeWindowImpl = reinterpret_cast<NativeWindowImpl_Win32*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
NativeWindowImpl_Win32* nativeWindowImpl = reinterpret_cast<NativeWindowImpl_Win32*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
// If set to true, call DefWindowProc to ensure the default Windows behavior occurs
bool shouldBubbleEventUp = false;
switch (message)
{
@@ -276,14 +279,19 @@ namespace AzFramework
uint32_t refreshRate = DisplayConfig.dmDisplayFrequency;
WindowNotificationBus::Event(
nativeWindowImpl->GetWindowHandle(), &WindowNotificationBus::Events::OnRefreshRateChanged, refreshRate);
shouldBubbleEventUp = true;
break;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
shouldBubbleEventUp = true;
break;
}
return 0;
if (!shouldBubbleEventUp)
{
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
void NativeWindowImpl_Win32::WindowSizeChanged(const uint32_t width, const uint32_t height)
@@ -27,7 +27,7 @@ namespace AzFramework
const WindowGeometry& geometry,
const WindowStyleMasks& styleMasks) override;
NativeWindowHandle GetWindowHandle() const override;
uint32_t GetMainDisplayRefreshRate() const override;
uint32_t GetDisplayRefreshRate() const override;
private:
UIWindow* m_nativeWindow;
@@ -66,7 +66,7 @@ namespace AzFramework
return m_nativeWindow;
}
uint32_t NativeWindowImpl_Ios::GetMainDisplayRefreshRate() const
uint32_t NativeWindowImpl_Ios::GetDisplayRefreshRate() const
{
return m_mainDisplayRefreshRate;
}
@@ -10,22 +10,9 @@
namespace AzNetworking
{
StringifySerializer::StringifySerializer(char delimeter, bool outputFieldNames, const AZStd::string& seperator)
: m_delimeter(delimeter)
, m_outputFieldNames(outputFieldNames)
, m_separator(seperator)
const StringifySerializer::ValueMap& StringifySerializer::GetValueMap() const
{
;
}
const AZStd::string& StringifySerializer::GetString() const
{
return m_string;
}
const StringifySerializer::StringMap& StringifySerializer::GetValueMap() const
{
return m_map;
return m_valueMap;
}
SerializerMode StringifySerializer::GetSerializerMode() const
@@ -137,22 +124,9 @@ namespace AzNetworking
template <typename T>
bool StringifySerializer::ProcessData(const char* name, const T& value)
{
// Only add delimeters after we have processed at least one element
if (!m_string.empty())
{
m_string += m_delimeter;
}
if (m_outputFieldNames)
{
m_string += m_prefix;
m_string += name;
m_string += m_separator;
}
AZ::CVarFixedString string = AZ::ConsoleTypeHelpers::ValueToString(value);
m_string += string.c_str();
m_map[m_prefix + name] = string.c_str();
const AZStd::string keyString = m_prefix + name;
AZ::CVarFixedString valueString = AZ::ConsoleTypeHelpers::ValueToString(value);
m_valueMap[keyString] = valueString.c_str();
return true;
}
}
@@ -20,17 +20,12 @@ namespace AzNetworking
{
public:
using StringMap = AZStd::map<AZStd::string, AZStd::string>;
using ValueMap = AZStd::map<AZStd::string, AZStd::string>;
StringifySerializer(char delimeter = ' ', bool outputFieldNames = true, const AZStd::string& seperator = "=");
StringifySerializer() = default;
// GetString
// After serializing objects, get the serialized values as a single string
const AZStd::string& GetString() const;
// GetValueMap
// After serializing objects, get the serialized values as key value pairs
const StringMap& GetValueMap() const;
//! After serializing objects, get the serialized values as a map of key/value pairs.
const ValueMap& GetValueMap() const;
// ISerializer interfaces
SerializerMode GetSerializerMode() const override;
@@ -62,15 +57,8 @@ namespace AzNetworking
template <typename T>
bool ProcessData(const char* name, const T& value);
private:
char m_delimeter;
bool m_outputFieldNames = true;
StringMap m_map;
AZStd::string m_string;
ValueMap m_valueMap;
AZStd::string m_prefix;
AZStd::string m_separator;
AZStd::deque<AZStd::size_t> m_prefixSizeStack;
};
}
@@ -1882,7 +1882,10 @@ namespace AzQtComponents
return;
}
QApplication::setOverrideCursor(m_dragCursor);
if (!QApplication::overrideCursor())
{
QApplication::setOverrideCursor(m_dragCursor);
}
QPoint relativePressPos = pressPos;
@@ -841,9 +841,6 @@ namespace AzToolsFramework
*/
virtual AZStd::string GetComponentIconPath(const AZ::Uuid& /*componentType*/, AZ::Crc32 /*componentIconAttrib*/, AZ::Component* /*component*/) { return AZStd::string(); }
/// Resource Selector hook, returns a path for a resource.
virtual AZStd::string SelectResource(const AZStd::string& /*resourceType*/, const AZStd::string& /*previousValue*/) { return AZStd::string(); }
/**
* Calculate the navigation 2D radius in units of an agent given its Navigation Type Name
* @param angentTypeName the name that identifies the agent navigation type
@@ -219,42 +219,10 @@ namespace AzToolsFramework
bool PrefabEditorEntityOwnershipService::SaveToStream(AZ::IO::GenericStream& stream, AZStd::string_view filename)
{
AZ::IO::Path relativePath = m_loaderInterface->GenerateRelativePath(filename);
AzToolsFramework::Prefab::TemplateId templateId = m_prefabSystemComponent->GetTemplateIdFromFilePath(relativePath);
m_rootInstance->SetTemplateSourcePath(relativePath);
if (templateId == AzToolsFramework::Prefab::InvalidTemplateId)
{
m_rootInstance->m_containerEntity->AddComponent(aznew Prefab::EditorPrefabComponent());
HandleEntitiesAdded({ m_rootInstance->m_containerEntity.get() });
AzToolsFramework::Prefab::PrefabDom dom;
bool success = AzToolsFramework::Prefab::PrefabDomUtils::StoreInstanceInPrefabDom(*m_rootInstance, dom);
if (!success)
{
AZ_Error("Prefab", false, "Failed to convert current root instance into a DOM when saving file '%.*s'", AZ_STRING_ARG(filename));
return false;
}
templateId = m_prefabSystemComponent->AddTemplate(relativePath, AZStd::move(dom));
if (templateId == AzToolsFramework::Prefab::InvalidTemplateId)
{
AZ_Error("Prefab", false, "Couldn't add new template id '%i' when saving file '%.*s'", templateId, AZ_STRING_ARG(filename));
return false;
}
}
Prefab::TemplateId prevTemplateId = m_rootInstance->GetTemplateId();
m_rootInstance->SetTemplateId(templateId);
if (prevTemplateId != Prefab::InvalidTemplateId && templateId != prevTemplateId)
{
// Make sure we only have one level template loaded at a time
m_prefabSystemComponent->RemoveTemplate(prevTemplateId);
}
AZStd::string out;
if (!m_loaderInterface->SaveTemplateToString(m_rootInstance->GetTemplateId(), out))
{
return false;
@@ -266,7 +234,7 @@ namespace AzToolsFramework
{
return false;
}
m_prefabSystemComponent->SetTemplateDirtyFlag(templateId, false);
m_prefabSystemComponent->SetTemplateDirtyFlag(m_rootInstance->GetTemplateId(), false);
return true;
}
@@ -162,7 +162,6 @@ namespace AzToolsFramework
: QObject(sourceWidget)
, m_sourceWidget(sourceWidget)
, m_keyboardModifiers(AZStd::make_shared<AzFramework::ModifierKeyStates>())
, m_cursorPosition(AZStd::make_shared<AzFramework::InputChannel::PositionData2D>())
{
InitializeKeyMappings();
InitializeMouseButtonMappings();
@@ -230,24 +229,17 @@ namespace AzToolsFramework
return false;
}
// Because there's no "end" to mouse movement and wheel events, we reset mouse movement channels that have been opened
// during the next processed non-mouse event.
if (m_mouseChannelsNeedUpdate && event->type() != QEvent::Type::MouseMove && event->type() != QEvent::Type::Wheel)
{
m_cursorPosition->m_normalizedPositionDelta = AZ::Vector2::CreateZero();
ProcessPendingMouseEvents();
m_mouseChannelsNeedUpdate = false;
}
const auto eventType = event->type();
// Only accept mouse & key release events that originate from an object that is not our target widget,
// as we don't want to erroneously intercept user input meant for another component.
if (object != m_sourceWidget && event->type() != QEvent::Type::KeyRelease && event->type() != QEvent::Type::MouseButtonRelease)
if (object != m_sourceWidget && eventType != QEvent::Type::KeyRelease && eventType != QEvent::Type::MouseButtonRelease)
{
return false;
}
// If our focus changes, go ahead and reset all input devices.
if (event->type() == QEvent::FocusIn || event->type() == QEvent::FocusOut)
if (eventType == QEvent::FocusIn || eventType == QEvent::FocusOut)
{
HandleFocusChange(event);
}
@@ -255,27 +247,28 @@ namespace AzToolsFramework
// ShortcutOverride is used in lieu of KeyPress for high priority input channels like Alt
// that need to be accepted and stopped before they bubble up and cause unintended behavior.
else if (
event->type() == QEvent::Type::KeyPress || event->type() == QEvent::Type::KeyRelease ||
event->type() == QEvent::Type::ShortcutOverride)
eventType == QEvent::Type::KeyPress || eventType == QEvent::Type::KeyRelease || eventType == QEvent::Type::ShortcutOverride)
{
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
HandleKeyEvent(keyEvent);
}
// Map mouse events to input channels.
else if (event->type() == QEvent::Type::MouseButtonPress || event->type() == QEvent::Type::MouseButtonRelease || event->type() == QEvent::Type::MouseButtonDblClick)
else if (
eventType == QEvent::Type::MouseButtonPress || eventType == QEvent::Type::MouseButtonRelease ||
eventType == QEvent::Type::MouseButtonDblClick)
{
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
HandleMouseButtonEvent(mouseEvent);
}
// Map mouse movement to the movement input channels.
// This includes SystemCursorPosition alongside Movement::X and Movement::Y.
else if (event->type() == QEvent::Type::MouseMove)
else if (eventType == QEvent::Type::MouseMove)
{
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
HandleMouseMoveEvent(mouseEvent);
}
// Map wheel events to the mouse Z movement channel.
else if (event->type() == QEvent::Type::Wheel)
else if (eventType == QEvent::Type::Wheel)
{
QWheelEvent* wheelEvent = static_cast<QWheelEvent*>(event);
HandleWheelEvent(wheelEvent);
@@ -303,14 +296,16 @@ namespace AzToolsFramework
auto mouseWheelChannel =
GetInputChannel<AzFramework::InputChannelDeltaWithSharedPosition2D>(AzFramework::InputDeviceMouse::Movement::Z);
systemCursorChannel->ProcessRawInputEvent(m_cursorPosition->m_normalizedPositionDelta.GetLength());
systemCursorChannel->ProcessRawInputEvent(m_mouseDevice->m_cursorPositionData2D->m_normalizedPositionDelta.GetLength());
// Generate movement events based on the pixel delta divided by the DPI scaling factor, to calculate a rough approximation
// of cursor movement velocity.
movementXChannel->ProcessRawInputEvent(
m_cursorPosition->m_normalizedPositionDelta.GetX() * aznumeric_cast<float>(m_sourceWidget->width()) / m_sourceWidget->devicePixelRatioF());
m_mouseDevice->m_cursorPositionData2D->m_normalizedPositionDelta.GetX() * aznumeric_cast<float>(m_sourceWidget->width()) /
m_sourceWidget->devicePixelRatioF());
movementYChannel->ProcessRawInputEvent(
m_cursorPosition->m_normalizedPositionDelta.GetY() * aznumeric_cast<float>(m_sourceWidget->height()) / m_sourceWidget->devicePixelRatioF());
mouseWheelChannel->ProcessRawInputEvent(0.f);
m_mouseDevice->m_cursorPositionData2D->m_normalizedPositionDelta.GetY() * aznumeric_cast<float>(m_sourceWidget->height()) /
m_sourceWidget->devicePixelRatioF());
mouseWheelChannel->ProcessRawInputEvent(0.0f);
NotifyUpdateChannelIfNotIdle(systemCursorChannel, nullptr);
NotifyUpdateChannelIfNotIdle(movementXChannel, nullptr);
@@ -358,14 +353,13 @@ namespace AzToolsFramework
void QtEventToAzInputMapper::HandleMouseMoveEvent(QMouseEvent* mouseEvent)
{
AZ::Vector2 lastCursorPosition = m_cursorPosition->m_normalizedPosition;
AZ::Vector2 lastCursorPosition = m_mouseDevice->m_cursorPositionData2D->m_normalizedPosition;
const QPoint mousePos = mouseEvent->pos();
const AZ::Vector2 normalizedPosition = WidgetPositionToNormalizedPosition(mousePos);
m_cursorPosition->m_normalizedPositionDelta = normalizedPosition - m_cursorPosition->m_normalizedPosition;
m_cursorPosition->m_normalizedPosition = normalizedPosition;
m_mouseDevice->m_cursorPositionData2D->m_normalizedPositionDelta = normalizedPosition - m_mouseDevice->m_cursorPositionData2D->m_normalizedPosition;
m_mouseDevice->m_cursorPositionData2D->m_normalizedPosition = normalizedPosition;
ProcessPendingMouseEvents();
m_mouseChannelsNeedUpdate = true;
if (m_capturingCursor)
{
@@ -376,7 +370,7 @@ namespace AzToolsFramework
// Even though we just set the cursor position, there are edge cases such as remote desktop that will leave
// the cursor position unchanged. For safety, we re-cache our last cursor position for delta generation.
QPoint actualWidgetPosition = m_sourceWidget->mapFromGlobal(QCursor::pos());
m_cursorPosition->m_normalizedPosition = WidgetPositionToNormalizedPosition(actualWidgetPosition);
m_mouseDevice->m_cursorPositionData2D->m_normalizedPosition = WidgetPositionToNormalizedPosition(actualWidgetPosition);
}
}
@@ -427,21 +421,18 @@ namespace AzToolsFramework
}
cursorZChannel->ProcessRawInputEvent(aznumeric_cast<float>(wheelAngle));
NotifyUpdateChannelIfNotIdle(cursorZChannel, wheelEvent);
m_mouseChannelsNeedUpdate = true;
}
void QtEventToAzInputMapper::HandleFocusChange(QEvent* event)
{
for (auto& channelData : m_channels)
{
// If resetting the input device changed the channel state, submit it to the mapped channel list
// for processing.
// If resetting the input device changed the channel state, submit it to the mapped channel list for processing.
if (channelData.second->IsActive())
{
channelData.second->UpdateState(false);
NotifyUpdateChannelIfNotIdle(channelData.second, event);
}
}
m_mouseChannelsNeedUpdate = false;
}
} // namespace AzToolsFramework
@@ -138,8 +138,6 @@ namespace AzToolsFramework
// The current keyboard modifier state used by our synthetic key input channels.
AZStd::shared_ptr<AzFramework::ModifierKeyStates> m_keyboardModifiers;
// The current normalized cursor position used by our synthetic system cursor event.
AZStd::shared_ptr<AzFramework::InputChannel::PositionData2D> m_cursorPosition;
// A lookup table for Qt key -> AZ input channel.
AZStd::unordered_map<Qt::Key, AzFramework::InputChannelId> m_keyMappings;
// A lookup table for Qt mouse button -> AZ input channel.
@@ -152,8 +150,6 @@ namespace AzToolsFramework
AZStd::unordered_map<AzFramework::InputChannelId, AzFramework::InputChannel*> m_channels;
// The source widget to map events from, used to calculate the relative mouse position within the widget bounds.
QWidget* m_sourceWidget;
// Flags when mouse movement channels have been opened and may need to be closed (as there are no movement ended events).
bool m_mouseChannelsNeedUpdate = false;
// Flags whether or not Qt events should currently be processed.
bool m_enabled = true;
// Flags whether or not the cursor is being constrained to the source widget (for invisible mouse movement).
@@ -5,11 +5,9 @@
*
*/
#include <AzToolsFramework/Logger/TraceLogger.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/Logger/TraceLogger.h>
namespace AzToolsFramework
{
@@ -25,6 +23,22 @@ namespace AzToolsFramework
bool TraceLogger::OnOutput(const char* window, const char* message)
{
for (const auto& filter : m_windowFilters)
{
if (AZ::StringFunc::Contains(window, filter))
{
return true;
}
}
for (const auto& filter : m_messageFilters)
{
if (AZ::StringFunc::Contains(message, filter))
{
return true;
}
}
if (m_logFile)
{
m_logFile->AppendLog(AzFramework::LogFile::SEV_NORMAL, window, message);
@@ -36,10 +50,10 @@ namespace AzToolsFramework
return false;
}
void TraceLogger::WriteStartupLog(const AZStd::string& logFileName)
{
void TraceLogger::PrepareLogFile(const AZStd::string& logFileName)
{
using namespace AzFramework;
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
AZ_Assert(fileIO != nullptr, "FileIO should be running at this point");
@@ -71,4 +85,34 @@ namespace AzToolsFramework
m_logFile->FlushLog();
}
}
void TraceLogger::AddWindowFilter(const AZStd::string& filter)
{
m_windowFilters.insert(filter);
}
void TraceLogger::RemoveWindowFilter(const AZStd::string& filter)
{
m_windowFilters.erase(filter);
}
void TraceLogger::ClearWindowFilter()
{
m_windowFilters.clear();
}
void TraceLogger::AddMessageFilter(const AZStd::string& filter)
{
m_messageFilters.insert(filter);
}
void TraceLogger::RemoveMessageFilter(const AZStd::string& filter)
{
m_messageFilters.erase(filter);
}
void TraceLogger::ClearMessageFilter()
{
m_messageFilters.clear();
}
} // namespace AzToolsFramework
@@ -22,8 +22,26 @@ namespace AzToolsFramework
TraceLogger();
~TraceLogger();
//! Intalize logging for O3DEToolsApplications
void WriteStartupLog(const AZStd::string& logFileName);
//! Open log file and dump log sink into it
void PrepareLogFile(const AZStd::string& logFileName);
//! Add filter to ignore messages for windows with matching names
void AddWindowFilter(const AZStd::string& filter);
//! Remove window filter
void RemoveWindowFilter(const AZStd::string& filter);
//! Clear window filters
void ClearWindowFilter();
//! Add filter to ignore messages with matching names
void AddMessageFilter(const AZStd::string& filter);
//! Remove message filter
void RemoveMessageFilter(const AZStd::string& filter);
//! Clear message filters
void ClearMessageFilter();
protected:
//////////////////////////////////////////////////////////////////////////
@@ -38,6 +56,8 @@ namespace AzToolsFramework
AZStd::string message;
};
AZStd::vector<LogMessage> m_startupLogSink;
AZStd::unordered_set<AZStd::string> m_windowFilters;
AZStd::unordered_set<AZStd::string> m_messageFilters;
AZStd::unique_ptr<AzFramework::LogFile> m_logFile;
};
} // namespace AzToolsFramework
@@ -15,6 +15,7 @@
#include <AzToolsFramework/Prefab/Instance/InstanceEntityMapperInterface.h>
#include <AzToolsFramework/Prefab/PrefabLoaderInterface.h>
#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
#include <Prefab/PrefabDomUtils.h>
namespace AzToolsFramework
{
@@ -81,6 +82,15 @@ namespace AzToolsFramework
result.Combine(resultInstances);
}
PrefabDomUtils::LinkIdMetadata* subPathLinkId = context.GetMetadata().Find<PrefabDomUtils::LinkIdMetadata>();
if (subPathLinkId)
{
AZ::ScopedContextPath subPathSource(context, "m_linkId");
result = ContinueStoringToJsonObjectField(
outputValue, "LinkId", &(instance->m_linkId), &InvalidLinkId, azrtti_typeid<decltype(instance->m_linkId)>(), context);
}
return context.Report(result,
result.GetProcessing() == JSR::Processing::Completed ? "Successfully stored Instance information for Prefab." :
"Failed to store Instance information for Prefab.");
@@ -88,6 +88,11 @@ namespace AzToolsFramework
settings.m_keepDefaults = true;
}
if ((flags & StoreFlags::StoreLinkIds) != StoreFlags::None)
{
settings.m_metadata.Create<LinkIdMetadata>();
}
AZStd::string scratchBuffer;
auto issueReportingCallback = [&scratchBuffer]
(AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result,
@@ -45,7 +45,11 @@ namespace AzToolsFramework
//! By default an instance will be stored with default values. In cases where we want to store less json without defaults
//! such as saving to disk, this flag will control that behavior.
StripDefaultValues = 1 << 0
StripDefaultValues = 1 << 0,
//! We do not save linkIds to file. However when loading a level we want to temporarily save
//! linkIds to instance dom so any nested prefabs will have linkIds correctly set.
StoreLinkIds = 1 << 1
};
AZ_DEFINE_ENUM_BITWISE_OPERATORS(StoreFlags);
@@ -150,6 +154,14 @@ namespace AzToolsFramework
[[maybe_unused]] const AZStd::string_view printMessage,
[[maybe_unused]] const AzToolsFramework::Prefab::PrefabDomValue& prefabDomValue);
//! An empty struct for passing to JsonSerializerSettings.m_metadata that is consumed by InstanceSerializer::Store.
//! If present in metadata, linkIds will be stored to instance dom.
struct LinkIdMetadata
{
AZ_RTTI(LinkIdMetadata, "{8FF7D299-14E3-41D4-90C5-393A240FAE7C}");
virtual ~LinkIdMetadata() {}
};
} // namespace PrefabDomUtils
} // namespace Prefab
} // namespace AzToolsFramework
@@ -300,7 +300,7 @@ namespace AzToolsFramework
}
PrefabDom storedPrefabDom(&loadedTemplateDom->get().GetAllocator());
if (!PrefabDomUtils::StoreInstanceInPrefabDom(loadedPrefabInstance, storedPrefabDom))
if (!PrefabDomUtils::StoreInstanceInPrefabDom(loadedPrefabInstance, storedPrefabDom, PrefabDomUtils::StoreFlags::StoreLinkIds))
{
return false;
}
@@ -6,7 +6,6 @@
*
*/
// Description : For listing available script commands with their descriptions
#include "ScriptHelpDialog.h"
@@ -23,6 +22,7 @@
// AzToolsFramework
#include <AzToolsFramework/API/EditorPythonConsoleBus.h> // for EditorPythonConsoleInterface
#include <AzToolsFramework/API/EditorWindowRequestBus.h>
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
#include <AzToolsFramework/PythonTerminal/ui_ScriptHelpDialog.h>
@@ -313,6 +313,45 @@ namespace AzToolsFramework
connect(ui->tableView, &ScriptTableView::doubleClicked, this, &CScriptHelpDialog::OnDoubleClick);
}
CScriptHelpDialog* CScriptHelpDialog::GetInstance()
{
static CScriptHelpDialog* pInstance = nullptr;
if (!pInstance)
{
QMainWindow* mainWindow = GetMainWindowOfCurrentApplication();
if (!mainWindow)
{
AZ_Assert(false, "Failed to find MainWindow.");
return nullptr;
}
QWidget* parentWidget = mainWindow->window()
? mainWindow->window()
: mainWindow; // MainWindow might have a WindowDecorationWrapper parent. Makes a difference on macOS.
pInstance = new CScriptHelpDialog(parentWidget);
}
return pInstance;
}
QMainWindow* CScriptHelpDialog::GetMainWindowOfCurrentApplication()
{
QWidget* mainWindowWidget = nullptr;
EditorWindowRequestBus::BroadcastResult(mainWindowWidget, &EditorWindowRequests::GetAppMainWindow);
if (QMainWindow* mainWindow = qobject_cast<QMainWindow*>(mainWindowWidget))
{
return mainWindow;
}
for (QWidget* topLevelWidget : qApp->topLevelWidgets())
{
if (QMainWindow* mainWindow = qobject_cast<QMainWindow*>(topLevelWidget))
{
return mainWindow;
}
}
return nullptr;
}
void CScriptHelpDialog::OnDoubleClick(const QModelIndex& index)
{
if (!index.isValid())
@@ -132,43 +132,13 @@ namespace AzToolsFramework
{
Q_OBJECT
public:
static CScriptHelpDialog* GetInstance()
{
static CScriptHelpDialog* pInstance = nullptr;
if (!pInstance)
{
QMainWindow* mainWindow = GetMainWindowOfCurrentApplication();
if (!mainWindow)
{
AZ_Assert(false, "Failed to find MainWindow.");
return nullptr;
}
QWidget* parentWidget = mainWindow->window() ? mainWindow->window() : mainWindow; // MainWindow might have a WindowDecorationWrapper parent. Makes a difference on macOS.
pInstance = new CScriptHelpDialog(parentWidget);
}
return pInstance;
}
static CScriptHelpDialog* GetInstance();
private Q_SLOTS:
void OnDoubleClick(const QModelIndex&);
private:
static QMainWindow* GetMainWindowOfCurrentApplication()
{
QMainWindow* mainWindow = nullptr;
for (QWidget* w : qApp->topLevelWidgets())
{
mainWindow = qobject_cast<QMainWindow*>(w);
if (mainWindow)
{
return mainWindow;
}
}
return nullptr;
}
explicit CScriptHelpDialog(QWidget* parent = nullptr);
static QMainWindow* GetMainWindowOfCurrentApplication();
QScopedPointer<Ui::ScriptDialog> ui;
};
} // namespace AzToolsFramework
@@ -19,6 +19,7 @@
#include <AzCore/Component/Component.h>
#include <AzCore/Component/ComponentBus.h>
#include <AzCore/Component/EntityBus.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
#include <AzToolsFramework/Undo/UndoSystem.h>
@@ -110,6 +111,7 @@ namespace AzToolsFramework
, public EditorInspectorComponentNotificationBus::MultiHandler
, private AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler
, public AZ::EntitySystemBus::Handler
, public AZ::TickBus::Handler
, private EditorWindowUIRequestBus::Handler
{
Q_OBJECT;
@@ -117,6 +119,23 @@ namespace AzToolsFramework
AZ_CLASS_ALLOCATOR(EntityPropertyEditor, AZ::SystemAllocator, 0)
enum class ReorderState
{
Inactive, // No row widget reordering operation is in progress.
DraggingComponent, // User is dragging a component editor.
DraggingRowWidget, // User is dragging a row widget around.
UsingMenu, // User has the context menu open and may hover over a move up/down operation.
MenuOperationInProgress, // User has selected a move/up down menu item.
WaitForRedraw, // Wait for rebuild of RPE.
HighlightMovedRow // User has moved a row, highlight the new position.
};
enum class DropArea
{
Above,
Below
};
EntityPropertyEditor(QWidget* pParent = NULL, Qt::WindowFlags flags = Qt::WindowFlags(), bool isLevelEntityEditor = false);
virtual ~EntityPropertyEditor();
@@ -151,6 +170,16 @@ namespace AzToolsFramework
bool IsLockedToSpecificEntities() const { return !m_overrideSelectedEntityIds.empty(); }
static bool AreComponentsCopyable(const AZ::Entity::ComponentArrayType& components, const ComponentFilter& filter);
ReorderState GetReorderState() const;
ComponentEditor* GetEditorForCurrentReorderRowWidget() const;
PropertyRowWidget* GetReorderRowWidget() const;
PropertyRowWidget* GetReorderDropTarget() const;
DropArea GetReorderDropArea() const;
QPixmap GetReorderRowWidgetImage() const;
float GetMoveIndicatorAlpha() const;
PropertyRowWidget* GetRowToHighlight();
Q_SIGNALS:
void SelectedEntityNameChanged(const AZ::EntityId& entityId, const AZStd::string& name);
@@ -211,6 +240,9 @@ namespace AzToolsFramework
void GetSelectedEntities(EntityIdList& selectedEntityIds) override;
void SetNewComponentId(AZ::ComponentId componentId) override;
// TickBus
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
// EditorWindowRequestBus overrides
void SetEditorUiEnabled(bool enable) override;
@@ -253,6 +285,10 @@ namespace AzToolsFramework
void ContextMenuActionPullFieldData(AZ::Component* parentComponent, InstanceDataNode* fieldNode);
void ContextMenuActionSetDataFlag(InstanceDataNode* node, AZ::DataPatch::Flag flag, bool additive);
void GenerateRowWidgetIndexMapToChildIndex(PropertyRowWidget* parent, int destIndex);
void ContextMenuActionMoveItemUp(ComponentEditor* componentEditor, PropertyRowWidget* rowWidget);
void ContextMenuActionMoveItemDown(ComponentEditor* componentEditor, PropertyRowWidget* rowWidget);
/// Given an InstanceDataNode, calculate a DataPatch address relative to the entity.
/// @return true if successful.
bool GetEntityDataPatchAddress(const InstanceDataNode* componentFieldNode, AZ::DataPatch::AddressType& dataPatchAddressOut, AZ::EntityId* entityIdOut = nullptr) const;
@@ -341,8 +377,6 @@ namespace AzToolsFramework
QAction* m_actionToMoveComponentsBottom = nullptr;
QAction* m_resetToSliceAction = nullptr;
bool m_isShowingContextMenu = false;
void CreateActions();
void UpdateActions();
@@ -390,6 +424,10 @@ namespace AzToolsFramework
void ResetToSlice();
bool DoesOwnFocus() const;
AZ::u32 GetHeightOfRowAndVisibleChildren(const PropertyRowWidget* row) const;
QRect GetWidgetAndVisibleChildrenGlobalRect(const PropertyRowWidget* widget) const;
PropertyRowWidget* GetRowWidgetAtSameLevelAfter(PropertyRowWidget* widget) const;
PropertyRowWidget* GetRowWidgetAtSameLevelBefore(PropertyRowWidget* widget) const;
QRect GetWidgetGlobalRect(const QWidget* widget) const;
bool DoesIntersectWidget(const QRect& globalRect, const QWidget* widget) const;
bool DoesIntersectSelectedComponentEditor(const QRect& globalRect) const;
@@ -445,6 +483,8 @@ namespace AzToolsFramework
bool HandleSelectionEvents(QObject* object, QEvent* event);
bool m_selectionEventAccepted;
bool HandleMenuEvent(QObject* object, QEvent* event);
// drag and drop events
QRect GetInflatedRectFromPoint(const QPoint& point, int radius) const;
bool GetComponentsAtDropEventPosition(QDropEvent* event, AZ::Entity::ComponentArrayType& targetComponents);
@@ -458,8 +498,12 @@ namespace AzToolsFramework
ComponentEditor* GetReorderDropTarget(const QRect& globalRect) const;
bool ResetDrag(QMouseEvent* event);
bool FindAllowedRowWidgetReorderDropTarget(const QPoint& globalPos);
bool UpdateRowWidgetDrag(const QPoint& localPos, Qt::MouseButtons mouseButtons, const QMimeData* mimeData);
PropertyRowWidget* FindPropertyRowWidgetAt(QPoint globalPos);
bool UpdateDrag(const QPoint& localPos, Qt::MouseButtons mouseButtons, const QMimeData* mimeData);
bool StartDrag(QMouseEvent* event);
void EndRowWidgetReorder();
bool HandleDrop(QDropEvent* event);
bool HandleDropForComponentTypes(QDropEvent* event);
bool HandleDropForComponentAssets(QDropEvent* event);
@@ -468,6 +512,8 @@ namespace AzToolsFramework
bool CanDropForComponentTypes(const QMimeData* mimeData) const;
bool CanDropForComponentAssets(const QMimeData* mimeData) const;
bool CanDropForAssetBrowserEntries(const QMimeData* mimeData) const;
void SetRowWidgetHighlighted(PropertyRowWidget* rowWidget);
AZStd::vector<AZ::s32> ExtractComponentEditorIndicesFromMimeData(const QMimeData* mimeData) const;
ComponentEditorVector GetComponentEditorsFromIndices(const AZStd::vector<AZ::s32>& indices) const;
ComponentEditor* GetComponentEditorsFromIndex(const AZ::s32 index) const;
@@ -559,6 +605,8 @@ namespace AzToolsFramework
QIcon m_emptyIcon;
QIcon m_clearIcon;
QIcon m_dragIcon;
QCursor m_dragCursor;
QStandardItem* m_comboItems[StatusItems];
EntityIdSet m_overrideSelectedEntityIds;
@@ -566,6 +614,19 @@ namespace AzToolsFramework
Prefab::PrefabPublicInterface* m_prefabPublicInterface = nullptr;
bool m_prefabsAreEnabled = false;
// Reordering row widgets within the RPE.
static constexpr float MoveFadeSeconds = 0.5f;
ReorderState m_currentReorderState = ReorderState::Inactive;
ComponentEditor* m_reorderRowWidgetEditor = nullptr;
InstanceDataNode* m_nodeToMove = nullptr;
PropertyRowWidget* m_reorderRowWidget = nullptr;
PropertyRowWidget* m_reorderDropTarget = nullptr;
DropArea m_reorderDropArea = DropArea::Above;
QPixmap m_reorderRowImage;
float m_moveFadeSecondsRemaining;
AZStd::vector<int> m_indexMapOfMovedRow;
// When m_initiatingPropertyChangeNotification is set to true, it means this EntityPropertyEditor is
// broadcasting a change to all listeners about a property change for a given entity. This is needed
// so that we don't update the values twice for this inspector
@@ -573,6 +634,9 @@ namespace AzToolsFramework
void ConnectToEntityBuses(const AZ::EntityId& entityId);
void DisconnectFromEntityBuses(const AZ::EntityId& entityId);
void BeginMoveRowWidgetFade();
void HighlightMovedRowWidget();
//! Stores a component id to be focused on next time the UI updates.
AZStd::optional<AZ::ComponentId> m_newComponentId;
@@ -594,6 +658,8 @@ namespace AzToolsFramework
bool SelectedEntitiesAreFromSameSourceSliceEntity() const;
void DragStopped();
AZ::Entity* GetSelectedEntityById(AZ::EntityId& entityId) const;
};
@@ -7,8 +7,8 @@
*/
#include "PropertyAudioCtrl.h"
#include "PropertyQTConstants.h"
#include <UI/PropertyEditor/PropertyAudioCtrl.h>
#include <UI/PropertyEditor/PropertyQTConstants.h>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLineEdit>
@@ -34,7 +34,7 @@ namespace AzToolsFramework
: QWidget(parent)
, m_browseEdit(nullptr)
, m_mainLayout(nullptr)
, m_propertyType(AudioPropertyType::Invalid)
, m_propertyType(AudioPropertyType::NumTypes)
{
// create the gui
m_mainLayout = new QHBoxLayout();
@@ -96,7 +96,7 @@ namespace AzToolsFramework
return;
}
if (type != AudioPropertyType::Invalid)
if (type != AudioPropertyType::NumTypes)
{
m_propertyType = type;
}
@@ -136,10 +136,11 @@ namespace AzToolsFramework
void AudioControlSelectorWidget::OnOpenAudioControlSelector()
{
AZStd::string resourceResult;
AZStd::string resourceType(GetResourceSelectorNameFromType(m_propertyType));
AZStd::string currentValue(m_controlName.toStdString().c_str());
EditorRequests::Bus::BroadcastResult(resourceResult, &EditorRequests::Bus::Events::SelectResource, resourceType, currentValue);
AZStd::string resourceResult;
AudioControlSelectorRequestBus::EventResult(
resourceResult, m_propertyType,
&AudioControlSelectorRequestBus::Events::SelectResource, currentValue);
SetControlName(QString(resourceResult.c_str()));
}
@@ -167,12 +168,12 @@ namespace AzToolsFramework
{
case AudioPropertyType::Trigger:
return { "AudioTrigger" };
case AudioPropertyType::Rtpc:
return { "AudioRTPC" };
case AudioPropertyType::Switch:
return { "AudioSwitch" };
case AudioPropertyType::SwitchState:
return { "AudioSwitchState" };
case AudioPropertyType::Rtpc:
return { "AudioRTPC" };
case AudioPropertyType::Environment:
return { "AudioEnvironment" };
case AudioPropertyType::Preload:
@@ -29,6 +29,27 @@ class QMimeData;
namespace AzToolsFramework
{
//=============================================================================
// Audio Control Selector Request Bus
// For connecting UI proper
//=============================================================================
class AudioControlSelectorRequests
: public AZ::EBusTraits
{
public:
// EBusTraits
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
using BusIdType = AudioPropertyType;
virtual AZStd::string SelectResource(AZStd::string_view previousValue)
{
return previousValue;
}
};
using AudioControlSelectorRequestBus = AZ::EBus<AudioControlSelectorRequests>;
//=============================================================================
// Audio Control Selector Widget
//=============================================================================
@@ -18,15 +18,15 @@
namespace AzToolsFramework
{
//=========================================================================
enum class AudioPropertyType
enum class AudioPropertyType : AZ::u32
{
Invalid = 0,
Trigger,
Trigger = 0,
Rtpc,
Switch,
SwitchState,
Rtpc,
Environment,
Preload,
NumTypes,
};
//=========================================================================
@@ -40,7 +40,7 @@ namespace AzToolsFramework
virtual ~CReflectedVarAudioControl() = default;
AZStd::string m_controlName;
AudioPropertyType m_propertyType = AudioPropertyType::Invalid;
AudioPropertyType m_propertyType = AudioPropertyType::NumTypes;
static void Reflect(AZ::ReflectContext* context)
{
@@ -368,10 +368,15 @@ namespace AzToolsFramework
delete m_containerAddButton;
}
this->unsetCursor();
if ((m_parentRow) && (m_parentRow->IsContainerEditable()))
{
if (!m_elementRemoveButton)
{
QIcon icon = QIcon(QStringLiteral(":/Cursors/Grab_release.svg"));
this->setCursor(QCursor(icon.pixmap(16), 5, 2));
static QIcon s_iconRemove(QStringLiteral(":/stylesheet/img/UI20/delete-16.svg"));
m_elementRemoveButton = new QToolButton(this);
m_elementRemoveButton->setAutoRaise(true);
@@ -570,7 +575,12 @@ namespace AzToolsFramework
AZ_Assert(m_selectionEnabled, "Property is not selectable");
m_isSelected = selected;
m_nameLabel->setProperty("selected", selected);
}
}
bool PropertyRowWidget::GetSelected()
{
return m_isSelected;
}
void PropertyRowWidget::SetSelectionEnabled(bool selectionEnabled)
{
@@ -1395,6 +1405,21 @@ namespace AzToolsFramework
return !m_childrenRows.empty();
}
AZ::u32 PropertyRowWidget::GetChildRowCount() const
{
return static_cast<AZ::u32>(m_childrenRows.size());
}
PropertyRowWidget* PropertyRowWidget::GetChildRowByIndex(AZ::u32 index) const
{
if (index >= m_childrenRows.size())
{
return nullptr;
}
return m_childrenRows[index];
}
bool PropertyRowWidget::ShouldPreValidatePropertyChange() const
{
return (m_changeValidators.size() > 0);
@@ -1722,6 +1747,162 @@ namespace AzToolsFramework
return m_parentRow->CanChildrenBeReordered();
}
int PropertyRowWidget::GetIndexInParent() const
{
if (!GetParentRow())
{
return -1;
}
for (AZ::u32 index = 0; index < GetParentRow()->GetChildRowCount(); index++)
{
if (GetParentRow()->GetChildrenRows()[index] == this)
{
return index;
}
}
return -1;
}
bool PropertyRowWidget::CanMoveUp() const
{
if (!CanBeReordered())
{
return false;
}
return this != m_parentRow->GetChildRowByIndex(0);
}
bool PropertyRowWidget::CanMoveDown() const
{
if (!CanBeReordered())
{
return false;
}
AZ::u32 numChildrenOfParent = m_parentRow->GetChildRowCount();
return this != m_parentRow->GetChildRowByIndex(numChildrenOfParent - 1);
}
int PropertyRowWidget::GetContainingEditorFrameWidth()
{
QWidget* parent = parentWidget();
// Find the first ancestor that can be cast to a QFrame, this will be the RPE.
while (!qobject_cast<QFrame*>(parent))
{
parent = parent->parentWidget();
}
if (!parent)
{
return 0;
}
// The parent of the RPE is the size we want.
parent = parent->parentWidget();
return parent->rect().width();
}
int PropertyRowWidget::GetHeightOfRowAndVisibleChildren()
{
int height = rect().height();
if (!GetChildRowCount() || !IsExpanded())
{
return height;
}
for (auto childRow : GetChildrenRows())
{
height += childRow->GetHeightOfRowAndVisibleChildren();
}
return height;
}
int PropertyRowWidget::DrawDragImageAndVisibleChildrenInto(QPainter& painter, int xpos, int ypos)
{
// Render our image into the given painter.
int ystart = ypos;
render(&painter, QPoint(xpos, ypos));
if (!GetChildRowCount() || !IsExpanded())
{
return rect().height();
}
ypos += rect().height();
// Recursively draw any children.
for (auto childRow : GetChildrenRows())
{
ypos += childRow->DrawDragImageAndVisibleChildrenInto(painter, xpos, ypos);
}
return ypos - ystart;
}
QPixmap PropertyRowWidget::createDragImage(
const QColor backgroundColor, const QColor borderColor, const float alpha, DragImageType imageType)
{
// Make the drag box as wide as the containing editor minus a gap each side for the border.
static constexpr int ParentEditorBorderSize = 2;
int width = GetContainingEditorFrameWidth() - ParentEditorBorderSize * 2;
int height = 0;
if (imageType == DragImageType::IncludeVisibleChildren)
{
height = GetHeightOfRowAndVisibleChildren();
}
else
{
height = rect().height();
}
const auto dpr = devicePixelRatioF();
QPixmap dragImage(width * dpr, height * dpr);
dragImage.setDevicePixelRatio(dpr);
dragImage.fill(Qt::transparent);
QRect imageRect = QRect(0, 0, width, height);
QPainter dragPainter(&dragImage);
dragPainter.setCompositionMode(QPainter::CompositionMode_Source);
dragPainter.fillRect(imageRect, Qt::transparent);
dragPainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
dragPainter.setOpacity(alpha);
dragPainter.fillRect(imageRect, backgroundColor);
dragPainter.setOpacity(1.0f);
int marginWidth = (imageRect.width() - rect().width()) / 2 + ParentEditorBorderSize - 1;
if (imageType == DragImageType::IncludeVisibleChildren)
{
DrawDragImageAndVisibleChildrenInto(dragPainter, marginWidth, 0);
}
else
{
render(&dragPainter, QPoint(marginWidth, 0));
}
QPen pen;
pen.setColor(QColor(borderColor));
pen.setWidth(1);
dragPainter.setPen(pen);
dragPainter.drawRect(0, 0, imageRect.width() - 1, imageRect.height() - 1);
dragPainter.end();
return dragImage;
}
}
#include "UI/PropertyEditor/moc_PropertyRowWidget.cpp"
@@ -45,6 +45,13 @@ namespace AzToolsFramework
Q_PROPERTY(bool appendDefaultLabelToName READ GetAppendDefaultLabelToName WRITE AppendDefaultLabelToName)
public:
AZ_CLASS_ALLOCATOR(PropertyRowWidget, AZ::SystemAllocator, 0)
enum class DragImageType
{
SingleRow,
IncludeVisibleChildren
};
PropertyRowWidget(QWidget* pParent);
virtual ~PropertyRowWidget();
@@ -86,6 +93,9 @@ namespace AzToolsFramework
bool GetAppendDefaultLabelToName();
void AppendDefaultLabelToName(bool doAppend);
AZ::u32 GetChildRowCount() const;
PropertyRowWidget* GetChildRowByIndex(AZ::u32 index) const;
AZStd::vector<PropertyRowWidget*>& GetChildrenRows() { return m_childrenRows; }
bool HasChildRows() const;
@@ -124,6 +134,7 @@ namespace AzToolsFramework
void SetSelectionEnabled(bool selectionEnabled);
void SetSelected(bool selected);
bool GetSelected();
bool eventFilter(QObject *watched, QEvent *event) override;
void paintEvent(QPaintEvent*) override;
@@ -152,9 +163,18 @@ namespace AzToolsFramework
bool CanChildrenBeReordered() const;
bool CanBeReordered() const;
int GetIndexInParent() const;
bool CanMoveUp() const;
bool CanMoveDown() const;
int GetContainingEditorFrameWidth();
QPixmap createDragImage(const QColor backgroundColor, const QColor borderColor, const float alpha, DragImageType imageType);
protected:
int CalculateLabelWidth() const;
int GetHeightOfRowAndVisibleChildren();
int DrawDragImageAndVisibleChildrenInto(QPainter& painter, int xpos, int ypos);
bool IsHidden(InstanceDataNode* node) const;
struct ChangeNotification;
@@ -216,6 +236,7 @@ namespace AzToolsFramework
bool m_isMultiSizeContainer = false;
bool m_isFixedSizeOrSmartPtrContainer = false;
bool m_custom = false;
bool m_canChildrenBeReordered = false;
bool m_isSelected = false;
bool m_selectionEnabled = false;
@@ -19,6 +19,7 @@
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QScrollArea>
#include <QtWidgets/QApplication>
#include <QPainter>
AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") // 'QTextFormat::d': class 'QSharedDataPointer<QTextFormatPrivate>' needs to have dll-interface to be used by clients of class 'QTextFormat'
#include <QtWidgets/QInputDialog>
AZ_POP_DISABLE_WARNING
@@ -1343,7 +1344,7 @@ namespace AzToolsFramework
// calculate the index/offset of the instance data node in the container
// (useful for notifying which element in a vector was modified/removed)
static size_t CalculateElementIndexInContainer(
static int CalculateElementIndexInContainer(
InstanceDataNode* node, void* parentInstanceNode,
AZ::SerializeContext::IDataContainer* container, AZStd::vector<void*>& nodeInstancesOut)
{
@@ -1358,7 +1359,7 @@ namespace AzToolsFramework
}
}
size_t elementIndex = 0;
int elementIndex = 0;
void* elementPtr = nodeInstancesOut.empty() ? nullptr : nodeInstancesOut.front();
// find the index of the element we are about to remove
@@ -1429,7 +1430,7 @@ namespace AzToolsFramework
// if the element being modified exists in a container, calculate
// the index to be passed through to PropertyNotify
const auto calculateElementIndex = [](InstanceDataNode* node) -> size_t {
const auto calculateElementIndex = [](InstanceDataNode* node) -> int {
if (InstanceDataNode* parent = node->GetParent())
{
if (AZ::SerializeContext::IDataContainer* container = parent->GetClassMetadata()->m_container)
@@ -1656,6 +1657,221 @@ namespace AzToolsFramework
AzToolsFramework::Refresh_EntireTree);
}
InstanceDataNode* ReflectedPropertyEditor::FindContainerNodeForNode(InstanceDataNode* node) const
{
// Locate the owning container. There may be a level of indirection due to wrappers, such as DynamicSerializableField.
InstanceDataNode* pContainerNode = node->GetParent();
if (!pContainerNode)
{
return nullptr;
}
while (pContainerNode && !pContainerNode->GetClassMetadata()->m_container)
{
pContainerNode = pContainerNode->GetParent();
node = node->GetParent();
}
// Check for pContainerNode again, can happen if a node is deleted during operation.
if (!pContainerNode)
{
return nullptr;
}
if (IsParentAssociativeContainer(pContainerNode) && IsPairContainer(pContainerNode))
{
// Go up one more level to the associative container, we'll remove the pair from that container
pContainerNode = pContainerNode->GetParent();
node = node->GetParent();
}
AZ_Assert(
pContainerNode, "Failed to locate parent container for element \"%s\" of type %s.",
node->GetElementMetadata() ? node->GetElementMetadata()->m_name : node->GetClassMetadata()->m_name,
node->GetClassMetadata()->m_typeId.ToString<AZStd::string>().c_str());
return pContainerNode;
}
InstanceDataNode* ReflectedPropertyEditor::GetNodeAtIndex(int index)
{
if (index >= m_impl->m_widgetsInDisplayOrder.size())
{
return nullptr;
}
return GetNodeFromWidget(m_impl->m_widgetsInDisplayOrder[index]);
}
QSet<PropertyRowWidget*> ReflectedPropertyEditor::GetTopLevelWidgets()
{
return m_impl->getTopLevelWidgets();
}
void ReflectedPropertyEditor::ChangeNodeIndex(InstanceDataNode* containerNode, InstanceDataNode* node, int fromIndex, int toIndex)
{
auto container = containerNode->GetElementMetadata()
? containerNode->GetElementMetadata()->m_genericClassInfo->GetClassData()->m_container
: nullptr;
if (fromIndex == toIndex)
{
return;
}
if (!container || container->GetAssociativeContainerInterface())
{
return;
}
AZ::Uuid typeId = node->GetClassMetadata()->m_typeId;
if (m_impl->m_ptrNotify)
{
m_impl->m_ptrNotify->BeforePropertyModified(containerNode);
}
const AZ::SerializeContext::ClassElement* containerClassElement = container->GetElement(container->GetDefaultElementNameCrc());
AZ::SerializeContext* serializeContext = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
// Backup the item we're moving.
void* srcElement = nullptr;
void* destElement = nullptr;
int destIndex = -1;
int srcIndex = fromIndex;
srcElement = container->GetElementByIndex(containerNode->GetInstance(0), containerClassElement, srcIndex);
void* tmpBuffer = serializeContext->CloneObject(srcElement, typeId);
// Shuffle all intervening items up (or down).
int indexOffset = (toIndex < fromIndex) ? -1 : 1;
while (destIndex != toIndex - indexOffset)
{
destIndex = srcIndex;
srcIndex += indexOffset;
destElement = srcElement;
srcElement = container->GetElementByIndex(containerNode->GetInstance(0), containerClassElement, srcIndex);
serializeContext->CloneObjectInplace(destElement, srcElement, typeId);
}
// Now replace the final element with the one backed up previously.
destElement = srcElement;
serializeContext->CloneObjectInplace(destElement, tmpBuffer, typeId);
if (m_impl->m_ptrNotify)
{
m_impl->m_ptrNotify->AfterPropertyModified(containerNode);
m_impl->m_ptrNotify->SealUndoStack();
}
// Need to refresh any pinned inspectors as well to keep the container state in sync
QueueInvalidation(Refresh_Values);
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_Values);
}
void ReflectedPropertyEditor::MoveNodeToIndex(InstanceDataNode* node, int index)
{
InstanceDataNode* pContainerNode = FindContainerNodeForNode(node);
if (!pContainerNode)
{
return;
}
AZ::SerializeContext::IDataContainer* container = pContainerNode->GetClassMetadata()->m_container;
AZStd::vector<void*> nodeInstancesOut;
const int elementIndex = CalculateElementIndexInContainer(node, pContainerNode->GetInstance(0), container, nodeInstancesOut);
ChangeNodeIndex(pContainerNode, node, elementIndex, index);
}
void ReflectedPropertyEditor::MoveNodeBefore(InstanceDataNode* nodeToMove, InstanceDataNode* nodeToMoveBefore)
{
InstanceDataNode* pContainerNode = FindContainerNodeForNode(nodeToMove);
InstanceDataNode* pContainerNodeTarget = FindContainerNodeForNode(nodeToMoveBefore);
if (nodeToMove == nodeToMoveBefore)
{
return;
}
// Can only move nodes within the same parent.
if (pContainerNode != pContainerNodeTarget)
{
return;
}
AZ::SerializeContext::IDataContainer* container = pContainerNode->GetClassMetadata()->m_container;
AZStd::vector<void*> nodeInstancesOut;
int elementIndex = CalculateElementIndexInContainer(nodeToMove, pContainerNode->GetInstance(0), container, nodeInstancesOut);
nodeInstancesOut.clear();
int elementIndexTarget =
CalculateElementIndexInContainer(nodeToMoveBefore, pContainerNode->GetInstance(0), container, nodeInstancesOut);
if (elementIndex < elementIndexTarget)
{
elementIndexTarget -= 1;
}
ChangeNodeIndex(pContainerNode, nodeToMove, elementIndex, elementIndexTarget);
}
void ReflectedPropertyEditor::MoveNodeAfter(InstanceDataNode* nodeToMove, InstanceDataNode* nodeToMoveBefore)
{
InstanceDataNode* pContainerNode = FindContainerNodeForNode(nodeToMove);
InstanceDataNode* pContainerNodeTarget = FindContainerNodeForNode(nodeToMoveBefore);
if (nodeToMove == nodeToMoveBefore)
{
return;
}
// Can only move nodes within the same parent.
if (pContainerNode != pContainerNodeTarget)
{
return;
}
AZ::SerializeContext::IDataContainer* container = pContainerNode->GetClassMetadata()->m_container;
AZStd::vector<void*> nodeInstancesOut;
int elementIndex = CalculateElementIndexInContainer(nodeToMove, pContainerNode->GetInstance(0), container, nodeInstancesOut);
nodeInstancesOut.clear();
int elementIndexTarget =
CalculateElementIndexInContainer(nodeToMoveBefore, pContainerNode->GetInstance(0), container, nodeInstancesOut);
if (elementIndex > elementIndexTarget)
{
elementIndexTarget += 1;
}
ChangeNodeIndex(pContainerNode, nodeToMove, elementIndex, elementIndexTarget);
}
int ReflectedPropertyEditor::GetNodeIndexInContainer(InstanceDataNode* node)
{
InstanceDataNode* pContainerNode = FindContainerNodeForNode(node);
AZ::SerializeContext::IDataContainer* container = pContainerNode->GetClassMetadata()->m_container;
AZStd::vector<void*> nodeInstancesOut;
int elementIndex = CalculateElementIndexInContainer(node, pContainerNode->GetInstance(0), container, nodeInstancesOut);
return elementIndex;
}
void ReflectedPropertyEditor::OnPropertyRowRequestContainerRemoveItem(PropertyRowWidget* widget, InstanceDataNode* node)
{
// Locate the owning container. There may be a level of indirection due to wrappers, such as DynamicSerializableField.
@@ -1690,7 +1906,7 @@ namespace AzToolsFramework
// the index of the element being removed
AZStd::vector<void*> nodeInstancesOut;
const size_t elementIndex = CalculateElementIndexInContainer(
const int elementIndex = CalculateElementIndexInContainer(
node, pContainerNode->GetInstance(0), container, nodeInstancesOut);
// pass the context as the last parameter to actually delete the related data.
@@ -155,9 +155,19 @@ namespace AzToolsFramework
using VisibilityCallback = AZStd::function<void(InstanceDataNode* node, NodeDisplayVisibility& visibility, bool& checkChildVisibility)>;
void SetVisibilityCallback(VisibilityCallback callback);
void MoveNodeToIndex(InstanceDataNode* node, int index);
void MoveNodeBefore(InstanceDataNode* nodeToMove, InstanceDataNode* nodeToMoveBefore);
void MoveNodeAfter(InstanceDataNode* nodeToMove, InstanceDataNode* nodeToMoveBefore);
int GetNodeIndexInContainer(InstanceDataNode* node);
InstanceDataNode* GetNodeAtIndex(int index);
QSet<PropertyRowWidget*> GetTopLevelWidgets();
signals:
void OnExpansionContractionDone();
private:
InstanceDataNode* FindContainerNodeForNode(InstanceDataNode* node) const;
void ChangeNodeIndex(InstanceDataNode* containerNode, InstanceDataNode* node, int oldIndex, int newIndex);
class Impl;
std::unique_ptr<Impl> m_impl;
@@ -27,6 +27,35 @@ using namespace AzToolsFramework;
namespace UnitTest
{
void MousePressAndMove(
QWidget* widget, const QPoint& initialPositionWidget, const QPoint& mouseDelta, const Qt::MouseButton mouseButton)
{
QPoint position = widget->mapToGlobal(initialPositionWidget);
QTest::mousePress(widget, mouseButton, Qt::NoModifier, position);
MouseMove(widget, initialPositionWidget, mouseDelta, mouseButton);
}
// Note: There are a series of bugs in Qt that appear to be preventing mouseMove events
// firing when sent through the QTest framework. This is a work around for our version
// of Qt. In future this can hopefully be simplified. See ^1 for workaround.
// More info: Issues with mouse move in Qt
// - https://bugreports.qt.io/browse/QTBUG-5232
// - https://bugreports.qt.io/browse/QTBUG-69414
// - https://lists.qt-project.org/pipermail/development/2019-July/036873.html
void MouseMove(QWidget* widget, const QPoint& initialPositionWidget, const QPoint& mouseDelta, const Qt::MouseButton mouseButton)
{
QPoint nextPosition = widget->mapToGlobal(initialPositionWidget + mouseDelta);
// ^1 To ensure a mouse move event is fired we must call the test mouse move function
// and also send a mouse move event that matches. Each on their own do not appear to
// work - please see the links above for more context.
QTest::mouseMove(widget, nextPosition);
QMouseEvent mouseMoveEvent(
QEvent::MouseMove, QPointF(nextPosition), QPointF(nextPosition), Qt::NoButton, mouseButton, Qt::NoModifier);
QApplication::sendEvent(widget, &mouseMoveEvent);
}
bool TestWidget::eventFilter(QObject* watched, QEvent* event)
{
AZ_UNUSED(watched);
@@ -59,6 +59,21 @@ namespace UnitTest
{
constexpr AZStd::string_view prefabSystemSetting = "/Amazon/Preferences/EnablePrefabSystem";
/// Performs a mouse press and move event on the provided widget.
/// @param widget The widget to perform the mouse press and move on.
/// @param initialPositionWidget The position of the mouse relative to the widget (will be remapped to a global position internally).
/// @param mouseDelta How far to move the mouse.
/// @param mouseButton The button to be used during the press and move.
void MousePressAndMove(
QWidget* widget, const QPoint& initialPositionWidget, const QPoint& mouseDelta, Qt::MouseButton mouseButton = Qt::LeftButton);
/// Performs a mouse move event on the provided widget.
/// @param widget The widget to perform the mouse move on.
/// @param initialPositionWidget The position of the mouse relative to the widget (will be remapped to a global position internally).
/// @param mouseDelta How far to move the mouse (note: mouseDelta may be zero and the mouse will only be moved to initialPosition).
/// @param mouseButton The button to be held during the move.
void MouseMove(QWidget* widget, const QPoint& initialPosition, const QPoint& mouseDelta, Qt::MouseButton mouseButton = Qt::NoButton);
/// Test widget to store QActions generated by EditorTransformComponentSelection.
class TestWidget : public QWidget
{
@@ -313,7 +313,7 @@ namespace AzToolsFramework
//! Utility function to return EntityContextId.
inline AzFramework::EntityContextId GetEntityContextId()
{
AzFramework::EntityContextId entityContextId;
auto entityContextId = AzFramework::EntityContextId::CreateNull();
EditorEntityContextRequestBus::BroadcastResult(entityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
return entityContextId;
@@ -60,6 +60,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
PUBLIC
AZ::AzTestShared
PRIVATE
3rdParty::Qt::Test
3rdParty::googletest::GMock
3rdParty::GoogleBenchmark
AZ::AzToolsFramework
@@ -76,8 +77,9 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
PRIVATE
Tests
BUILD_DEPENDENCIES
PRIVATE
PUBLIC
AZ::AzTestShared
PRIVATE
3rdParty::Qt::Test
AZ::AzFrameworkTestShared
AZ::AzToolsFramework
@@ -107,31 +107,6 @@ namespace UnitTest
EXPECT_THAT(m_doubleSpinBoxWithLineEdit, Ne(nullptr));
}
// Note: There are a series of bugs in Qt that appear to be preventing mouseMove events
// firing when sent through the QTest framework. This is a work around for our version
// of Qt. In future this can hopefully be simplified. See ^1 for workaround.
// More info: Issues with mouse move in Qt
// - https://bugreports.qt.io/browse/QTBUG-5232
// - https://bugreports.qt.io/browse/QTBUG-69414
// - https://lists.qt-project.org/pipermail/development/2019-July/036873.html
void MousePressAndMove(
QWidget* widget, const QPoint& widgetScreenPosition, const QPoint& mouseDelta)
{
QPoint position = widget->mapToGlobal(widgetScreenPosition);
QPoint nextPosition = widget->mapToGlobal(widgetScreenPosition + mouseDelta);
QTest::mousePress(widget, Qt::LeftButton, Qt::NoModifier, position);
// ^1 To ensure a mouse move event is fired we must call the test mouse move function
// and also send a mouse move event that matches. Each on their own do not appear to
// work - please see the links above for more context.
QTest::mouseMove(widget, nextPosition);
QMouseEvent mouseMoveEvent(
QEvent::MouseMove, QPointF(nextPosition), QPointF(nextPosition),
Qt::NoButton, Qt::LeftButton, Qt::NoModifier);
QApplication::sendEvent(widget, &mouseMoveEvent);
}
TEST_F(SpinBoxFixture, SpinBoxMousePressAndMoveRightScrollsValue)
{
m_doubleSpinBox->setValue(10.0);
@@ -7,6 +7,7 @@
*/
#include <unistd.h>
#include <AzCore/std/string/string.h>
namespace GridMate
{
@@ -7,6 +7,7 @@
*/
#include <unistd.h>
#include <AzCore/std/string/string.h>
namespace GridMate
{
@@ -10,6 +10,7 @@
#include <O3DEApplication_Mac.h>
#include <../Common/Apple/Launcher_Apple.h>
#include <../Common/UnixLike/Launcher_UnixLike.h>
#include <AzCore/Math/Vector2.h>
#if AZ_TESTS_ENABLED
@@ -9,6 +9,7 @@
#include <CryCommon/CryLibrary.h>
#include <AzCore/Math/Vector2.h>
#include <AzCore/Memory/SystemAllocator.h>
int APIENTRY WinMain([[maybe_unused]] HINSTANCE hInstance, [[maybe_unused]] HINSTANCE hPrevInstance, [[maybe_unused]] LPSTR lpCmdLine, [[maybe_unused]] int nCmdShow)
{
+15
View File
@@ -226,6 +226,21 @@ typedef uint64 __uint64;
#define _PTRDIFF_T_DEFINED 1
typedef union _LARGE_INTEGER
{
struct
{
DWORD LowPart;
LONG HighPart;
};
struct
{
DWORD LowPart;
LONG HighPart;
} u;
long long QuadPart;
} LARGE_INTEGER;
#define _A_RDONLY (0x01) /* Read only file */
#define _A_HIDDEN (0x02) /* Hidden file */
#define _A_SUBDIR (0x10) /* Subdirectory */
+2 -2
View File
@@ -72,7 +72,7 @@ bool CryAssert(const char* szCondition, const char* szFile, unsigned int line, b
static const int max_len = 4096;
static char gs_command_str[4096];
static CryLockT<CRYLOCK_RECURSIVE> lock;
static AZStd::recursive_mutex lock;
gEnv->pSystem->OnAssert(szCondition, gs_szMessage, szFile, line);
@@ -80,7 +80,7 @@ bool CryAssert(const char* szCondition, const char* szFile, unsigned int line, b
if (!gEnv->bNoAssertDialog && !gEnv->bIgnoreAllAsserts)
{
CryAutoLock< CryLockT<CRYLOCK_RECURSIVE> > lk (lock);
AZStd::scoped_lock lk(lock);
snprintf(gs_command_str, max_len, "xterm -geometry 100x20 -n 'Assert Dialog [Linux Launcher]' -T 'Assert Dialog [Linux Launcher]' -e 'BinLinux/assert_term \"%s\" \"%s\" %d \"%s\"; echo \"$?\" > .assert_return'",
szCondition, (file_len > 60) ? szFile + (file_len - 61) : szFile, line, gs_szMessage);
int ret = system(gs_command_str);
-2
View File
@@ -70,8 +70,6 @@ bool CryAssert(const char* szCondition, const char* szFile, unsigned int line, b
static const int max_len = 4096;
static char gs_command_str[4096];
static CryLockT<CRYLOCK_RECURSIVE> lock;
gEnv->pSystem->OnAssert(szCondition, gs_szMessage, szFile, line);
size_t file_len = strlen(szFile);
+1 -1
View File
@@ -49,7 +49,7 @@
*/
#include <stdio.h>
#include <AzCore/PlatformDef.h>
#include <AzCore/PlatformIncl.h>
#include <AzCore/Module/Environment.h>
#define INJECT_ENVIRONMENT_FUNCTION "InjectEnvironment"
-186
View File
@@ -1,186 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
// Description : Public include file for the multi-threading API.
#pragma once
// Include basic multithread primitives.
#include "MultiThread.h"
#include "BitFiddling.h"
#include <AzCore/std/string/string.h>
//////////////////////////////////////////////////////////////////////////
// Lock types:
//
// CRYLOCK_FAST
// A fast potentially (non-recursive) mutex.
// CRYLOCK_RECURSIVE
// A recursive mutex.
//////////////////////////////////////////////////////////////////////////
enum CryLockType
{
CRYLOCK_FAST = 1,
CRYLOCK_RECURSIVE = 2,
};
#define CRYLOCK_HAVE_FASTLOCK 1
/////////////////////////////////////////////////////////////////////////////
//
// Primitive locks and conditions.
//
// Primitive locks are represented by instance of class CryLockT<Type>
//
//
template<CryLockType Type>
class CryLockT
{
/* Unsupported lock type. */
};
//////////////////////////////////////////////////////////////////////////
// Typedefs.
//////////////////////////////////////////////////////////////////////////
typedef CryLockT<CRYLOCK_RECURSIVE> CryCriticalSection;
typedef CryLockT<CRYLOCK_FAST> CryCriticalSectionNonRecursive;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// CryAutoCriticalSection implements a helper class to automatically
// lock critical section in constructor and release on destructor.
//
//////////////////////////////////////////////////////////////////////////
template<class LockClass>
class CryAutoLock
{
private:
LockClass* m_pLock;
CryAutoLock();
CryAutoLock(const CryAutoLock<LockClass>&);
CryAutoLock<LockClass>& operator = (const CryAutoLock<LockClass>&);
public:
CryAutoLock(LockClass& Lock)
: m_pLock(&Lock) { m_pLock->Lock(); }
CryAutoLock(const LockClass& Lock)
: m_pLock(const_cast<LockClass*>(&Lock)) { m_pLock->Lock(); }
~CryAutoLock() { m_pLock->Unlock(); }
};
//////////////////////////////////////////////////////////////////////////
//
// Auto critical section is the most commonly used type of auto lock.
//
//////////////////////////////////////////////////////////////////////////
typedef CryAutoLock<CryCriticalSection> CryAutoCriticalSection;
/////////////////////////////////////////////////////////////////////////////
//
// Threads.
// Base class for runnable objects.
//
// A runnable is an object with a Run() and a Cancel() method. The Run()
// method should perform the runnable's job. The Cancel() method may be
// called by another thread requesting early termination of the Run() method.
// The runnable may ignore the Cancel() call, the default implementation of
// Cancel() does nothing.
class CryRunnable
{
public:
virtual ~CryRunnable() { }
virtual void Run() = 0;
virtual void Cancel() { }
};
// Class holding information about a thread.
//
// A reference to the thread information can be obtained by calling GetInfo()
// on the CrySimpleThread (or derived class) instance.
//
// NOTE:
// If the code is compiled with NO_THREADINFO defined, then the GetInfo()
// method will return a reference to a static dummy instance of this
// structure. It is currently undecided if NO_THREADINFO will be defined for
// release builds!
struct CryThreadInfo
{
// The symbolic name of the thread.
//
// You may set this name directly or through the SetName() method of
// CrySimpleThread (or derived class).
AZStd::string m_Name;
// A thread identification number.
// The number is unique but architecture specific. Do not assume anything
// about that number except for being unique.
//
// This field is filled when the thread is started (i.e. before the Run()
// method or thread routine is called). It is advised that you do not
// change this number manually.
uint32 m_ID;
};
// Simple thread class.
//
// CrySimpleThread is a simple wrapper around a system thread providing
// nothing but system-level functionality of a thread. There are two typical
// ways to use a simple thread:
//
// 1. Derive from the CrySimpleThread class and provide an implementation of
// the Run() (and optionally Cancel()) methods.
// 2. Specify a runnable object when the thread is started. The default
// runnable type is CryRunnable.
//
// The Runnable class specfied as the template argument must provide Run()
// and Cancel() methods compatible with the following signatures:
//
// void Runnable::Run();
// void Runnable::Cancel();
//
// If the Runnable does not support cancellation, then the Cancel() method
// should do nothing.
//
// The same instance of CrySimpleThread may be used for multiple thread
// executions /in sequence/, i.e. it is valid to re-start the thread by
// calling Start() after the thread has been joined by calling WaitForThread().
template<class Runnable = CryRunnable>
class CrySimpleThread;
///////////////////////////////////////////////////////////////////////////////
// Include architecture specific code.
#if AZ_LEGACY_CRYCOMMON_TRAIT_USE_PTHREADS
#include <CryThread_pthreads.h>
#define AZ_RESTRICTED_SECTION_IMPLEMENTED
#elif defined(WIN32) || defined(WIN64)
#include <CryThread_windows.h>
#define AZ_RESTRICTED_SECTION_IMPLEMENTED
#elif defined(AZ_RESTRICTED_PLATFORM)
#include AZ_RESTRICTED_FILE(CryThread_h)
#endif
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
#else
// Put other platform specific includes here!
#include <CryThread_dummy.h>
#endif
#if !defined _CRYTHREAD_CONDLOCK_GLITCH
typedef CryLockT<CRYLOCK_RECURSIVE> CryMutex;
#endif // !_CRYTHREAD_CONDLOCK_GLITCH
// Include all multithreading containers.
#include "MultiThread_Containers.h"
-29
View File
@@ -1,29 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <CryThread.h>
// Include architecture specific code.
#if defined(LINUX) || defined(APPLE)
#include <CryThreadImpl_pthreads.h>
#define AZ_RESTRICTED_SECTION_IMPLEMENTED
#elif defined(WIN32) || defined(WIN64)
#include <CryThreadImpl_windows.h>
#define AZ_RESTRICTED_SECTION_IMPLEMENTED
#elif defined(AZ_RESTRICTED_PLATFORM)
#include AZ_RESTRICTED_FILE(CryThreadImpl_h)
#endif
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
#else
// Put other platform specific includes here!
#endif
@@ -1,104 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_CRYCOMMON_CRYTHREADIMPL_PTHREADS_H
#define CRYINCLUDE_CRYCOMMON_CRYTHREADIMPL_PTHREADS_H
#pragma once
#include "CryThread_pthreads.h"
AZ_THREAD_LOCAL CrySimpleThreadSelf* CrySimpleThreadSelf::m_Self = NULL;
//////////////////////////////////////////////////////////////////////////
// CryEvent(Timed) implementation
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
void CryEventTimed::Reset()
{
m_lockNotify.Lock();
m_flag = false;
m_lockNotify.Unlock();
}
//////////////////////////////////////////////////////////////////////////
void CryEventTimed::Set()
{
m_lockNotify.Lock();
m_flag = true;
m_cond.Notify();
m_lockNotify.Unlock();
}
//////////////////////////////////////////////////////////////////////////
void CryEventTimed::Wait()
{
m_lockNotify.Lock();
if (!m_flag)
{
m_cond.Wait(m_lockNotify);
}
m_flag = false;
m_lockNotify.Unlock();
}
//////////////////////////////////////////////////////////////////////////
bool CryEventTimed::Wait(const uint32 timeoutMillis)
{
bool bResult = true;
m_lockNotify.Lock();
if (!m_flag)
{
bResult = m_cond.TimedWait(m_lockNotify, timeoutMillis);
}
m_flag = false;
m_lockNotify.Unlock();
return bResult;
}
///////////////////////////////////////////////////////////////////////////////
// CryCriticalSection implementation
///////////////////////////////////////////////////////////////////////////////
typedef CryLockT<CRYLOCK_RECURSIVE> TCritSecType;
void CryDeleteCriticalSection(void* cs)
{
delete ((TCritSecType*)cs);
}
void CryEnterCriticalSection(void* cs)
{
((TCritSecType*)cs)->Lock();
}
bool CryTryCriticalSection(void* cs)
{
return false;
}
void CryLeaveCriticalSection(void* cs)
{
((TCritSecType*)cs)->Unlock();
}
void CryCreateCriticalSectionInplace(void* pCS)
{
new (pCS) TCritSecType;
}
void CryDeleteCriticalSectionInplace(void*)
{
}
void* CryCreateCriticalSection()
{
return (void*) new TCritSecType;
}
#endif // CRYINCLUDE_CRYCOMMON_CRYTHREADIMPL_PTHREADS_H
@@ -1,345 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/PlatformIncl.h>
#include <AzCore/std/parallel/semaphore.h> // for CreateSemaphore
struct SThreadNameDesc
{
DWORD dwType;
LPCSTR szName;
DWORD dwThreadID;
DWORD dwFlags;
};
AZ_THREAD_LOCAL CrySimpleThreadSelf* CrySimpleThreadSelf::m_Self = NULL;
//////////////////////////////////////////////////////////////////////////
CryEvent::CryEvent()
{
m_handle = (void*)CreateEvent(NULL, FALSE, FALSE, NULL);
}
//////////////////////////////////////////////////////////////////////////
CryEvent::~CryEvent()
{
CloseHandle(m_handle);
}
//////////////////////////////////////////////////////////////////////////
void CryEvent::Reset()
{
ResetEvent(m_handle);
}
//////////////////////////////////////////////////////////////////////////
void CryEvent::Set()
{
SetEvent(m_handle);
}
//////////////////////////////////////////////////////////////////////////
void CryEvent::Wait() const
{
WaitForSingleObject(m_handle, INFINITE);
}
//////////////////////////////////////////////////////////////////////////
bool CryEvent::Wait(const uint32 timeoutMillis) const
{
if (WaitForSingleObject(m_handle, timeoutMillis) == WAIT_TIMEOUT)
{
return false;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
// CryLock_WinMutex
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
CryLock_WinMutex::CryLock_WinMutex()
: m_hdl(CreateMutex(NULL, FALSE, NULL)) {}
CryLock_WinMutex::~CryLock_WinMutex()
{
CloseHandle(m_hdl);
}
//////////////////////////////////////////////////////////////////////////
void CryLock_WinMutex::Lock()
{
WaitForSingleObject(m_hdl, INFINITE);
}
//////////////////////////////////////////////////////////////////////////
void CryLock_WinMutex::Unlock()
{
ReleaseMutex(m_hdl);
}
//////////////////////////////////////////////////////////////////////////
bool CryLock_WinMutex::TryLock()
{
return WaitForSingleObject(m_hdl, 0) != WAIT_TIMEOUT;
}
//////////////////////////////////////////////////////////////////////////
// CryLock_CritSection
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
CryLock_CritSection::CryLock_CritSection()
{
InitializeCriticalSection((CRITICAL_SECTION*)&m_cs);
}
//////////////////////////////////////////////////////////////////////////
CryLock_CritSection::~CryLock_CritSection()
{
DeleteCriticalSection((CRITICAL_SECTION*)&m_cs);
}
//////////////////////////////////////////////////////////////////////////
void CryLock_CritSection::Lock()
{
EnterCriticalSection((CRITICAL_SECTION*)&m_cs);
}
//////////////////////////////////////////////////////////////////////////
void CryLock_CritSection::Unlock()
{
LeaveCriticalSection((CRITICAL_SECTION*)&m_cs);
}
//////////////////////////////////////////////////////////////////////////
bool CryLock_CritSection::TryLock()
{
return TryEnterCriticalSection((CRITICAL_SECTION*)&m_cs) != FALSE;
}
//////////////////////////////////////////////////////////////////////////
// most of this is taken from http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
//////////////////////////////////////////////////////////////////////////
CryConditionVariable::CryConditionVariable()
{
m_waitersCount = 0;
m_wasBroadcast = 0;
m_sema = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
InitializeCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock);
m_waitersDone = CreateEvent(NULL, FALSE, FALSE, NULL);
}
//////////////////////////////////////////////////////////////////////////
CryConditionVariable::~CryConditionVariable()
{
CloseHandle(m_sema);
DeleteCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock);
CloseHandle(m_waitersDone);
}
//////////////////////////////////////////////////////////////////////////
void CryConditionVariable::Wait(LockType& lock)
{
EnterCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock);
m_waitersCount++;
LeaveCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock);
SignalObjectAndWait(lock._get_win32_handle(), m_sema, INFINITE, FALSE);
EnterCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock);
m_waitersCount--;
bool lastWaiter = m_wasBroadcast && m_waitersCount == 0;
LeaveCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock);
if (lastWaiter)
{
SignalObjectAndWait(m_waitersDone, lock._get_win32_handle(), INFINITE, FALSE);
}
else
{
WaitForSingleObject(lock._get_win32_handle(), INFINITE);
}
}
//////////////////////////////////////////////////////////////////////////
bool CryConditionVariable::TimedWait(LockType& lock, uint32 millis)
{
EnterCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock);
m_waitersCount++;
LeaveCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock);
bool ok = true;
if (WAIT_TIMEOUT == SignalObjectAndWait(lock._get_win32_handle(), m_sema, millis, FALSE))
{
ok = false;
}
EnterCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock);
m_waitersCount--;
bool lastWaiter = m_wasBroadcast && m_waitersCount == 0;
LeaveCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock);
if (lastWaiter)
{
SignalObjectAndWait(m_waitersDone, lock._get_win32_handle(), INFINITE, FALSE);
}
else
{
WaitForSingleObject(lock._get_win32_handle(), INFINITE);
}
return ok;
}
//////////////////////////////////////////////////////////////////////////
void CryConditionVariable::NotifySingle()
{
EnterCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock);
bool haveWaiters = m_waitersCount > 0;
LeaveCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock);
if (haveWaiters)
{
ReleaseSemaphore(m_sema, 1, 0);
}
}
//////////////////////////////////////////////////////////////////////////
void CryConditionVariable::Notify()
{
EnterCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock);
bool haveWaiters = false;
if (m_waitersCount > 0)
{
m_wasBroadcast = 1;
haveWaiters = true;
}
if (haveWaiters)
{
ReleaseSemaphore(m_sema, m_waitersCount, 0);
LeaveCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock);
WaitForSingleObject(m_waitersDone, INFINITE);
m_wasBroadcast = 0;
}
else
{
LeaveCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock);
}
}
//////////////////////////////////////////////////////////////////////////
CrySemaphore::CrySemaphore(int nMaximumCount, int nInitialCount)
{
m_Semaphore = (void*)CreateSemaphore(NULL, nInitialCount, nMaximumCount, NULL);
}
//////////////////////////////////////////////////////////////////////////
CrySemaphore::~CrySemaphore()
{
CloseHandle((HANDLE)m_Semaphore);
}
//////////////////////////////////////////////////////////////////////////
void CrySemaphore::Acquire()
{
WaitForSingleObject((HANDLE)m_Semaphore, INFINITE);
}
//////////////////////////////////////////////////////////////////////////
void CrySemaphore::Release()
{
ReleaseSemaphore((HANDLE)m_Semaphore, 1, NULL);
}
//////////////////////////////////////////////////////////////////////////
CryFastSemaphore::CryFastSemaphore(int nMaximumCount, int nInitialCount)
: m_Semaphore(nMaximumCount)
, m_nCounter(nInitialCount)
{
}
//////////////////////////////////////////////////////////////////////////
CryFastSemaphore::~CryFastSemaphore()
{
}
//////////////////////////////////////////////////////////////////////////
void CryFastSemaphore::Acquire()
{
int nCount = ~0;
do
{
nCount = *const_cast<volatile int*>(&m_nCounter);
} while (CryInterlockedCompareExchange(alias_cast<volatile LONG*>(&m_nCounter), nCount - 1, nCount) != nCount);
// if the count would have been 0 or below, go to kernel semaphore
if ((nCount - 1) < 0)
{
m_Semaphore.Acquire();
}
}
//////////////////////////////////////////////////////////////////////////
void CryFastSemaphore::Release()
{
int nCount = ~0;
do
{
nCount = *const_cast<volatile int*>(&m_nCounter);
} while (CryInterlockedCompareExchange(alias_cast<volatile LONG*>(&m_nCounter), nCount + 1, nCount) != nCount);
// wake up kernel semaphore if we have waiter
if (nCount < 0)
{
m_Semaphore.Release();
}
}
//////////////////////////////////////////////////////////////////////////
CrySimpleThreadSelf::CrySimpleThreadSelf()
: m_thread(NULL)
, m_threadId(0)
{
}
//////////////////////////////////////////////////////////////////////////
void CrySimpleThreadSelf::WaitForThread()
{
assert(m_thread);
PREFAST_ASSUME(m_thread);
if (GetCurrentThreadId() != m_threadId)
{
WaitForSingleObject((HANDLE)m_thread, INFINITE);
}
}
CrySimpleThreadSelf::~CrySimpleThreadSelf()
{
if (m_thread)
{
CloseHandle(m_thread);
}
}
void CrySimpleThreadSelf::StartThread(unsigned (__stdcall * func)(void*), void* argList)
{
#if defined(AZ_RESTRICTED_PLATFORM)
#include AZ_RESTRICTED_FILE(CryThreadImpl_windows_h)
#endif
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
#else
m_thread = (void*)_beginthreadex(NULL, 0, func, argList, CREATE_SUSPENDED, &m_threadId);
#endif
assert(m_thread);
PREFAST_ASSUME(m_thread);
ResumeThread((HANDLE)m_thread);
}
-152
View File
@@ -1,152 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_CRYCOMMON_CRYTHREAD_DUMMY_H
#define CRYINCLUDE_CRYCOMMON_CRYTHREAD_DUMMY_H
#pragma once
#include <AzCore/base.h>
//////////////////////////////////////////////////////////////////////////
CryEvent::CryEvent() {}
CryEvent::~CryEvent() {}
void CryEvent::Reset() {}
void CryEvent::Set() {}
void CryEvent::Wait() const {}
bool CryEvent::Wait(const uint32 timeoutMillis) const {}
typedef CryEvent CryEventTimed;
//////////////////////////////////////////////////////////////////////////
class _DummyLock
{
public:
_DummyLock();
void Lock();
bool TryLock();
void Unlock();
#if defined(AZ_DEBUG_BUILD)
bool IsLocked();
#endif
};
template<>
class CryLock<CRYLOCK_FAST>
: public _DummyLock
{
CryLock(const CryLock<CRYLOCK_FAST>&);
void operator = (const CryLock<CRYLOCK_FAST>&);
public:
CryLock();
};
template<>
class CryLock<CRYLOCK_RECURSIVE>
: public _DummyLock
{
CryLock(const CryLock<CRYLOCK_RECURSIVE>&);
void operator = (const CryLock<CRYLOCK_RECURSIVE>&);
public:
CryLock();
};
template<>
class CryCondLock<CRYLOCK_FAST>
: public CryLock<CRYLOCK_FAST>
{
};
template<>
class CryCondLock<CRYLOCK_RECURSIVE>
: public CryLock<CRYLOCK_FAST>
{
};
template<>
class CryCond< CryLock<CRYLOCK_FAST> >
{
typedef CryLock<CRYLOCK_FAST> LockT;
CryCond(const CryCond<LockT>&);
void operator = (const CryCond<LockT>&);
public:
CryCond();
void Notify();
void NotifySingle();
void Wait(LockT&);
bool TimedWait(LockT &, uint32);
};
template<>
class CryCond< CryLock<CRYLOCK_RECURSIVE> >
{
typedef CryLock<CRYLOCK_RECURSIVE> LockT;
CryCond(const CryCond<LockT>&);
void operator = (const CryCond<LockT>&);
public:
CryCond();
void Notify();
void NotifySingle();
void Wait(LockT&);
bool TimedWait(LockT &, uint32);
};
class _DummyRWLock
{
public:
_DummyRWLock() { }
void RLock();
bool TryRLock();
void WLock();
bool TryWLock();
void Lock() { WLock(); }
bool TryLock() { return TryWLock(); }
void Unlock();
};
template<class Runnable>
class CrySimpleThread
: public CryRunnable
{
public:
typedef void (* ThreadFunction)(void*);
CrySimpleThread();
virtual ~CrySimpleThread();
#if !defined(NO_THREADINFO)
CryThreadInfo& GetInfo();
#endif
const char* GetName();
void SetName(const char*);
virtual void Run();
virtual void Cancel();
virtual void Start(Runnable&, unsigned = 0, const char* = NULL);
virtual void Start(unsigned = 0, const char* = NULL);
void StartFunction(ThreadFunction, void* = NULL, unsigned = 0);
void Exit();
void Join();
unsigned SetCpuMask(unsigned);
unsigned GetCpuMask();
void Stop();
bool IsStarted() const;
bool IsRunning() const;
};
#endif // CRYINCLUDE_CRYCOMMON_CRYTHREAD_DUMMY_H
File diff suppressed because it is too large Load Diff
-387
View File
@@ -1,387 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <process.h>
#if defined(AZ_RESTRICTED_PLATFORM)
#undef AZ_RESTRICTED_SECTION
#define CRYTHREAD_WINDOWS_H_SECTION_1 1
#define CRYTHREAD_WINDOWS_H_SECTION_2 2
#endif
//////////////////////////////////////////////////////////////////////////
// CryEvent represent a synchronization event
//////////////////////////////////////////////////////////////////////////
class CryEvent
{
public:
CryEvent();
~CryEvent();
// Reset the event to the unsignalled state.
void Reset();
// Set the event to the signalled state.
void Set();
// Access a HANDLE to wait on.
void* GetHandle() const { return m_handle; };
// Wait indefinitely for the object to become signalled.
void Wait() const;
// Wait, with a time limit, for the object to become signalled.
bool Wait(const uint32 timeoutMillis) const;
private:
CryEvent(const CryEvent&);
CryEvent& operator = (const CryEvent&);
private:
void* m_handle;
};
typedef CryEvent CryEventTimed;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// from winnt.h
struct CRY_CRITICAL_SECTION
{
void* DebugInfo;
long LockCount;
long RecursionCount;
threadID OwningThread;
void* LockSemaphore;
unsigned long* SpinCount; // force size on 64-bit systems when packed
};
//////////////////////////////////////////////////////////////////////////
// kernel mutex - don't use... use CryMutex instead
class CryLock_WinMutex
{
public:
CryLock_WinMutex();
~CryLock_WinMutex();
void Lock();
void Unlock();
bool TryLock();
void* _get_win32_handle() { return m_hdl; }
private:
CryLock_WinMutex(const CryLock_WinMutex&);
CryLock_WinMutex& operator = (const CryLock_WinMutex&);
private:
void* m_hdl;
};
// critical section... don't use... use CryCriticalSection instead
class CryLock_CritSection
{
public:
CryLock_CritSection();
~CryLock_CritSection();
void Lock();
void Unlock();
bool TryLock();
bool IsLocked()
{
return m_cs.RecursionCount > 0 && m_cs.OwningThread == CryGetCurrentThreadId();
}
private:
CryLock_CritSection(const CryLock_CritSection&);
CryLock_CritSection& operator = (const CryLock_CritSection&);
private:
CRY_CRITICAL_SECTION m_cs;
};
template <>
class CryLockT<CRYLOCK_RECURSIVE>
: public CryLock_CritSection
{
};
template <>
class CryLockT<CRYLOCK_FAST>
: public CryLock_CritSection
{
};
class CryMutex
: public CryLock_WinMutex
{
};
#define _CRYTHREAD_CONDLOCK_GLITCH 1
//////////////////////////////////////////////////////////////////////////
class CryConditionVariable
{
public:
typedef CryMutex LockType;
CryConditionVariable();
~CryConditionVariable();
void Wait(LockType& lock);
bool TimedWait(LockType& lock, uint32 millis);
void NotifySingle();
void Notify();
private:
CryConditionVariable(const CryConditionVariable&);
CryConditionVariable& operator = (const CryConditionVariable&);
private:
int m_waitersCount;
CRY_CRITICAL_SECTION m_waitersCountLock;
void* m_sema;
void* m_waitersDone;
size_t m_wasBroadcast;
};
//////////////////////////////////////////////////////////////////////////
// Platform independet wrapper for a counting semaphore
class CrySemaphore
{
public:
CrySemaphore(int nMaximumCount, int nInitialCount = 0);
~CrySemaphore();
void Acquire();
void Release();
private:
void* m_Semaphore;
};
//////////////////////////////////////////////////////////////////////////
// Platform independet wrapper for a counting semaphore
// except that this version uses C-A-S only until a blocking call is needed
// -> No kernel call if there are object in the semaphore
class CryFastSemaphore
{
public:
CryFastSemaphore(int nMaximumCount, int nInitialCount = 0);
~CryFastSemaphore();
void Acquire();
void Release();
private:
CrySemaphore m_Semaphore;
volatile int32 m_nCounter;
};
//////////////////////////////////////////////////////////////////////////
class CrySimpleThreadSelf
{
public:
CrySimpleThreadSelf();
void WaitForThread();
virtual ~CrySimpleThreadSelf();
protected:
void StartThread(unsigned (__stdcall * func)(void*), void* argList);
static AZ_THREAD_LOCAL CrySimpleThreadSelf* m_Self;
private:
CrySimpleThreadSelf(const CrySimpleThreadSelf&);
CrySimpleThreadSelf& operator = (const CrySimpleThreadSelf&);
protected:
void* m_thread;
uint32 m_threadId;
};
template<class Runnable>
class CrySimpleThread
: public CryRunnable
, public CrySimpleThreadSelf
{
public:
typedef void (* ThreadFunction)(void*);
typedef CryRunnable RunnableT;
void SetName(const char* Name)
{
m_name = Name;
}
const char* GetName() { return m_name; }
const volatile bool& GetStartedState() const { return m_bIsStarted; }
private:
Runnable* m_Runnable;
struct
{
ThreadFunction m_ThreadFunction;
void* m_ThreadParameter;
} m_ThreadFunction;
volatile bool m_bIsStarted;
volatile bool m_bIsRunning;
volatile bool m_bCreatedThread;
AZStd::string m_name;
protected:
virtual void Terminate()
{
// This method must be empty.
// Derived classes overriding Terminate() are not required to call this
// method.
}
private:
static unsigned __stdcall RunRunnable(void* thisPtr)
{
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION CRYTHREAD_WINDOWS_H_SECTION_1
#include AZ_RESTRICTED_FILE(CryThread_windows_h)
#endif
CrySimpleThread<Runnable>* const self = (CrySimpleThread<Runnable>*)thisPtr;
self->m_bIsStarted = true;
self->m_bIsRunning = true;
self->m_Runnable->Run();
self->m_bIsRunning = false;
self->m_bCreatedThread = false;
self->Terminate();
return 0;
}
static unsigned __stdcall RunThis(void* thisPtr)
{
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION CRYTHREAD_WINDOWS_H_SECTION_2
#include AZ_RESTRICTED_FILE(CryThread_windows_h)
#endif
CrySimpleThread<Runnable>* const self = (CrySimpleThread<Runnable>*)thisPtr;
self->m_bIsStarted = true;
self->m_bIsRunning = true;
self->Run();
self->m_bIsRunning = false;
self->m_bCreatedThread = false;
self->Terminate();
return 0;
}
CrySimpleThread(const CrySimpleThread<Runnable>&);
void operator = (const CrySimpleThread<Runnable>&);
public:
CrySimpleThread()
: m_bIsStarted(false)
, m_bIsRunning(false)
, m_bCreatedThread(false)
{
m_thread = NULL;
m_Runnable = NULL;
}
void* GetHandle() { return m_thread; }
virtual ~CrySimpleThread()
{
if (IsStarted())
{
if (gEnv && gEnv->pLog)
{
gEnv->pLog->LogError("Runaway thread %p '%s'", m_thread, m_name.c_str());
}
}
if (m_bCreatedThread)
{
Cancel();
WaitForThread();
}
}
virtual void Run()
{
// This Run() implementation supports the void StartFunction() method.
// However, code using this class (or derived classes) should eventually
// be refactored to use one of the other Start() methods. This code will
// be removed some day and the default implementation of Run() will be
// empty.
if (m_ThreadFunction.m_ThreadFunction != NULL)
{
m_ThreadFunction.m_ThreadFunction(m_ThreadFunction.m_ThreadParameter);
}
}
// Cancel the running thread.
//
// If the thread class is implemented as a derived class of CrySimpleThread,
// then the derived class should provide an appropriate implementation for
// this method. Calling the base class implementation is _not_ required.
//
// If the thread was started by specifying a Runnable (template argument),
// then the Cancel() call is passed on to the specified runnable.
//
// If the thread was started using the StartFunction() method, then the
// caller must find other means to inform the thread about the cancellation
// request.
virtual void Cancel()
{
if (IsStarted() && m_Runnable != NULL)
{
m_Runnable->Cancel();
}
}
virtual void Start(Runnable& runnable, [[maybe_unused]] unsigned cpuMask = 0, const char* = NULL, int32 = 0)
{
if (m_bCreatedThread)
{
// Don't start thread more than once!
return;
}
m_Runnable = &runnable;
m_bCreatedThread = true;
StartThread(RunRunnable, this);
}
virtual void Start([[maybe_unused]] unsigned cpuMask = 0, const char* = NULL, int32 = 0, int32 = 0)
{
if (m_bCreatedThread)
{
// Don't start thread more than once!
return;
}
m_bCreatedThread = true;
StartThread(RunThis, this);
}
void StartFunction(
ThreadFunction threadFunction,
void* threadParameter = NULL
)
{
m_ThreadFunction.m_ThreadFunction = threadFunction;
m_ThreadFunction.m_ThreadParameter = threadParameter;
Start();
}
static CrySimpleThread<Runnable>* Self()
{
return reinterpret_cast<CrySimpleThread<Runnable>*>(m_Self);
}
void Exit()
{
assert(!"implemented");
}
void Stop()
{
m_bIsStarted = false;
}
bool IsStarted() const { return m_bIsStarted; }
bool IsRunning() const { return m_bIsRunning; }
};
+4 -4
View File
@@ -14,7 +14,7 @@
#define CRYINCLUDE_CRYCOMMON_IFUNCTORBASE_H
#pragma once
#include <CryCommon/CryThread.h>
#include <AzCore/std/parallel/atomic.h>
// Base class for functor storage.
// Not intended for direct usage.
@@ -28,19 +28,19 @@ public:
void AddRef()
{
CryInterlockedIncrement(&m_nReferences);
m_nReferences.fetch_add(1, AZStd::memory_order_acq_rel);
}
void Release()
{
if (CryInterlockedDecrement(&m_nReferences) <= 0)
if (m_nReferences.fetch_sub(1, AZStd::memory_order_acq_rel) == 1)
{
delete this;
}
}
protected:
volatile int m_nReferences;
AZStd::atomic_int m_nReferences;
};
// Base Template for specialization.

Some files were not shown because too many files have changed in this diff Show More