git mv Code\Sandbox\Plugins Code/Editor/Plugins

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
Esteban Papp
2021-06-29 12:42:54 -07:00
parent e34e36cb35
commit 1696680240
215 changed files with 0 additions and 0 deletions
@@ -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
)
@@ -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"