git mv Code\Sandbox\Plugins Code/Editor/Plugins
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "EditorCommon_precompiled.h"
|
||||
#include <ActionOutput.h>
|
||||
#include <QWidget>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
ActionOutput::ActionOutput()
|
||||
: m_errorCount(0)
|
||||
, m_warningCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
void ActionOutput::AddError(const AZStd::string& error)
|
||||
{
|
||||
AddError(error, "");
|
||||
}
|
||||
|
||||
void ActionOutput::AddError(const AZStd::string& error, const AZStd::string& details)
|
||||
{
|
||||
m_errorToDetails[error].push_back(details);
|
||||
++m_errorCount;
|
||||
}
|
||||
|
||||
bool ActionOutput::HasAnyErrors() const
|
||||
{
|
||||
return m_errorCount > 0;
|
||||
}
|
||||
|
||||
AZStd::string ActionOutput::BuildErrorMessage() const
|
||||
{
|
||||
return BuildMessage(m_errorToDetails);
|
||||
}
|
||||
|
||||
void ActionOutput::AddWarning(const AZStd::string& warning)
|
||||
{
|
||||
AddWarning(warning, "");
|
||||
}
|
||||
|
||||
void ActionOutput::AddWarning(const AZStd::string& warning, const AZStd::string& details)
|
||||
{
|
||||
m_warningToDetails[warning].push_back(details);
|
||||
++m_warningCount;
|
||||
}
|
||||
|
||||
bool ActionOutput::HasAnyWarnings() const
|
||||
{
|
||||
return m_warningCount > 0;
|
||||
}
|
||||
|
||||
AZStd::string ActionOutput::BuildWarningMessage() const
|
||||
{
|
||||
return BuildMessage(m_warningToDetails);
|
||||
}
|
||||
|
||||
AZStd::string ActionOutput::BuildMessage(const IssueToDetails& issues) const
|
||||
{
|
||||
AZStd::string message;
|
||||
for (const auto& it : issues)
|
||||
{
|
||||
message += it.first;
|
||||
message += ":\n";
|
||||
const DetailList& details = it.second;
|
||||
for (size_t i = 0; i < details.size(); ++i)
|
||||
{
|
||||
message += " ";
|
||||
message += details[i];
|
||||
message += "\n";
|
||||
}
|
||||
|
||||
message += "\n";
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/containers/map.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
#include <EditorCommonAPI.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
// Stores the error output from save actions. Pairs error messages with a "details" context. That way if you could
|
||||
// do something like:
|
||||
// output->AddError("Failed to save file", fileName);
|
||||
//
|
||||
// Then if that error gets added a few times with different files, the final error message will be aggregated as
|
||||
// follows:
|
||||
// Failed to save file:
|
||||
// thing1.cdf
|
||||
// thing2.chr
|
||||
class EDITOR_COMMON_API ActionOutput
|
||||
{
|
||||
public:
|
||||
using DetailList = AZStd::vector<AZStd::string>;
|
||||
using IssueToDetails = AZStd::map<AZStd::string, DetailList>;
|
||||
|
||||
ActionOutput();
|
||||
|
||||
void AddError(const AZStd::string& error);
|
||||
void AddError(const AZStd::string& error, const AZStd::string& details);
|
||||
bool HasAnyErrors() const;
|
||||
AZStd::string BuildErrorMessage() const;
|
||||
|
||||
void AddWarning(const AZStd::string& error);
|
||||
void AddWarning(const AZStd::string& error, const AZStd::string& details);
|
||||
bool HasAnyWarnings() const;
|
||||
AZStd::string BuildWarningMessage() const;
|
||||
|
||||
private:
|
||||
AZStd::string BuildMessage(const IssueToDetails& issues) const;
|
||||
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
IssueToDetails m_errorToDetails;
|
||||
IssueToDetails m_warningToDetails;
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
int m_errorCount;
|
||||
int m_warningCount;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorCommon_precompiled.h"
|
||||
#include "../../Editor/RenderHelpers/AxisHelperShared.inl"
|
||||
@@ -0,0 +1,49 @@
|
||||
#
|
||||
# Copyright (c) Contributors to the Open 3D Engine Project
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
#
|
||||
#
|
||||
|
||||
if(NOT PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Header only target to prevent linkage against editor libraries when it is not needed. Eventually the targets that depend
|
||||
# on editor headers should cleanup dependencies and interact with the editor through buses or other mechanisms
|
||||
ly_add_target(
|
||||
NAME EditorCommon.Headers HEADERONLY
|
||||
NAMESPACE Legacy
|
||||
FILES_CMAKE
|
||||
editorcommon_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
INTERFACE
|
||||
.
|
||||
)
|
||||
|
||||
ly_add_target(
|
||||
NAME EditorCommon SHARED
|
||||
NAMESPACE Legacy
|
||||
AUTOMOC
|
||||
AUTORCC
|
||||
FILES_CMAKE
|
||||
editorcommon_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PUBLIC
|
||||
.
|
||||
COMPILE_DEFINITIONS
|
||||
PRIVATE
|
||||
EDITOR_COMMON_EXPORTS
|
||||
INTERFACE
|
||||
EDITOR_COMMON_IMPORTS
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
3rdParty::zlib
|
||||
3rdParty::Qt::Core
|
||||
3rdParty::Qt::Widgets
|
||||
Legacy::CryCommon
|
||||
Legacy::EditorCore
|
||||
AZ::AzCore
|
||||
AZ::AzToolsFramework
|
||||
AZ::AzQtComponents
|
||||
)
|
||||
@@ -0,0 +1,699 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
// Copied utils functions from CryPhysics that are used by non-physics systems
|
||||
// This functions will be eventually removed, DO *NOT* use these functions
|
||||
// TO-DO: Re-implement users using new code
|
||||
// LY-109806
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Cry_Math.h"
|
||||
|
||||
namespace LegacyCryPhysicsUtils
|
||||
{
|
||||
namespace polynomial_tpl_IMPL
|
||||
{
|
||||
template<class ftype, int degree>
|
||||
class polynomial_tpl
|
||||
{
|
||||
public:
|
||||
explicit polynomial_tpl() { denom = (ftype)1; };
|
||||
explicit polynomial_tpl(ftype op) { zero(); data[degree] = op; }
|
||||
AZ_FORCE_INLINE polynomial_tpl& zero()
|
||||
{
|
||||
for (int i = 0; i <= degree; i++)
|
||||
{
|
||||
data[i] = 0;
|
||||
}
|
||||
denom = (ftype)1;
|
||||
return *this;
|
||||
}
|
||||
polynomial_tpl(const polynomial_tpl<ftype, degree>& src) { *this = src; }
|
||||
polynomial_tpl& operator=(const polynomial_tpl<ftype, degree>& src)
|
||||
{
|
||||
denom = src.denom;
|
||||
for (int i = 0; i <= degree; i++)
|
||||
{
|
||||
data[i] = src.data[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
template<int degree1>
|
||||
AZ_FORCE_INLINE polynomial_tpl& operator=(const polynomial_tpl<ftype, degree1>& src)
|
||||
{
|
||||
int i;
|
||||
denom = src.denom;
|
||||
for (i = 0; i <= min(degree, degree1); i++)
|
||||
{
|
||||
data[i] = src.data[i];
|
||||
}
|
||||
for (; i < degree; i++)
|
||||
{
|
||||
data[i] = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
AZ_FORCE_INLINE polynomial_tpl& set(ftype* pdata)
|
||||
{
|
||||
for (int i = 0; i <= degree; i++)
|
||||
{
|
||||
data[degree - i] = pdata[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
AZ_FORCE_INLINE ftype& operator[](int idx) { return data[idx]; }
|
||||
|
||||
void calc_deriviative(polynomial_tpl<ftype, degree>& deriv, int curdegree = degree) const;
|
||||
|
||||
AZ_FORCE_INLINE polynomial_tpl& fixsign()
|
||||
{
|
||||
ftype sg = sgnnz(denom);
|
||||
denom *= sg;
|
||||
for (int i = 0; i <= degree; i++)
|
||||
{
|
||||
data[i] *= sg;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
int findroots(ftype start, ftype end, ftype* proots, int nIters = 20, int curdegree = degree, bool noDegreeCheck = false) const;
|
||||
int nroots(ftype start, ftype end) const;
|
||||
|
||||
AZ_FORCE_INLINE ftype eval(ftype x) const
|
||||
{
|
||||
ftype res = 0;
|
||||
for (int i = degree; i >= 0; i--)
|
||||
{
|
||||
res = res * x + data[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
AZ_FORCE_INLINE ftype eval(ftype x, int subdegree) const
|
||||
{
|
||||
ftype res = data[subdegree];
|
||||
for (int i = subdegree - 1; i >= 0; i--)
|
||||
{
|
||||
res = res * x + data[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
AZ_FORCE_INLINE polynomial_tpl& operator+=(ftype op) { data[0] += op * denom; return *this; }
|
||||
AZ_FORCE_INLINE polynomial_tpl& operator-=(ftype op) { data[0] -= op * denom; return *this; }
|
||||
AZ_FORCE_INLINE polynomial_tpl operator*(ftype op) const
|
||||
{
|
||||
polynomial_tpl<ftype, degree> res;
|
||||
res.denom = denom;
|
||||
for (int i = 0; i <= degree; i++)
|
||||
{
|
||||
res.data[i] = data[i] * op;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
AZ_FORCE_INLINE polynomial_tpl& operator*=(ftype op)
|
||||
{
|
||||
for (int i = 0; i <= degree; i++)
|
||||
{
|
||||
data[i] *= op;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
AZ_FORCE_INLINE polynomial_tpl operator/(ftype op) const
|
||||
{
|
||||
polynomial_tpl<ftype, degree> res = *this;
|
||||
res.denom = denom * op;
|
||||
return res;
|
||||
}
|
||||
AZ_FORCE_INLINE polynomial_tpl& operator/=(ftype op) { denom *= op; return *this; }
|
||||
|
||||
AZ_FORCE_INLINE polynomial_tpl<ftype, degree * 2> sqr() const { return *this * *this; }
|
||||
|
||||
ftype denom;
|
||||
ftype data[degree + 1];
|
||||
};
|
||||
|
||||
template <class ftype>
|
||||
struct tagPolyE
|
||||
{
|
||||
inline static ftype polye() { return (ftype)1E-10; }
|
||||
};
|
||||
|
||||
template<>
|
||||
inline float tagPolyE<float>::polye() { return 1e-6f; }
|
||||
|
||||
template <class ftype>
|
||||
inline ftype polye() { return tagPolyE<ftype>::polye(); }
|
||||
|
||||
// Don't use this macro; use AZStd::max instead. This is only here to make the template const arguments below readable
|
||||
// and because Visual Studio 2013 doesn't have a const_expr version of std::max
|
||||
#define deprecated_degmax(degree1, degree2) (((degree1) > (degree2)) ? (degree1) : (degree2))
|
||||
|
||||
template<class ftype, int degree>
|
||||
AZ_FORCE_INLINE polynomial_tpl<ftype, degree> operator+(const polynomial_tpl<ftype, degree>& pn, ftype op)
|
||||
{
|
||||
polynomial_tpl<ftype, degree> res = pn;
|
||||
res.data[0] += op * res.denom;
|
||||
return res;
|
||||
}
|
||||
template<class ftype, int degree>
|
||||
AZ_FORCE_INLINE polynomial_tpl<ftype, degree> operator-(const polynomial_tpl<ftype, degree>& pn, ftype op)
|
||||
{
|
||||
polynomial_tpl<ftype, degree> res = pn;
|
||||
res.data[0] -= op * res.denom;
|
||||
return res;
|
||||
}
|
||||
|
||||
template<class ftype, int degree>
|
||||
AZ_FORCE_INLINE polynomial_tpl<ftype, degree> operator+(ftype op, const polynomial_tpl<ftype, degree>& pn)
|
||||
{
|
||||
polynomial_tpl<ftype, degree> res = pn;
|
||||
res.data[0] += op * res.denom;
|
||||
return res;
|
||||
}
|
||||
template<class ftype, int degree>
|
||||
AZ_FORCE_INLINE polynomial_tpl<ftype, degree> operator-(ftype op, const polynomial_tpl<ftype, degree>& pn)
|
||||
{
|
||||
polynomial_tpl<ftype, degree> res = pn;
|
||||
res.data[0] -= op * res.denom;
|
||||
for (int i = 0; i <= degree; i++)
|
||||
{
|
||||
res.data[i] = -res.data[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
template<class ftype, int degree>
|
||||
polynomial_tpl<ftype, degree * 2> AZ_FORCE_INLINE psqr(const polynomial_tpl<ftype, degree>& op) { return op * op; }
|
||||
|
||||
template <class ftype, int degree1, int degree2>
|
||||
AZ_FORCE_INLINE polynomial_tpl<ftype, deprecated_degmax(degree1, degree2)> operator+(const polynomial_tpl<ftype, degree1>& op1, const polynomial_tpl<ftype, degree2>& op2)
|
||||
{
|
||||
polynomial_tpl<ftype, deprecated_degmax(degree1, degree2)> res;
|
||||
int i;
|
||||
for (i = 0; i <= min(degree1, degree2); i++)
|
||||
{
|
||||
res.data[i] = op1.data[i] * op2.denom + op2.data[i] * op1.denom;
|
||||
}
|
||||
for (; i <= degree1; i++)
|
||||
{
|
||||
res.data[i] = op1.data[i] * op2.denom;
|
||||
}
|
||||
for (; i <= degree2; i++)
|
||||
{
|
||||
res.data[i] = op2.data[i] * op1.denom;
|
||||
}
|
||||
res.denom = op1.denom * op2.denom;
|
||||
return res;
|
||||
}
|
||||
template <class ftype, int degree1, int degree2>
|
||||
AZ_FORCE_INLINE polynomial_tpl<ftype, deprecated_degmax(degree1, degree2)> operator-(const polynomial_tpl<ftype, degree1>& op1, const polynomial_tpl<ftype, degree2>& op2)
|
||||
{
|
||||
polynomial_tpl<ftype, deprecated_degmax(degree1, degree2)> res;
|
||||
int i;
|
||||
for (i = 0; i <= min(degree1, degree2); i++)
|
||||
{
|
||||
res.data[i] = op1.data[i] * op2.denom - op2.data[i] * op1.denom;
|
||||
}
|
||||
for (; i <= degree1; i++)
|
||||
{
|
||||
res.data[i] = op1.data[i] * op2.denom;
|
||||
}
|
||||
for (; i <= degree2; i++)
|
||||
{
|
||||
res.data[i] = op2.data[i] * op1.denom;
|
||||
}
|
||||
res.denom = op1.denom * op2.denom;
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class ftype, int degree1, int degree2>
|
||||
AZ_FORCE_INLINE polynomial_tpl<ftype, degree1>& operator+=(polynomial_tpl<ftype, degree1>& op1, const polynomial_tpl<ftype, degree2>& op2)
|
||||
{
|
||||
for (int i = 0; i < min(degree1, degree2); i++)
|
||||
{
|
||||
op1.data[i] = op1.data[i] * op2.denom + op2.data[i] * op1.denom;
|
||||
}
|
||||
op1.denom *= op2.denom;
|
||||
return op1;
|
||||
}
|
||||
template <class ftype, int degree1, int degree2>
|
||||
AZ_FORCE_INLINE polynomial_tpl<ftype, degree1>& operator-=(polynomial_tpl<ftype, degree1>& op1, const polynomial_tpl<ftype, degree2>& op2)
|
||||
{
|
||||
for (int i = 0; i < min(degree1, degree2); i++)
|
||||
{
|
||||
op1.data[i] = op1.data[i] * op2.denom - op2.data[i] * op1.denom;
|
||||
}
|
||||
op1.denom *= op2.denom;
|
||||
return op1;
|
||||
}
|
||||
|
||||
template <class ftype, int degree1, int degree2>
|
||||
AZ_FORCE_INLINE polynomial_tpl<ftype, degree1 + degree2> operator*(const polynomial_tpl<ftype, degree1>& op1, const polynomial_tpl<ftype, degree2>& op2)
|
||||
{
|
||||
polynomial_tpl<ftype, degree1 + degree2> res;
|
||||
res.zero();
|
||||
int j;
|
||||
switch (degree1)
|
||||
{
|
||||
case 8:
|
||||
for (j = 0; j <= degree2; j++)
|
||||
{
|
||||
res.data[8 + j] += op1.data[8] * op2.data[j];
|
||||
}
|
||||
case 7:
|
||||
for (j = 0; j <= degree2; j++)
|
||||
{
|
||||
res.data[7 + j] += op1.data[7] * op2.data[j];
|
||||
}
|
||||
case 6:
|
||||
for (j = 0; j <= degree2; j++)
|
||||
{
|
||||
res.data[6 + j] += op1.data[6] * op2.data[j];
|
||||
}
|
||||
case 5:
|
||||
for (j = 0; j <= degree2; j++)
|
||||
{
|
||||
res.data[5 + j] += op1.data[5] * op2.data[j];
|
||||
}
|
||||
case 4:
|
||||
for (j = 0; j <= degree2; j++)
|
||||
{
|
||||
res.data[4 + j] += op1.data[4] * op2.data[j];
|
||||
}
|
||||
case 3:
|
||||
for (j = 0; j <= degree2; j++)
|
||||
{
|
||||
res.data[3 + j] += op1.data[3] * op2.data[j];
|
||||
}
|
||||
case 2:
|
||||
for (j = 0; j <= degree2; j++)
|
||||
{
|
||||
res.data[2 + j] += op1.data[2] * op2.data[j];
|
||||
}
|
||||
case 1:
|
||||
for (j = 0; j <= degree2; j++)
|
||||
{
|
||||
res.data[1 + j] += op1.data[1] * op2.data[j];
|
||||
}
|
||||
case 0:
|
||||
for (j = 0; j <= degree2; j++)
|
||||
{
|
||||
res.data[0 + j] += op1.data[0] * op2.data[j];
|
||||
}
|
||||
}
|
||||
res.denom = op1.denom * op2.denom;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
template <class ftype>
|
||||
AZ_FORCE_INLINE void polynomial_divide(const polynomial_tpl<ftype, 8>& num, const polynomial_tpl<ftype, 8>& den, polynomial_tpl<ftype, 8>& quot,
|
||||
polynomial_tpl<ftype, 8>& rem, int degree1, int degree2)
|
||||
{
|
||||
int i, j, k, l;
|
||||
ftype maxel;
|
||||
for (i = 0; i <= degree1; i++)
|
||||
{
|
||||
rem.data[i] = num.data[i];
|
||||
}
|
||||
for (i = 0; i <= degree1 - degree2; i++)
|
||||
{
|
||||
quot.data[i] = 0;
|
||||
}
|
||||
for (i = 1, maxel = fabs_tpl(num.data[0]); i <= degree1; i++)
|
||||
{
|
||||
maxel = max(maxel, num.data[i]);
|
||||
}
|
||||
for (maxel *= polye<ftype>(); degree1 >= 0 && fabs_tpl(num.data[degree1]) < maxel; degree1--)
|
||||
{
|
||||
;
|
||||
}
|
||||
for (i = 1, maxel = fabs_tpl(den.data[0]); i <= degree2; i++)
|
||||
{
|
||||
maxel = max(maxel, den.data[i]);
|
||||
}
|
||||
for (maxel *= polye<ftype>(); degree2 >= 0 && fabs_tpl(den.data[degree2]) < maxel; degree2--)
|
||||
{
|
||||
;
|
||||
}
|
||||
rem.denom = num.denom;
|
||||
quot.denom = (ftype)1;
|
||||
if (degree1 < 0 || degree2 < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (k = degree1 - degree2, l = degree1; l >= degree2; l--, k--)
|
||||
{
|
||||
quot.data[k] = rem.data[l] * den.denom;
|
||||
quot.denom *= den.data[degree2];
|
||||
for (i = degree1 - degree2; i > k; i--)
|
||||
{
|
||||
quot.data[i] *= den.data[degree2];
|
||||
}
|
||||
for (i = degree2 - 1, j = l - 1; i >= 0; i--, j--)
|
||||
{
|
||||
rem.data[j] = rem.data[j] * den.data[degree2] - den.data[i] * rem.data[l];
|
||||
}
|
||||
for (; j >= 0; j--)
|
||||
{
|
||||
rem.data[j] *= den.data[degree2];
|
||||
}
|
||||
rem.denom *= den.data[degree2];
|
||||
}
|
||||
}
|
||||
|
||||
template <class ftype, int degree1, int degree2>
|
||||
AZ_FORCE_INLINE polynomial_tpl<ftype, degree1 - degree2> operator/(const polynomial_tpl<ftype, degree1>& num, const polynomial_tpl<ftype, degree2>& den)
|
||||
{
|
||||
polynomial_tpl<ftype, degree1 - degree2> quot;
|
||||
polynomial_tpl<ftype, degree1> rem;
|
||||
polynomial_divide((polynomial_tpl<ftype, 8>&)num, (polynomial_tpl<ftype, 8>&)den, (polynomial_tpl<ftype, 8>&)quot,
|
||||
(polynomial_tpl<ftype, 8>&)rem, degree1, degree2);
|
||||
return quot;
|
||||
}
|
||||
template <class ftype, int degree1, int degree2>
|
||||
AZ_FORCE_INLINE polynomial_tpl<ftype, degree2 - 1> operator%(const polynomial_tpl<ftype, degree1>& num, const polynomial_tpl<ftype, degree2>& den)
|
||||
{
|
||||
polynomial_tpl<ftype, degree1 - degree2> quot;
|
||||
polynomial_tpl<ftype, degree1> rem;
|
||||
polynomial_divide((polynomial_tpl<ftype, 8>&)num, (polynomial_tpl<ftype, 8>&)den, (polynomial_tpl<ftype, 8>&)quot,
|
||||
(polynomial_tpl<ftype, 8>&)rem, degree1, degree2);
|
||||
return (polynomial_tpl<ftype, degree2 - 1>&)rem;
|
||||
}
|
||||
|
||||
template <class ftype, int degree>
|
||||
AZ_FORCE_INLINE void polynomial_tpl<ftype, degree>::calc_deriviative(polynomial_tpl<ftype, degree>& deriv, int curdegree) const
|
||||
{
|
||||
for (int i = 0; i < curdegree; i++)
|
||||
{
|
||||
deriv.data[i] = data[i + 1] * (i + 1);
|
||||
}
|
||||
deriv.denom = denom;
|
||||
}
|
||||
|
||||
template<typename to_t, typename from_t>
|
||||
to_t* convert_type(from_t* input)
|
||||
{
|
||||
typedef union
|
||||
{
|
||||
to_t* to;
|
||||
from_t* from;
|
||||
} convert_union;
|
||||
convert_union u;
|
||||
u.from = input;
|
||||
return u.to;
|
||||
}
|
||||
|
||||
template <class ftype, int degree>
|
||||
AZ_FORCE_INLINE int polynomial_tpl<ftype, degree>::nroots(ftype start, ftype end) const
|
||||
{
|
||||
polynomial_tpl<ftype, degree> f[degree + 1];
|
||||
int i, j, sg_a, sg_b;
|
||||
ftype val, prevval;
|
||||
|
||||
calc_deriviative(f[0]);
|
||||
polynomial_divide(*convert_type<polynomial_tpl<ftype, 8> >(this), *convert_type< polynomial_tpl<ftype, 8> >(&f[0]), *convert_type<polynomial_tpl<ftype, 8> >(&f[degree]),
|
||||
*convert_type<polynomial_tpl<ftype, 8> >(&f[1]), degree, degree - 1);
|
||||
f[1].denom = -f[1].denom;
|
||||
for (i = 2; i < degree; i++)
|
||||
{
|
||||
polynomial_divide(*convert_type<polynomial_tpl<ftype, 8> >(&f[i - 2]), *convert_type<polynomial_tpl<ftype, 8> >(&f[i - 1]), *convert_type<polynomial_tpl<ftype, 8> >(&f[degree]),
|
||||
*convert_type<polynomial_tpl<ftype, 8> >(&f[i]), degree + 1 - i, degree - i);
|
||||
f[i].denom = -f[i].denom;
|
||||
if (fabs_tpl(f[i].denom) > (ftype)1E10)
|
||||
{
|
||||
for (j = 0; j <= degree - 1 - i; j++)
|
||||
{
|
||||
f[i].data[j] *= (ftype)1E-10;
|
||||
}
|
||||
f[i].denom *= (ftype)1E-10;
|
||||
}
|
||||
}
|
||||
|
||||
prevval = eval(start) * denom;
|
||||
for (i = sg_a = 0; i < degree; i++, prevval = val)
|
||||
{
|
||||
val = f[i].eval(start, degree - 1 - i) * f[i].denom;
|
||||
sg_a += isneg(val * prevval);
|
||||
}
|
||||
|
||||
prevval = eval(end) * denom;
|
||||
for (i = sg_b = 0; i < degree; i++, prevval = val)
|
||||
{
|
||||
val = f[i].eval(end, degree - 1 - i) * f[i].denom;
|
||||
sg_b += isneg(val * prevval);
|
||||
}
|
||||
|
||||
return fabs_tpl(sg_a - sg_b);
|
||||
}
|
||||
|
||||
template<class ftype>
|
||||
AZ_FORCE_INLINE ftype cubert_tpl(ftype x) { return fabs_tpl(x) > (ftype)1E-20 ? exp_tpl(log_tpl(fabs_tpl(x)) * (ftype)(1.0 / 3)) * sgnnz(x) : x; }
|
||||
template<class ftype>
|
||||
AZ_FORCE_INLINE ftype pow_tpl(ftype x, ftype pow) { return fabs_tpl(x) > (ftype)1E-20 ? exp_tpl(log_tpl(fabs_tpl(x)) * pow) * sgnnz(x) : x; }
|
||||
template<class ftype>
|
||||
AZ_FORCE_INLINE void swap(ftype* ptr, int i, int j) { ftype t = ptr[i]; ptr[i] = ptr[j]; ptr[j] = t; }
|
||||
|
||||
template <class ftype, int maxdegree>
|
||||
int polynomial_tpl<ftype, maxdegree>::findroots(ftype start, ftype end, ftype* proots, [[maybe_unused]] int nIters, int degree, bool noDegreeCheck) const
|
||||
{
|
||||
AZ_UNUSED(nIters);
|
||||
int i, j, nRoots = 0;
|
||||
ftype maxel;
|
||||
if (!noDegreeCheck)
|
||||
{
|
||||
for (i = 1, maxel = fabs_tpl(data[0]); i <= degree; i++)
|
||||
{
|
||||
maxel = max(maxel, data[i]);
|
||||
}
|
||||
for (maxel *= polye<ftype>(); degree > 0 && fabs_tpl(data[degree]) <= maxel; degree--)
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (maxdegree >= 1)
|
||||
{
|
||||
if (degree == 1)
|
||||
{
|
||||
proots[0] = data[0] / data[1];
|
||||
nRoots = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (maxdegree >= 2)
|
||||
{
|
||||
if (degree == 2)
|
||||
{
|
||||
ftype a, b, c, d, bound[2], sg;
|
||||
|
||||
a = data[2];
|
||||
b = data[1];
|
||||
c = data[0];
|
||||
d = aznumeric_cast<ftype>(sgnnz(a));
|
||||
a *= d;
|
||||
b *= d;
|
||||
c *= d;
|
||||
d = b * b - a * c * 4;
|
||||
bound[0] = start * a * 2 + b;
|
||||
bound[1] = end * a * 2 + b;
|
||||
sg = aznumeric_cast<ftype>((sgnnz(bound[0] * bound[1]) + 1) >> 1);
|
||||
bound[0] *= bound[0];
|
||||
bound[1] *= bound[1];
|
||||
bound[isneg(fabs_tpl(bound[1]) - fabs_tpl(bound[0]))] *= sg;
|
||||
|
||||
if (isnonneg(d) & inrange(d, bound[0], bound[1]))
|
||||
{
|
||||
d = sqrt_tpl(d);
|
||||
a = (ftype)0.5 / a;
|
||||
proots[nRoots] = (-b - d) * a;
|
||||
nRoots += inrange(proots[nRoots], start, end);
|
||||
proots[nRoots] = (-b + d) * a;
|
||||
nRoots += inrange(proots[nRoots], start, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (maxdegree >= 3)
|
||||
{
|
||||
if (degree == 3)
|
||||
{
|
||||
ftype t, a, b, c, a3, p, q, Q, Qr, Ar, Ai, phi;
|
||||
|
||||
t = (ftype)1.0 / data[3];
|
||||
a = data[2] * t;
|
||||
b = data[1] * t;
|
||||
c = data[0] * t;
|
||||
a3 = a * (ftype)(1.0 / 3);
|
||||
p = b - a * a3;
|
||||
q = (a3 * b - c) * (ftype)0.5 - cube(a3);
|
||||
Q = cube(p * (ftype)(1.0 / 3)) + q * q;
|
||||
Qr = sqrt_tpl(fabs_tpl(Q));
|
||||
|
||||
if (Q > 0)
|
||||
{
|
||||
proots[0] = cubert_tpl(q + Qr) + cubert_tpl(q - Qr) - a3;
|
||||
nRoots = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
phi = atan2_tpl(Qr, q) * (ftype)(1.0 / 3);
|
||||
t = pow_tpl(Qr * Qr + q * q, (ftype)(1.0 / 6));
|
||||
Ar = t * cos_tpl(phi);
|
||||
Ai = t * sin_tpl(phi);
|
||||
proots[0] = 2 * Ar - a3;
|
||||
proots[1] = aznumeric_cast<ftype>(-Ar + Ai * sqrt3 - a3);
|
||||
proots[2] = aznumeric_cast<ftype>(-Ar - Ai * sqrt3 - a3);
|
||||
i = idxmax3(proots);
|
||||
swap(proots, i, 2);
|
||||
i = isneg(proots[0] - proots[1]);
|
||||
swap(proots, i, 1);
|
||||
nRoots = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (maxdegree >= 4)
|
||||
{
|
||||
if (degree == 4)
|
||||
{
|
||||
ftype t, a3, a2, a1, a0, y, R, D, E, subroots[3];
|
||||
const ftype e = (ftype)1E-9;
|
||||
|
||||
t = (ftype)1.0 / data[4];
|
||||
a3 = data[3] * t;
|
||||
a2 = data[2] * t;
|
||||
a1 = data[1] * t;
|
||||
a0 = data[0] * t;
|
||||
polynomial_tpl<ftype, 3> p3aux;
|
||||
ftype kp3aux[] = { 1, -a2, a1 * a3 - 4 * a0, 4 * a2 * a0 - a1 * a1 - a3 * a3 * a0 };
|
||||
p3aux.set(kp3aux);
|
||||
if (!p3aux.findroots((ftype)-1E20, (ftype)1E20, subroots))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
R = a3 * a3 * (ftype)0.25 - a2 + (y = subroots[0]);
|
||||
|
||||
if (R > -e)
|
||||
{
|
||||
if (R < e)
|
||||
{
|
||||
D = E = a3 * a3 * (ftype)(3.0 / 4) - 2 * a2;
|
||||
t = y * y - 4 * a0;
|
||||
if (t < -e)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
t = 2 * sqrt_tpl(max((ftype)0, t));
|
||||
}
|
||||
else
|
||||
{
|
||||
R = sqrt_tpl(max((ftype)0, R));
|
||||
D = E = a3 * a3 * (ftype)(3.0 / 4) - R * R - 2 * a2;
|
||||
t = (4 * a3 * a2 - 8 * a1 - a3 * a3 * a3) / R * (ftype)0.25;
|
||||
}
|
||||
if (D + t > -e)
|
||||
{
|
||||
D = sqrt_tpl(max((ftype)0, D + t));
|
||||
proots[nRoots++] = a3 * (ftype)-0.25 + (R - D) * (ftype)0.5;
|
||||
proots[nRoots++] = a3 * (ftype)-0.25 + (R + D) * (ftype)0.5;
|
||||
}
|
||||
if (E - t > -e)
|
||||
{
|
||||
E = sqrt_tpl(max((ftype)0, E - t));
|
||||
proots[nRoots++] = a3 * (ftype)-0.25 - (R + E) * (ftype)0.5;
|
||||
proots[nRoots++] = a3 * (ftype)-0.25 - (R - E) * (ftype)0.5;
|
||||
}
|
||||
if (nRoots == 4)
|
||||
{
|
||||
i = idxmax3(proots);
|
||||
if (proots[3] < proots[i])
|
||||
{
|
||||
swap(proots, i, 3);
|
||||
}
|
||||
i = idxmax3(proots);
|
||||
swap(proots, i, 2);
|
||||
i = isneg(proots[0] - proots[1]);
|
||||
swap(proots, i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (maxdegree > 4)
|
||||
{
|
||||
if (degree > 4)
|
||||
{
|
||||
ftype roots[maxdegree + 1], prevroot, val, prevval[2], curval, bound[2], middle;
|
||||
polynomial_tpl<ftype, maxdegree> deriv;
|
||||
int nExtremes, iter, iBound;
|
||||
calc_deriviative(deriv);
|
||||
|
||||
// find a subset of deriviative extremes between start and end
|
||||
for (nExtremes = deriv.findroots(start, end, roots + 1, nIters, degree - 1) + 1; nExtremes > 1 && roots[nExtremes - 1] > end; nExtremes--)
|
||||
{
|
||||
;
|
||||
}
|
||||
for (i = 1; i < nExtremes && roots[i] < start; i++)
|
||||
{
|
||||
;
|
||||
}
|
||||
roots[i - 1] = start;
|
||||
PREFAST_ASSUME(nExtremes < maxdegree + 1);
|
||||
roots[nExtremes++] = end;
|
||||
|
||||
for (prevroot = start, prevval[0] = eval(start, degree), nRoots = 0; i < nExtremes; prevval[0] = val, prevroot = roots[i++])
|
||||
{
|
||||
val = eval(roots[i], degree);
|
||||
if (val * prevval[0] < 0)
|
||||
{
|
||||
// we have exactly one root between prevroot and roots[i]
|
||||
bound[0] = prevroot;
|
||||
bound[1] = roots[i];
|
||||
iter = 0;
|
||||
do
|
||||
{
|
||||
middle = (bound[0] + bound[1]) * (ftype)0.5;
|
||||
curval = eval(middle, degree);
|
||||
iBound = isneg(prevval[0] * curval);
|
||||
bound[iBound] = middle;
|
||||
prevval[iBound] = curval;
|
||||
} while (++iter < nIters);
|
||||
proots[nRoots++] = middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < nRoots && proots[i] < start; i++)
|
||||
{
|
||||
;
|
||||
}
|
||||
for (; nRoots > i&& proots[nRoots - 1] > end; nRoots--)
|
||||
{
|
||||
;
|
||||
}
|
||||
for (j = i; j < nRoots; j++)
|
||||
{
|
||||
proots[j - i] = proots[j];
|
||||
}
|
||||
|
||||
return nRoots - i;
|
||||
}
|
||||
} // namespace polynomial_tpl_IMPL
|
||||
template<class ftype, int degree>
|
||||
using polynomial_tpl = polynomial_tpl_IMPL::polynomial_tpl<ftype, degree>;
|
||||
|
||||
typedef polynomial_tpl<real, 3> P3;
|
||||
typedef polynomial_tpl<real, 2> P2;
|
||||
typedef polynomial_tpl<real, 1> P1;
|
||||
typedef polynomial_tpl<float, 3> P3f;
|
||||
typedef polynomial_tpl<float, 2> P2f;
|
||||
typedef polynomial_tpl<float, 1> P1f;
|
||||
} // namespace LegacyCryPhysicsUtils
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "DeepFilterProxyModel.h"
|
||||
#include <QPalette>
|
||||
|
||||
DeepFilterProxyModel::DeepFilterProxyModel(QObject* parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void DeepFilterProxyModel::setFilterString(const QString& filter)
|
||||
{
|
||||
m_filter = filter;
|
||||
m_filterParts = m_filter.split(' ', Qt::SkipEmptyParts);
|
||||
m_acceptCache.clear();
|
||||
}
|
||||
|
||||
void DeepFilterProxyModel::invalidate()
|
||||
{
|
||||
QSortFilterProxyModel::invalidate();
|
||||
m_acceptCache.clear();
|
||||
}
|
||||
|
||||
QVariant DeepFilterProxyModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if (role == Qt::ForegroundRole)
|
||||
{
|
||||
QModelIndex sourceIndex = mapToSource(index);
|
||||
if (matchFilter(sourceIndex.row(), sourceIndex.parent()))
|
||||
{
|
||||
return QSortFilterProxyModel::data(index, role);
|
||||
}
|
||||
else
|
||||
{
|
||||
return QPalette().color(QPalette::Disabled, QPalette::Text);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return QSortFilterProxyModel::data(index, role);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DeepFilterProxyModel::setFilterWildcard(const QString& pattern)
|
||||
{
|
||||
m_acceptCache.clear();
|
||||
QSortFilterProxyModel::setFilterWildcard(pattern);
|
||||
}
|
||||
|
||||
bool DeepFilterProxyModel::matchFilter(int sourceRow, const QModelIndex& sourceParent) const
|
||||
{
|
||||
int columnCount = sourceModel()->columnCount(sourceParent);
|
||||
for (int i = 0; i < m_filterParts.size(); ++i)
|
||||
{
|
||||
bool atLeastOneContains = false;
|
||||
for (int j = 0; j < columnCount; ++j)
|
||||
{
|
||||
QModelIndex index = sourceModel()->index(sourceRow, j, sourceParent);
|
||||
QVariant data = sourceModel()->data(index, Qt::DisplayRole);
|
||||
QString str(data.toString());
|
||||
if (str.isEmpty())
|
||||
{
|
||||
if (m_filterParts.empty())
|
||||
{
|
||||
atLeastOneContains = true;
|
||||
}
|
||||
}
|
||||
else if (str.contains(m_filterParts[i], Qt::CaseInsensitive))
|
||||
{
|
||||
atLeastOneContains = true;
|
||||
}
|
||||
}
|
||||
if (!atLeastOneContains)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeepFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
|
||||
{
|
||||
if (matchFilter(sourceRow, sourceParent))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hasAcceptedChildrenCached(sourceRow, sourceParent))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeepFilterProxyModel::hasAcceptedChildrenCached(int sourceRow, const QModelIndex& sourceParent) const
|
||||
{
|
||||
std::pair<QModelIndex, int> indexId = std::make_pair(sourceParent, sourceRow);
|
||||
TAcceptCache::iterator it = m_acceptCache.find(indexId);
|
||||
if (it == m_acceptCache.end())
|
||||
{
|
||||
bool result = hasAcceptedChildren(sourceRow, sourceParent);
|
||||
m_acceptCache[indexId] = result;
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
bool DeepFilterProxyModel::hasAcceptedChildren(int sourceRow, const QModelIndex& sourceParent) const
|
||||
{
|
||||
QModelIndex item = sourceModel()->index(sourceRow, 0, sourceParent);
|
||||
if (!item.isValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int childCount = item.model()->rowCount(item);
|
||||
if (childCount == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < childCount; ++i)
|
||||
{
|
||||
if (filterAcceptsRow(i, item))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QModelIndex DeepFilterProxyModel::findFirstMatchingIndex(const QModelIndex& root)
|
||||
{
|
||||
int rowCount = this->rowCount(root);
|
||||
for (int i = 0; i < rowCount; ++i)
|
||||
{
|
||||
QModelIndex index = this->index(i, 0, root);
|
||||
if (!index.isValid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
QModelIndex sourceIndex = mapToSource(index);
|
||||
if (!sourceIndex.isValid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (matchFilter(sourceIndex.row(), sourceIndex.parent()))
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
QModelIndex child = findFirstMatchingIndex(index);
|
||||
if (child.isValid())
|
||||
{
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return QModelIndex();
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITORCOMMON_DEEPFILTERPROXYMODEL_H
|
||||
#define CRYINCLUDE_EDITORCOMMON_DEEPFILTERPROXYMODEL_H
|
||||
#pragma once
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QModelIndex>
|
||||
#include <QStringList>
|
||||
#include "EditorCommonAPI.h"
|
||||
|
||||
class EDITOR_COMMON_API DeepFilterProxyModel
|
||||
: public QSortFilterProxyModel
|
||||
{
|
||||
public:
|
||||
DeepFilterProxyModel(QObject* parent);
|
||||
|
||||
void setFilterString(const QString& filter);
|
||||
void invalidate();
|
||||
|
||||
QVariant data(const QModelIndex& index, int role) const override;
|
||||
|
||||
void setFilterWildcard(const QString& pattern);
|
||||
|
||||
bool matchFilter(int source_row, const QModelIndex& source_parent) const;
|
||||
bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override;
|
||||
bool hasAcceptedChildrenCached(int source_row, const QModelIndex& source_parent) const;
|
||||
bool hasAcceptedChildren(int source_row, const QModelIndex& source_parent) const;
|
||||
|
||||
QModelIndex findFirstMatchingIndex(const QModelIndex& root);
|
||||
|
||||
private:
|
||||
QString m_filter;
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
QStringList m_filterParts;
|
||||
typedef std::map<std::pair<QModelIndex, int>, bool> TAcceptCache;
|
||||
mutable TAcceptCache m_acceptCache;
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_EDITORCOMMON_DEEPFILTERPROXYMODEL_H
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorCommon_precompiled.h"
|
||||
#include "../../Editor/Objects/DisplayContextShared.inl"
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "DockTitleBarWidget.h"
|
||||
#include <QStyle>
|
||||
#include <QStyleOptionToolButton>
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
|
||||
namespace DockTitleBarInterpolate
|
||||
{
|
||||
static QColor Interpolate(const QColor& a, const QColor& b, float k)
|
||||
{
|
||||
float mk = 1.0f - k;
|
||||
return QColor(aznumeric_cast<int>(a.red() * mk + b.red() * k),
|
||||
aznumeric_cast<int>(a.green() * mk + b.green() * k),
|
||||
aznumeric_cast<int>(a.blue() * mk + b.blue() * k),
|
||||
aznumeric_cast<int>(a.alpha() * mk + b.alpha() * k));
|
||||
}
|
||||
}
|
||||
|
||||
class CDockWidgetTitleButton
|
||||
: public QAbstractButton
|
||||
{
|
||||
public:
|
||||
CDockWidgetTitleButton(QWidget* parent);
|
||||
|
||||
QSize sizeHint() const;
|
||||
QSize minimumSizeHint() const { return sizeHint(); }
|
||||
|
||||
protected:
|
||||
void enterEvent(QEvent* ev);
|
||||
void leaveEvent(QEvent* ev);
|
||||
void paintEvent(QPaintEvent* ev);
|
||||
};
|
||||
|
||||
class CTitleBarText
|
||||
: public QWidget
|
||||
{
|
||||
public:
|
||||
|
||||
CTitleBarText(QWidget* parent, QDockWidget* dockWidget)
|
||||
: QWidget(parent)
|
||||
, m_dockWidget(dockWidget)
|
||||
{
|
||||
QFont font;
|
||||
font.setBold(true);
|
||||
setFont(font);
|
||||
}
|
||||
|
||||
void paintEvent([[maybe_unused]] QPaintEvent* ev) override
|
||||
{
|
||||
QPainter p(this);
|
||||
p.setRenderHint(QPainter::Antialiasing, true);
|
||||
QRect r = rect().adjusted(2, 2, -3, -3);
|
||||
p.translate(0.5f, 0.5f);
|
||||
QColor color = DockTitleBarInterpolate::Interpolate(palette().color(QPalette::Window), palette().color(QPalette::Shadow), 0.2f);
|
||||
p.setBrush(QBrush(color));
|
||||
p.setPen(Qt::NoPen);
|
||||
p.drawRoundedRect(r, 4, 4, Qt::AbsoluteSize);
|
||||
p.setPen(QPen(palette().color(QPalette::WindowText)));
|
||||
QTextOption textOption(Qt::AlignLeft | Qt::AlignVCenter);
|
||||
textOption.setWrapMode(QTextOption::NoWrap);
|
||||
p.drawText(r.adjusted(4, 0, 0, 0), m_dockWidget->windowTitle(), textOption);
|
||||
}
|
||||
private:
|
||||
QDockWidget* m_dockWidget;
|
||||
};
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
CDockWidgetTitleButton::CDockWidgetTitleButton(QWidget* parent)
|
||||
: QAbstractButton(parent)
|
||||
{
|
||||
setFocusPolicy(Qt::NoFocus);
|
||||
}
|
||||
|
||||
QSize CDockWidgetTitleButton::sizeHint() const
|
||||
{
|
||||
ensurePolished();
|
||||
|
||||
int size = 2 * style()->pixelMetric(QStyle::PM_DockWidgetTitleBarButtonMargin, 0, this);
|
||||
if (!icon().isNull())
|
||||
{
|
||||
int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this);
|
||||
QSize sz = icon().actualSize(QSize(iconSize, iconSize));
|
||||
size += qMax(sz.width(), sz.height());
|
||||
}
|
||||
|
||||
return QSize(size, size);
|
||||
}
|
||||
|
||||
void CDockWidgetTitleButton::enterEvent(QEvent* ev)
|
||||
{
|
||||
if (isEnabled())
|
||||
{
|
||||
update();
|
||||
}
|
||||
QAbstractButton::enterEvent(ev);
|
||||
}
|
||||
|
||||
void CDockWidgetTitleButton::leaveEvent(QEvent* ev)
|
||||
{
|
||||
if (isEnabled())
|
||||
{
|
||||
update();
|
||||
}
|
||||
QAbstractButton::leaveEvent(ev);
|
||||
}
|
||||
|
||||
void CDockWidgetTitleButton::paintEvent([[maybe_unused]] QPaintEvent* ev)
|
||||
{
|
||||
QPainter painter(this);
|
||||
|
||||
QStyleOptionToolButton opt;
|
||||
opt.state = QStyle::State_AutoRaise;
|
||||
opt.init(this);
|
||||
opt.state |= QStyle::State_AutoRaise;
|
||||
|
||||
if (isEnabled() && underMouse() && !isChecked() && !isDown())
|
||||
{
|
||||
opt.state |= QStyle::State_Raised;
|
||||
}
|
||||
if (isChecked())
|
||||
{
|
||||
opt.state |= QStyle::State_On;
|
||||
}
|
||||
if (isDown())
|
||||
{
|
||||
opt.state |= QStyle::State_Sunken;
|
||||
}
|
||||
if (opt.state & (QStyle::State_Raised | QStyle::State_Sunken))
|
||||
{
|
||||
style()->drawPrimitive(QStyle::PE_PanelButtonTool, &opt, &painter, this);
|
||||
}
|
||||
|
||||
opt.icon = icon();
|
||||
opt.subControls = QStyle::SubControls();
|
||||
opt.activeSubControls = QStyle::SubControls();
|
||||
opt.features = QStyleOptionToolButton::None;
|
||||
opt.arrowType = Qt::NoArrow;
|
||||
int size = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this);
|
||||
opt.iconSize = QSize(size, size);
|
||||
style()->drawComplexControl(QStyle::CC_ToolButton, &opt, &painter, this);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
CDockTitleBarWidget::CDockTitleBarWidget(QDockWidget* dockWidget)
|
||||
: m_dockWidget(dockWidget)
|
||||
{
|
||||
CTitleBarText* textWidget = new CTitleBarText(this, dockWidget);
|
||||
|
||||
m_layout = new QBoxLayout(QBoxLayout::LeftToRight);
|
||||
m_layout->setContentsMargins(0, 0, 0, 0);
|
||||
m_layout->setSpacing(0);
|
||||
m_layout->addWidget(textWidget, 1);
|
||||
|
||||
QStyleOptionDockWidget opt;
|
||||
opt.initFrom(dockWidget);
|
||||
opt.closable = dockWidget->features() & QDockWidget::DockWidgetClosable;
|
||||
opt.movable = dockWidget->features() & QDockWidget::DockWidgetMovable;
|
||||
opt.floatable = dockWidget->features() & QDockWidget::DockWidgetFloatable;
|
||||
|
||||
m_buttonLayout = new QBoxLayout(QBoxLayout::LeftToRight);
|
||||
m_buttonLayout->setContentsMargins(0, 0, 0, 0);
|
||||
m_buttonLayout->setSpacing(0);
|
||||
m_layout->addLayout(m_buttonLayout, 0);
|
||||
|
||||
m_floatButton = new CDockWidgetTitleButton(dockWidget);
|
||||
m_floatButton->setIcon(QIcon("Icons/float.png"));
|
||||
m_floatButton->setVisible(opt.floatable);
|
||||
m_floatButton->setToolTip("Toggle Floating");
|
||||
connect(m_floatButton, SIGNAL(clicked()), SLOT(OnFloatButtonPressed()));
|
||||
m_layout->addWidget(m_floatButton, 0);
|
||||
|
||||
m_closeButton = new CDockWidgetTitleButton(dockWidget);
|
||||
// close.png is a standard icon that looks similar to one in Fusion theme but
|
||||
// uses alpha so it can be used on dark theme as well.
|
||||
// style()->standardIcon(QStyle::SP_TitleBarCloseButton, &opt, dockWidget)
|
||||
QIcon closeIcon("Icons/close.png");
|
||||
m_closeButton->setIcon(closeIcon);
|
||||
m_closeButton->setVisible(opt.closable);
|
||||
m_closeButton->setToolTip("Close");
|
||||
connect(m_closeButton, SIGNAL(clicked()), SLOT(OnCloseButtonPressed()));
|
||||
m_layout->addWidget(m_closeButton, 0);
|
||||
|
||||
setLayout(m_layout);
|
||||
}
|
||||
|
||||
void CDockTitleBarWidget::AddCustomButton(const QIcon& icon, const char* tooltip, int id)
|
||||
{
|
||||
SCustomButton slot;
|
||||
slot.button = new CDockWidgetTitleButton(m_dockWidget);
|
||||
slot.button->setIcon(icon);
|
||||
slot.button->setToolTip(tooltip);
|
||||
connect(slot.button, SIGNAL(clicked()), SLOT(OnCustomButtonPressed()));
|
||||
slot.id = id;
|
||||
m_buttonLayout->addWidget(slot.button, 0);
|
||||
m_customButtons.push_back(slot);
|
||||
}
|
||||
|
||||
void CDockTitleBarWidget::OnFloatButtonPressed()
|
||||
{
|
||||
m_dockWidget->setFloating(!m_dockWidget->isFloating());
|
||||
}
|
||||
|
||||
void CDockTitleBarWidget::OnCloseButtonPressed()
|
||||
{
|
||||
m_dockWidget->close();
|
||||
}
|
||||
|
||||
void CDockTitleBarWidget::OnCustomButtonPressed()
|
||||
{
|
||||
QObject* button = sender();
|
||||
for (size_t i = 0; i < m_customButtons.size(); ++i)
|
||||
{
|
||||
if (button == m_customButtons[i].button)
|
||||
{
|
||||
SignalCustomButtonPressed(m_customButtons[i].id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#include <moc_DockTitleBarWidget.cpp>
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "EditorCommonAPI.h"
|
||||
#include <QAbstractButton>
|
||||
#include <QWidget>
|
||||
#include <QPainter>
|
||||
#include <QDockWidget>
|
||||
#include <QBoxLayout>
|
||||
|
||||
#include <vector>
|
||||
#endif
|
||||
|
||||
class EDITOR_COMMON_API CDockTitleBarWidget
|
||||
: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CDockTitleBarWidget(QDockWidget* dockWidget);
|
||||
|
||||
QSize sizeHint() const override
|
||||
{
|
||||
QFontMetrics fm(font());
|
||||
return QSize(40, fm.height() + 8);
|
||||
}
|
||||
|
||||
void AddCustomButton(const QIcon& icon, const char* tooltip, int id);
|
||||
signals:
|
||||
void SignalCustomButtonPressed(int id);
|
||||
private slots:
|
||||
void OnCloseButtonPressed();
|
||||
void OnFloatButtonPressed();
|
||||
void OnCustomButtonPressed();
|
||||
private:
|
||||
QDockWidget* m_dockWidget;
|
||||
QBoxLayout* m_layout;
|
||||
QBoxLayout* m_buttonLayout;
|
||||
|
||||
QAbstractButton* m_floatButton;
|
||||
QAbstractButton* m_closeButton;
|
||||
|
||||
struct SCustomButton
|
||||
{
|
||||
int id;
|
||||
QAbstractButton* button;
|
||||
};
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
std::vector<SCustomButton> m_customButtons;
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
};
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorCommon_precompiled.h"
|
||||
#include "Ruler.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPalette>
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
|
||||
namespace DrawingPrimitives
|
||||
{
|
||||
enum
|
||||
{
|
||||
RULER_MIN_PIXELS_PER_TICK = 3,
|
||||
};
|
||||
|
||||
std::vector<STick> CalculateTicks(uint size, Range visibleRange, Range rulerRange, int* pRulerPrecision, Range* pScreenRulerRange)
|
||||
{
|
||||
std::vector<STick> ticks;
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
if (pRulerPrecision)
|
||||
{
|
||||
*pRulerPrecision = 0;
|
||||
}
|
||||
|
||||
return ticks;
|
||||
}
|
||||
|
||||
const float pixelsPerUnit = visibleRange.Length() > 0.0f ? (float)size / visibleRange.Length() : 1.0f;
|
||||
|
||||
const float startTime = rulerRange.start;
|
||||
const float endTime = rulerRange.end;
|
||||
const float totalDuration = endTime - startTime;
|
||||
|
||||
const float ticksMinPower = log10f(RULER_MIN_PIXELS_PER_TICK);
|
||||
const float ticksPowerDelta = ticksMinPower - log10f(pixelsPerUnit);
|
||||
|
||||
const int digitsAfterPoint = max(-int(ceil(ticksPowerDelta)) - 1, 0);
|
||||
if (pRulerPrecision)
|
||||
{
|
||||
*pRulerPrecision = digitsAfterPoint;
|
||||
}
|
||||
|
||||
const float scaleStep = powf(10.0f, ceil(ticksPowerDelta));
|
||||
const float scaleStepPixels = scaleStep * pixelsPerUnit;
|
||||
const int numMarkers = int(totalDuration / scaleStep) + 1;
|
||||
|
||||
const float startTimeRound = int(startTime / scaleStep) * scaleStep;
|
||||
const int startOffsetMod = int(startTime / scaleStep) % 10;
|
||||
const int scaleOffsetPixels = aznumeric_cast<int>((startTime - startTimeRound) * pixelsPerUnit);
|
||||
|
||||
const int startX = aznumeric_cast<int>((rulerRange.start - visibleRange.start) * pixelsPerUnit);
|
||||
const int endX = aznumeric_cast<int>(startX + (numMarkers - 1) * scaleStepPixels - scaleOffsetPixels);
|
||||
|
||||
if (pScreenRulerRange)
|
||||
{
|
||||
*pScreenRulerRange = Range(aznumeric_cast<float>(startX), aznumeric_cast<float>(endX));
|
||||
}
|
||||
|
||||
const int startLoop = std::max((int)((scaleOffsetPixels - startX) / scaleStepPixels) - 1, 0);
|
||||
const int endLoop = std::min((int)((size + scaleOffsetPixels - startX) / scaleStepPixels) + 1, numMarkers);
|
||||
|
||||
for (int i = startLoop; i < endLoop; ++i)
|
||||
{
|
||||
STick tick;
|
||||
|
||||
const int x = aznumeric_cast<int>(startX + i * scaleStepPixels - scaleOffsetPixels);
|
||||
const float value = startTimeRound + i * scaleStep;
|
||||
|
||||
tick.m_bTenth = (startOffsetMod + i) % 10 != 0;
|
||||
tick.m_position = x;
|
||||
tick.m_value = value;
|
||||
|
||||
ticks.push_back(tick);
|
||||
}
|
||||
|
||||
return ticks;
|
||||
}
|
||||
|
||||
QColor Interpolate(const QColor& a, const QColor& b, float k)
|
||||
{
|
||||
float mk = 1.0f - k;
|
||||
return QColor(aznumeric_cast<int>(a.red() * mk + b.red() * k),
|
||||
aznumeric_cast<int>(a.green() * mk + b.green() * k),
|
||||
aznumeric_cast<int>(a.blue() * mk + b.blue() * k),
|
||||
aznumeric_cast<int>(a.alpha() * mk + b.alpha() * k));
|
||||
}
|
||||
|
||||
void DrawTicks(const std::vector<STick>& ticks, QPainter& painter, const QPalette& palette, const STickOptions& options)
|
||||
{
|
||||
QColor midDark = DrawingPrimitives::Interpolate(palette.color(QPalette::Dark), palette.color(QPalette::Button), 0.5f);
|
||||
painter.setPen(QPen(midDark));
|
||||
|
||||
const int height = options.m_rect.height();
|
||||
const int top = options.m_rect.top();
|
||||
|
||||
for (const STick& tick : ticks)
|
||||
{
|
||||
const int x = tick.m_position + options.m_rect.left();
|
||||
|
||||
if (tick.m_bTenth)
|
||||
{
|
||||
painter.drawLine(QPoint(x, top + height - options.m_markHeight / 2), QPoint(x, top + height));
|
||||
}
|
||||
else
|
||||
{
|
||||
painter.drawLine(QPoint(x, top + height - options.m_markHeight), QPoint(x, top + height));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawTicks(QPainter& painter, const QPalette& palette, const SRulerOptions& options)
|
||||
{
|
||||
const std::vector<STick> ticks = CalculateTicks(options.m_rect.width(), options.m_visibleRange, options.m_rulerRange, nullptr, nullptr);
|
||||
DrawTicks(ticks, painter, palette, options);
|
||||
}
|
||||
|
||||
void DrawRuler(QPainter& painter, const QPalette& palette, const SRulerOptions& options, int* pRulerPrecision)
|
||||
{
|
||||
int rulerPrecision;
|
||||
Range screenRulerRange;
|
||||
const std::vector<STick> ticks = CalculateTicks(options.m_rect.width(), options.m_visibleRange, options.m_rulerRange, &rulerPrecision, &screenRulerRange);
|
||||
|
||||
if (pRulerPrecision)
|
||||
{
|
||||
*pRulerPrecision = rulerPrecision;
|
||||
}
|
||||
|
||||
if (options.m_shadowSize > 0)
|
||||
{
|
||||
QRect shadowRect = QRect(options.m_rect.left(), options.m_rect.height(), options.m_rect.width(), options.m_shadowSize);
|
||||
QLinearGradient upperGradient(shadowRect.left(), shadowRect.top(), shadowRect.left(), shadowRect.bottom());
|
||||
upperGradient.setColorAt(0.0f, QColor(0, 0, 0, 128));
|
||||
upperGradient.setColorAt(1.0f, QColor(0, 0, 0, 0));
|
||||
QBrush upperBrush(upperGradient);
|
||||
painter.fillRect(shadowRect, upperBrush);
|
||||
}
|
||||
|
||||
painter.fillRect(options.m_rect, DrawingPrimitives::Interpolate(palette.color(QPalette::Button), palette.color(QPalette::Midlight), 0.25f));
|
||||
if (options.m_drawBackgroundCallback)
|
||||
{
|
||||
options.m_drawBackgroundCallback();
|
||||
}
|
||||
|
||||
QColor midDark = DrawingPrimitives::Interpolate(palette.color(QPalette::Dark), palette.color(QPalette::Button), 0.5f);
|
||||
painter.setPen(QPen(midDark));
|
||||
|
||||
QFont font;
|
||||
font.setPixelSize(10);
|
||||
painter.setFont(font);
|
||||
|
||||
|
||||
char format[16] = "";
|
||||
sprintf_s(format, "%%.%df", rulerPrecision);
|
||||
|
||||
const int height = options.m_rect.height();
|
||||
const int top = options.m_rect.top();
|
||||
|
||||
QString str;
|
||||
for (const STick& tick : ticks)
|
||||
{
|
||||
const int x = tick.m_position + options.m_rect.left();
|
||||
const float value = tick.m_value;
|
||||
|
||||
if (tick.m_bTenth)
|
||||
{
|
||||
painter.drawLine(QPoint(x, top + height - options.m_markHeight / 2), QPoint(x, top + height));
|
||||
}
|
||||
else
|
||||
{
|
||||
painter.drawLine(QPoint(x, top + height - options.m_markHeight), QPoint(x, top + height));
|
||||
painter.setPen(palette.color(QPalette::Disabled, QPalette::Text));
|
||||
str.asprintf(format, value);
|
||||
painter.drawText(QPoint(x + 2, top + height - options.m_markHeight + 1), str);
|
||||
painter.setPen(midDark);
|
||||
}
|
||||
}
|
||||
|
||||
painter.setPen(QPen(palette.color(QPalette::Dark)));
|
||||
painter.drawLine(QPoint(aznumeric_cast<int>(options.m_rect.left() + screenRulerRange.start), 0), QPoint(aznumeric_cast<int>(options.m_rect.left() + screenRulerRange.start), options.m_rect.top() + height));
|
||||
painter.drawLine(QPoint(aznumeric_cast<int>(options.m_rect.left() + screenRulerRange.end), 0), QPoint(aznumeric_cast<int>(options.m_rect.left() + screenRulerRange.end), options.m_rect.top() + height));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Range.h"
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <QRect>
|
||||
|
||||
class QPainter;
|
||||
class QPalette;
|
||||
|
||||
namespace DrawingPrimitives
|
||||
{
|
||||
struct SRulerOptions;
|
||||
typedef std::function<void()> TDrawCallback;
|
||||
|
||||
struct SRulerOptions
|
||||
{
|
||||
QRect m_rect;
|
||||
Range m_visibleRange;
|
||||
Range m_rulerRange;
|
||||
int m_textXOffset;
|
||||
int m_textYOffset;
|
||||
int m_markHeight;
|
||||
int m_shadowSize;
|
||||
|
||||
TDrawCallback m_drawBackgroundCallback;
|
||||
};
|
||||
|
||||
struct STick
|
||||
{
|
||||
bool m_bTenth;
|
||||
int m_position;
|
||||
float m_value;
|
||||
};
|
||||
|
||||
typedef SRulerOptions STickOptions;
|
||||
|
||||
std::vector<STick> CalculateTicks(uint size, Range visibleRange, Range rulerRange, int* pRulerPrecision, Range* pScreenRulerRange);
|
||||
void DrawTicks(const std::vector<STick>& ticks, QPainter& painter, const QPalette& palette, const STickOptions& options);
|
||||
void DrawTicks(QPainter& painter, const QPalette& palette, const STickOptions& options);
|
||||
void DrawRuler(QPainter& painter, const QPalette& palette, const SRulerOptions& options, int* pRulerPrecision);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorCommon_precompiled.h"
|
||||
#include "TimeSlider.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPalette>
|
||||
|
||||
namespace DrawingPrimitives
|
||||
{
|
||||
void DrawTimeSlider(QPainter& painter, const QPalette& palette, const STimeSliderOptions& options)
|
||||
{
|
||||
QString text = QString::number(options.m_time, 'f', options.m_precision + 1);
|
||||
|
||||
QFontMetrics fm(painter.font());
|
||||
const int textWidth = fm.horizontalAdvance(text) + fm.height();
|
||||
const int markerHeight = fm.height();
|
||||
|
||||
const int thumbX = options.m_position;
|
||||
const bool fits = thumbX + textWidth < options.m_rect.right();
|
||||
|
||||
const QRect timeRect(fits ? thumbX : thumbX - textWidth, 3, textWidth, fm.height());
|
||||
painter.fillRect(timeRect.adjusted(fits ? 0 : -1, 0, fits ? 1 : 0, 0), options.m_bHasFocus ? palette.highlight() : palette.shadow());
|
||||
painter.setPen(palette.color(QPalette::HighlightedText));
|
||||
painter.drawText(timeRect.adjusted(fits ? 0 : aznumeric_cast<int>(markerHeight * 0.2f), -1, fits ? aznumeric_cast<int>(-markerHeight * 0.2f) : 0, 0), text, QTextOption(fits ? Qt::AlignRight : Qt::AlignLeft));
|
||||
|
||||
painter.setPen(palette.color(QPalette::Text));
|
||||
painter.drawLine(QPointF(thumbX, 0), QPointF(thumbX, options.m_rect.height()));
|
||||
QPointF points[3] =
|
||||
{
|
||||
QPointF(thumbX, markerHeight),
|
||||
QPointF(thumbX - markerHeight * 0.66f, 0),
|
||||
QPointF(thumbX + markerHeight * 0.66f, 0)
|
||||
};
|
||||
|
||||
painter.setBrush(palette.base());
|
||||
painter.setPen(palette.color(QPalette::Text));
|
||||
painter.drawPolygon(points, 3);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Range.h"
|
||||
|
||||
#include <QRect>
|
||||
|
||||
class QPainter;
|
||||
class QPalette;
|
||||
|
||||
namespace DrawingPrimitives
|
||||
{
|
||||
struct STimeSliderOptions
|
||||
{
|
||||
QRect m_rect;
|
||||
int m_precision;
|
||||
int m_position;
|
||||
float m_time;
|
||||
bool m_bHasFocus;
|
||||
};
|
||||
|
||||
void DrawTimeSlider(QPainter& painter, const QPalette& palette, const STimeSliderOptions& options);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#include "EditorCommon_precompiled.h"
|
||||
|
||||
#include <platform.h>
|
||||
#include "EditorCommon.h"
|
||||
|
||||
#include "EditorCommonAPI.h"
|
||||
|
||||
CEditorCommonApp::CEditorCommonApp()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void EDITOR_COMMON_API InitializeEditorCommon([[maybe_unused]] IEditor* editor)
|
||||
{
|
||||
}
|
||||
|
||||
void EDITOR_COMMON_API UninitializeEditorCommon()
|
||||
{
|
||||
}
|
||||
|
||||
void EDITOR_COMMON_API InitializeEditorCommonISystem(ISystem* pSystem)
|
||||
{
|
||||
ModuleInitISystem(pSystem, "EditorCommon");
|
||||
}
|
||||
|
||||
void EDITOR_COMMON_API UninitializeEditorCommonISystem(ISystem* pSystem)
|
||||
{
|
||||
ModuleShutdownISystem(pSystem);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
; EditorCommon.def : Declares the module parameters for the DLL.
|
||||
|
||||
LIBRARY
|
||||
|
||||
EXPORTS
|
||||
; Explicit exports can go here
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef CRYINCLUDE_EDITORCOMMON_EDITORCOMMON_H
|
||||
#define CRYINCLUDE_EDITORCOMMON_EDITORCOMMON_H
|
||||
|
||||
class CEditorCommonApp
|
||||
{
|
||||
public:
|
||||
CEditorCommonApp();
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_EDITORCOMMON_EDITORCOMMON_H
|
||||
Binary file not shown.
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
#ifndef CRYINCLUDE_EDITORCOMMON_EDITORCOMMONAPI_H
|
||||
#define CRYINCLUDE_EDITORCOMMON_EDITORCOMMONAPI_H
|
||||
|
||||
#include <AzCore/PlatformDef.h>
|
||||
|
||||
#if defined(EDITOR_COMMON_EXPORTS)
|
||||
|
||||
#define EDITOR_COMMON_API AZ_DLL_EXPORT
|
||||
|
||||
#elif defined(EDITOR_COMMON_IMPORTS)
|
||||
|
||||
#define EDITOR_COMMON_API AZ_DLL_IMPORT
|
||||
|
||||
#else
|
||||
|
||||
#define EDITOR_COMMON_API
|
||||
|
||||
#endif
|
||||
|
||||
struct IEditor;
|
||||
struct ISystem;
|
||||
|
||||
void EDITOR_COMMON_API InitializeEditorCommon(IEditor* editor);
|
||||
void EDITOR_COMMON_API UninitializeEditorCommon();
|
||||
|
||||
void EDITOR_COMMON_API InitializeEditorCommonISystem(ISystem* pSystem);
|
||||
void EDITOR_COMMON_API UninitializeEditorCommonISystem(ISystem* pSystem);
|
||||
|
||||
#endif // CRYINCLUDE_EDITORCOMMON_EDITORCOMMONAPI_H
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef VC_EXTRALEAN
|
||||
#define VC_EXTRALEAN
|
||||
#endif
|
||||
|
||||
// These redicilous dependencies are needed just to be able to use
|
||||
// Sandbox gizmos drawing and hit-testing code =(
|
||||
|
||||
#include "ISystem.h"
|
||||
#include "Include/EditorCoreAPI.h"
|
||||
#include "Util/EditorUtils.h"
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3e60156229cc8677e0294d297486f04bd78867ef4e0922b35444c8b45f78584d
|
||||
size 1090
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fd29a16a1d1d9a363e4b154d51910c2cba2787fbbe1360cfd107b393053d2e49
|
||||
size 1226
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:244005cde119238bbfc2815f36a343c6135c3233d0b72a5c97a6080604568e8f
|
||||
size 1160
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:33176a8ea6b0798adf1114fdbea4b0f5c708f40c3d48a047b1cb0fa6ebcbbded
|
||||
size 1181
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c122557745cc377768491ce59c5b5b17e54671aa59f7f87101766aa61758959e
|
||||
size 939
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3c2a360a56a37bfae2bea16b495f5b6ee482caa28d0949e8eadea48fdaae654f
|
||||
size 845
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:eb0f43228bdb5246ea3bfde0726f07e0df0468279610ba4c801b21e264b33123
|
||||
size 765
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:97a2e879222323bc70787efbe2cbc1c47bbabb7b10df8465857e600a9084abb2
|
||||
size 795
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:58e8476b7bec1ed8eddfde3d5228f58fcfba11329318f5dfef3d98eb99f3a897
|
||||
size 1113
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a7847e8b7f3dd76395d893888916e4bd97ddf3f678d37d19836da04c2923791e
|
||||
size 871
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:470266956c6911690299f29539c400122ae707f88d9b6ba3516faf196a8fd571
|
||||
size 877
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorCommon_precompiled.h"
|
||||
#include "platform.h"
|
||||
|
||||
#pragma warning(disable: 4266) // disabled warning from afk overrides
|
||||
|
||||
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS
|
||||
#include <afxwin.h>
|
||||
#include <vector>
|
||||
|
||||
#include "QtViewPane.h"
|
||||
|
||||
#include "Include/IViewPane.h"
|
||||
#include "Util/RefCountBase.h"
|
||||
#include "QtWinMigrate/qwinwidget.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QEvent>
|
||||
#include <QApplication>
|
||||
#include <QCloseEvent>
|
||||
#include <QHBoxLayout>
|
||||
|
||||
#include "QtUtil.h"
|
||||
|
||||
// ugly dependencies:
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4244) // warning C4244: 'argument' : conversion from 'A' to 'B', possible loss of data
|
||||
#include "Functor.h"
|
||||
class CXmlArchive;
|
||||
#include <IRenderer.h>
|
||||
#include "Util/PathUtil.h"
|
||||
#pragma warning(pop)
|
||||
// ^^^
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by EditorCommon.rc
|
||||
//
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
#define _APS_NEXT_RESOURCE_VALUE 1000
|
||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
||||
#define _APS_NEXT_SYMED_VALUE 1000
|
||||
#define _APS_NEXT_COMMAND_VALUE 32771
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "EditorCommon_precompiled.h"
|
||||
#include <SaveUtilities/AsyncSaveRunner.h>
|
||||
#include <AzToolsFramework/SourceControl/SourceControlAPI.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <ActionOutput.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
/* -------------------------- *
|
||||
* == Save Operation Cache == *
|
||||
* -------------------------- */
|
||||
|
||||
SaveOperationController::SaveOperationCache::SaveOperationCache(const AZStd::string& fullPath, SynchronousSaveOperation saveOperation, SaveOperationController& owner, bool isDelete)
|
||||
: m_fullSavePath(fullPath)
|
||||
, m_saveOperation(saveOperation)
|
||||
, m_owner(owner)
|
||||
, m_isDelete(isDelete)
|
||||
{
|
||||
}
|
||||
|
||||
void SaveOperationController::SaveOperationCache::Run(const AZStd::shared_ptr<ActionOutput>& actionOutput)
|
||||
{
|
||||
if (m_isDelete)
|
||||
{
|
||||
RunDelete(actionOutput);
|
||||
return;
|
||||
}
|
||||
// Create the callback to pass to the SourceControlAPI
|
||||
AzToolsFramework::SourceControlResponseCallback callback =
|
||||
[this, actionOutput](bool success, const AzToolsFramework::SourceControlFileInfo& info)
|
||||
{
|
||||
if (success || !info.IsReadOnly())
|
||||
{
|
||||
if (m_saveOperation && !m_saveOperation(m_fullSavePath, actionOutput))
|
||||
{
|
||||
success = false;
|
||||
|
||||
if (actionOutput)
|
||||
{
|
||||
actionOutput->AddError("Failed to save entries/dependencies", m_fullSavePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!success && actionOutput)
|
||||
{
|
||||
AZStd::string message;
|
||||
AZStd::string details = m_fullSavePath;
|
||||
|
||||
// If there's no attempt to save any data it's assumed that this function was called to add an existing file to source control.
|
||||
// Rather than report this as an error, report it as a warning as no data was lost.
|
||||
bool reportAsWarning = !m_saveOperation;
|
||||
bool moreDetails = true;
|
||||
|
||||
// Be more specific with errors so as to give the user the best chance at fixing them
|
||||
if (!info.HasFlag(AzToolsFramework::SCF_OpenByUser))
|
||||
{
|
||||
if (info.HasFlag(AzToolsFramework::SCF_OutOfDate))
|
||||
{
|
||||
message = "The file being worked on doesn't contain the latest changes from source control";
|
||||
moreDetails = false;
|
||||
}
|
||||
else if (info.IsLockedByOther())
|
||||
{
|
||||
message = "The file is already exclusively opened by another user";
|
||||
details = info.m_StatusUser + " -> " + m_fullSavePath;
|
||||
moreDetails = false;
|
||||
}
|
||||
else if (info.m_status == AzToolsFramework::SourceControlStatus::SCS_ProviderIsDown)
|
||||
{
|
||||
message = "Failed to put entries/dependencies into source control as the provider is not available.\n";
|
||||
}
|
||||
else if (info.m_status == AzToolsFramework::SourceControlStatus::SCS_CertificateInvalid)
|
||||
{
|
||||
message = "Failed to put entries/dependencies into source control as the source control has an invalid certificate.\n";
|
||||
}
|
||||
else if (info.m_status == AzToolsFramework::SourceControlStatus::SCS_ProviderError)
|
||||
{
|
||||
message = "Failed to put entries/dependencies into source control as the provider reported an error.\n";
|
||||
}
|
||||
else if (!info.IsManaged())
|
||||
{
|
||||
message = "Failed to put entries/dependencies into source control as they are outside the current workspace mapping.\n";
|
||||
reportAsWarning = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
message = "Make sure the disk is not full or the file is not write-protected or not currently in use.\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
message = "File marked as 'Open By User' but still failed.\n";
|
||||
}
|
||||
|
||||
if (moreDetails)
|
||||
{
|
||||
message += "Please see the source control icon in the status bar for further details";
|
||||
}
|
||||
|
||||
if (reportAsWarning)
|
||||
{
|
||||
actionOutput->AddWarning(message, details);
|
||||
success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
actionOutput->AddError(message, details);
|
||||
}
|
||||
}
|
||||
|
||||
m_owner.HandleOperationComplete(this, success);
|
||||
};
|
||||
|
||||
using SCCommandBus = AzToolsFramework::SourceControlCommandBus;
|
||||
SCCommandBus::Broadcast(&SCCommandBus::Events::RequestEdit, m_fullSavePath.c_str(), true, callback);
|
||||
}
|
||||
|
||||
void SaveOperationController::SaveOperationCache::RunDelete(const AZStd::shared_ptr<ActionOutput>& actionOutput)
|
||||
{
|
||||
// Create the callback to pass to the SourceControlAPI
|
||||
AzToolsFramework::SourceControlResponseCallback callback =
|
||||
[this, actionOutput](bool success, const AzToolsFramework::SourceControlFileInfo& info)
|
||||
{
|
||||
if (success || !info.IsManaged())
|
||||
{
|
||||
success = true;
|
||||
if (m_saveOperation && !m_saveOperation(m_fullSavePath, actionOutput))
|
||||
{
|
||||
success = false;
|
||||
|
||||
if (actionOutput)
|
||||
{
|
||||
actionOutput->AddError("Failed to delete entry", m_fullSavePath.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (actionOutput)
|
||||
{
|
||||
// Be more specific with errors so as to give the user the best chance at fixing them
|
||||
if (!info.HasFlag(AzToolsFramework::SCF_OpenByUser))
|
||||
{
|
||||
if (info.HasFlag(AzToolsFramework::SourceControlFlags::SCF_OutOfDate))
|
||||
{
|
||||
actionOutput->AddError("Source Control Issue - You do not have latest changes from source control for file", m_fullSavePath);
|
||||
}
|
||||
else if (info.IsLockedByOther())
|
||||
{
|
||||
actionOutput->AddError("Source Control Issue - File exclusively opened by another user", info.m_StatusUser + " -> " + m_fullSavePath);
|
||||
}
|
||||
else if (info.m_status == AzToolsFramework::SourceControlStatus::SCS_ProviderIsDown
|
||||
|| info.m_status == AzToolsFramework::SourceControlStatus::SCS_CertificateInvalid
|
||||
|| info.m_status == AzToolsFramework::SourceControlStatus::SCS_ProviderError)
|
||||
{
|
||||
actionOutput->AddError("Source Control Issue - Failed to remove file from source control, check your connection to your source control service", m_fullSavePath.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
actionOutput->AddError("Unknown Issue with source control.", m_fullSavePath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
actionOutput->AddError("Source Control Issue - File marked as 'Open By User' but still failed.", m_fullSavePath);
|
||||
}
|
||||
}
|
||||
|
||||
m_owner.HandleOperationComplete(this, success);
|
||||
};
|
||||
|
||||
using SCCommandBus = AzToolsFramework::SourceControlCommandBus;
|
||||
SCCommandBus::Broadcast(&SCCommandBus::Events::RequestDelete, m_fullSavePath.c_str(), callback);
|
||||
}
|
||||
|
||||
/* ------------------------------- *
|
||||
* == Save Operation Controller == *
|
||||
* ------------------------------- */
|
||||
|
||||
SaveOperationController::SaveOperationController(AsyncSaveRunner& owner)
|
||||
: m_owner(owner)
|
||||
, m_completedCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
void SaveOperationController::AddDeleteOperation(const AZStd::string& fullPath, SynchronousSaveOperation saveOperation)
|
||||
{
|
||||
m_allSaveOperations.push_back(AZStd::make_shared<SaveOperationCache>(fullPath, saveOperation, *this, true));
|
||||
}
|
||||
|
||||
void SaveOperationController::AddSaveOperation(const AZStd::string& fullPath, SynchronousSaveOperation saveOperation)
|
||||
{
|
||||
m_allSaveOperations.push_back(AZStd::make_shared<SaveOperationCache>(fullPath, saveOperation, *this));
|
||||
}
|
||||
|
||||
void SaveOperationController::SetOnCompleteCallback(SaveCompleteCallback onThisRunnerComplete)
|
||||
{
|
||||
m_onSaveComplete = onThisRunnerComplete;
|
||||
}
|
||||
void SaveOperationController::RunAll(const AZStd::shared_ptr<ActionOutput>& actionOutput)
|
||||
{
|
||||
m_completedCount = 0;
|
||||
|
||||
// If for some reason there are no save operations in this controller, then we need
|
||||
// to notify the runner and return so that this controller can be properly counted
|
||||
// as being completed.
|
||||
if (m_allSaveOperations.empty())
|
||||
{
|
||||
m_owner.HandleRunnerFinished(this, true);
|
||||
return;
|
||||
}
|
||||
|
||||
for (AZStd::shared_ptr<SaveOperationCache>& saveOperation : m_allSaveOperations)
|
||||
{
|
||||
saveOperation->Run(actionOutput);
|
||||
}
|
||||
}
|
||||
|
||||
void SaveOperationController::HandleOperationComplete([[maybe_unused]] SaveOperationCache* saveOperation, bool success)
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
m_currentSaveResult = false;
|
||||
}
|
||||
|
||||
AZ_Assert(AZStd::find_if(m_allSaveOperations.begin(), m_allSaveOperations.end(),
|
||||
[saveOperation](const AZStd::shared_ptr<SaveOperationCache>& target) -> bool
|
||||
{
|
||||
return target.get() == saveOperation;
|
||||
}) != m_allSaveOperations.end(),
|
||||
"Attempting to cleanup completed save operation failed. Operation not found. Target file was: '%s'",
|
||||
saveOperation->m_fullSavePath.c_str());
|
||||
|
||||
m_completedCount++;
|
||||
if (m_completedCount >= m_allSaveOperations.size())
|
||||
{
|
||||
if (m_onSaveComplete)
|
||||
{
|
||||
m_onSaveComplete(m_currentSaveResult);
|
||||
}
|
||||
|
||||
m_owner.HandleRunnerFinished(this, m_currentSaveResult);
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------- *
|
||||
* == Async Save Runner == *
|
||||
* ----------------------- */
|
||||
|
||||
AZStd::shared_ptr<SaveOperationController> AsyncSaveRunner::GenerateController()
|
||||
{
|
||||
AZStd::shared_ptr<SaveOperationController> saveEntryController = AZStd::make_shared<SaveOperationController>(*this);
|
||||
m_allSaveControllers.push_back(saveEntryController);
|
||||
return saveEntryController;
|
||||
}
|
||||
|
||||
void AsyncSaveRunner::Run(const AZStd::shared_ptr<ActionOutput>& actionOutput, SaveCompleteCallback onSaveAllComplete, ControllerOrder order)
|
||||
{
|
||||
m_counter = 0;
|
||||
m_order = order;
|
||||
m_actionOutput = actionOutput;
|
||||
m_onSaveAllComplete = onSaveAllComplete;
|
||||
|
||||
// If for some reason there are no save operations in this runner, then we need to run
|
||||
// the callback now and return so that the caller is properly notified.
|
||||
if (m_allSaveControllers.empty())
|
||||
{
|
||||
if (m_onSaveAllComplete)
|
||||
{
|
||||
m_onSaveAllComplete(true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (order == ControllerOrder::Random)
|
||||
{
|
||||
for (auto& saveOp : m_allSaveControllers)
|
||||
{
|
||||
saveOp->RunAll(actionOutput);
|
||||
}
|
||||
}
|
||||
else if (order == ControllerOrder::Sequential)
|
||||
{
|
||||
m_allSaveControllers[0]->RunAll(actionOutput);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, "Invalid ControllerOrder: %i", order);
|
||||
}
|
||||
}
|
||||
void AsyncSaveRunner::HandleRunnerFinished([[maybe_unused]] SaveOperationController* runner, bool success)
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
m_allWereSuccessfull = false;
|
||||
}
|
||||
|
||||
if (m_order == ControllerOrder::Random)
|
||||
{
|
||||
AZ_Assert(AZStd::find_if(m_allSaveControllers.begin(), m_allSaveControllers.end(),
|
||||
[runner](const AZStd::shared_ptr<SaveOperationController>& target) -> bool
|
||||
{
|
||||
return target.get() == runner;
|
||||
}) != m_allSaveControllers.end(), "Attempting to cleanup completed save runner failed");
|
||||
|
||||
m_counter++;
|
||||
}
|
||||
else if (m_order == ControllerOrder::Sequential)
|
||||
{
|
||||
AZ_Assert(m_counter < m_allSaveControllers.size(),
|
||||
"Counter for save controllers has become invalid (%i vs. %i).", static_cast<int>(m_counter), m_allSaveControllers.size());
|
||||
AZ_Assert(m_allSaveControllers[m_counter].get() == runner, "Completed incorrect save runner for index %i.", static_cast<int>(m_counter));
|
||||
|
||||
m_counter++;
|
||||
if (m_counter < m_allSaveControllers.size())
|
||||
{
|
||||
m_allSaveControllers[m_counter]->RunAll(m_actionOutput);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, "Invalid ControllerOrder: %i", m_order);
|
||||
}
|
||||
|
||||
if (m_counter >= m_allSaveControllers.size())
|
||||
{
|
||||
m_actionOutput.reset();
|
||||
if (m_onSaveAllComplete)
|
||||
{
|
||||
m_onSaveAllComplete(m_allWereSuccessfull);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <EditorCommonAPI.h>
|
||||
|
||||
/*
|
||||
------------------
|
||||
AsyncSaveRunner:
|
||||
------------------
|
||||
== Overview ==
|
||||
This class is meant to be a container for 1-n save operations that need to work with async source control commands. The asynchronous aspect of the SourceControlBus becomes
|
||||
much more difficult when you have many operations because there is a management problem in knowing how soon until all commands have completed. This class will provide you
|
||||
with an easy to use interface for specifying the save operations, and providing a single callback to be called once all those operations have been completed.
|
||||
|
||||
== Note ==
|
||||
This class accepts lambdas and operates asynchronously. While the callbacks will be called on the main thread, **YOU MUST GUARANTEE LIFETIME YOURSELF**
|
||||
|
||||
== Usage ==
|
||||
To use this class, you need to guarantee the lifetime of the save runner. The best way to do that is to store it as a member variable in the class that runs the save. Storing
|
||||
it in a pointer type (or smart-pointer type) will help you control it's lifetime and memory.
|
||||
|
||||
Once you have a guaranteed lifetime AsyncSaveRunner, you'll build SaveOperationController instances that will manage all of your individual save operations, and will
|
||||
run the source control pieces for you. This allows you to focus on specifying the pieces you care about.
|
||||
|
||||
This is easiest to see why you would want that, would be a 'Save All' scenario.
|
||||
Lets imagine a save function that saves an item, which consists of saving a "header" file and an "entry" file:
|
||||
void SaveItem(int index)
|
||||
{
|
||||
auto item = m_items[index];
|
||||
|
||||
auto controller = m_saveRunner->GenerateController();
|
||||
controller->AddSaveOperation(m_headerSaver.getPath(), [item](const AZStd::string& fullPath, const AZStd::shared_ptr<ActionOutput>& actionOutput)->bool
|
||||
{
|
||||
return item->headerSaver.save();
|
||||
}
|
||||
);
|
||||
|
||||
controller->AddSaveOperation(m_entry.getPath(), [item](const AZStd::string& fullPath, const AZStd::shared_ptr<ActionOutput>& actionOutput)->bool
|
||||
{
|
||||
return item->entry.save();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
You can see that the AsyncSaveRunner was used to make a save operation controller, called 'controller' and that controller was filled out with save operations.
|
||||
If it was desired, you could even add a callback per controller to know when each controller is finished (in case you have to run a custom notification or something
|
||||
on the item).
|
||||
|
||||
You could imagine SaveItem being called 1-n times, adding more and more SaveOperationController instances to the AsyncSaveRunner. Once the runner is all filled out
|
||||
you call run on it and pass it a callback. This callback will only be called once. This leaves our example to look like this:
|
||||
|
||||
void SaveAll(AZStd::shared_ptr<AZ::ActionOutput> output, AZ::SaveCompleteCallback onComplete)
|
||||
{
|
||||
m_saveRunner = AZStd::make_shared<AZ::AsyncSaveRunner>();
|
||||
for(int index = 0; index < m_numItems; ++index)
|
||||
{
|
||||
Saveitem(index);
|
||||
}
|
||||
|
||||
m_saveRunner->Run(output,
|
||||
[this](bool success)
|
||||
{
|
||||
m_saveRunner = nullptr;
|
||||
|
||||
if(onComplete)
|
||||
{
|
||||
onComplete(success);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
*/
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class ActionOutput;
|
||||
|
||||
using SaveCompleteCallback = AZStd::function<void(bool success)>;
|
||||
using SynchronousSaveOperation = AZStd::function<bool(const AZStd::string& fullPath, const AZStd::shared_ptr<ActionOutput>& actionOutput)>;
|
||||
|
||||
class AsyncSaveRunner;
|
||||
|
||||
// Stores a cache of synchronous save operations, and runs them on completion of asynchronous source control operations.
|
||||
class EDITOR_COMMON_API SaveOperationController
|
||||
{
|
||||
public:
|
||||
explicit SaveOperationController(AsyncSaveRunner& owner);
|
||||
void AddSaveOperation(const AZStd::string& fullPath, SynchronousSaveOperation saveOperation);
|
||||
void AddDeleteOperation(const AZStd::string& fullPath, SynchronousSaveOperation saveOperation);
|
||||
void SetOnCompleteCallback(SaveCompleteCallback onThisRunnerComplete);
|
||||
|
||||
void RunAll(const AZStd::shared_ptr<ActionOutput>& actionOutput);
|
||||
|
||||
// Caches all synchronous save operations and associated data. Controlled by a SaveOperationController.
|
||||
class SaveOperationCache
|
||||
{
|
||||
public:
|
||||
SaveOperationCache(const AZStd::string& fullPath, SynchronousSaveOperation saveOperation, SaveOperationController& owner, bool isDelete = false);
|
||||
|
||||
void Run(const AZStd::shared_ptr<ActionOutput>& actionOutput);
|
||||
void RunDelete(const AZStd::shared_ptr<ActionOutput>& actionOutput);
|
||||
friend class SaveOperationController;
|
||||
|
||||
private:
|
||||
AZStd::string m_fullSavePath;
|
||||
SynchronousSaveOperation m_saveOperation;
|
||||
SaveOperationController& m_owner;
|
||||
bool m_isDelete;
|
||||
};
|
||||
|
||||
void HandleOperationComplete(SaveOperationCache* saveOperation, bool success);
|
||||
|
||||
friend class SaveRunner;
|
||||
|
||||
private:
|
||||
AsyncSaveRunner& m_owner;
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
AZStd::vector<AZStd::shared_ptr<SaveOperationCache>> m_allSaveOperations;
|
||||
SaveCompleteCallback m_onSaveComplete;
|
||||
AZStd::atomic<size_t> m_completedCount;
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
bool m_currentSaveResult = true;
|
||||
};
|
||||
|
||||
// Builds, stores and executes SaveOperationController instances
|
||||
class EDITOR_COMMON_API AsyncSaveRunner
|
||||
{
|
||||
public:
|
||||
enum class ControllerOrder
|
||||
{
|
||||
// Random will run controllers at once and completion will happen randomly.
|
||||
Random,
|
||||
// Controllers are executed in order, waiting for one controller before starting
|
||||
// the next one. Controllers internally will still have their executions
|
||||
// complete in random order.
|
||||
Sequential
|
||||
};
|
||||
|
||||
AZStd::shared_ptr<SaveOperationController> GenerateController();
|
||||
void Run(const AZStd::shared_ptr<ActionOutput>& actionOutput, SaveCompleteCallback onSaveAllComplete, ControllerOrder order);
|
||||
|
||||
private:
|
||||
friend class SaveOperationController;
|
||||
void HandleRunnerFinished(SaveOperationController* runner, bool success);
|
||||
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
AZStd::vector<AZStd::shared_ptr<SaveOperationController>> m_allSaveControllers;
|
||||
SaveCompleteCallback m_onSaveAllComplete;
|
||||
AZStd::shared_ptr<ActionOutput> m_actionOutput;
|
||||
// If controller order is random this keeps track of the number of completed tasks, if the order is sequential it
|
||||
// keeps track of the currently executing controller.
|
||||
AZStd::atomic<size_t> m_counter;
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
ControllerOrder m_order;
|
||||
bool m_allWereSuccessfull = true;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <LyShine/UiBase.h>
|
||||
|
||||
class UndoStack;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//! Interface class that the UI Editor needs to implement
|
||||
class UiEditorDLLInterface
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public: // member functions
|
||||
|
||||
virtual ~UiEditorDLLInterface(){}
|
||||
|
||||
//! Get the selected elements in the UiEditor
|
||||
virtual LyShine::EntityArray GetSelectedElements() = 0;
|
||||
|
||||
//! Get the id of the active Canvas the UiEditor
|
||||
virtual AZ::EntityId GetActiveCanvasId() = 0;
|
||||
|
||||
//! Get the active undo stack for the UI Editor
|
||||
virtual UndoStack* GetActiveUndoStack() = 0;
|
||||
|
||||
//! Soft-switch to the given file. Note that this should prompt for unsaved changes, etc.
|
||||
virtual void OpenSourceCanvasFile(QString absolutePathToFile) = 0;
|
||||
|
||||
public: // static member functions
|
||||
|
||||
static const char* GetUniqueName() { return "UiEditorDLLInterface"; }
|
||||
};
|
||||
|
||||
typedef AZ::EBus<UiEditorDLLInterface> UiEditorDLLBus;
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "EditorCommonAPI.h"
|
||||
#include "IEditor.h"
|
||||
|
||||
|
||||
#include <WinWidget/WinWidgetManager.h>
|
||||
#include <Core/QtEditorApplication.h>
|
||||
#include <QWidget>
|
||||
|
||||
namespace WinWidget
|
||||
{
|
||||
template<class TWidget>
|
||||
bool RegisterWinWidget()
|
||||
{
|
||||
static QWidget* winWidget {nullptr}; // Must declare outside of lambda
|
||||
|
||||
WinWidget::WinWidgetManager::WinWidgetCreateCall createCall = []() -> QWidget*
|
||||
{
|
||||
if (!winWidget)
|
||||
{
|
||||
winWidget = new QWidget(GetIEditor()->GetEditorMainWindow());
|
||||
}
|
||||
|
||||
// Ensure only one instance of each window type exists
|
||||
QList<TWidget*> existingWidgets = winWidget->findChildren<TWidget*>();
|
||||
if (existingWidgets.size() > 0) // Note that the list should contain 0 or 1 entries
|
||||
{
|
||||
if (existingWidgets.first()->isVisible())
|
||||
{
|
||||
return nullptr; // TWidget type already in use - continue using it and don't create another
|
||||
}
|
||||
delete existingWidgets.first(); // Closed TWidget - remove
|
||||
}
|
||||
|
||||
TWidget* createWidget = new TWidget(winWidget);
|
||||
|
||||
createWidget->Display();
|
||||
return winWidget;
|
||||
};
|
||||
|
||||
return GetIEditor()->GetWinWidgetManager()->RegisterWinWidget(TWidget::GetWWId(), createCall);
|
||||
}
|
||||
|
||||
template<class TWidget>
|
||||
void UnregisterWinWidget()
|
||||
{
|
||||
GetIEditor()->GetWinWidgetManager()->UnregisterWinWidget(TWidget::GetWWId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "EditorCommon_precompiled.h"
|
||||
#include <WinWidget/WinWidgetManager.h>
|
||||
|
||||
namespace WinWidget
|
||||
{
|
||||
WinWidgetManager::WinWidgetManager()
|
||||
: m_createCalls(size_t(WinWidgetId::NUM_WIN_WIDGET_IDS) + 1)
|
||||
{
|
||||
}
|
||||
|
||||
size_t WinWidgetManager::GetIndexForId(WinWidgetId thisId) const
|
||||
{
|
||||
size_t thisIndex = static_cast<size_t>(thisId);
|
||||
if (thisIndex >= m_createCalls.size())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return thisIndex;
|
||||
}
|
||||
|
||||
WinWidgetManager::WinWidgetCreateCall WinWidgetManager::GetCreateCall(WinWidgetId thisId) const
|
||||
{
|
||||
size_t thisIndex = GetIndexForId(thisId);
|
||||
if (!thisIndex)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return m_createCalls[thisIndex];
|
||||
}
|
||||
|
||||
bool WinWidgetManager::RegisterWinWidget(WinWidgetId thisId, WinWidgetCreateCall createCall)
|
||||
{
|
||||
size_t thisIndex = GetIndexForId(thisId);
|
||||
if (m_createCalls[thisIndex] != nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_createCalls[thisIndex] = createCall;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WinWidgetManager::UnregisterWinWidget(WinWidgetId thisId)
|
||||
{
|
||||
size_t thisIndex = GetIndexForId(thisId);
|
||||
if (m_createCalls[thisIndex] == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_createCalls[thisIndex] = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QWidget* WinWidgetManager::OpenWinWidget(WinWidgetId createId) const
|
||||
{
|
||||
WinWidgetManager::WinWidgetCreateCall createCall = GetCreateCall(createId);
|
||||
if (!createCall)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return createCall();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <WinWidgetId.h>
|
||||
#include "EditorCommonAPI.h"
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
namespace WinWidget
|
||||
{
|
||||
class EDITOR_COMMON_API WinWidgetManager
|
||||
{
|
||||
public:
|
||||
using WinWidgetCreateCall = std::function<QWidget*()>;
|
||||
|
||||
WinWidgetManager();
|
||||
~WinWidgetManager() {}
|
||||
|
||||
bool RegisterWinWidget(WinWidgetId thisId, WinWidgetCreateCall createCall);
|
||||
bool UnregisterWinWidget(WinWidgetId thisId);
|
||||
|
||||
QWidget* OpenWinWidget(WinWidgetId) const;
|
||||
private:
|
||||
WinWidgetCreateCall GetCreateCall(WinWidgetId thisId) const;
|
||||
size_t GetIndexForId(WinWidgetId thisId) const;
|
||||
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
std::vector<WinWidgetCreateCall> m_createCalls;
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#
|
||||
# Copyright (c) Contributors to the Open 3D Engine Project
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
#
|
||||
#
|
||||
|
||||
set(FILES
|
||||
EditorCommon.h
|
||||
EditorCommon.cpp
|
||||
EditorCommon.rc
|
||||
EditorCommonAPI.h
|
||||
EditorCommon_precompiled.h
|
||||
ActionOutput.h
|
||||
ActionOutput.cpp
|
||||
UiEditorDLLBus.h
|
||||
DockTitleBarWidget.cpp
|
||||
DockTitleBarWidget.h
|
||||
SaveUtilities/AsyncSaveRunner.h
|
||||
SaveUtilities/AsyncSaveRunner.cpp
|
||||
AxisHelper.cpp
|
||||
DisplayContext.cpp
|
||||
DeepFilterProxyModel.cpp
|
||||
DeepFilterProxyModel.h
|
||||
Resource.h
|
||||
DrawingPrimitives/Ruler.cpp
|
||||
DrawingPrimitives/Ruler.h
|
||||
DrawingPrimitives/TimeSlider.cpp
|
||||
DrawingPrimitives/TimeSlider.h
|
||||
WinWidget/WinWidget.h
|
||||
WinWidget/WinWidgetManager.h
|
||||
WinWidget/WinWidgetManager.cpp
|
||||
)
|
||||
Binary file not shown.
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// EditorCommon.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "EditorCommon_precompiled.h"
|
||||
Reference in New Issue
Block a user