/* * GDevelop Core * Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights * reserved. This project is released under the MIT License. */ #pragma once #include #include #include "GDCore/Serialization/SerializerElement.h" #include "GDCore/String.h" #include "GDCore/Project/QuickCustomization.h" #include "GDCore/Project/MemoryTrackedRegistry.h" namespace gd { class Project; class Object; class SerializerElement; class ObjectsContainer; } // namespace gd namespace gd { /** * \brief Class representing a folder structure in order to organize objects * in folders (to be used with an ObjectsContainer.) * * \see gd::ObjectsContainer */ class GD_CORE_API ObjectFolderOrObject { public: /** * \brief Default constructor creating an empty instance. Useful for the null * object pattern. */ ObjectFolderOrObject(); virtual ~ObjectFolderOrObject(); /** * \brief Constructor for creating an instance representing a folder. */ ObjectFolderOrObject(gd::String folderName_, ObjectFolderOrObject* parent_ = nullptr); /** * \brief Constructor for creating an instance representing an object. */ ObjectFolderOrObject(gd::Object* object_, ObjectFolderOrObject* parent_ = nullptr); /** * \brief Returns the object behind the instance. */ gd::Object& GetObject() const { return *object; } /** * \brief Returns true if the instance represents a folder. */ bool IsFolder() const { return !folderName.empty(); } /** * \brief Returns the name of the folder. */ const gd::String& GetFolderName() const { return folderName; } /** * \brief Set the folder name. Does nothing if called on an instance not * representing a folder. */ void SetFolderName(const gd::String& name); /** * \brief Returns true if the instance represents the object with the given * name or if any of the children does (recursive search). */ bool HasObjectNamed(const gd::String& name); /** * \brief Returns the child instance holding the object with the given name * (recursive search). */ ObjectFolderOrObject& GetObjectNamed(const gd::String& name); /** * \brief Returns the number of children. Returns 0 if the instance represents * an object. */ std::size_t GetChildrenCount() const { if (IsFolder()) return children.size(); return 0; } /** * \brief Returns the child ObjectFolderOrObject at the given index. */ ObjectFolderOrObject& GetChildAt(std::size_t index); /** * \brief Returns the child ObjectFolderOrObject at the given index. */ const ObjectFolderOrObject& GetChildAt(std::size_t index) const; /** * \brief Returns the child ObjectFolderOrObject that represents the object * with the given name. To use only if sure that the instance holds the object * in its direct children (no recursive search). * * \note The equivalent method to get a folder by its name cannot be * implemented because there is no unicity enforced on the folder name. */ ObjectFolderOrObject& GetObjectChild(const gd::String& name); /** * \brief Returns the parent of the instance. If the instance has no parent * (root folder), the null object is returned. */ ObjectFolderOrObject& GetParent() { if (parent == nullptr) { return badObjectFolderOrObject; } return *parent; }; /** * \brief Returns true if the instance is a root folder (that's to say it * has no parent). */ bool IsRootFolder() { return !object && !parent; } /** * \brief Moves a child from a position to a new one. */ void MoveChild(std::size_t oldIndex, std::size_t newIndex); /** * \brief Removes the given child from the instance's children. If the given * child contains children of its own, does nothing. */ void RemoveFolderChild(const ObjectFolderOrObject& childToRemove); /** * \brief Removes the child representing the object with the given name from * the instance children and recursively does it for every folder children. */ void RemoveRecursivelyObjectNamed(const gd::String& name); /** * \brief Clears all children */ void Clear(); /** * \brief Inserts an instance representing the given object at the given * position. */ void InsertObject(gd::Object* insertedObject, std::size_t position = (size_t)-1); /** * \brief Inserts an instance representing a folder with the given name at the * given position. */ ObjectFolderOrObject& InsertNewFolder(const gd::String& newFolderName, std::size_t position); /** * \brief Return a folder with the given name and create it if it didn't * exist. */ ObjectFolderOrObject &GetOrCreateFolderChild(const gd::String &name); /** * \brief Returns true if the instance is a descendant of the given instance * of ObjectFolderOrObject. */ bool IsADescendantOf(const ObjectFolderOrObject& otherObjectFolderOrObject); /** * \brief Returns the position of the given instance of ObjectFolderOrObject * in the instance's children. */ std::size_t GetChildPosition(const ObjectFolderOrObject& child) const; /** * \brief Moves the given child ObjectFolderOrObject to the given folder at * the given position. */ void MoveObjectFolderOrObjectToAnotherFolder( gd::ObjectFolderOrObject& objectFolderOrObject, gd::ObjectFolderOrObject& newParentFolder, std::size_t newPosition); QuickCustomization::Visibility GetQuickCustomizationVisibility() const { return quickCustomizationVisibility; } void SetQuickCustomizationVisibility(QuickCustomization::Visibility visibility) { quickCustomizationVisibility = visibility; } /** \name Saving and loading * Members functions related to saving and loading the objects of the class. */ ///@{ /** * \brief Serialize the ObjectFolderOrObject instance. */ void SerializeTo(SerializerElement& element) const; /** * \brief Unserialize the ObjectFolderOrObject instance. */ void UnserializeFrom(gd::Project& project, const SerializerElement& element, ObjectsContainer& objectsContainer); ///@} private: static gd::ObjectFolderOrObject badObjectFolderOrObject; gd::ObjectFolderOrObject* parent = nullptr; // nullptr if root folder, points to the parent folder otherwise. QuickCustomization::Visibility quickCustomizationVisibility; // Representing an object: gd::Object* object; // nullptr if folderName is set. // or representing a folder: gd::String folderName; // Empty if object is set. std::vector> children; // Folder children. gd::MemoryTracked _memoryTracked{this, "ObjectFolderOrObject"}; }; } // namespace gd