Merge branch 'development' into cmake/SPEC-7182
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> # Conflicts: # Code/Editor/QtUtil.h # Code/Legacy/CryCommon/Linux_Win32Wrapper.h # Code/Legacy/CryCommon/ProjectDefines.h # Code/Legacy/CryCommon/StringUtils.h # Code/Legacy/CryCommon/UnicodeBinding.h # Code/Legacy/CryCommon/UnicodeEncoding.h # Code/Legacy/CryCommon/UnicodeFunctions.h # Code/Legacy/CryCommon/UnicodeIterator.h # Code/Legacy/CryCommon/WinBase.cpp # Code/Legacy/CryCommon/platform.h # Code/Legacy/CryCommon/platform_impl.cpp # Gems/LyShine/Code/Source/Animation/UiAnimationSystem.cpp # Gems/Maestro/Code/Source/Cinematics/Movie.cppmonroegm-disable-blank-issue-2
commit
37ffe90353
@ -1,149 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "EditorDefs.h"
|
|
||||||
#include "SkeletonHierarchy.h"
|
|
||||||
|
|
||||||
using namespace Skeleton;
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
CHierarchy
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
CHierarchy::CHierarchy()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CHierarchy::~CHierarchy()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
uint32 CHierarchy::AddNode(const char* name, const QuatT& pose, int32 parent)
|
|
||||||
{
|
|
||||||
int32 index = FindNodeIndexByName(name);
|
|
||||||
|
|
||||||
if (index < 0)
|
|
||||||
{
|
|
||||||
m_nodes.push_back(SNode());
|
|
||||||
index = int32(m_nodes.size() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_nodes[index].name = name;
|
|
||||||
m_nodes[index].pose = pose;
|
|
||||||
m_nodes[index].parent = parent;
|
|
||||||
return uint32(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 CHierarchy::FindNodeIndexByName(const char* name) const
|
|
||||||
{
|
|
||||||
uint32 count = uint32(m_nodes.size());
|
|
||||||
for (uint32 i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
if (::_stricmp(m_nodes[i].name, name))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CHierarchy::SNode* CHierarchy::FindNode(const char* name) const
|
|
||||||
{
|
|
||||||
int32 index = FindNodeIndexByName(name);
|
|
||||||
return index < 0 ? nullptr : &m_nodes[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
void CHierarchy::CreateFrom(IDefaultSkeleton* pIDefaultSkeleton)
|
|
||||||
{
|
|
||||||
const uint32 jointCount = pIDefaultSkeleton->GetJointCount();
|
|
||||||
|
|
||||||
m_nodes.clear();
|
|
||||||
m_nodes.reserve(jointCount);
|
|
||||||
for (uint32 i = 0; i < jointCount; ++i)
|
|
||||||
{
|
|
||||||
m_nodes.push_back(SNode());
|
|
||||||
|
|
||||||
m_nodes.back().name = pIDefaultSkeleton->GetJointNameByID(int32(i));
|
|
||||||
m_nodes.back().pose = pIDefaultSkeleton->GetDefaultAbsJointByID(int32(i));
|
|
||||||
|
|
||||||
m_nodes.back().parent = pIDefaultSkeleton->GetJointParentIDByID(int32(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
ValidateReferences();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CHierarchy::ValidateReferences()
|
|
||||||
{
|
|
||||||
uint32 nodeCount = m_nodes.size();
|
|
||||||
if (!nodeCount)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32 i = 0; i < nodeCount; ++i)
|
|
||||||
{
|
|
||||||
if (m_nodes[i].parent < nodeCount)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_nodes[i].parent = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CHierarchy::AbsoluteToRelative(const QuatT* pSource, QuatT* pDestination)
|
|
||||||
{
|
|
||||||
uint32 count = uint32(m_nodes.size());
|
|
||||||
std::vector<QuatT> absolutes(count);
|
|
||||||
for (uint32 i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
absolutes[i] = pSource[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32 i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
int32 parent = m_nodes[i].parent;
|
|
||||||
if (parent < 0)
|
|
||||||
{
|
|
||||||
pDestination[i] = absolutes[i];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
pDestination[i].t = (absolutes[i].t - absolutes[parent].t) * absolutes[parent].q;
|
|
||||||
pDestination[i].q = absolutes[parent].q.GetInverted() * absolutes[i].q;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CHierarchy::SerializeTo(XmlNodeRef& node)
|
|
||||||
{
|
|
||||||
XmlNodeRef hierarchy = node->newChild("Hierarchy");
|
|
||||||
|
|
||||||
uint32 nodeCount = uint32(m_nodes.size());
|
|
||||||
std::vector<IXmlNode*> nodes(nodeCount);
|
|
||||||
for (uint32 i = 0; i < nodeCount; ++i)
|
|
||||||
{
|
|
||||||
XmlNodeRef parent = hierarchy;
|
|
||||||
if (m_nodes[i].parent > -1)
|
|
||||||
{
|
|
||||||
parent = nodes[m_nodes[i].parent];
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes[i] = parent->newChild("Node");
|
|
||||||
nodes[i]->setAttr("name", m_nodes[i].name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef CRYINCLUDE_EDITOR_ANIMATION_SKELETONHIERARCHY_H
|
|
||||||
#define CRYINCLUDE_EDITOR_ANIMATION_SKELETONHIERARCHY_H
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace Skeleton {
|
|
||||||
class CHierarchy
|
|
||||||
: public _reference_target_t
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct SNode
|
|
||||||
{
|
|
||||||
string name;
|
|
||||||
QuatT pose;
|
|
||||||
|
|
||||||
int32 parent;
|
|
||||||
|
|
||||||
/* TODO: Implement
|
|
||||||
uint32 childrenIndex;
|
|
||||||
uint32 childrenCount;
|
|
||||||
*/
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
CHierarchy();
|
|
||||||
~CHierarchy();
|
|
||||||
|
|
||||||
public:
|
|
||||||
uint32 AddNode(const char* name, const QuatT& pose, int32 parent = -1);
|
|
||||||
uint32 GetNodeCount() const { return uint32(m_nodes.size()); }
|
|
||||||
SNode* GetNode(uint32 index) { return &m_nodes[index]; }
|
|
||||||
const SNode* GetNode(uint32 index) const { return &m_nodes[index]; }
|
|
||||||
int32 FindNodeIndexByName(const char* name) const;
|
|
||||||
const SNode* FindNode(const char* name) const;
|
|
||||||
void ClearNodes() { m_nodes.clear(); }
|
|
||||||
|
|
||||||
void CreateFrom(IDefaultSkeleton* rIDefaultSkeleton);
|
|
||||||
void ValidateReferences();
|
|
||||||
|
|
||||||
void AbsoluteToRelative(const QuatT* pSource, QuatT* pDestination);
|
|
||||||
|
|
||||||
bool SerializeTo(XmlNodeRef& node);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<SNode> m_nodes;
|
|
||||||
};
|
|
||||||
} // namespace Skeleton
|
|
||||||
|
|
||||||
#endif // CRYINCLUDE_EDITOR_ANIMATION_SKELETONHIERARCHY_H
|
|
||||||
@ -1,368 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "EditorDefs.h"
|
|
||||||
|
|
||||||
#include "SkeletonMapper.h"
|
|
||||||
|
|
||||||
using namespace Skeleton;
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
CMapper
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
CMapper::CMapper()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CMapper::~CMapper()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
void CMapper::CreateFromHierarchy()
|
|
||||||
{
|
|
||||||
m_nodes.clear();
|
|
||||||
|
|
||||||
uint32 nodeCount = m_hierarchy.GetNodeCount();
|
|
||||||
m_nodes.resize(nodeCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
uint32 CMapper::CreateLocation(const char* name)
|
|
||||||
{
|
|
||||||
int32 index = FindLocation(name);
|
|
||||||
if (index < 1)
|
|
||||||
{
|
|
||||||
CMapperLocation* pLocation = new CMapperLocation();
|
|
||||||
pLocation->SetName(name);
|
|
||||||
m_locations.push_back(pLocation);
|
|
||||||
}
|
|
||||||
return uint32(m_locations.size() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CMapper::ClearLocations()
|
|
||||||
{
|
|
||||||
uint32 count = uint32(m_nodes.size());
|
|
||||||
for (uint32 i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
m_nodes[i].position = nullptr;
|
|
||||||
m_nodes[i].orientation = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_locations.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 CMapper::FindLocation(const char* name) const
|
|
||||||
{
|
|
||||||
uint32 count = uint32(m_locations.size());
|
|
||||||
for (uint32 i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
if (::_stricmp(m_locations[i]->GetName(), name))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return int32(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CMapper::SetLocation(CMapperLocation& location)
|
|
||||||
{
|
|
||||||
int32 index = FindLocation(location.GetName());
|
|
||||||
if (index < 0)
|
|
||||||
{
|
|
||||||
m_locations.push_back(&location);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_locations[index] = &location;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
bool CMapper::CreateLocationsHierarchy(uint32 index, CHierarchy& hierarchy, int32 hierarchyParent)
|
|
||||||
{
|
|
||||||
if (NodeHasLocation(index))
|
|
||||||
{
|
|
||||||
const CHierarchy::SNode* pNode = m_hierarchy.GetNode(index);
|
|
||||||
uint32 nodeIndex = hierarchy.AddNode(pNode->name, pNode->pose, hierarchyParent);
|
|
||||||
hierarchyParent = uint32(nodeIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint32> children;
|
|
||||||
GetChildrenIndices(index, children);
|
|
||||||
uint32 childCount = uint32(children.size());
|
|
||||||
for (uint32 i = 0; i < childCount; ++i)
|
|
||||||
{
|
|
||||||
CreateLocationsHierarchy(children[i], hierarchy, hierarchyParent);
|
|
||||||
}
|
|
||||||
|
|
||||||
return hierarchy.GetNodeCount() != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CMapper::CreateLocationsHierarchy(CHierarchy& hierarchy)
|
|
||||||
{
|
|
||||||
hierarchy.ClearNodes();
|
|
||||||
if (!CreateLocationsHierarchy(0, hierarchy, -1))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
hierarchy.ValidateReferences();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CMapper::Map(QuatT* pResult)
|
|
||||||
{
|
|
||||||
uint32 outputCount = m_hierarchy.GetNodeCount();
|
|
||||||
std::vector<Quat> absolutes(outputCount);
|
|
||||||
for (uint32 i = 0; i < outputCount; ++i)
|
|
||||||
{
|
|
||||||
pResult[i].SetIdentity();
|
|
||||||
absolutes[i].SetIdentity();
|
|
||||||
|
|
||||||
CHierarchy::SNode* pNode = m_hierarchy.GetNode(i);
|
|
||||||
if (!pNode)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
CHierarchy::SNode* pParent = pNode->parent < 0 ?
|
|
||||||
nullptr : m_hierarchy.GetNode(pNode->parent);
|
|
||||||
if (pParent)
|
|
||||||
{
|
|
||||||
pResult[i].t =
|
|
||||||
(pNode->pose.t - pParent->pose.t) * pParent->pose.q;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_nodes[i].position)
|
|
||||||
{
|
|
||||||
pResult[i].t = m_nodes[i].position->Compute().t;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_nodes[i].orientation)
|
|
||||||
{
|
|
||||||
absolutes[i] = m_nodes[i].orientation->Compute().q;
|
|
||||||
}
|
|
||||||
else if (pParent)
|
|
||||||
{
|
|
||||||
Quat relative = pParent->pose.q.GetInverted() * pNode->pose.q;
|
|
||||||
absolutes[i] = absolutes[pNode->parent] * relative;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32 i = 0; i < outputCount; ++i)
|
|
||||||
{
|
|
||||||
CHierarchy::SNode* pNode = m_hierarchy.GetNode(i);
|
|
||||||
if (!pNode)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
CHierarchy::SNode* pParent = pNode->parent < 0 ?
|
|
||||||
nullptr : m_hierarchy.GetNode(pNode->parent);
|
|
||||||
if (!pParent)
|
|
||||||
{
|
|
||||||
pResult[i].q = absolutes[i];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
pResult[i].q = absolutes[i];
|
|
||||||
if (!m_nodes[i].position)
|
|
||||||
{
|
|
||||||
pResult[i].t = pResult[pNode->parent].t +
|
|
||||||
pResult[i].t * absolutes[pNode->parent].GetInverted();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
bool CMapper::NodeHasLocation(uint32 index)
|
|
||||||
{
|
|
||||||
if (CMapperOperator* pOperator = m_nodes[index].position)
|
|
||||||
{
|
|
||||||
if (pOperator->IsOfClass("Location"))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (pOperator->HasLinksOfClass("Location"))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CMapperOperator* pOperator = m_nodes[index].orientation)
|
|
||||||
{
|
|
||||||
if (pOperator->IsOfClass("Location"))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (pOperator->HasLinksOfClass("Location"))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CMapper::GetChildrenIndices(uint32 parent, std::vector<uint32>& children)
|
|
||||||
{
|
|
||||||
uint32 nodeCount = m_hierarchy.GetNodeCount();
|
|
||||||
for (uint32 i = 0; i < nodeCount; ++i)
|
|
||||||
{
|
|
||||||
if (m_hierarchy.GetNode(i)->parent != parent)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
children.push_back(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CMapper::ChildrenHaveLocation(uint32 index)
|
|
||||||
{
|
|
||||||
std::vector<uint32> children;
|
|
||||||
GetChildrenIndices(index, children);
|
|
||||||
|
|
||||||
uint32 childrenCount = uint32(children.size());
|
|
||||||
for (uint32 i = 0; i < childrenCount; ++i)
|
|
||||||
{
|
|
||||||
if (ChildrenHaveLocation(children[i]))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CMapper::NodeOrChildrenHaveLocation(uint32 index)
|
|
||||||
{
|
|
||||||
if (NodeHasLocation(index))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint32> children;
|
|
||||||
GetChildrenIndices(index, children);
|
|
||||||
|
|
||||||
uint32 childrenCount = uint32(children.size());
|
|
||||||
for (uint32 i = 0; i < childrenCount; ++i)
|
|
||||||
{
|
|
||||||
if (NodeOrChildrenHaveLocation(children[i]))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CMapper::SerializeTo(XmlNodeRef& node)
|
|
||||||
{
|
|
||||||
XmlNodeRef hierarchy = node->newChild("Hierarchy");
|
|
||||||
|
|
||||||
uint32 nodeCount = GetNodeCount();
|
|
||||||
std::vector<IXmlNode*> nodes(nodeCount);
|
|
||||||
for (uint32 i = 0; i < nodeCount; ++i)
|
|
||||||
{
|
|
||||||
if (!NodeOrChildrenHaveLocation(i))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
CHierarchy::SNode* pNode = m_hierarchy.GetNode(i);
|
|
||||||
if (!pNode)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
XmlNodeRef xmlParent = hierarchy;
|
|
||||||
int32 parent = pNode->parent;
|
|
||||||
if (parent > -1)
|
|
||||||
{
|
|
||||||
xmlParent = nodes[parent];
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes[i] = xmlParent->newChild("Node");
|
|
||||||
nodes[i]->setAttr("name", pNode->name);
|
|
||||||
|
|
||||||
if (CMapperOperator* pOperator = m_nodes[i].position)
|
|
||||||
{
|
|
||||||
XmlNodeRef position = nodes[i]->newChild("Position");
|
|
||||||
XmlNodeRef child = position->newChild("Operator");
|
|
||||||
if (!pOperator->SerializeWithLinksTo(child))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CMapperOperator* pOperator = m_nodes[i].orientation)
|
|
||||||
{
|
|
||||||
XmlNodeRef orientation = nodes[i]->newChild("Orientation");
|
|
||||||
XmlNodeRef child = orientation->newChild("Operator");
|
|
||||||
if (!pOperator->SerializeWithLinksTo(child))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CMapper::SerializeFrom(XmlNodeRef& node, int32 parent)
|
|
||||||
{
|
|
||||||
int childCount = uint32(node->getChildCount());
|
|
||||||
for (int i = 0; i < childCount; ++i)
|
|
||||||
{
|
|
||||||
XmlNodeRef child = node->getChild(i);
|
|
||||||
if (::_stricmp(child->getTag(), "Node"))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 index = m_hierarchy.AddNode(child->getAttr("name"), QuatT(IDENTITY), parent);
|
|
||||||
if (!SerializeFrom(child, int32(index)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CMapper::SerializeFrom(XmlNodeRef& node)
|
|
||||||
{
|
|
||||||
XmlNodeRef hierarchy = node->findChild("Hierarchy");
|
|
||||||
if (!hierarchy)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_hierarchy.ClearNodes();
|
|
||||||
|
|
||||||
if (!SerializeFrom(hierarchy, -1))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_nodes.resize(m_hierarchy.GetNodeCount());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef CRYINCLUDE_EDITOR_ANIMATION_SKELETONMAPPER_H
|
|
||||||
#define CRYINCLUDE_EDITOR_ANIMATION_SKELETONMAPPER_H
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include "SkeletonHierarchy.h"
|
|
||||||
#include "SkeletonMapperOperator.h"
|
|
||||||
|
|
||||||
namespace Skeleton {
|
|
||||||
class CMapper
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct SNode
|
|
||||||
{
|
|
||||||
_smart_ptr<CMapperOperator> position;
|
|
||||||
_smart_ptr<CMapperOperator> orientation;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
CMapper();
|
|
||||||
~CMapper();
|
|
||||||
|
|
||||||
public:
|
|
||||||
CHierarchy& GetHierarchy() { return m_hierarchy; }
|
|
||||||
void CreateFromHierarchy();
|
|
||||||
|
|
||||||
uint32 GetNodeCount() const { return uint32(m_nodes.size()); }
|
|
||||||
SNode* GetNode(uint32 index) { return &m_nodes[index]; }
|
|
||||||
const SNode* GetNode(uint32 index) const { return &m_nodes[index]; }
|
|
||||||
|
|
||||||
uint32 CreateLocation(const char* name);
|
|
||||||
void ClearLocations();
|
|
||||||
int32 FindLocation(const char* name) const;
|
|
||||||
|
|
||||||
uint32 GetLocationCount() const { return uint32(m_locations.size()); }
|
|
||||||
void SetLocation(CMapperLocation& location);
|
|
||||||
CMapperLocation* GetLocation(uint32 index) { return m_locations[index]; }
|
|
||||||
const CMapperLocation* GetLocation(uint32 index) const { return m_locations[index]; }
|
|
||||||
|
|
||||||
bool CreateLocationsHierarchy(CHierarchy& hierarchy);
|
|
||||||
|
|
||||||
void Map(QuatT* pResult);
|
|
||||||
|
|
||||||
bool SerializeTo(XmlNodeRef& node);
|
|
||||||
bool SerializeFrom(XmlNodeRef& node);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool NodeHasLocation(uint32 index);
|
|
||||||
bool ChildrenHaveLocation(uint32 index);
|
|
||||||
bool NodeOrChildrenHaveLocation(uint32 index);
|
|
||||||
|
|
||||||
bool SerializeFrom(XmlNodeRef& node, int32 parent);
|
|
||||||
|
|
||||||
bool CreateLocationsHierarchy(uint32 index, CHierarchy& hierarchy, int32 hierarchyParent = -1);
|
|
||||||
|
|
||||||
// TEMP
|
|
||||||
void GetChildrenIndices(uint32 parent, std::vector<uint32>& children);
|
|
||||||
|
|
||||||
private:
|
|
||||||
CHierarchy m_hierarchy;
|
|
||||||
std::vector<_smart_ptr<CMapperLocation> > m_locations;
|
|
||||||
|
|
||||||
std::vector<SNode> m_nodes;
|
|
||||||
};
|
|
||||||
} // namespace Skeleton
|
|
||||||
|
|
||||||
#endif // CRYINCLUDE_EDITOR_ANIMATION_SKELETONMAPPER_H
|
|
||||||
@ -1,284 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "EditorDefs.h"
|
|
||||||
|
|
||||||
#include "SkeletonMapperOperator.h"
|
|
||||||
|
|
||||||
using namespace Skeleton;
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
CMapperOperatorDesc
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
std::vector<CMapperOperatorDesc*> CMapperOperatorDesc::s_descs;
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
CMapperOperatorDesc::CMapperOperatorDesc(const char* name)
|
|
||||||
{
|
|
||||||
s_descs.push_back(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
CMapperOperator
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
CMapperOperator::CMapperOperator(const char* className, uint32 positionCount, uint32 orientationCount)
|
|
||||||
{
|
|
||||||
m_className = className;
|
|
||||||
m_position.resize(positionCount, nullptr);
|
|
||||||
m_orientation.resize(orientationCount, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
CMapperOperator::~CMapperOperator()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
bool CMapperOperator::IsOfClass(const char* className)
|
|
||||||
{
|
|
||||||
if (::_stricmp(m_className, className))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 CMapperOperator::HasLinksOfClass(const char* className)
|
|
||||||
{
|
|
||||||
uint32 count = 0;
|
|
||||||
|
|
||||||
uint32 positionCount = m_position.size();
|
|
||||||
for (uint32 i = 0; i < positionCount; ++i)
|
|
||||||
{
|
|
||||||
CMapperOperator* pOperator = m_position[i];
|
|
||||||
if (!pOperator)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pOperator->IsOfClass(className))
|
|
||||||
{
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 orientationCount = m_orientation.size();
|
|
||||||
for (uint32 i = 0; i < orientationCount; ++i)
|
|
||||||
{
|
|
||||||
CMapperOperator* pOperator = m_orientation[i];
|
|
||||||
if (!pOperator)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pOperator->IsOfClass(className))
|
|
||||||
{
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
bool CMapperOperator::SerializeTo(XmlNodeRef& node)
|
|
||||||
{
|
|
||||||
node->setAttr("class", m_className);
|
|
||||||
|
|
||||||
uint32 parameterCount = uint32(m_parameters.size());
|
|
||||||
for (uint32 i = 0; i < parameterCount; ++i)
|
|
||||||
{
|
|
||||||
m_parameters[i]->Serialize(node, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CMapperOperator::SerializeFrom(XmlNodeRef& node)
|
|
||||||
{
|
|
||||||
uint32 parameterCount = uint32(m_parameters.size());
|
|
||||||
for (uint32 i = 0; i < parameterCount; ++i)
|
|
||||||
{
|
|
||||||
m_parameters[i]->Serialize(node, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CMapperOperator::SerializeWithLinksTo(XmlNodeRef& node)
|
|
||||||
{
|
|
||||||
if (!SerializeTo(node))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 positionCount = uint32(m_position.size());
|
|
||||||
for (uint32 i = 0; i < positionCount; ++i)
|
|
||||||
{
|
|
||||||
CMapperOperator* pOperator = m_position[i];
|
|
||||||
if (!pOperator)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
XmlNodeRef position = node->newChild("Position");
|
|
||||||
position->setAttr("index", i);
|
|
||||||
|
|
||||||
XmlNodeRef child = position->newChild("Operator");
|
|
||||||
if (!pOperator->SerializeWithLinksTo(child))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 orientationCount = uint32(m_orientation.size());
|
|
||||||
for (uint32 i = 0; i < orientationCount; ++i)
|
|
||||||
{
|
|
||||||
CMapperOperator* pOperator = m_orientation[i];
|
|
||||||
if (!pOperator)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
XmlNodeRef orientation = node->newChild("Orientation");
|
|
||||||
orientation->setAttr("index", i);
|
|
||||||
|
|
||||||
XmlNodeRef child = orientation->newChild("Operator");
|
|
||||||
if (!pOperator->SerializeWithLinksTo(child))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CMapperOperator::SerializeWithLinksFrom(XmlNodeRef& node)
|
|
||||||
{
|
|
||||||
if (!SerializeFrom(node))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
|
|
||||||
CMapperOperator_Transform
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
class CMapperOperator_Transform
|
|
||||||
: public CMapperOperator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CMapperOperator_Transform()
|
|
||||||
: CMapperOperator("Transform", 1, 1)
|
|
||||||
{
|
|
||||||
m_pAngles = new CVariable<Vec3>();
|
|
||||||
m_pAngles->SetName("rotation");
|
|
||||||
m_pAngles->Set(Vec3(0.0f, 0.0f, 0.0f));
|
|
||||||
m_pAngles->SetLimits(-180.0f, 180.0f);
|
|
||||||
AddParameter(*m_pAngles);
|
|
||||||
|
|
||||||
m_pVector = new CVariable<Vec3>();
|
|
||||||
m_pVector->SetName("vector");
|
|
||||||
m_pVector->Set(Vec3(0.0f, 0.0f, 0.0f));
|
|
||||||
AddParameter(*m_pVector);
|
|
||||||
|
|
||||||
m_pScale = new CVariable<Vec3>();
|
|
||||||
m_pScale->SetName("scale");
|
|
||||||
m_pScale->Set(Vec3(1.0f, 1.0f, 1.0f));
|
|
||||||
AddParameter(*m_pScale);
|
|
||||||
}
|
|
||||||
|
|
||||||
// CMapperOperator
|
|
||||||
public:
|
|
||||||
virtual QuatT CMapperOperator_Transform::Compute()
|
|
||||||
{
|
|
||||||
QuatT result(IDENTITY);
|
|
||||||
m_pVector->Get(result.t);
|
|
||||||
|
|
||||||
Vec3 scale;
|
|
||||||
m_pScale->Get(scale);
|
|
||||||
|
|
||||||
Vec3 angles;
|
|
||||||
m_pAngles->Get(angles);
|
|
||||||
|
|
||||||
result.q = Quat::CreateRotationXYZ(
|
|
||||||
Ang3(DEG2RAD(angles.x), DEG2RAD(angles.y), DEG2RAD(angles.z)));
|
|
||||||
|
|
||||||
if (CMapperOperator* pOperator = GetPosition(0))
|
|
||||||
{
|
|
||||||
result.t = pOperator->Compute().t.CompMul(scale) + result.t;
|
|
||||||
}
|
|
||||||
if (CMapperOperator* pOperator = GetOrientation(0))
|
|
||||||
{
|
|
||||||
result.q = pOperator->Compute().q * result.q;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
CVariable<Vec3>* m_pVector;
|
|
||||||
CVariable<Vec3>* m_pAngles;
|
|
||||||
CVariable<Vec3>* m_pScale;
|
|
||||||
};
|
|
||||||
|
|
||||||
SkeletonMapperOperatorRegister(Transform, CMapperOperator_Transform)
|
|
||||||
|
|
||||||
class CMapperOperator_PositionsToOrientation
|
|
||||||
: public CMapperOperator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CMapperOperator_PositionsToOrientation()
|
|
||||||
: CMapperOperator("PositionsToOrientation", 3, 0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// CMapperOperator
|
|
||||||
public:
|
|
||||||
virtual QuatT Compute()
|
|
||||||
{
|
|
||||||
CMapperOperator* pOperator0 = GetPosition(0);
|
|
||||||
CMapperOperator* pOperator1 = GetPosition(1);
|
|
||||||
CMapperOperator* pOperator2 = GetPosition(2);
|
|
||||||
if (!pOperator0 || !pOperator1 || !pOperator2)
|
|
||||||
{
|
|
||||||
return QuatT(IDENTITY);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3 p0 = pOperator0->Compute().t;
|
|
||||||
Vec3 p1 = pOperator1->Compute().t;
|
|
||||||
Vec3 p2 = pOperator2->Compute().t;
|
|
||||||
|
|
||||||
Vec3 m = (p1 + p2) * 0.5f;
|
|
||||||
Vec3 y = (m - p0).GetNormalized();
|
|
||||||
Vec3 z = (p1 - p2).GetNormalized();
|
|
||||||
Vec3 x = y % z;
|
|
||||||
z = x % y;
|
|
||||||
|
|
||||||
Matrix33 m33;
|
|
||||||
m33.SetFromVectors(x, y, z);
|
|
||||||
QuatT result(IDENTITY);
|
|
||||||
result.q = Quat(m33);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
SkeletonMapperOperatorRegister(PositionsToOrientation, CMapperOperator_PositionsToOrientation)
|
|
||||||
@ -1,164 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef CRYINCLUDE_EDITOR_ANIMATION_SKELETONMAPPEROPERATOR_H
|
|
||||||
#define CRYINCLUDE_EDITOR_ANIMATION_SKELETONMAPPEROPERATOR_H
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include "../Util/Variable.h"
|
|
||||||
|
|
||||||
#undef GetClassName
|
|
||||||
|
|
||||||
#define SkeletonMapperOperatorRegister(name, className) \
|
|
||||||
class CMapperOperatorDesc_##name \
|
|
||||||
: public CMapperOperatorDesc \
|
|
||||||
{ \
|
|
||||||
public: \
|
|
||||||
CMapperOperatorDesc_##name() \
|
|
||||||
: CMapperOperatorDesc(#name) { } \
|
|
||||||
protected: \
|
|
||||||
virtual const char* GetName() { return #name; } \
|
|
||||||
virtual CMapperOperator* Create() { return new className(); } \
|
|
||||||
} mapperOperatorDesc__##name;
|
|
||||||
|
|
||||||
namespace Skeleton {
|
|
||||||
class CMapperOperator;
|
|
||||||
|
|
||||||
class CMapperOperatorDesc
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static uint32 GetCount() { return uint32(s_descs.size()); }
|
|
||||||
static const char* GetName(uint32 index) { return s_descs[index]->GetName(); }
|
|
||||||
static CMapperOperator* Create(uint32 index) { return s_descs[index]->Create(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
static std::vector<CMapperOperatorDesc*> s_descs;
|
|
||||||
|
|
||||||
public:
|
|
||||||
CMapperOperatorDesc(const char* name);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual const char* GetName() = 0;
|
|
||||||
virtual CMapperOperator* Create() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CMapperOperator
|
|
||||||
: public _reference_target_t
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
CMapperOperator(const char* className, uint32 positionCount, uint32 orientationCount);
|
|
||||||
~CMapperOperator();
|
|
||||||
|
|
||||||
public:
|
|
||||||
const char* GetClassName() { return m_className; }
|
|
||||||
|
|
||||||
uint32 GetPositionCount() const { return uint32(m_position.size()); }
|
|
||||||
void SetPosition(uint32 index, CMapperOperator* pOperator) { m_position[index] = pOperator; }
|
|
||||||
CMapperOperator* GetPosition(uint32 index) { return m_position[index]; }
|
|
||||||
|
|
||||||
uint32 GetOrientationCount() const { return uint32(m_orientation.size()); }
|
|
||||||
void SetOrientation(uint32 index, CMapperOperator* pOperator) { m_orientation[index] = pOperator; }
|
|
||||||
CMapperOperator* GetOrientation(uint32 index) { return m_orientation[index]; }
|
|
||||||
|
|
||||||
uint32 GetParameterCount() { return uint32(m_parameters.size()); }
|
|
||||||
IVariable* GetParameter(uint32 index) { return m_parameters[index]; }
|
|
||||||
|
|
||||||
bool IsOfClass(const char* className);
|
|
||||||
uint32 HasLinksOfClass(const char* className);
|
|
||||||
|
|
||||||
bool SerializeTo(XmlNodeRef& node);
|
|
||||||
bool SerializeFrom(XmlNodeRef& node);
|
|
||||||
|
|
||||||
bool SerializeWithLinksTo(XmlNodeRef& node);
|
|
||||||
bool SerializeWithLinksFrom(XmlNodeRef& node);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void AddParameter(IVariable& variable) { m_parameters.push_back(&variable); }
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual QuatT Compute() = 0;
|
|
||||||
|
|
||||||
private:
|
|
||||||
const char* m_className;
|
|
||||||
std::vector<_smart_ptr<CMapperOperator> > m_position;
|
|
||||||
std::vector<_smart_ptr<CMapperOperator> > m_orientation;
|
|
||||||
|
|
||||||
std::vector<IVariablePtr> m_parameters;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CMapperLocation
|
|
||||||
: public CMapperOperator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CMapperLocation()
|
|
||||||
: CMapperOperator("Location", 0, 0)
|
|
||||||
{
|
|
||||||
m_pName = new CVariable<CString>();
|
|
||||||
m_pName->SetName("name");
|
|
||||||
m_pName->SetFlags(m_pName->GetFlags() | IVariable::UI_INVISIBLE);
|
|
||||||
AddParameter(*m_pName);
|
|
||||||
|
|
||||||
m_pAxis = new CVariable<Vec3>();
|
|
||||||
m_pAxis->SetName("axis");
|
|
||||||
m_pAxis->SetLimits(-3.0f, +3.0f);
|
|
||||||
m_pAxis->Set(Vec3(1.0f, 2.0f, 3.0f));
|
|
||||||
AddParameter(*m_pAxis);
|
|
||||||
|
|
||||||
m_location = QuatT(IDENTITY);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
void SetName(const char* name) { m_pName->Set(name); }
|
|
||||||
CString GetName() const { CString s; m_pName->Get(s); return s; }
|
|
||||||
|
|
||||||
void SetLocation(const QuatT& location) { m_location = location; }
|
|
||||||
const QuatT& GetLocation() const { return m_location; }
|
|
||||||
|
|
||||||
// CMapperOperator
|
|
||||||
public:
|
|
||||||
virtual QuatT Compute()
|
|
||||||
{
|
|
||||||
Vec3 axis;
|
|
||||||
m_pAxis->Get(axis);
|
|
||||||
|
|
||||||
uint32 x = fabs_tpl(axis.x);
|
|
||||||
uint32 y = fabs_tpl(axis.y);
|
|
||||||
uint32 z = fabs_tpl(axis.z);
|
|
||||||
if (x < 1 || y < 1 || z < 1 ||
|
|
||||||
x > 3 || y > 3 || y > 3 ||
|
|
||||||
x == y || x == z || y == z)
|
|
||||||
{
|
|
||||||
return QuatT(IDENTITY);
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix33 matrix;
|
|
||||||
matrix.SetFromVectors(
|
|
||||||
m_location.q.GetColumn(x - 1) * f32(::sgn(axis.x)),
|
|
||||||
m_location.q.GetColumn(y - 1) * f32(::sgn(axis.y)),
|
|
||||||
m_location.q.GetColumn(z - 1) * f32(::sgn(axis.z)));
|
|
||||||
if (!matrix.IsOrthonormalRH(0.01f))
|
|
||||||
{
|
|
||||||
return QuatT(IDENTITY);
|
|
||||||
}
|
|
||||||
|
|
||||||
QuatT result = m_location;
|
|
||||||
result.q = Quat(matrix);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
CVariable<CString>* m_pName;
|
|
||||||
CVariable<Vec3>* m_pAxis;
|
|
||||||
|
|
||||||
QuatT m_location;
|
|
||||||
};
|
|
||||||
} // namespace Skeleton
|
|
||||||
|
|
||||||
#endif // CRYINCLUDE_EDITOR_ANIMATION_SKELETONMAPPEROPERATOR_H
|
|
||||||
@ -1,135 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "EditorDefs.h"
|
|
||||||
#include "ControlMRU.h"
|
|
||||||
|
|
||||||
IMPLEMENT_XTP_CONTROL(CControlMRU, CXTPControlRecentFileList)
|
|
||||||
|
|
||||||
bool CControlMRU::DoesFileExist(CString& sFileName)
|
|
||||||
{
|
|
||||||
return (_access(sFileName.GetBuffer(), 0) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CControlMRU::OnCalcDynamicSize(DWORD dwMode)
|
|
||||||
{
|
|
||||||
CRecentFileList* pRecentFileList = GetRecentFileList();
|
|
||||||
|
|
||||||
if (!pRecentFileList)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CString* pArrNames = pRecentFileList->m_arrNames;
|
|
||||||
|
|
||||||
assert(pArrNames != nullptr);
|
|
||||||
if (!pArrNames)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (m_nIndex + 1 < m_pControls->GetCount())
|
|
||||||
{
|
|
||||||
CXTPControl* pControl = m_pControls->GetAt(m_nIndex + 1);
|
|
||||||
assert(pControl);
|
|
||||||
if (pControl->GetID() >= GetFirstMruID()
|
|
||||||
&& pControl->GetID() <= GetFirstMruID() + pRecentFileList->m_nSize)
|
|
||||||
{
|
|
||||||
m_pControls->Remove(pControl);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_pParent->IsCustomizeMode())
|
|
||||||
{
|
|
||||||
m_dwHideFlags = 0;
|
|
||||||
SetEnabled(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pArrNames[0].IsEmpty())
|
|
||||||
{
|
|
||||||
SetCaption(CString(MAKEINTRESOURCE(IDS_NORECENTFILE_CAPTION)));
|
|
||||||
SetDescription("No recently opened files");
|
|
||||||
m_dwHideFlags = 0;
|
|
||||||
SetEnabled(false);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetCaption(CString(MAKEINTRESOURCE(IDS_RECENTFILE_CAPTION)));
|
|
||||||
SetDescription("Open this document");
|
|
||||||
}
|
|
||||||
|
|
||||||
m_dwHideFlags |= xtpHideGeneric;
|
|
||||||
|
|
||||||
CString sCurDir = (Path::GetEditingGameDataFolder() + "\\").c_str();
|
|
||||||
int nCurDir = sCurDir.GetLength();
|
|
||||||
|
|
||||||
CString strName;
|
|
||||||
CString strTemp;
|
|
||||||
int iLastValidMRU = 0;
|
|
||||||
|
|
||||||
for (int iMRU = 0; iMRU < pRecentFileList->m_nSize; iMRU++)
|
|
||||||
{
|
|
||||||
if (!pRecentFileList->GetDisplayName(strName, iMRU, sCurDir.GetBuffer(), nCurDir))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DoesFileExist(pArrNames[iMRU]))
|
|
||||||
{
|
|
||||||
CString sCurEntryDir = pArrNames[iMRU].Left(nCurDir);
|
|
||||||
|
|
||||||
if (sCurEntryDir.CompareNoCase(sCurDir) != 0)
|
|
||||||
{
|
|
||||||
//unavailable entry (wrong directory)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//invalid entry (not existing)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nId = iMRU + GetFirstMruID();
|
|
||||||
|
|
||||||
CXTPControl* pControl = m_pControls->Add(xtpControlButton, nId, _T(""), m_nIndex + iLastValidMRU + 1, true);
|
|
||||||
assert(pControl);
|
|
||||||
|
|
||||||
pControl->SetCaption(CXTPControlWindowList::ConstructCaption(strName, iLastValidMRU + 1));
|
|
||||||
pControl->SetFlags(xtpFlagManualUpdate);
|
|
||||||
pControl->SetBeginGroup(iLastValidMRU == 0 && m_nIndex != 0);
|
|
||||||
pControl->SetParameter(pArrNames[iMRU]);
|
|
||||||
|
|
||||||
CString sDescription = "Open file: " + pArrNames[iMRU];
|
|
||||||
pControl->SetDescription(sDescription);
|
|
||||||
|
|
||||||
if ((GetFlags() & xtpFlagWrapRow) && iMRU == 0)
|
|
||||||
{
|
|
||||||
pControl->SetFlags(pControl->GetFlags() | xtpFlagWrapRow);
|
|
||||||
}
|
|
||||||
|
|
||||||
++iLastValidMRU;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if no entry was valid, treat as none would exist
|
|
||||||
if (iLastValidMRU == 0)
|
|
||||||
{
|
|
||||||
SetCaption(CString(MAKEINTRESOURCE(IDS_NORECENTFILE_CAPTION)));
|
|
||||||
SetDescription("No recently opened files");
|
|
||||||
m_dwHideFlags = 0;
|
|
||||||
SetEnabled(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#ifndef CRYINCLUDE_EDITOR_CONTROLMRU_H
|
|
||||||
#define CRYINCLUDE_EDITOR_CONTROLMRU_H
|
|
||||||
|
|
||||||
class CControlMRU
|
|
||||||
: public CXTPControlRecentFileList
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
virtual void OnCalcDynamicSize(DWORD dwMode);
|
|
||||||
|
|
||||||
private:
|
|
||||||
DECLARE_XTP_CONTROL(CControlMRU)
|
|
||||||
bool DoesFileExist(CString& sFileName);
|
|
||||||
};
|
|
||||||
#endif // CRYINCLUDE_EDITOR_CONTROLMRU_H
|
|
||||||
@ -1,543 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "EditorDefs.h"
|
|
||||||
#include "ConsoleSCBMFC.h"
|
|
||||||
#include "PropertiesDialog.h"
|
|
||||||
#include "QtViewPaneManager.h"
|
|
||||||
#include "Core/QtEditorApplication.h"
|
|
||||||
|
|
||||||
#include <Controls/ui_ConsoleSCBMFC.h>
|
|
||||||
|
|
||||||
#include <QtUtil.h>
|
|
||||||
#include <QtUtilWin.h>
|
|
||||||
|
|
||||||
#include <QtCore/QStringList>
|
|
||||||
#include <QtCore/QScopedPointer>
|
|
||||||
#include <QtCore/QPoint>
|
|
||||||
#include <QtGui/QCursor>
|
|
||||||
#include <QtGui/QMouseEvent>
|
|
||||||
#include <QtWidgets/QStyle>
|
|
||||||
#include <QtWidgets/QStyleFactory>
|
|
||||||
#include <QtWidgets/QMenu>
|
|
||||||
#include <QtWidgets/QScrollBar>
|
|
||||||
#include <QtWidgets/QVBoxLayout>
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace MFC
|
|
||||||
{
|
|
||||||
|
|
||||||
static CPropertiesDialog* gPropertiesDlg = nullptr;
|
|
||||||
static CString mfc_popup_helper(HWND hwnd, int x, int y);
|
|
||||||
static CConsoleSCB* s_consoleSCB = nullptr;
|
|
||||||
|
|
||||||
static QString RemoveColorCode(const QString& text, int& iColorCode)
|
|
||||||
{
|
|
||||||
QString cleanString;
|
|
||||||
cleanString.reserve(text.size());
|
|
||||||
|
|
||||||
const int textSize = text.size();
|
|
||||||
for (int i = 0; i < textSize; ++i)
|
|
||||||
{
|
|
||||||
QChar c = text.at(i);
|
|
||||||
bool isLast = i == textSize - 1;
|
|
||||||
if (c == '$' && !isLast && text.at(i + 1).isDigit())
|
|
||||||
{
|
|
||||||
if (iColorCode == 0)
|
|
||||||
{
|
|
||||||
iColorCode = text.at(i + 1).digitValue();
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '\r' || c == '\n')
|
|
||||||
{
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanString.append(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
return cleanString;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConsoleLineEdit::ConsoleLineEdit(QWidget* parent)
|
|
||||||
: QLineEdit(parent)
|
|
||||||
, m_historyIndex(0)
|
|
||||||
, m_bReusedHistory(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConsoleLineEdit::mousePressEvent(QMouseEvent* ev)
|
|
||||||
{
|
|
||||||
if (ev->type() == QEvent::MouseButtonPress && ev->button() & Qt::RightButton)
|
|
||||||
{
|
|
||||||
Q_EMIT variableEditorRequested();
|
|
||||||
}
|
|
||||||
|
|
||||||
QLineEdit::mousePressEvent(ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConsoleLineEdit::mouseDoubleClickEvent(QMouseEvent* ev)
|
|
||||||
{
|
|
||||||
Q_EMIT variableEditorRequested();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ConsoleLineEdit::event(QEvent* ev)
|
|
||||||
{
|
|
||||||
// Tab key doesn't go to keyPressEvent(), must be processed here
|
|
||||||
|
|
||||||
if (ev->type() != QEvent::KeyPress)
|
|
||||||
{
|
|
||||||
return QLineEdit::event(ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
|
|
||||||
if (ke->key() != Qt::Key_Tab)
|
|
||||||
{
|
|
||||||
return QLineEdit::event(ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString inputStr = text();
|
|
||||||
QString newStr;
|
|
||||||
|
|
||||||
QStringList tokens = inputStr.split(" ");
|
|
||||||
inputStr = tokens.isEmpty() ? QString() : tokens.first();
|
|
||||||
IConsole* console = GetIEditor()->GetSystem()->GetIConsole();
|
|
||||||
|
|
||||||
const bool ctrlPressed = ke->modifiers() & Qt::ControlModifier;
|
|
||||||
CString cstring = QtUtil::ToCString(inputStr); // TODO: Use QString once the backend stops using QString
|
|
||||||
if (ctrlPressed)
|
|
||||||
{
|
|
||||||
newStr = QtUtil::ToString(console->AutoCompletePrev(cstring));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
newStr = QtUtil::ToString(console->ProcessCompletion(cstring));
|
|
||||||
newStr = QtUtil::ToString(console->AutoComplete(cstring));
|
|
||||||
|
|
||||||
if (newStr.isEmpty())
|
|
||||||
{
|
|
||||||
newStr = QtUtil::ToQString(GetIEditor()->GetCommandManager()->AutoComplete(QtUtil::ToString(newStr)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!newStr.isEmpty())
|
|
||||||
{
|
|
||||||
newStr += " ";
|
|
||||||
setText(newStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
deselect();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConsoleLineEdit::keyPressEvent(QKeyEvent* ev)
|
|
||||||
{
|
|
||||||
IConsole* console = GetIEditor()->GetSystem()->GetIConsole();
|
|
||||||
auto commandManager = GetIEditor()->GetCommandManager();
|
|
||||||
|
|
||||||
console->ResetAutoCompletion();
|
|
||||||
|
|
||||||
switch (ev->key())
|
|
||||||
{
|
|
||||||
case Qt::Key_Enter:
|
|
||||||
case Qt::Key_Return:
|
|
||||||
{
|
|
||||||
QString str = text().trimmed();
|
|
||||||
if (!str.isEmpty())
|
|
||||||
{
|
|
||||||
if (commandManager->IsRegistered(QtUtil::ToCString(str)))
|
|
||||||
{
|
|
||||||
commandManager->Execute(QtUtil::ToString(str));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CLogFile::WriteLine(QtUtil::ToCString(str));
|
|
||||||
GetIEditor()->GetSystem()->GetIConsole()->ExecuteString(QtUtil::ToCString(str));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a history command was reused directly via up arrow enter, do not reset history index
|
|
||||||
if (m_history.size() > 0 && m_historyIndex < m_history.size() && m_history[m_historyIndex] == str)
|
|
||||||
{
|
|
||||||
m_bReusedHistory = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_historyIndex = m_history.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not add the same string if it is the top of the stack, but allow duplicate entries otherwise
|
|
||||||
if (m_history.isEmpty() || m_history.back() != str)
|
|
||||||
{
|
|
||||||
m_history.push_back(str);
|
|
||||||
if (!m_bReusedHistory)
|
|
||||||
{
|
|
||||||
m_historyIndex = m_history.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_historyIndex = m_history.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
setText(QString());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Qt::Key_AsciiTilde: // ~
|
|
||||||
case Qt::Key_Agrave: // `
|
|
||||||
// disable log.
|
|
||||||
GetIEditor()->ShowConsole(false);
|
|
||||||
setText(QString());
|
|
||||||
m_historyIndex = m_history.size();
|
|
||||||
break;
|
|
||||||
case Qt::Key_Escape:
|
|
||||||
setText(QString());
|
|
||||||
m_historyIndex = m_history.size();
|
|
||||||
break;
|
|
||||||
case Qt::Key_Up:
|
|
||||||
DisplayHistory(false /*bForward*/);
|
|
||||||
break;
|
|
||||||
case Qt::Key_Down:
|
|
||||||
DisplayHistory(true /*bForward*/);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
QLineEdit::keyPressEvent(ev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConsoleLineEdit::DisplayHistory(bool bForward)
|
|
||||||
{
|
|
||||||
if (m_history.isEmpty())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Immediately after reusing a history entry, ensure up arrow re-displays command just used
|
|
||||||
if (!m_bReusedHistory || bForward)
|
|
||||||
{
|
|
||||||
m_historyIndex = static_cast<unsigned int>(clamp_tpl(static_cast<int>(m_historyIndex) + (bForward ? 1 : -1), 0, m_history.size() - 1));
|
|
||||||
}
|
|
||||||
m_bReusedHistory = false;
|
|
||||||
|
|
||||||
setText(m_history[m_historyIndex]);
|
|
||||||
}
|
|
||||||
|
|
||||||
ConsoleTextEdit::ConsoleTextEdit(QWidget* parent)
|
|
||||||
: QTextEdit(parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Lines CConsoleSCB::s_pendingLines;
|
|
||||||
|
|
||||||
CConsoleSCB::CConsoleSCB(QWidget* parent)
|
|
||||||
: QWidget(parent)
|
|
||||||
, ui(new Ui::ConsoleMFC())
|
|
||||||
, m_richEditTextLength(0)
|
|
||||||
, m_backgroundTheme(gSettings.consoleBackgroundColorTheme)
|
|
||||||
{
|
|
||||||
m_lines = s_pendingLines;
|
|
||||||
s_pendingLines.clear();
|
|
||||||
s_consoleSCB = this;
|
|
||||||
ui->setupUi(this);
|
|
||||||
setMinimumHeight(120);
|
|
||||||
|
|
||||||
// Setup the color table for the default (light) theme
|
|
||||||
m_colorTable << QColor(0, 0, 0)
|
|
||||||
<< QColor(0, 0, 0)
|
|
||||||
<< QColor(0, 0, 200) // blue
|
|
||||||
<< QColor(0, 200, 0) // green
|
|
||||||
<< QColor(200, 0, 0) // red
|
|
||||||
<< QColor(0, 200, 200) // cyan
|
|
||||||
<< QColor(128, 112, 0) // yellow
|
|
||||||
<< QColor(200, 0, 200) // red+blue
|
|
||||||
<< QColor(0x000080ff)
|
|
||||||
<< QColor(0x008f8f8f);
|
|
||||||
OnStyleSettingsChanged();
|
|
||||||
|
|
||||||
connect(ui->button, &QPushButton::clicked, this, &CConsoleSCB::showVariableEditor);
|
|
||||||
connect(ui->lineEdit, &MFC::ConsoleLineEdit::variableEditorRequested, this, &MFC::CConsoleSCB::showVariableEditor);
|
|
||||||
connect(Editor::EditorQtApplication::instance(), &Editor::EditorQtApplication::skinChanged, this, &MFC::CConsoleSCB::OnStyleSettingsChanged);
|
|
||||||
|
|
||||||
if (GetIEditor()->IsInConsolewMode())
|
|
||||||
{
|
|
||||||
// Attach / register edit box
|
|
||||||
//CLogFile::AttachEditBox(m_edit.GetSafeHwnd()); // FIXME
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CConsoleSCB::~CConsoleSCB()
|
|
||||||
{
|
|
||||||
s_consoleSCB = nullptr;
|
|
||||||
delete gPropertiesDlg;
|
|
||||||
gPropertiesDlg = nullptr;
|
|
||||||
CLogFile::AttachEditBox(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CConsoleSCB::RegisterViewClass()
|
|
||||||
{
|
|
||||||
QtViewOptions opts;
|
|
||||||
opts.preferedDockingArea = Qt::BottomDockWidgetArea;
|
|
||||||
opts.isDeletable = false;
|
|
||||||
opts.isStandard = true;
|
|
||||||
opts.showInMenu = true;
|
|
||||||
opts.builtInActionId = ID_VIEW_CONSOLEWINDOW;
|
|
||||||
opts.sendViewPaneNameBackToAmazonAnalyticsServers = true;
|
|
||||||
RegisterQtViewPane<CConsoleSCB>(GetIEditor(), LyViewPane::Console, LyViewPane::CategoryTools, opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CConsoleSCB::OnStyleSettingsChanged()
|
|
||||||
{
|
|
||||||
ui->button->setIcon(QIcon(QString(":/controls/img/cvar_dark.bmp")));
|
|
||||||
|
|
||||||
// Set the debug/warning text colors appropriately for the background theme
|
|
||||||
// (e.g. not have black text on black background)
|
|
||||||
QColor textColor = Qt::black;
|
|
||||||
m_backgroundTheme = gSettings.consoleBackgroundColorTheme;
|
|
||||||
if (m_backgroundTheme == SEditorSettings::ConsoleColorTheme::Dark)
|
|
||||||
{
|
|
||||||
textColor = Qt::white;
|
|
||||||
}
|
|
||||||
m_colorTable[0] = textColor;
|
|
||||||
m_colorTable[1] = textColor;
|
|
||||||
|
|
||||||
QColor bgColor;
|
|
||||||
if (!GetIEditor()->IsInConsolewMode() && CConsoleSCB::GetCreatedInstance() && m_backgroundTheme == SEditorSettings::ConsoleColorTheme::Dark)
|
|
||||||
{
|
|
||||||
bgColor = Qt::black;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bgColor = Qt::white;
|
|
||||||
}
|
|
||||||
|
|
||||||
ui->textEdit->setStyleSheet(QString("QTextEdit{ background: %1 }").arg(bgColor.name(QColor::HexRgb)));
|
|
||||||
|
|
||||||
// Clear out the console text when we change our background color since
|
|
||||||
// some of the previous text colors may not be appropriate for the
|
|
||||||
// new background color
|
|
||||||
ui->textEdit->clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CConsoleSCB::showVariableEditor()
|
|
||||||
{
|
|
||||||
const QPoint cursorPos = QCursor::pos();
|
|
||||||
CString str = mfc_popup_helper(0, cursorPos.x(), cursorPos.y());
|
|
||||||
if (!str.IsEmpty())
|
|
||||||
{
|
|
||||||
ui->lineEdit->setText(QtUtil::ToQString(str));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CConsoleSCB::SetInputFocus()
|
|
||||||
{
|
|
||||||
ui->lineEdit->setFocus();
|
|
||||||
ui->lineEdit->setText(QString());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CConsoleSCB::AddToConsole(const QString& text, bool bNewLine)
|
|
||||||
{
|
|
||||||
m_lines.push_back({ text, bNewLine });
|
|
||||||
FlushText();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CConsoleSCB::FlushText()
|
|
||||||
{
|
|
||||||
if (m_lines.empty())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store our current cursor in case we need to restore it, and check if
|
|
||||||
// the user has scrolled the text edit away from the bottom
|
|
||||||
const QTextCursor oldCursor = ui->textEdit->textCursor();
|
|
||||||
QScrollBar* scrollBar = ui->textEdit->verticalScrollBar();
|
|
||||||
const int oldScrollValue = scrollBar->value();
|
|
||||||
bool scrolledOffBottom = oldScrollValue != scrollBar->maximum();
|
|
||||||
|
|
||||||
ui->textEdit->moveCursor(QTextCursor::End);
|
|
||||||
QTextCursor textCursor = ui->textEdit->textCursor();
|
|
||||||
|
|
||||||
while (!m_lines.empty())
|
|
||||||
{
|
|
||||||
ConsoleLine line = m_lines.front();
|
|
||||||
m_lines.pop_front();
|
|
||||||
|
|
||||||
int iColor = 0;
|
|
||||||
QString text = MFC::RemoveColorCode(line.text, iColor);
|
|
||||||
if (iColor < 0 || iColor >= m_colorTable.size())
|
|
||||||
{
|
|
||||||
iColor = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.newLine)
|
|
||||||
{
|
|
||||||
text = QtUtil::trimRight(text);
|
|
||||||
text = "\r\n" + text;
|
|
||||||
}
|
|
||||||
|
|
||||||
QTextCharFormat format;
|
|
||||||
const QColor color(m_colorTable[iColor]);
|
|
||||||
format.setForeground(color);
|
|
||||||
|
|
||||||
if (iColor != 0)
|
|
||||||
{
|
|
||||||
format.setFontWeight(QFont::Bold);
|
|
||||||
}
|
|
||||||
|
|
||||||
textCursor.setCharFormat(format);
|
|
||||||
textCursor.insertText(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the user has selected some text in the text edit area or has scrolled
|
|
||||||
// away from the bottom, then restore the previous cursor and keep the scroll
|
|
||||||
// bar in the same location
|
|
||||||
if (oldCursor.hasSelection() || scrolledOffBottom)
|
|
||||||
{
|
|
||||||
ui->textEdit->setTextCursor(oldCursor);
|
|
||||||
scrollBar->setValue(oldScrollValue);
|
|
||||||
}
|
|
||||||
// Otherwise scroll to the bottom so the latest text can be seen
|
|
||||||
else
|
|
||||||
{
|
|
||||||
scrollBar->setValue(scrollBar->maximum());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QSize CConsoleSCB::minimumSizeHint() const
|
|
||||||
{
|
|
||||||
return QSize(-1, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
QSize CConsoleSCB::sizeHint() const
|
|
||||||
{
|
|
||||||
return QSize(100, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** static */
|
|
||||||
void CConsoleSCB::AddToPendingLines(const QString& text, bool bNewLine)
|
|
||||||
{
|
|
||||||
s_pendingLines.push_back({ text, bNewLine });
|
|
||||||
}
|
|
||||||
|
|
||||||
static CVarBlock* VarBlockFromConsoleVars()
|
|
||||||
{
|
|
||||||
IConsole* console = GetIEditor()->GetSystem()->GetIConsole();
|
|
||||||
std::vector<const char*> cmds;
|
|
||||||
cmds.resize(console->GetNumVars());
|
|
||||||
size_t cmdCount = console->GetSortedVars(&cmds[0], cmds.size());
|
|
||||||
|
|
||||||
CVarBlock* vb = new CVarBlock;
|
|
||||||
IVariable* pVariable = 0;
|
|
||||||
for (int i = 0; i < cmdCount; i++)
|
|
||||||
{
|
|
||||||
ICVar* pCVar = console->GetCVar(cmds[i]);
|
|
||||||
if (!pCVar)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int varType = pCVar->GetType();
|
|
||||||
|
|
||||||
switch (varType)
|
|
||||||
{
|
|
||||||
case CVAR_INT:
|
|
||||||
pVariable = new CVariable<int>();
|
|
||||||
pVariable->Set(pCVar->GetIVal());
|
|
||||||
break;
|
|
||||||
case CVAR_FLOAT:
|
|
||||||
pVariable = new CVariable<float>();
|
|
||||||
pVariable->Set(pCVar->GetFVal());
|
|
||||||
break;
|
|
||||||
case CVAR_STRING:
|
|
||||||
pVariable = new CVariable<CString>();
|
|
||||||
pVariable->Set(pCVar->GetString());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
pVariable->SetDescription(pCVar->GetHelp());
|
|
||||||
pVariable->SetName(cmds[i]);
|
|
||||||
|
|
||||||
if (pVariable)
|
|
||||||
{
|
|
||||||
vb->AddVariable(pVariable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return vb;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void OnConsoleVariableUpdated(IVariable* pVar)
|
|
||||||
{
|
|
||||||
if (!pVar)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CString varName = pVar->GetName();
|
|
||||||
ICVar* pCVar = GetIEditor()->GetSystem()->GetIConsole()->GetCVar(varName);
|
|
||||||
if (!pCVar)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (pVar->GetType() == IVariable::INT)
|
|
||||||
{
|
|
||||||
int val;
|
|
||||||
pVar->Get(val);
|
|
||||||
pCVar->Set(val);
|
|
||||||
}
|
|
||||||
else if (pVar->GetType() == IVariable::FLOAT)
|
|
||||||
{
|
|
||||||
float val;
|
|
||||||
pVar->Get(val);
|
|
||||||
pCVar->Set(val);
|
|
||||||
}
|
|
||||||
else if (pVar->GetType() == IVariable::STRING)
|
|
||||||
{
|
|
||||||
CString val;
|
|
||||||
pVar->Get(val);
|
|
||||||
pCVar->Set(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static CString mfc_popup_helper(HWND hwnd, int x, int y)
|
|
||||||
{
|
|
||||||
IConsole* console = GetIEditor()->GetSystem()->GetIConsole();
|
|
||||||
|
|
||||||
TSmartPtr<CVarBlock> vb = VarBlockFromConsoleVars();
|
|
||||||
XmlNodeRef node;
|
|
||||||
if (!gPropertiesDlg)
|
|
||||||
{
|
|
||||||
gPropertiesDlg = new CPropertiesDialog("Console Variables", node, AfxGetMainWnd(), true);
|
|
||||||
}
|
|
||||||
if (!gPropertiesDlg->m_hWnd)
|
|
||||||
{
|
|
||||||
gPropertiesDlg->Create(CPropertiesDialog::IDD, AfxGetMainWnd());
|
|
||||||
gPropertiesDlg->SetUpdateCallback(AZStd::bind(OnConsoleVariableUpdated, AZStd::placeholders::_1));
|
|
||||||
}
|
|
||||||
gPropertiesDlg->ShowWindow(SW_SHOW);
|
|
||||||
gPropertiesDlg->BringWindowToTop();
|
|
||||||
gPropertiesDlg->GetPropertyCtrl()->AddVarBlock(vb);
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
CConsoleSCB* CConsoleSCB::GetCreatedInstance()
|
|
||||||
{
|
|
||||||
return s_consoleSCB;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace MFC
|
|
||||||
|
|
||||||
#include <Controls/moc_ConsoleSCBMFC.cpp>
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef CRYINCLUDE_EDITOR_UTIL_IXMLHISTORYMANAGER_H
|
|
||||||
#define CRYINCLUDE_EDITOR_UTIL_IXMLHISTORYMANAGER_H
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
// Helper class to handle Redo/Undo on set of Xml nodes
|
|
||||||
struct IXmlUndoEventHandler
|
|
||||||
{
|
|
||||||
virtual bool SaveToXml(XmlNodeRef& xmlNode) = 0;
|
|
||||||
virtual bool LoadFromXml(const XmlNodeRef& xmlNode) = 0;
|
|
||||||
virtual bool ReloadFromXml(const XmlNodeRef& xmlNode) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IXmlHistoryEventListener
|
|
||||||
{
|
|
||||||
enum EHistoryEventType
|
|
||||||
{
|
|
||||||
eHET_HistoryDeleted,
|
|
||||||
eHET_HistoryCleared,
|
|
||||||
eHET_HistorySaved,
|
|
||||||
|
|
||||||
eHET_VersionChanged,
|
|
||||||
eHET_VersionAdded,
|
|
||||||
|
|
||||||
eHET_HistoryInvalidate,
|
|
||||||
|
|
||||||
eHET_HistoryGroupChanged,
|
|
||||||
eHET_HistoryGroupAdded,
|
|
||||||
eHET_HistoryGroupRemoved,
|
|
||||||
};
|
|
||||||
virtual void OnEvent(EHistoryEventType event, void* pData = nullptr) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IXmlHistoryView
|
|
||||||
{
|
|
||||||
virtual bool LoadXml(int typeId, const XmlNodeRef& xmlNode, IXmlUndoEventHandler*& pUndoEventHandler, uint32 userindex) = 0;
|
|
||||||
virtual void UnloadXml(int typeId) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IXmlHistoryManager
|
|
||||||
{
|
|
||||||
// Undo/Redo
|
|
||||||
virtual bool Undo() = 0;
|
|
||||||
virtual bool Redo() = 0;
|
|
||||||
virtual bool Goto(int historyNum) = 0;
|
|
||||||
virtual void RecordUndo(IXmlUndoEventHandler* pEventHandler, const char* desc) = 0;
|
|
||||||
virtual void UndoEventHandlerDestroyed(IXmlUndoEventHandler* pEventHandler, uint32 typeId = 0, bool destoryForever = false) = 0;
|
|
||||||
virtual void RestoreUndoEventHandler(IXmlUndoEventHandler* pEventHandler, uint32 typeId) = 0;
|
|
||||||
|
|
||||||
virtual void RegisterEventListener(IXmlHistoryEventListener* pEventListener) = 0;
|
|
||||||
virtual void UnregisterEventListener(IXmlHistoryEventListener* pEventListener) = 0;
|
|
||||||
|
|
||||||
// History
|
|
||||||
virtual void ClearHistory(bool flagAsSaved = false) = 0;
|
|
||||||
virtual int GetVersionCount() const = 0;
|
|
||||||
virtual const string& GetVersionDesc(int number) const = 0;
|
|
||||||
virtual int GetCurrentVersionNumber() const = 0;
|
|
||||||
|
|
||||||
// Views
|
|
||||||
virtual void RegisterView(IXmlHistoryView* pView) = 0;
|
|
||||||
virtual void UnregisterView(IXmlHistoryView* pView) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CRYINCLUDE_EDITOR_UTIL_IXMLHISTORYMANAGER_H
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// Description : Utility class to help in STL algorithms on containers with
|
|
||||||
// CStrings when intending to use case insensitive searches or sorting for
|
|
||||||
// example.
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef CRYINCLUDE_EDITOR_UTIL_STRINGNOCASEPREDICATE_H
|
|
||||||
#define CRYINCLUDE_EDITOR_UTIL_STRINGNOCASEPREDICATE_H
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
/*
|
|
||||||
Utility class to help in STL algorithms on containers with CStrings
|
|
||||||
when intending to use case insensitive searches or sorting for example.
|
|
||||||
|
|
||||||
e.g.
|
|
||||||
std::vector< CString > v;
|
|
||||||
...
|
|
||||||
std::sort( v.begin(), v.end(), CStringNoCasePredicate::LessThan() );
|
|
||||||
std::find_if( v.begin(), v.end(), CStringNoCasePredicate::Equal( stringImLookingFor ) );
|
|
||||||
*/
|
|
||||||
class CStringNoCasePredicate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
struct Equal
|
|
||||||
{
|
|
||||||
Equal(const QString& referenceString)
|
|
||||||
: m_referenceString(referenceString)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator() (const QString& arg) const
|
|
||||||
{
|
|
||||||
return (m_referenceString.compare(arg, Qt::CaseInsensitive) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const QString& m_referenceString;
|
|
||||||
};
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
struct LessThan
|
|
||||||
{
|
|
||||||
bool operator() (const QString& arg1, const QString& arg2) const
|
|
||||||
{
|
|
||||||
return (arg1.CompareNoCase(arg2) < 0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif // CRYINCLUDE_EDITOR_UTIL_STRINGNOCASEPREDICATE_H
|
|
||||||
@ -1,875 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "EditorDefs.h"
|
|
||||||
|
|
||||||
#include "XmlHistoryManager.h"
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
SXmlHistory::SXmlHistory(CXmlHistoryManager* pManager, const XmlNodeRef& xmlBaseVersion, uint32 typeId)
|
|
||||||
: m_pManager(pManager)
|
|
||||||
, m_typeId(typeId)
|
|
||||||
, m_DeletedVersion(-1)
|
|
||||||
, m_SavedVersion(-1)
|
|
||||||
{
|
|
||||||
int newVersionNumber = m_pManager->GetCurrentVersionNumber() + (m_pManager->IsPreparedForNextVersion() ? 1 : 0);
|
|
||||||
m_xmlVersionList[ newVersionNumber ] = xmlBaseVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
void SXmlHistory::AddToHistory(const XmlNodeRef& newXmlVersion)
|
|
||||||
{
|
|
||||||
int newVersionNumber = m_pManager->IncrementVersion(this);
|
|
||||||
m_xmlVersionList[ newVersionNumber ] = newXmlVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
const XmlNodeRef& SXmlHistory::Undo(bool* bVersionExist)
|
|
||||||
{
|
|
||||||
m_pManager->Undo();
|
|
||||||
return GetCurrentVersion(bVersionExist);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
const XmlNodeRef& SXmlHistory::Redo()
|
|
||||||
{
|
|
||||||
m_pManager->Redo();
|
|
||||||
return GetCurrentVersion();
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
const XmlNodeRef& SXmlHistory::GetCurrentVersion(bool* bVersionExist, int* iVersionNumber) const
|
|
||||||
{
|
|
||||||
int currentVersion = m_pManager->GetCurrentVersionNumber();
|
|
||||||
|
|
||||||
TXmlVersionMap::const_iterator it = m_xmlVersionList.begin();
|
|
||||||
TXmlVersionMap::const_iterator previt = m_xmlVersionList.begin();
|
|
||||||
while (it != m_xmlVersionList.end())
|
|
||||||
{
|
|
||||||
if (it->first > currentVersion)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
previt = it;
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bVersionExist)
|
|
||||||
{
|
|
||||||
*bVersionExist = currentVersion >= m_xmlVersionList.begin()->first;
|
|
||||||
}
|
|
||||||
if (iVersionNumber)
|
|
||||||
{
|
|
||||||
*iVersionNumber = previt->first;
|
|
||||||
}
|
|
||||||
|
|
||||||
return previt->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool SXmlHistory::IsModified() const
|
|
||||||
{
|
|
||||||
int currVersion;
|
|
||||||
GetCurrentVersion(nullptr, &currVersion);
|
|
||||||
return m_SavedVersion != currVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
void SXmlHistory::FlagAsDeleted()
|
|
||||||
{
|
|
||||||
assert(m_pManager->IsPreparedForNextVersion());
|
|
||||||
m_DeletedVersion = m_pManager->GetCurrentVersionNumber() + 1;
|
|
||||||
m_SavedVersion = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
void SXmlHistory::FlagAsSaved()
|
|
||||||
{
|
|
||||||
if (Exist())
|
|
||||||
{
|
|
||||||
int currVersion;
|
|
||||||
GetCurrentVersion(nullptr, &currVersion);
|
|
||||||
m_SavedVersion = currVersion;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool SXmlHistory::Exist() const
|
|
||||||
{
|
|
||||||
// int currentVersion = m_pManager->GetCurrentVersionNumber();
|
|
||||||
// bool deleted = m_DeletedVersion != -1 && currentVersion >= m_DeletedVersion;
|
|
||||||
// bool exist = currentVersion >= m_xmlVersionList.begin()->first;
|
|
||||||
// return !deleted && exist;
|
|
||||||
int currentVersion = m_pManager->GetCurrentVersionNumber();
|
|
||||||
return currentVersion >= m_xmlVersionList.begin()->first && (m_DeletedVersion == -1 || currentVersion < m_DeletedVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
void SXmlHistory::ClearRedo()
|
|
||||||
{
|
|
||||||
int currentVersion = m_pManager->GetCurrentVersionNumber();
|
|
||||||
if (m_DeletedVersion > currentVersion + (m_pManager->IsPreparedForNextVersion() ? 1 : 0))
|
|
||||||
{
|
|
||||||
m_DeletedVersion = -1;
|
|
||||||
}
|
|
||||||
TXmlVersionMap::iterator it = m_xmlVersionList.begin();
|
|
||||||
for (; it != m_xmlVersionList.end(); ++it)
|
|
||||||
{
|
|
||||||
if (it->first > currentVersion)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (it != m_xmlVersionList.end())
|
|
||||||
{
|
|
||||||
++it;
|
|
||||||
while (it != m_xmlVersionList.end())
|
|
||||||
{
|
|
||||||
m_xmlVersionList.erase(it++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
void SXmlHistory::ClearHistory(bool flagAsSaved)
|
|
||||||
{
|
|
||||||
bool wasModified = !flagAsSaved && IsModified();
|
|
||||||
m_DeletedVersion = Exist() ? -1 : 0;
|
|
||||||
ClearRedo();
|
|
||||||
XmlNodeRef latest = m_xmlVersionList.rbegin()->second;
|
|
||||||
m_xmlVersionList.clear();
|
|
||||||
m_xmlVersionList[ 0 ] = latest;
|
|
||||||
m_SavedVersion = wasModified ? -1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
SXmlHistoryGroup::SXmlHistoryGroup(CXmlHistoryManager* pManager, uint32 typeId)
|
|
||||||
: m_pManager(pManager)
|
|
||||||
, m_typeId(typeId)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
SXmlHistory* SXmlHistoryGroup::GetHistory(int index) const
|
|
||||||
{
|
|
||||||
THistoryList::const_iterator it = m_List.begin();
|
|
||||||
while (index > 0 && it != m_List.end())
|
|
||||||
{
|
|
||||||
++it;
|
|
||||||
if ((*it)->Exist())
|
|
||||||
{
|
|
||||||
--index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return it != m_List.end() ? *it : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
int SXmlHistoryGroup::GetHistoryCount() const
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
for (THistoryList::const_iterator it = m_List.begin(); it != m_List.end(); ++it)
|
|
||||||
{
|
|
||||||
if ((*it)->Exist())
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
SXmlHistory* SXmlHistoryGroup::GetHistoryByTypeId(uint32 typeId, int index /*= 0*/) const
|
|
||||||
{
|
|
||||||
for (int i = 0; i < GetHistoryCount(); ++i)
|
|
||||||
{
|
|
||||||
SXmlHistory* pHistory = GetHistory(i);
|
|
||||||
if (pHistory->GetTypeId() == typeId)
|
|
||||||
{
|
|
||||||
index--;
|
|
||||||
}
|
|
||||||
if (index == -1)
|
|
||||||
{
|
|
||||||
return pHistory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
int SXmlHistoryGroup::GetHistoryCountByTypeId(uint32 typeId) const
|
|
||||||
{
|
|
||||||
int res = 0;
|
|
||||||
for (int i = 0; i < GetHistoryCount(); ++i)
|
|
||||||
{
|
|
||||||
if (GetHistory(i)->GetTypeId() == typeId)
|
|
||||||
{
|
|
||||||
res++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
int SXmlHistoryGroup::CreateXmlHistory(uint32 typeId, const XmlNodeRef& xmlBaseVersion)
|
|
||||||
{
|
|
||||||
if (m_pManager)
|
|
||||||
{
|
|
||||||
m_List.push_back(m_pManager->CreateXmlHistory(typeId, xmlBaseVersion));
|
|
||||||
return m_List.size() - 1;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
int SXmlHistoryGroup::GetHistoryIndex(const SXmlHistory* pHistory) const
|
|
||||||
{
|
|
||||||
int index = 0;
|
|
||||||
for (THistoryList::const_iterator it = m_List.begin(); it != m_List.end(); ++it)
|
|
||||||
{
|
|
||||||
if (*it == pHistory)
|
|
||||||
{
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
CXmlHistoryManager::CXmlHistoryManager()
|
|
||||||
: m_CurrentVersion(0)
|
|
||||||
, m_LatestVersion(0)
|
|
||||||
, m_pExclusiveListener(nullptr)
|
|
||||||
, m_RecordNextVersion(false)
|
|
||||||
, m_pExActiveGroup(nullptr)
|
|
||||||
, m_bIsActiveGroupEx(false)
|
|
||||||
{
|
|
||||||
m_pNullGroup = new SXmlHistoryGroup(this, (uint32) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
CXmlHistoryManager::~CXmlHistoryManager()
|
|
||||||
{
|
|
||||||
delete m_pNullGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool CXmlHistoryManager::Undo()
|
|
||||||
{
|
|
||||||
if (m_CurrentVersion > 0)
|
|
||||||
{
|
|
||||||
int prevVersion = m_CurrentVersion;
|
|
||||||
const SXmlHistoryGroup* pPrevCurrGroup = GetActiveGroup();
|
|
||||||
m_CurrentVersion--;
|
|
||||||
ReloadCurrentVersion(pPrevCurrGroup, prevVersion);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool CXmlHistoryManager::Redo()
|
|
||||||
{
|
|
||||||
if (m_CurrentVersion < m_LatestVersion)
|
|
||||||
{
|
|
||||||
int prevVersion = m_CurrentVersion;
|
|
||||||
const SXmlHistoryGroup* pPrevCurrGroup = GetActiveGroup();
|
|
||||||
m_CurrentVersion++;
|
|
||||||
ReloadCurrentVersion(pPrevCurrGroup, prevVersion);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool CXmlHistoryManager::Goto(int historyNum)
|
|
||||||
{
|
|
||||||
if (historyNum >= 0 && historyNum <= m_LatestVersion)
|
|
||||||
{
|
|
||||||
int prevVersion = m_CurrentVersion;
|
|
||||||
const SXmlHistoryGroup* pPrevCurrGroup = GetActiveGroup();
|
|
||||||
m_CurrentVersion = historyNum;
|
|
||||||
ReloadCurrentVersion(pPrevCurrGroup, prevVersion);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::RecordUndo(IXmlUndoEventHandler* pEventHandler, const char* desc)
|
|
||||||
{
|
|
||||||
ClearRedo();
|
|
||||||
SXmlHistory* pChangedXml = m_UndoEventHandlerMap[ pEventHandler ].CurrentData;
|
|
||||||
assert(pChangedXml);
|
|
||||||
|
|
||||||
XmlNodeRef newData = gEnv->pSystem->CreateXmlNode();
|
|
||||||
#if !defined(NDEBUG)
|
|
||||||
bool bRes =
|
|
||||||
#endif
|
|
||||||
pEventHandler->SaveToXml(newData);
|
|
||||||
assert(bRes);
|
|
||||||
|
|
||||||
TXmlHistotyGroupPtrList activeGroups = m_HistoryInfoMap[ m_CurrentVersion ].ActiveGroups;
|
|
||||||
|
|
||||||
pChangedXml->AddToHistory(newData);
|
|
||||||
m_UndoEventHandlerMap[ pEventHandler ].HistoryData[ m_CurrentVersion ] = pChangedXml;
|
|
||||||
m_HistoryInfoMap[ m_CurrentVersion ].HistoryDescription = desc;
|
|
||||||
m_HistoryInfoMap[ m_CurrentVersion ].IsNullUndo = false;
|
|
||||||
m_HistoryInfoMap[ m_CurrentVersion ].ActiveGroups = activeGroups;
|
|
||||||
m_HistoryInfoMap[ m_CurrentVersion ].HistoryInvalidated = false;
|
|
||||||
NotifyUndoEventListener(IXmlHistoryEventListener::eHET_VersionAdded);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::UndoEventHandlerDestroyed(IXmlUndoEventHandler* pEventHandler, uint32 typeId /*= 0*/, bool destoryForever /*= false*/)
|
|
||||||
{
|
|
||||||
if (destoryForever)
|
|
||||||
{
|
|
||||||
UnregisterUndoEventHandler(pEventHandler);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_InvalidHandlerMap[typeId] = pEventHandler;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::RestoreUndoEventHandler(IXmlUndoEventHandler* pEventHandler, uint32 typeId)
|
|
||||||
{
|
|
||||||
TInvalidUndoEventListener::iterator it = m_InvalidHandlerMap.find(typeId);
|
|
||||||
if (it != m_InvalidHandlerMap.end())
|
|
||||||
{
|
|
||||||
IXmlUndoEventHandler* pLastHandler = it->second;
|
|
||||||
TUndoEventHandlerMap::iterator lastit = m_UndoEventHandlerMap.find(pLastHandler);
|
|
||||||
if (lastit != m_UndoEventHandlerMap.end())
|
|
||||||
{
|
|
||||||
m_UndoEventHandlerMap[pEventHandler] = lastit->second;
|
|
||||||
m_UndoEventHandlerMap.erase(lastit);
|
|
||||||
}
|
|
||||||
m_InvalidHandlerMap.erase(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::RegisterEventListener(IXmlHistoryEventListener* pEventListener)
|
|
||||||
{
|
|
||||||
stl::push_back_unique(m_EventListener, pEventListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::UnregisterEventListener(IXmlHistoryEventListener* pEventListener)
|
|
||||||
{
|
|
||||||
m_EventListener.remove(pEventListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::PrepareForNextVersion()
|
|
||||||
{
|
|
||||||
assert(!m_RecordNextVersion);
|
|
||||||
m_RecordNextVersion = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::RecordNextVersion(SXmlHistory* pHistory, XmlNodeRef newData, const char* undoDesc /*= nullptr*/)
|
|
||||||
{
|
|
||||||
assert(m_RecordNextVersion);
|
|
||||||
RegisterUndoEventHandler(this, pHistory);
|
|
||||||
m_newHistoryData = newData;
|
|
||||||
RecordUndo(this, undoDesc ? undoDesc : "<UNDEFINED>");
|
|
||||||
m_RecordNextVersion = false;
|
|
||||||
m_HistoryInfoMap[ m_CurrentVersion ].HistoryInvalidated = true;
|
|
||||||
UnregisterUndoEventHandler(this);
|
|
||||||
SetActiveGroupInt(GetActiveGroup());
|
|
||||||
NotifyUndoEventListener(IXmlHistoryEventListener::eHET_HistoryInvalidate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool CXmlHistoryManager::SaveToXml(XmlNodeRef& xmlNode)
|
|
||||||
{
|
|
||||||
assert(m_newHistoryData);
|
|
||||||
xmlNode = m_newHistoryData;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::ClearHistory(bool flagAsSaved)
|
|
||||||
{
|
|
||||||
TXmlHistotyGroupPtrList activeGropus = m_HistoryInfoMap[ m_CurrentVersion ].ActiveGroups;
|
|
||||||
for (TXmlHistoryList::iterator it = m_XmlHistoryList.begin(); it != m_XmlHistoryList.end(); ++it)
|
|
||||||
{
|
|
||||||
it->ClearHistory(flagAsSaved);
|
|
||||||
}
|
|
||||||
|
|
||||||
SetActiveGroup(nullptr);
|
|
||||||
|
|
||||||
m_CurrentVersion = 0;
|
|
||||||
m_LatestVersion = 0;
|
|
||||||
|
|
||||||
m_UndoEventHandlerMap.clear();
|
|
||||||
m_HistoryInfoMap.clear();
|
|
||||||
|
|
||||||
m_HistoryInfoMap[ 0 ].HistoryDescription = "New History";
|
|
||||||
m_HistoryInfoMap[ 0 ].ActiveGroups = activeGropus;
|
|
||||||
NotifyUndoEventListener(IXmlHistoryEventListener::eHET_HistoryCleared);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
const string& CXmlHistoryManager::GetVersionDesc(int number) const
|
|
||||||
{
|
|
||||||
THistoryInfoMap::const_iterator it = m_HistoryInfoMap.find(number);
|
|
||||||
if (it != m_HistoryInfoMap.end())
|
|
||||||
{
|
|
||||||
return it->second.HistoryDescription;
|
|
||||||
}
|
|
||||||
|
|
||||||
static string undef("UNDEFINED");
|
|
||||||
return undef;
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::RegisterView(IXmlHistoryView* pView)
|
|
||||||
{
|
|
||||||
stl::push_back_unique(m_Views, pView);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::UnregisterView(IXmlHistoryView* pView)
|
|
||||||
{
|
|
||||||
m_Views.remove(pView);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
SXmlHistoryGroup* CXmlHistoryManager::CreateXmlGroup(uint32 typeId)
|
|
||||||
{
|
|
||||||
m_Groups.push_back(SXmlHistoryGroup(this, typeId));
|
|
||||||
return &(*m_Groups.rbegin());
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::AddXmlGroup(const SXmlHistoryGroup* pGroup, const char* undoDesc /*= nullptr*/)
|
|
||||||
{
|
|
||||||
RecordUndoInternal(undoDesc ? undoDesc : "New XML Group added");
|
|
||||||
m_HistoryInfoMap[ m_CurrentVersion ].ActiveGroups.push_back(pGroup);
|
|
||||||
NotifyUndoEventListener(IXmlHistoryEventListener::eHET_HistoryGroupAdded, (void*)pGroup);
|
|
||||||
}
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::RemoveXmlGroup(const SXmlHistoryGroup* pGroup, const char* undoDesc /*= nullptr*/)
|
|
||||||
{
|
|
||||||
bool unload = m_HistoryInfoMap[ m_CurrentVersion ].CurrGroup == pGroup;
|
|
||||||
RecordUndoInternal(undoDesc ? undoDesc : "XML Group deleted");
|
|
||||||
TXmlHistotyGroupPtrList& list = m_HistoryInfoMap[ m_CurrentVersion ].ActiveGroups;
|
|
||||||
stl::find_and_erase(list, pGroup);
|
|
||||||
if (unload)
|
|
||||||
{
|
|
||||||
SetActiveGroupInt(nullptr);
|
|
||||||
}
|
|
||||||
m_HistoryInfoMap[ m_CurrentVersion ].CurrGroup = m_pNullGroup;
|
|
||||||
NotifyUndoEventListener(IXmlHistoryEventListener::eHET_HistoryGroupRemoved, (void*)pGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::SetActiveGroup(const SXmlHistoryGroup* pGroup, const char* displayName /*= nullptr*/, const TGroupIndexMap& groupIndex /*= TGroupIndexMap()*/, bool setExternal /*= false*/)
|
|
||||||
{
|
|
||||||
TGroupIndexMap userIndex;
|
|
||||||
const SXmlHistoryGroup* pActiveGroup = GetActiveGroup(userIndex);
|
|
||||||
if (pGroup != pActiveGroup || userIndex != groupIndex || setExternal)
|
|
||||||
{
|
|
||||||
const bool isEx = m_CurrentVersion != m_LatestVersion || setExternal;
|
|
||||||
m_pExActiveGroup = const_cast<SXmlHistoryGroup*>(pGroup);
|
|
||||||
m_ExCurrentIndex = groupIndex;
|
|
||||||
m_bIsActiveGroupEx = true;
|
|
||||||
SetActiveGroupInt(pGroup, displayName, !isEx, groupIndex);
|
|
||||||
m_bIsActiveGroupEx = isEx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CXmlHistoryManager::SetActiveGroupInt(const SXmlHistoryGroup* pGroup, const char* displayName /*= nullptr*/, bool bRecordNullUndo /*= false*/, const TGroupIndexMap& groupIndex /*= TGroupIndexMap()*/)
|
|
||||||
{
|
|
||||||
UnloadInt();
|
|
||||||
|
|
||||||
TEventHandlerList eventHandler;
|
|
||||||
string undoDesc;
|
|
||||||
|
|
||||||
if (pGroup)
|
|
||||||
{
|
|
||||||
for (TViews::iterator it = m_Views.begin(); it != m_Views.end(); ++it)
|
|
||||||
{
|
|
||||||
IXmlHistoryView* pView = *it;
|
|
||||||
|
|
||||||
std::map<uint32, int> userIndexCount;
|
|
||||||
|
|
||||||
for (SXmlHistoryGroup::THistoryList::const_iterator history = pGroup->m_List.begin(); history != pGroup->m_List.end(); ++history)
|
|
||||||
{
|
|
||||||
std::map<uint32, int>::iterator it2 = userIndexCount.find((*history)->GetTypeId());
|
|
||||||
if (it2 == userIndexCount.end())
|
|
||||||
{
|
|
||||||
userIndexCount[ (*history)->GetTypeId() ] = 0;
|
|
||||||
}
|
|
||||||
uint32 userindex = userIndexCount[ (*history)->GetTypeId() ];
|
|
||||||
IXmlUndoEventHandler* pEventHandler = nullptr;
|
|
||||||
TGroupIndexMap::const_iterator indexIter = groupIndex.find((*history)->GetTypeId());
|
|
||||||
if (indexIter == groupIndex.end() || indexIter->second == userindex)
|
|
||||||
{
|
|
||||||
if ((*history)->Exist())
|
|
||||||
{
|
|
||||||
if (pView->LoadXml((*history)->GetTypeId(), (*history)->GetCurrentVersion(), pEventHandler, userindex))
|
|
||||||
{
|
|
||||||
if (pEventHandler)
|
|
||||||
{
|
|
||||||
m_UndoHandlerViewMap[ pEventHandler ] = pView;
|
|
||||||
RegisterUndoEventHandler(pEventHandler, *history);
|
|
||||||
eventHandler.push_back(pEventHandler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((*history)->Exist())
|
|
||||||
{
|
|
||||||
userIndexCount[ (*history)->GetTypeId() ]++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
undoDesc.Format("Changed View to \"%s\"", displayName ? displayName : "UNDEFINED");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
undoDesc = "Unloaded Views";
|
|
||||||
for (TUndoEventHandlerMap::iterator it = m_UndoEventHandlerMap.begin(); it != m_UndoEventHandlerMap.end(); ++it)
|
|
||||||
{
|
|
||||||
eventHandler.push_back(it->first);
|
|
||||||
}
|
|
||||||
pGroup = m_pNullGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bRecordNullUndo)
|
|
||||||
{
|
|
||||||
RecordNullUndo(eventHandler, undoDesc.c_str());
|
|
||||||
m_HistoryInfoMap[ m_CurrentVersion ].CurrGroup = pGroup;
|
|
||||||
m_HistoryInfoMap[ m_CurrentVersion ].CurrUserIndex = groupIndex;
|
|
||||||
}
|
|
||||||
NotifyUndoEventListener(IXmlHistoryEventListener::eHET_HistoryGroupChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
const SXmlHistoryGroup* CXmlHistoryManager::GetActiveGroup() const
|
|
||||||
{
|
|
||||||
TGroupIndexMap userIndex;
|
|
||||||
return GetActiveGroup(userIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
const SXmlHistoryGroup* CXmlHistoryManager::GetActiveGroup(TGroupIndexMap& currUserIndex /*out*/) const
|
|
||||||
{
|
|
||||||
if (m_bIsActiveGroupEx)
|
|
||||||
{
|
|
||||||
currUserIndex = m_ExCurrentIndex;
|
|
||||||
return m_pExActiveGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
int currVersion = m_CurrentVersion;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
THistoryInfoMap::const_iterator it = m_HistoryInfoMap.find(currVersion);
|
|
||||||
if (it != m_HistoryInfoMap.end())
|
|
||||||
{
|
|
||||||
const SXmlHistoryGroup* pGroup = it->second.CurrGroup;
|
|
||||||
if (it != m_HistoryInfoMap.end() && pGroup)
|
|
||||||
{
|
|
||||||
currUserIndex = it->second.CurrUserIndex;
|
|
||||||
return pGroup == m_pNullGroup ? nullptr : pGroup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
currVersion--;
|
|
||||||
} while (currVersion >= 0);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
SXmlHistory* CXmlHistoryManager::CreateXmlHistory(uint32 typeId, const XmlNodeRef& xmlBaseVersion)
|
|
||||||
{
|
|
||||||
m_XmlHistoryList.push_back(SXmlHistory(this, xmlBaseVersion, typeId));
|
|
||||||
return &(*m_XmlHistoryList.rbegin());
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::DeleteXmlHistory(const SXmlHistory* pXmlHistry)
|
|
||||||
{
|
|
||||||
for (TXmlHistoryList::iterator it = m_XmlHistoryList.begin(); it != m_XmlHistoryList.end(); ++it)
|
|
||||||
{
|
|
||||||
if (&(*it) == pXmlHistry)
|
|
||||||
{
|
|
||||||
m_XmlHistoryList.erase(it);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::UnloadInt()
|
|
||||||
{
|
|
||||||
for (TViews::iterator it = m_Views.begin(); it != m_Views.end(); ++it)
|
|
||||||
{
|
|
||||||
IXmlHistoryView* pView = *it;
|
|
||||||
pView->UnloadXml(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
template< class T >
|
|
||||||
void ClearAfterVersion(T& container, int version)
|
|
||||||
{
|
|
||||||
auto foundit = container.end();
|
|
||||||
do
|
|
||||||
{
|
|
||||||
auto it = container.find(version);
|
|
||||||
if (it != container.end())
|
|
||||||
{
|
|
||||||
foundit = it;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
version--;
|
|
||||||
} while (version >= 0);
|
|
||||||
if (foundit != container.end())
|
|
||||||
{
|
|
||||||
for (auto it = ++foundit; it != container.end(); )
|
|
||||||
{
|
|
||||||
container.erase(it++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CXmlHistoryManager::ClearRedo()
|
|
||||||
{
|
|
||||||
ClearAfterVersion(m_HistoryInfoMap, m_CurrentVersion);
|
|
||||||
for (TUndoEventHandlerMap::iterator it = m_UndoEventHandlerMap.begin(); it != m_UndoEventHandlerMap.end(); ++it)
|
|
||||||
{
|
|
||||||
ClearAfterVersion(it->second.HistoryData, m_CurrentVersion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::DeleteAll()
|
|
||||||
{
|
|
||||||
ClearHistory();
|
|
||||||
m_Groups.clear();
|
|
||||||
m_UndoEventHandlerMap.clear();
|
|
||||||
NotifyUndoEventListener(IXmlHistoryEventListener::eHET_HistoryDeleted);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::FlagHistoryAsSaved()
|
|
||||||
{
|
|
||||||
for (TXmlHistoryList::iterator it = m_XmlHistoryList.begin(); it != m_XmlHistoryList.end(); ++it)
|
|
||||||
{
|
|
||||||
it->FlagAsSaved();
|
|
||||||
}
|
|
||||||
NotifyUndoEventListener(IXmlHistoryEventListener::eHET_HistorySaved);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::RecordNullUndo(const TEventHandlerList& eventHandler, const char* desc, bool isNull /*= true*/)
|
|
||||||
{
|
|
||||||
TXmlHistotyGroupPtrList activeGroups = m_HistoryInfoMap[ m_CurrentVersion ].ActiveGroups;
|
|
||||||
|
|
||||||
// if current version is already null undo, overwrite it instead of create a new version
|
|
||||||
if (m_HistoryInfoMap[ m_CurrentVersion ].IsNullUndo && isNull)
|
|
||||||
{
|
|
||||||
assert(m_CurrentVersion);
|
|
||||||
m_CurrentVersion--;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClearRedo();
|
|
||||||
IncrementVersion();
|
|
||||||
|
|
||||||
for (TEventHandlerList::const_iterator it = eventHandler.begin(); it != eventHandler.end(); ++it)
|
|
||||||
{
|
|
||||||
SXmlHistory* pChangedXml = m_UndoEventHandlerMap[ *it ].CurrentData;
|
|
||||||
m_UndoEventHandlerMap[ *it ].HistoryData[ m_CurrentVersion ] = pChangedXml;
|
|
||||||
}
|
|
||||||
m_HistoryInfoMap[ m_CurrentVersion ].HistoryDescription = desc;
|
|
||||||
m_HistoryInfoMap[ m_CurrentVersion ].IsNullUndo = isNull;
|
|
||||||
m_HistoryInfoMap[ m_CurrentVersion ].ActiveGroups = activeGroups;
|
|
||||||
m_HistoryInfoMap[ m_CurrentVersion ].HistoryInvalidated = false;
|
|
||||||
NotifyUndoEventListener(IXmlHistoryEventListener::eHET_VersionAdded);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::ReloadCurrentVersion(const SXmlHistoryGroup* pPrevGroup, int prevVersion)
|
|
||||||
{
|
|
||||||
m_bIsActiveGroupEx = false;
|
|
||||||
const SXmlHistoryGroup* pActiveGroup = GetActiveGroup();
|
|
||||||
|
|
||||||
bool bInvalidated = false;
|
|
||||||
int start = min(prevVersion, m_CurrentVersion);
|
|
||||||
int end = max(prevVersion, m_CurrentVersion);
|
|
||||||
for (int i = start; i <= end; ++i)
|
|
||||||
{
|
|
||||||
if (m_HistoryInfoMap[i].HistoryInvalidated)
|
|
||||||
{
|
|
||||||
bInvalidated = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bInvalidated && pPrevGroup == pActiveGroup)
|
|
||||||
{
|
|
||||||
for (TUndoEventHandlerMap::iterator it = m_UndoEventHandlerMap.begin(); it != m_UndoEventHandlerMap.end(); ++it)
|
|
||||||
{
|
|
||||||
IXmlUndoEventHandler* pEventHandler = it->first;
|
|
||||||
if (!IsEventHandlerValid(pEventHandler))
|
|
||||||
{
|
|
||||||
assert(false);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
SXmlHistory* pXmlHistory = GetLatestHistory(m_UndoEventHandlerMap[ pEventHandler ]); /*m_UndoEventHandlerMap[ pEventHandler ].HistoryData[ m_CurrentVersion ];*/
|
|
||||||
if (pXmlHistory)
|
|
||||||
{
|
|
||||||
if (pXmlHistory->Exist())
|
|
||||||
{
|
|
||||||
pEventHandler->ReloadFromXml(pXmlHistory->GetCurrentVersion());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NotifyUndoEventListener(IXmlHistoryEventListener::eHET_VersionChanged);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetActiveGroupInt(pActiveGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bInvalidated)
|
|
||||||
{
|
|
||||||
NotifyUndoEventListener(IXmlHistoryEventListener::eHET_HistoryInvalidate);
|
|
||||||
}
|
|
||||||
|
|
||||||
TXmlHistotyGroupPtrList oldActiveGroups = m_HistoryInfoMap[ prevVersion ].ActiveGroups;
|
|
||||||
TXmlHistotyGroupPtrList newActiveGroups = m_HistoryInfoMap[ m_CurrentVersion ].ActiveGroups;
|
|
||||||
|
|
||||||
RemoveListFromList(newActiveGroups, oldActiveGroups);
|
|
||||||
RemoveListFromList(oldActiveGroups, m_HistoryInfoMap[ m_CurrentVersion ].ActiveGroups);
|
|
||||||
|
|
||||||
for (TXmlHistotyGroupPtrList::iterator it = newActiveGroups.begin(); it != newActiveGroups.end(); ++it)
|
|
||||||
{
|
|
||||||
NotifyUndoEventListener(IXmlHistoryEventListener::eHET_HistoryGroupAdded, (void*) *it);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (TXmlHistotyGroupPtrList::iterator it = oldActiveGroups.begin(); it != oldActiveGroups.end(); ++it)
|
|
||||||
{
|
|
||||||
NotifyUndoEventListener(IXmlHistoryEventListener::eHET_HistoryGroupRemoved, (void*) *it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::RemoveListFromList(TXmlHistotyGroupPtrList& list, const TXmlHistotyGroupPtrList& removeList)
|
|
||||||
{
|
|
||||||
for (TXmlHistotyGroupPtrList::const_iterator rit = removeList.begin(); rit != removeList.end(); ++rit)
|
|
||||||
{
|
|
||||||
for (TXmlHistotyGroupPtrList::iterator it = list.begin(); it != list.end(); ++it)
|
|
||||||
{
|
|
||||||
if (*it == *rit)
|
|
||||||
{
|
|
||||||
list.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
SXmlHistory* CXmlHistoryManager::GetLatestHistory(SUndoEventHandlerData& eventHandlerData)
|
|
||||||
{
|
|
||||||
int currVersion = m_CurrentVersion;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
THistoryVersionMap::iterator it = eventHandlerData.HistoryData.find(currVersion);
|
|
||||||
if (it != eventHandlerData.HistoryData.end())
|
|
||||||
{
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
currVersion--;
|
|
||||||
} while (currVersion >= 0);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::NotifyUndoEventListener(IXmlHistoryEventListener::EHistoryEventType event, void* pData)
|
|
||||||
{
|
|
||||||
if (m_pExclusiveListener)
|
|
||||||
{
|
|
||||||
m_pExclusiveListener->OnEvent(event, pData);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (TEventListener::iterator it = m_EventListener.begin(); it != m_EventListener.end(); ++it)
|
|
||||||
{
|
|
||||||
(*it)->OnEvent(event, pData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
int CXmlHistoryManager::IncrementVersion([[maybe_unused]] SXmlHistory* pXmlHistry)
|
|
||||||
{
|
|
||||||
for (TXmlHistoryList::iterator it = m_XmlHistoryList.begin(); it != m_XmlHistoryList.end(); ++it)
|
|
||||||
{
|
|
||||||
it->ClearRedo();
|
|
||||||
}
|
|
||||||
return IncrementVersion();
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
int CXmlHistoryManager::IncrementVersion()
|
|
||||||
{
|
|
||||||
m_CurrentVersion++;
|
|
||||||
m_LatestVersion = m_CurrentVersion;
|
|
||||||
return m_CurrentVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::RegisterUndoEventHandler(IXmlUndoEventHandler* pEventHandler, SXmlHistory* pXmlData)
|
|
||||||
{
|
|
||||||
m_UndoEventHandlerMap[ pEventHandler ].CurrentData = pXmlData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::UnregisterUndoEventHandler(IXmlUndoEventHandler* pEventHandler)
|
|
||||||
{
|
|
||||||
TUndoEventHandlerMap::iterator it = m_UndoEventHandlerMap.find(pEventHandler);
|
|
||||||
if (it != m_UndoEventHandlerMap.end())
|
|
||||||
{
|
|
||||||
m_UndoEventHandlerMap.erase(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
void CXmlHistoryManager::RecordUndoInternal(const char* desc)
|
|
||||||
{
|
|
||||||
TEventHandlerList eventHandler;
|
|
||||||
for (TUndoEventHandlerMap::iterator it = m_UndoEventHandlerMap.begin(); it != m_UndoEventHandlerMap.end(); ++it)
|
|
||||||
{
|
|
||||||
eventHandler.push_back(it->first);
|
|
||||||
}
|
|
||||||
RecordNullUndo(eventHandler, desc, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool CXmlHistoryManager::IsEventHandlerValid(IXmlUndoEventHandler* pEventHandler)
|
|
||||||
{
|
|
||||||
for (TInvalidUndoEventListener::iterator it = m_InvalidHandlerMap.begin(); it != m_InvalidHandlerMap.end(); ++it)
|
|
||||||
{
|
|
||||||
if (it->second == pEventHandler)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@ -1,218 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef CRYINCLUDE_EDITOR_UTIL_XMLHISTORYMANAGER_H
|
|
||||||
#define CRYINCLUDE_EDITOR_UTIL_XMLHISTORYMANAGER_H
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include "IXmlHistoryManager.h"
|
|
||||||
|
|
||||||
class CXmlHistoryManager;
|
|
||||||
|
|
||||||
struct SXmlHistory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SXmlHistory(CXmlHistoryManager* pManager, const XmlNodeRef& xmlBaseVersion, uint32 typeId);
|
|
||||||
|
|
||||||
void AddToHistory(const XmlNodeRef& newXmlVersion);
|
|
||||||
|
|
||||||
const XmlNodeRef& Undo(bool* bVersionExist = nullptr);
|
|
||||||
const XmlNodeRef& Redo();
|
|
||||||
const XmlNodeRef& GetCurrentVersion(bool* bVersionExist = nullptr, int* iVersionNumber = nullptr) const;
|
|
||||||
bool IsModified() const;
|
|
||||||
uint32 GetTypeId() const {return m_typeId; }
|
|
||||||
void FlagAsDeleted();
|
|
||||||
void FlagAsSaved();
|
|
||||||
bool Exist() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class CXmlHistoryManager;
|
|
||||||
|
|
||||||
void ClearRedo();
|
|
||||||
void ClearHistory(bool flagAsSaved);
|
|
||||||
|
|
||||||
private:
|
|
||||||
CXmlHistoryManager* m_pManager;
|
|
||||||
uint32 m_typeId;
|
|
||||||
int m_DeletedVersion;
|
|
||||||
int m_SavedVersion;
|
|
||||||
|
|
||||||
typedef std::map< int, XmlNodeRef > TXmlVersionMap;
|
|
||||||
TXmlVersionMap m_xmlVersionList;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct SXmlHistoryGroup
|
|
||||||
{
|
|
||||||
SXmlHistoryGroup(CXmlHistoryManager* pManager, uint32 typeId);
|
|
||||||
|
|
||||||
SXmlHistory* GetHistory(int index) const;
|
|
||||||
int GetHistoryCount() const;
|
|
||||||
|
|
||||||
SXmlHistory* GetHistoryByTypeId(uint32 typeId, int index = 0) const;
|
|
||||||
int GetHistoryCountByTypeId(uint32 typeId) const;
|
|
||||||
|
|
||||||
int CreateXmlHistory(uint32 typeId, const XmlNodeRef& xmlBaseVersion);
|
|
||||||
uint32 GetTypeId() const {return m_typeId; }
|
|
||||||
|
|
||||||
int GetHistoryIndex(const SXmlHistory* pHistory) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class CXmlHistoryManager;
|
|
||||||
CXmlHistoryManager* m_pManager;
|
|
||||||
uint32 m_typeId;
|
|
||||||
|
|
||||||
typedef std::list< SXmlHistory* > THistoryList;
|
|
||||||
THistoryList m_List;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::map<uint32, int> TGroupIndexMap;
|
|
||||||
|
|
||||||
|
|
||||||
class CXmlHistoryManager
|
|
||||||
: public IXmlHistoryManager
|
|
||||||
, public IXmlUndoEventHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CXmlHistoryManager();
|
|
||||||
~CXmlHistoryManager();
|
|
||||||
|
|
||||||
// Undo/Redo
|
|
||||||
bool Undo();
|
|
||||||
bool Redo();
|
|
||||||
bool Goto(int historyNum);
|
|
||||||
void RecordUndo(IXmlUndoEventHandler* pEventHandler, const char* desc);
|
|
||||||
void UndoEventHandlerDestroyed(IXmlUndoEventHandler* pEventHandler, uint32 typeId = 0, bool destoryForever = false);
|
|
||||||
void RestoreUndoEventHandler(IXmlUndoEventHandler* pEventHandler, uint32 typeId);
|
|
||||||
|
|
||||||
void PrepareForNextVersion();
|
|
||||||
void RecordNextVersion(SXmlHistory* pHistory, XmlNodeRef newData, const char* undoDesc = nullptr);
|
|
||||||
bool IsPreparedForNextVersion() const {return m_RecordNextVersion; }
|
|
||||||
|
|
||||||
void RegisterEventListener(IXmlHistoryEventListener* pEventListener);
|
|
||||||
void UnregisterEventListener(IXmlHistoryEventListener* pEventListener);
|
|
||||||
void SetExclusiveListener(IXmlHistoryEventListener* pEventListener) { m_pExclusiveListener = pEventListener; }
|
|
||||||
|
|
||||||
// History
|
|
||||||
void ClearHistory(bool flagAsSaved = false);
|
|
||||||
int GetVersionCount() const { return m_LatestVersion; }
|
|
||||||
const string& GetVersionDesc(int number) const;
|
|
||||||
int GetCurrentVersionNumber() const { return m_CurrentVersion; }
|
|
||||||
|
|
||||||
// Views
|
|
||||||
void RegisterView(IXmlHistoryView* pView);
|
|
||||||
void UnregisterView(IXmlHistoryView* pView);
|
|
||||||
|
|
||||||
// Xml History Groups
|
|
||||||
SXmlHistoryGroup* CreateXmlGroup(uint32 typeId);
|
|
||||||
void SetActiveGroup(const SXmlHistoryGroup* pGroup, const char* displayName = nullptr, const TGroupIndexMap& groupIndex = TGroupIndexMap(), bool setExternal = false);
|
|
||||||
const SXmlHistoryGroup* GetActiveGroup() const;
|
|
||||||
const SXmlHistoryGroup* GetActiveGroup(TGroupIndexMap& currUserIndex /*out*/) const;
|
|
||||||
void AddXmlGroup(const SXmlHistoryGroup* pGroup, const char* undoDesc = nullptr);
|
|
||||||
void RemoveXmlGroup(const SXmlHistoryGroup* pGroup, const char* undoDesc = nullptr);
|
|
||||||
|
|
||||||
void DeleteAll();
|
|
||||||
|
|
||||||
void FlagHistoryAsSaved();
|
|
||||||
|
|
||||||
virtual bool SaveToXml(XmlNodeRef& xmlNode);
|
|
||||||
virtual bool LoadFromXml([[maybe_unused]] const XmlNodeRef& xmlNode) { return false; };
|
|
||||||
virtual bool ReloadFromXml([[maybe_unused]] const XmlNodeRef& xmlNode) { return false; };
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef std::list< SXmlHistory > TXmlHistoryList;
|
|
||||||
TXmlHistoryList m_XmlHistoryList;
|
|
||||||
int m_CurrentVersion;
|
|
||||||
int m_LatestVersion;
|
|
||||||
SXmlHistoryGroup* m_pNullGroup; // hack for unload view ...
|
|
||||||
XmlNodeRef m_newHistoryData;
|
|
||||||
bool m_RecordNextVersion;
|
|
||||||
bool m_bIsActiveGroupEx;
|
|
||||||
SXmlHistoryGroup* m_pExActiveGroup;
|
|
||||||
TGroupIndexMap m_ExCurrentIndex;
|
|
||||||
|
|
||||||
typedef std::list< SXmlHistoryGroup > TXmlHistotyGroupList;
|
|
||||||
TXmlHistotyGroupList m_Groups;
|
|
||||||
|
|
||||||
// event listener
|
|
||||||
typedef std::list< IXmlHistoryEventListener* > TEventListener;
|
|
||||||
TEventListener m_EventListener;
|
|
||||||
IXmlHistoryEventListener* m_pExclusiveListener;
|
|
||||||
|
|
||||||
// views
|
|
||||||
typedef std::list< IXmlHistoryView* > TViews;
|
|
||||||
TViews m_Views;
|
|
||||||
|
|
||||||
typedef std::list< const SXmlHistoryGroup* > TXmlHistotyGroupPtrList;
|
|
||||||
// history
|
|
||||||
struct SHistoryInfo
|
|
||||||
{
|
|
||||||
SHistoryInfo()
|
|
||||||
: IsNullUndo(false)
|
|
||||||
, CurrGroup(nullptr)
|
|
||||||
, HistoryInvalidated(false) {}
|
|
||||||
|
|
||||||
const SXmlHistoryGroup* CurrGroup;
|
|
||||||
TGroupIndexMap CurrUserIndex;
|
|
||||||
string HistoryDescription;
|
|
||||||
bool IsNullUndo;
|
|
||||||
bool HistoryInvalidated;
|
|
||||||
TXmlHistotyGroupPtrList ActiveGroups;
|
|
||||||
};
|
|
||||||
typedef std::map< int, SHistoryInfo > THistoryInfoMap;
|
|
||||||
THistoryInfoMap m_HistoryInfoMap;
|
|
||||||
|
|
||||||
// undo event handler
|
|
||||||
typedef std::map< int, SXmlHistory* > THistoryVersionMap;
|
|
||||||
struct SUndoEventHandlerData
|
|
||||||
{
|
|
||||||
SUndoEventHandlerData()
|
|
||||||
: CurrentData(nullptr) {}
|
|
||||||
|
|
||||||
SXmlHistory* CurrentData;
|
|
||||||
THistoryVersionMap HistoryData;
|
|
||||||
};
|
|
||||||
typedef std::map< IXmlUndoEventHandler*, SUndoEventHandlerData > TUndoEventHandlerMap;
|
|
||||||
TUndoEventHandlerMap m_UndoEventHandlerMap;
|
|
||||||
|
|
||||||
typedef std::map< IXmlUndoEventHandler*, IXmlHistoryView* > TUndoHandlerViewMap;
|
|
||||||
TUndoHandlerViewMap m_UndoHandlerViewMap;
|
|
||||||
|
|
||||||
typedef std::map< uint32, IXmlUndoEventHandler* > TInvalidUndoEventListener;
|
|
||||||
TInvalidUndoEventListener m_InvalidHandlerMap;
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend struct SXmlHistory;
|
|
||||||
friend struct SXmlHistoryGroup;
|
|
||||||
|
|
||||||
int IncrementVersion(SXmlHistory* pXmlHistry);
|
|
||||||
int IncrementVersion();
|
|
||||||
SXmlHistory* CreateXmlHistory(uint32 typeId, const XmlNodeRef& xmlBaseVersion);
|
|
||||||
void DeleteXmlHistory(const SXmlHistory* pXmlHistry);
|
|
||||||
|
|
||||||
void RegisterUndoEventHandler(IXmlUndoEventHandler* pEventHandler, SXmlHistory* pXmlData);
|
|
||||||
void UnregisterUndoEventHandler(IXmlUndoEventHandler* pEventHandler);
|
|
||||||
typedef std::list< IXmlUndoEventHandler* > TEventHandlerList;
|
|
||||||
void RecordNullUndo(const TEventHandlerList& eventHandler, const char* desc, bool isNull = true);
|
|
||||||
void ReloadCurrentVersion(const SXmlHistoryGroup* pPrevGroup, int prevVersion);
|
|
||||||
SXmlHistory* GetLatestHistory(SUndoEventHandlerData& eventHandlerData);
|
|
||||||
void NotifyUndoEventListener(IXmlHistoryEventListener::EHistoryEventType event, void* pData = nullptr);
|
|
||||||
|
|
||||||
void SetActiveGroupInt(const SXmlHistoryGroup* pGroup, const char* displayName = nullptr, bool bRecordNullUndo = false, const TGroupIndexMap& groupIndex = TGroupIndexMap());
|
|
||||||
void UnloadInt();
|
|
||||||
void ClearRedo();
|
|
||||||
|
|
||||||
void RecordUndoInternal(const char* desc);
|
|
||||||
void RemoveListFromList(TXmlHistotyGroupPtrList& list, const TXmlHistotyGroupPtrList& removeList);
|
|
||||||
|
|
||||||
bool IsEventHandlerValid(IXmlUndoEventHandler* pEventHandler);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CRYINCLUDE_EDITOR_UTIL_XMLHISTORYMANAGER_H
|
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||||
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AzCore/Math/Uuid.h>
|
||||||
|
#include <AzCore/std/typetraits/is_enum.h>
|
||||||
|
|
||||||
|
namespace AZ
|
||||||
|
{
|
||||||
|
using TypeId = AZ::Uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AZ_TYPE_INFO_INTERNAL_1(_ClassName) static_assert(false, "You must provide a ClassName,ClassUUID")
|
||||||
|
#define AZ_TYPE_INFO_INTERNAL_2(_ClassName, _ClassUuid) \
|
||||||
|
void TYPEINFO_Enable(){} \
|
||||||
|
static const char* TYPEINFO_Name() { return #_ClassName; } \
|
||||||
|
static const AZ::TypeId& TYPEINFO_Uuid() { static AZ::TypeId s_uuid(_ClassUuid); return s_uuid; }
|
||||||
|
|
||||||
|
#define AZ_TYPE_INFO_1 AZ_TYPE_INFO_INTERNAL_1
|
||||||
|
#define AZ_TYPE_INFO_2 AZ_TYPE_INFO_INTERNAL_2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this macro inside a class to allow it to be identified across modules and serialized (in different contexts).
|
||||||
|
* The expected input is the class and the assigned uuid as a string or an instance of a uuid.
|
||||||
|
* Example:
|
||||||
|
* class MyClass
|
||||||
|
* {
|
||||||
|
* public:
|
||||||
|
* AZ_TYPE_INFO(MyClass, "{BD5B1568-D232-4EBF-93BD-69DB66E3773F}");
|
||||||
|
* ...
|
||||||
|
*/
|
||||||
|
#define AZ_TYPE_INFO(...) AZ_MACRO_SPECIALIZE(AZ_TYPE_INFO_, AZ_VA_NUM_ARGS(__VA_ARGS__), (__VA_ARGS__))
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue