mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
282 lines
9.6 KiB
C++
282 lines
9.6 KiB
C++
/*
|
|
* GDevelop Core
|
|
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
|
|
* reserved. This project is released under the MIT License.
|
|
*/
|
|
#include "GDCore/Project/ObjectFolderOrObject.h"
|
|
|
|
#include <memory>
|
|
|
|
#include "GDCore/Project/Object.h"
|
|
#include "GDCore/Project/ObjectsContainer.h"
|
|
#include "GDCore/Serialization/SerializerElement.h"
|
|
#include "GDCore/Tools/Log.h"
|
|
|
|
using namespace std;
|
|
|
|
namespace gd {
|
|
|
|
ObjectFolderOrObject ObjectFolderOrObject::badObjectFolderOrObject;
|
|
|
|
ObjectFolderOrObject::ObjectFolderOrObject()
|
|
: folderName("__NULL"),
|
|
object(nullptr),
|
|
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {}
|
|
ObjectFolderOrObject::ObjectFolderOrObject(gd::String folderName_,
|
|
ObjectFolderOrObject* parent_)
|
|
: folderName(folderName_),
|
|
parent(parent_),
|
|
object(nullptr),
|
|
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {}
|
|
ObjectFolderOrObject::ObjectFolderOrObject(gd::Object* object_,
|
|
ObjectFolderOrObject* parent_)
|
|
: object(object_),
|
|
parent(parent_),
|
|
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {}
|
|
ObjectFolderOrObject::~ObjectFolderOrObject() {}
|
|
|
|
bool ObjectFolderOrObject::HasObjectNamed(const gd::String& name) {
|
|
if (IsFolder()) {
|
|
return std::any_of(
|
|
children.begin(),
|
|
children.end(),
|
|
[&name](
|
|
std::unique_ptr<gd::ObjectFolderOrObject>& objectFolderOrObject) {
|
|
return objectFolderOrObject->HasObjectNamed(name);
|
|
});
|
|
}
|
|
if (!object) return false;
|
|
return object->GetName() == name;
|
|
}
|
|
ObjectFolderOrObject& ObjectFolderOrObject::GetObjectNamed(
|
|
const gd::String& name) {
|
|
if (object && object->GetName() == name) {
|
|
return *this;
|
|
}
|
|
if (IsFolder()) {
|
|
for (std::size_t j = 0; j < children.size(); j++) {
|
|
ObjectFolderOrObject& foundInChild = children[j]->GetObjectNamed(name);
|
|
if (&(foundInChild) != &badObjectFolderOrObject) {
|
|
return foundInChild;
|
|
}
|
|
}
|
|
}
|
|
return badObjectFolderOrObject;
|
|
}
|
|
|
|
void ObjectFolderOrObject::SetFolderName(const gd::String& name) {
|
|
if (!IsFolder()) return;
|
|
folderName = name;
|
|
}
|
|
|
|
ObjectFolderOrObject& ObjectFolderOrObject::GetChildAt(std::size_t index) {
|
|
if (index >= children.size()) return badObjectFolderOrObject;
|
|
return *children[index];
|
|
}
|
|
const ObjectFolderOrObject& ObjectFolderOrObject::GetChildAt(
|
|
std::size_t index) const {
|
|
if (index >= children.size()) return badObjectFolderOrObject;
|
|
return *children[index];
|
|
}
|
|
ObjectFolderOrObject& ObjectFolderOrObject::GetObjectChild(
|
|
const gd::String& name) {
|
|
for (std::size_t j = 0; j < children.size(); j++) {
|
|
if (!children[j]->IsFolder()) {
|
|
if (children[j]->GetObject().GetName() == name) return *children[j];
|
|
};
|
|
}
|
|
return badObjectFolderOrObject;
|
|
}
|
|
|
|
void ObjectFolderOrObject::InsertObject(gd::Object* insertedObject,
|
|
std::size_t position) {
|
|
auto objectFolderOrObject =
|
|
gd::make_unique<ObjectFolderOrObject>(insertedObject, this);
|
|
if (position < children.size()) {
|
|
children.insert(children.begin() + position,
|
|
std::move(objectFolderOrObject));
|
|
} else {
|
|
children.push_back(std::move(objectFolderOrObject));
|
|
}
|
|
}
|
|
|
|
std::size_t ObjectFolderOrObject::GetChildPosition(
|
|
const ObjectFolderOrObject& child) const {
|
|
for (std::size_t j = 0; j < children.size(); j++) {
|
|
if (children[j].get() == &child) return j;
|
|
}
|
|
return gd::String::npos;
|
|
}
|
|
|
|
ObjectFolderOrObject& ObjectFolderOrObject::InsertNewFolder(
|
|
const gd::String& newFolderName, std::size_t position) {
|
|
auto newFolderPtr =
|
|
gd::make_unique<ObjectFolderOrObject>(newFolderName, this);
|
|
gd::ObjectFolderOrObject& newFolder = *(*(children.insert(
|
|
position < children.size() ? children.begin() + position : children.end(),
|
|
std::move(newFolderPtr))));
|
|
return newFolder;
|
|
};
|
|
|
|
void ObjectFolderOrObject::RemoveRecursivelyObjectNamed(
|
|
const gd::String& name) {
|
|
if (IsFolder()) {
|
|
children.erase(
|
|
std::remove_if(children.begin(),
|
|
children.end(),
|
|
[&name](std::unique_ptr<gd::ObjectFolderOrObject>&
|
|
objectFolderOrObject) {
|
|
return !objectFolderOrObject->IsFolder() &&
|
|
objectFolderOrObject->GetObject().GetName() ==
|
|
name;
|
|
}),
|
|
children.end());
|
|
for (auto& it : children) {
|
|
it->RemoveRecursivelyObjectNamed(name);
|
|
}
|
|
}
|
|
};
|
|
|
|
void ObjectFolderOrObject::Clear() {
|
|
if (IsFolder()) {
|
|
for (auto& it : children) {
|
|
it->Clear();
|
|
}
|
|
children.clear();
|
|
}
|
|
};
|
|
|
|
bool ObjectFolderOrObject::IsADescendantOf(
|
|
const ObjectFolderOrObject& otherObjectFolderOrObject) {
|
|
if (parent == nullptr) return false;
|
|
if (&(*parent) == &otherObjectFolderOrObject) return true;
|
|
return parent->IsADescendantOf(otherObjectFolderOrObject);
|
|
}
|
|
|
|
void ObjectFolderOrObject::MoveChild(std::size_t oldIndex,
|
|
std::size_t newIndex) {
|
|
if (!IsFolder()) return;
|
|
if (oldIndex >= children.size() || newIndex >= children.size()) return;
|
|
|
|
std::unique_ptr<gd::ObjectFolderOrObject> objectFolderOrObject =
|
|
std::move(children[oldIndex]);
|
|
children.erase(children.begin() + oldIndex);
|
|
children.insert(children.begin() + newIndex, std::move(objectFolderOrObject));
|
|
}
|
|
|
|
void ObjectFolderOrObject::RemoveFolderChild(
|
|
const ObjectFolderOrObject& childToRemove) {
|
|
if (!IsFolder() || !childToRemove.IsFolder() ||
|
|
childToRemove.GetChildrenCount() > 0) {
|
|
return;
|
|
}
|
|
std::vector<std::unique_ptr<gd::ObjectFolderOrObject>>::iterator it = find_if(
|
|
children.begin(),
|
|
children.end(),
|
|
[&childToRemove](std::unique_ptr<gd::ObjectFolderOrObject>& child) {
|
|
return child.get() == &childToRemove;
|
|
});
|
|
if (it == children.end()) return;
|
|
|
|
children.erase(it);
|
|
}
|
|
|
|
void ObjectFolderOrObject::MoveObjectFolderOrObjectToAnotherFolder(
|
|
gd::ObjectFolderOrObject& objectFolderOrObject,
|
|
gd::ObjectFolderOrObject& newParentFolder,
|
|
std::size_t newPosition) {
|
|
if (!newParentFolder.IsFolder()) return;
|
|
if (newParentFolder.IsADescendantOf(objectFolderOrObject)) return;
|
|
|
|
std::vector<std::unique_ptr<gd::ObjectFolderOrObject>>::iterator it =
|
|
find_if(children.begin(),
|
|
children.end(),
|
|
[&objectFolderOrObject](std::unique_ptr<gd::ObjectFolderOrObject>&
|
|
childObjectFolderOrObject) {
|
|
return childObjectFolderOrObject.get() == &objectFolderOrObject;
|
|
});
|
|
if (it == children.end()) return;
|
|
|
|
std::unique_ptr<gd::ObjectFolderOrObject> objectFolderOrObjectPtr =
|
|
std::move(*it);
|
|
children.erase(it);
|
|
|
|
objectFolderOrObjectPtr->parent = &newParentFolder;
|
|
newParentFolder.children.insert(
|
|
newPosition < newParentFolder.children.size()
|
|
? newParentFolder.children.begin() + newPosition
|
|
: newParentFolder.children.end(),
|
|
std::move(objectFolderOrObjectPtr));
|
|
}
|
|
|
|
void ObjectFolderOrObject::SerializeTo(SerializerElement& element) const {
|
|
if (IsFolder()) {
|
|
element.SetAttribute("folderName", GetFolderName());
|
|
if (children.size() > 0) {
|
|
SerializerElement& childrenElement = element.AddChild("children");
|
|
childrenElement.ConsiderAsArrayOf("objectFolderOrObject");
|
|
for (std::size_t j = 0; j < children.size(); j++) {
|
|
children[j]->SerializeTo(
|
|
childrenElement.AddChild("objectFolderOrObject"));
|
|
}
|
|
}
|
|
} else {
|
|
element.SetAttribute("objectName", GetObject().GetName());
|
|
}
|
|
|
|
if (quickCustomizationVisibility != QuickCustomization::Visibility::Default) {
|
|
element.SetStringAttribute(
|
|
"quickCustomizationVisibility",
|
|
quickCustomizationVisibility == QuickCustomization::Visibility::Visible
|
|
? "visible"
|
|
: "hidden");
|
|
}
|
|
}
|
|
|
|
void ObjectFolderOrObject::UnserializeFrom(
|
|
gd::Project& project,
|
|
const SerializerElement& element,
|
|
gd::ObjectsContainer& objectsContainer) {
|
|
children.clear();
|
|
gd::String potentialFolderName = element.GetStringAttribute("folderName", "");
|
|
|
|
if (!potentialFolderName.empty()) {
|
|
object = nullptr;
|
|
folderName = potentialFolderName;
|
|
|
|
if (element.HasChild("children")) {
|
|
const SerializerElement& childrenElements =
|
|
element.GetChild("children", 0);
|
|
childrenElements.ConsiderAsArrayOf("objectFolderOrObject");
|
|
for (std::size_t i = 0; i < childrenElements.GetChildrenCount(); ++i) {
|
|
std::unique_ptr<ObjectFolderOrObject> childObjectFolderOrObject =
|
|
make_unique<ObjectFolderOrObject>();
|
|
childObjectFolderOrObject->UnserializeFrom(
|
|
project, childrenElements.GetChild(i), objectsContainer);
|
|
childObjectFolderOrObject->parent = this;
|
|
children.push_back(std::move(childObjectFolderOrObject));
|
|
}
|
|
}
|
|
} else {
|
|
folderName = "";
|
|
gd::String objectName = element.GetStringAttribute("objectName");
|
|
if (objectsContainer.HasObjectNamed(objectName)) {
|
|
object = &objectsContainer.GetObject(objectName);
|
|
} else {
|
|
gd::LogError("Object with name " + objectName +
|
|
" not found in objects container.");
|
|
object = nullptr;
|
|
}
|
|
}
|
|
|
|
if (element.HasChild("quickCustomizationVisibility")) {
|
|
quickCustomizationVisibility =
|
|
element.GetStringAttribute("quickCustomizationVisibility") == "visible"
|
|
? QuickCustomization::Visibility::Visible
|
|
: QuickCustomization::Visibility::Hidden;
|
|
} else {
|
|
quickCustomizationVisibility = QuickCustomization::Visibility::Default;
|
|
}
|
|
};
|
|
|
|
} // namespace gd
|