From a29c5dc92618376e2136eee1f7daa7a68716cbae Mon Sep 17 00:00:00 2001 From: Yousef Khadadeh Date: Wed, 24 Dec 2025 12:42:27 +0300 Subject: [PATCH] Starting work on drawing program layers --- CMakeLists.txt | 1 + .../NetObjManagerTypeList.hpp | 2 + src/Bookmarks/BookmarkListItem.cpp | 42 ++-- src/Bookmarks/BookmarkListItem.hpp | 14 +- src/Bookmarks/BookmarkManager.cpp | 210 +++++++++--------- .../CanvasComponentAllocator.cpp | 4 +- .../CanvasComponentAllocator.hpp | 2 +- .../CanvasComponentContainer.cpp | 4 - .../CanvasComponentContainer.hpp | 3 +- .../Layers/DrawingProgramLayer.hpp | 10 + .../Layers/DrawingProgramLayerFolder.hpp | 10 + .../Layers/DrawingProgramLayerListItem.cpp | 115 ++++++++++ .../Layers/DrawingProgramLayerListItem.hpp | 50 +++++ src/World.cpp | 5 +- 14 files changed, 334 insertions(+), 138 deletions(-) create mode 100644 src/DrawingProgram/Layers/DrawingProgramLayer.hpp create mode 100644 src/DrawingProgram/Layers/DrawingProgramLayerFolder.hpp create mode 100644 src/DrawingProgram/Layers/DrawingProgramLayerListItem.cpp create mode 100644 src/DrawingProgram/Layers/DrawingProgramLayerListItem.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e8af6db..1c27a7a 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,7 @@ set(sources "src/main.cpp" "src/DrawingProgram/EllipseDrawEditTool.cpp" "src/DrawingProgram/RectDrawEditTool.cpp" "src/DrawingProgram/TextBoxEditTool.cpp" + "src/DrawingProgram/Layers/DrawingProgramLayerListItem.cpp" "src/CanvasComponents/CanvasComponentContainer.cpp" "src/CanvasComponents/CanvasComponentAllocator.cpp" "src/CanvasComponents/BrushStrokeCanvasComponent.cpp" diff --git a/include/Helpers/NetworkingObjects/NetObjManagerTypeList.hpp b/include/Helpers/NetworkingObjects/NetObjManagerTypeList.hpp index 2fcff17..22285e5 100644 --- a/include/Helpers/NetworkingObjects/NetObjManagerTypeList.hpp +++ b/include/Helpers/NetworkingObjects/NetObjManagerTypeList.hpp @@ -18,6 +18,8 @@ class NetObjManagerTypeList { std::function&, cereal::PortableBinaryInputArchive&, const std::shared_ptr&)> readUpdateFuncServer; }; template void register_class(const ServerClientClassFunctions& funcs) { + if((netTypeID + 1) == 0) // Unsigned type wraps around, so check if we're already at class count limit (if we are, we have to increase the size of NetTypeIDType) + throw std::runtime_error("[NetObjManagerTypeList::register_class] Reached limit of number of classes that can be registered. Increase the size of NetTypeIDType to continue"); typeIndexFunctionsClient[std::type_index(typeid(ClientT*))] = TypeIndexFunctions { .readConstructorFunc = [f = funcs.readConstructorFuncClient](const NetObjTemporaryPtr& obj, cereal::PortableBinaryInputArchive& message, const std::shared_ptr& c) { f(obj.cast(), message, c); diff --git a/src/Bookmarks/BookmarkListItem.cpp b/src/Bookmarks/BookmarkListItem.cpp index 5dd4073..cb6a044 100644 --- a/src/Bookmarks/BookmarkListItem.cpp +++ b/src/Bookmarks/BookmarkListItem.cpp @@ -11,18 +11,20 @@ void BookmarkData::jump_to(World& world) const { BookmarkListItem::BookmarkListItem() {} BookmarkListItem::BookmarkListItem(NetworkingObjects::NetObjManager& netObjMan, const std::string& initName, bool isFolder, const BookmarkData& initBookmarkData) { - name = initName; if(isFolder) { folderData = std::make_unique(); folderData->folderList = netObjMan.make_obj>(); } else bookmarkData = std::make_unique(initBookmarkData); + nameData = netObjMan.make_obj(); + nameData->name = initName; } void BookmarkListItem::reassign_netobj_ids_call() { if(folderData) folderData->folderList.reassign_ids(); + nameData.reassign_ids(); } bool BookmarkListItem::is_folder() const { @@ -37,8 +39,15 @@ const NetObjOwnerPtr>& BookmarkListItem::get return folderData->folderList; } +void BookmarkListItem::set_name(NetworkingObjects::DelayUpdateSerializedClassManager& delayedNetObjMan, const std::string& newName) { + if(nameData && nameData->name != newName) { + nameData->name = newName; + delayedNetObjMan.send_update_to_all(nameData, false); + } +} + const std::string& BookmarkListItem::get_name() const { - return name; + return nameData->name; } bool BookmarkListItem::is_folder_open() const { @@ -49,41 +58,29 @@ void BookmarkListItem::set_folder_open(bool newIsFolderOpen) { folderData->isFolderOpen = newIsFolderOpen; } -void BookmarkListItem::set_name(const NetworkingObjects::NetObjTemporaryPtr& o, const std::string& newName) { - o->name = newName; - o.send_update_to_all(RELIABLE_COMMAND_CHANNEL, [](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { - a(o->name); - }); -} - -void BookmarkListItem::register_class(NetObjManager& netObjMan) { - netObjMan.register_class({ +void BookmarkListItem::register_class(World& w) { + w.netObjMan.register_class({ .writeConstructorFuncClient = write_constructor_data, .readConstructorFuncClient = read_constructor_data, - .readUpdateFuncClient = [](const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) { - a(o->name); - }, + .readUpdateFuncClient = nullptr, .writeConstructorFuncServer = write_constructor_data, .readConstructorFuncServer = read_constructor_data, - .readUpdateFuncServer = [](const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) { - a(o->name); - o.send_server_update_to_all_clients(RELIABLE_COMMAND_CHANNEL, [](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { - a(o->name); - }); - }, + .readUpdateFuncServer = nullptr }); + NetworkingObjects::register_ordered_list_class(w.netObjMan); + w.delayedUpdateObjectManager.register_class(w.netObjMan); } void BookmarkListItem::write_constructor_data(const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { - a(o->name, o->is_folder()); + a(o->is_folder()); if(o->is_folder()) o->folderData->folderList.write_create_message(a); else a(*o->bookmarkData); + o->nameData.write_create_message(a); } void BookmarkListItem::read_constructor_data(const NetworkingObjects::NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) { - a(o->name); bool isFolder; a(isFolder); if(isFolder) { @@ -94,4 +91,5 @@ void BookmarkListItem::read_constructor_data(const NetworkingObjects::NetObjTemp o->bookmarkData = std::make_unique(); a(*o->bookmarkData); } + o->nameData = o.get_obj_man()->read_create_message(a, c); } diff --git a/src/Bookmarks/BookmarkListItem.hpp b/src/Bookmarks/BookmarkListItem.hpp index bdefebe..6a9fc1d 100644 --- a/src/Bookmarks/BookmarkListItem.hpp +++ b/src/Bookmarks/BookmarkListItem.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include #include "../CoordSpaceHelper.hpp" @@ -23,17 +24,24 @@ class BookmarkListItem { bool is_folder_open() const; void set_folder_open(bool newIsFolderOpen); const std::string& get_name() const; - static void register_class(NetworkingObjects::NetObjManager& netObjMan); - static void set_name(const NetworkingObjects::NetObjTemporaryPtr& o, const std::string& newName); // Set once after editing is finished + static void register_class(World& w); void reassign_netobj_ids_call(); + + void set_name(NetworkingObjects::DelayUpdateSerializedClassManager& delayedNetObjMan, const std::string& newName); private: struct BookmarkFolderData { NetworkingObjects::NetObjOwnerPtr> folderList; bool isFolderOpen = false; }; + struct NameData { + std::string name; + template void serialize(Archive& a) { + a(name); + } + }; static void write_constructor_data(const NetworkingObjects::NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a); static void read_constructor_data(const NetworkingObjects::NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c); std::unique_ptr folderData; std::unique_ptr bookmarkData; - std::string name; + NetworkingObjects::NetObjOwnerPtr nameData; }; diff --git a/src/Bookmarks/BookmarkManager.cpp b/src/Bookmarks/BookmarkManager.cpp index 6b6b21d..4c83a4a 100644 --- a/src/Bookmarks/BookmarkManager.cpp +++ b/src/Bookmarks/BookmarkManager.cpp @@ -27,109 +27,118 @@ void BookmarkManager::refresh_gui_data() { void BookmarkManager::setup_list_gui(const std::string& id) { using namespace NetworkingObjects; if(bookmarkListRoot) { - std::optional toDeleteParent; - std::optional toDeleteObject; auto& gui = world.main.toolbar.gui; gui.push_id(id); - gui.tree_listing("list", bookmarkListRoot.get_net_id(), GUIStuff::TreeListing::DisplayData{ - .getObjInListAtIndex = [&](NetObjID parentId, size_t index) -> std::optional { - NetObjOrderedList& bookmarkParentFolder = *world.netObjMan.get_obj_temporary_ref_from_id(parentId)->get_folder_list(); - if(bookmarkParentFolder.size() <= index) - return std::nullopt; - return GUIStuff::TreeListing::DisplayData::ObjInList{ - .id = bookmarkParentFolder.at(index)->obj.get_net_id(), - .isDirectory = bookmarkParentFolder.at(index)->obj->is_folder(), - .isDirectoryOpen = bookmarkParentFolder.at(index)->obj->is_folder() ? bookmarkParentFolder.at(index)->obj->is_folder_open() : false - }; - }, - .getIndexOfObjInList = [&](const GUIStuff::TreeListing::ParentObjectIDPair& idPair) { - return world.netObjMan.get_obj_temporary_ref_from_id(idPair.parent)->get_folder_list()->get(idPair.object)->pos; - }, - .setDirectoryOpen = [&](NetObjID netID, bool newDirectoryOpen) { - world.netObjMan.get_obj_temporary_ref_from_id(netID)->set_folder_open(newDirectoryOpen); - }, - .drawNonDirectoryObjIconGUI = [&](NetObjID netID) { - CLAY_AUTO_ID({ - .layout = { - .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}, - .padding = CLAY_PADDING_ALL(2), - }, - }) { - gui.svg_icon("bookmark ico", "data/icons/bookmark.svg"); - } - return false; - }, - .drawObjGUI = [&](const GUIStuff::TreeListing::ParentObjectIDPair& idPair) { - auto tempPtr = world.netObjMan.get_obj_temporary_ref_from_id(idPair.object); - if(Clay_Hovered() && gui.io->mouse.leftClick >= 2 && !tempPtr->is_folder()) - tempPtr->get_bookmark_data().jump_to(world); - CLAY_AUTO_ID({ - .layout = { - .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}, - .childAlignment = {.x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER} - }, - }) { - gui.text_label(tempPtr->get_name()); - } - if(!tempPtr->is_folder() && gui.svg_icon_button_transparent("jump button", "data/icons/jump.svg", false, GUIStuff::TreeListing::ENTRY_HEIGHT)) { - tempPtr->get_bookmark_data().jump_to(world); - return true; - } - if(gui.svg_icon_button_transparent("delete button", "data/icons/trash.svg", false, GUIStuff::TreeListing::ENTRY_HEIGHT)) { - toDeleteParent = idPair.parent; - toDeleteObject = idPair.object; - return true; - } - return false; - }, - .moveObjectsToListAtIndex = [&](NetObjID listObj, size_t index, const std::vector& objsToInsert) { - world.netObjMan.send_multi_update_messsage([&]() { - std::unordered_map> toEraseMap; - uint32_t newIndex = index; - std::vector> toInsertObjPtrs; - auto& listPtr = world.netObjMan.get_obj_temporary_ref_from_id(listObj)->get_folder_list(); - - for(size_t i = 0; i < objsToInsert.size(); i++) { - toEraseMap[objsToInsert[i].parent].emplace(objsToInsert[i].object); - if(newIndex != 0 && objsToInsert[i].parent == listObj && listPtr->get(objsToInsert[i].object)->pos <= index) - newIndex--; - } - - for(auto& [listToEraseFrom, setToErase] : toEraseMap) { - auto& listToEraseFromPtr = world.netObjMan.get_obj_temporary_ref_from_id(listToEraseFrom)->get_folder_list(); - listToEraseFromPtr->erase_unordered_set(listToEraseFromPtr, setToErase, &toInsertObjPtrs); - } - - std::vector>> toInsert; - for(uint32_t i = 0; i < objsToInsert.size(); i++) { - auto it = std::find_if(toInsertObjPtrs.begin(), toInsertObjPtrs.end(), [id = objsToInsert[i].object](NetObjOwnerPtr& objPtr) { - return objPtr.get_net_id() == id; - }); - toInsert.emplace_back(newIndex + i, std::move(*it)); - toInsert.back().second.reassign_ids(); - } - listPtr->insert_ordered_list_and_send_create(listPtr, toInsert); - }, NetObjManager::SendUpdateType::SEND_TO_ALL, nullptr); - } - }, selectionData); - - if(selectionData.objsSelected != oldSelection) { - oldSelection = selectionData.objsSelected; - if(selectionData.objsSelected.size() == 1) { - NetObjTemporaryPtr tempPtr = world.netObjMan.get_obj_temporary_ref_from_id(*selectionData.objsSelected.begin()); - if(tempPtr) - nameToEdit = tempPtr->get_name(); - else { - nameToEdit.clear(); - } - } - else - nameToEdit.clear(); + if(bookmarkListRoot->get_folder_list()->empty()) { + gui.text_label_centered("No bookmarks yet..."); + selectionData = GUIStuff::TreeListing::SelectionData(); + oldSelection.clear(); + nameToEdit.clear(); } + else { + std::optional toDeleteParent; + std::optional toDeleteObject; + gui.tree_listing("list", bookmarkListRoot.get_net_id(), GUIStuff::TreeListing::DisplayData{ + .getObjInListAtIndex = [&](NetObjID parentId, size_t index) -> std::optional { + NetObjOrderedList& bookmarkParentFolder = *world.netObjMan.get_obj_temporary_ref_from_id(parentId)->get_folder_list(); + if(bookmarkParentFolder.size() <= index) + return std::nullopt; + return GUIStuff::TreeListing::DisplayData::ObjInList{ + .id = bookmarkParentFolder.at(index)->obj.get_net_id(), + .isDirectory = bookmarkParentFolder.at(index)->obj->is_folder(), + .isDirectoryOpen = bookmarkParentFolder.at(index)->obj->is_folder() ? bookmarkParentFolder.at(index)->obj->is_folder_open() : false + }; + }, + .getIndexOfObjInList = [&](const GUIStuff::TreeListing::ParentObjectIDPair& idPair) { + return world.netObjMan.get_obj_temporary_ref_from_id(idPair.parent)->get_folder_list()->get(idPair.object)->pos; + }, + .setDirectoryOpen = [&](NetObjID netID, bool newDirectoryOpen) { + world.netObjMan.get_obj_temporary_ref_from_id(netID)->set_folder_open(newDirectoryOpen); + }, + .drawNonDirectoryObjIconGUI = [&](NetObjID netID) { + CLAY_AUTO_ID({ + .layout = { + .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}, + .padding = CLAY_PADDING_ALL(2), + }, + }) { + gui.svg_icon("bookmark ico", "data/icons/bookmark.svg"); + } + return false; + }, + .drawObjGUI = [&](const GUIStuff::TreeListing::ParentObjectIDPair& idPair) { + auto tempPtr = world.netObjMan.get_obj_temporary_ref_from_id(idPair.object); + if(Clay_Hovered() && gui.io->mouse.leftClick >= 2 && !tempPtr->is_folder() && selectionData.objsSelected.contains(idPair.object) && !gui.io->key.leftCtrl && !gui.io->key.leftShift) + tempPtr->get_bookmark_data().jump_to(world); + CLAY_AUTO_ID({ + .layout = { + .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}, + .childAlignment = {.x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER} + }, + }) { + gui.text_label(tempPtr->get_name()); + } + if(!tempPtr->is_folder() && gui.svg_icon_button_transparent("jump button", "data/icons/jump.svg", false, GUIStuff::TreeListing::ENTRY_HEIGHT)) { + tempPtr->get_bookmark_data().jump_to(world); + return true; + } + if(gui.svg_icon_button_transparent("delete button", "data/icons/trash.svg", false, GUIStuff::TreeListing::ENTRY_HEIGHT)) { + toDeleteParent = idPair.parent; + toDeleteObject = idPair.object; + return true; + } + return false; + }, + .moveObjectsToListAtIndex = [&](NetObjID listObj, size_t index, const std::vector& objsToInsert) { + world.netObjMan.send_multi_update_messsage([&]() { + std::unordered_map> toEraseMap; + uint32_t newIndex = index; + std::vector> toInsertObjPtrs; + auto& listPtr = world.netObjMan.get_obj_temporary_ref_from_id(listObj)->get_folder_list(); - if(toDeleteObject.has_value()) { - auto& folderList = world.netObjMan.get_obj_temporary_ref_from_id(toDeleteParent.value())->get_folder_list(); - folderList->erase(folderList, toDeleteObject.value()); + for(size_t i = 0; i < objsToInsert.size(); i++) { + toEraseMap[objsToInsert[i].parent].emplace(objsToInsert[i].object); + if(newIndex != 0 && objsToInsert[i].parent == listObj && listPtr->get(objsToInsert[i].object)->pos <= index) + newIndex--; + } + + for(auto& [listToEraseFrom, setToErase] : toEraseMap) { + auto& listToEraseFromPtr = world.netObjMan.get_obj_temporary_ref_from_id(listToEraseFrom)->get_folder_list(); + listToEraseFromPtr->erase_unordered_set(listToEraseFromPtr, setToErase, &toInsertObjPtrs); + } + + std::vector>> toInsert; + for(uint32_t i = 0; i < objsToInsert.size(); i++) { + auto it = std::find_if(toInsertObjPtrs.begin(), toInsertObjPtrs.end(), [id = objsToInsert[i].object](NetObjOwnerPtr& objPtr) { + return objPtr.get_net_id() == id; + }); + toInsert.emplace_back(newIndex + i, std::move(*it)); + toInsert.back().second.reassign_ids(); + } + listPtr->insert_ordered_list_and_send_create(listPtr, toInsert); + }, NetObjManager::SendUpdateType::SEND_TO_ALL, nullptr); + } + }, selectionData); + + + if(selectionData.objsSelected != oldSelection) { + oldSelection = selectionData.objsSelected; + if(selectionData.objsSelected.size() == 1) { + NetObjTemporaryPtr tempPtr = world.netObjMan.get_obj_temporary_ref_from_id(*selectionData.objsSelected.begin()); + if(tempPtr) + nameToEdit = tempPtr->get_name(); + else { + nameToEdit.clear(); + } + } + else + nameToEdit.clear(); + } + + if(toDeleteObject.has_value()) { + auto& folderList = world.netObjMan.get_obj_temporary_ref_from_id(toDeleteParent.value())->get_folder_list(); + folderList->erase(folderList, toDeleteObject.value()); + } } gui.left_to_right_line_layout([&]() { @@ -151,8 +160,7 @@ void BookmarkManager::setup_list_gui(const std::string& id) { if(tempPtr) { gui.text_label_centered(tempPtr->is_folder() ? "Edit Bookmark Folder" : "Edit Bookmark"); gui.input_text_field("input edit name", "Name", &nameToEdit); - if(nameToEdit != tempPtr->get_name()) - tempPtr->set_name(tempPtr, nameToEdit); + tempPtr->set_name(world.delayedUpdateObjectManager, nameToEdit); } } diff --git a/src/CanvasComponents/CanvasComponentAllocator.cpp b/src/CanvasComponents/CanvasComponentAllocator.cpp index b4925b3..df63cc6 100644 --- a/src/CanvasComponents/CanvasComponentAllocator.cpp +++ b/src/CanvasComponents/CanvasComponentAllocator.cpp @@ -11,8 +11,8 @@ CanvasComponentAllocator::CanvasComponentAllocator(CanvasComponentType typeToAll comp = std::unique_ptr(CanvasComponent::allocate_comp(typeToAllocate)); } -void CanvasComponentAllocator::register_class(World& world, NetworkingObjects::NetObjManager& objMan) { - world.delayedUpdateObjectManager.register_class(objMan, NetworkingObjects::DelayUpdateSerializedClassManager::CustomConstructors{ +void CanvasComponentAllocator::register_class(World& world) { + world.delayedUpdateObjectManager.register_class(world.netObjMan, NetworkingObjects::DelayUpdateSerializedClassManager::CustomConstructors{ .writeConstructor = [](const CanvasComponentAllocator& o, cereal::PortableBinaryOutputArchive& a) { a(o.comp->get_type()); a(*o.comp); diff --git a/src/CanvasComponents/CanvasComponentAllocator.hpp b/src/CanvasComponents/CanvasComponentAllocator.hpp index 030803b..cb1c1e8 100644 --- a/src/CanvasComponents/CanvasComponentAllocator.hpp +++ b/src/CanvasComponents/CanvasComponentAllocator.hpp @@ -12,5 +12,5 @@ class CanvasComponentAllocator { CanvasComponentAllocator(); CanvasComponentAllocator(CanvasComponentType typeToAllocate); std::unique_ptr comp; - static void register_class(World& world, NetworkingObjects::NetObjManager& objMan); + static void register_class(World& world); }; diff --git a/src/CanvasComponents/CanvasComponentContainer.cpp b/src/CanvasComponents/CanvasComponentContainer.cpp index 2ca5479..cf97378 100644 --- a/src/CanvasComponents/CanvasComponentContainer.cpp +++ b/src/CanvasComponents/CanvasComponentContainer.cpp @@ -41,10 +41,6 @@ void CanvasComponentContainer::read_constructor_func(const NetworkingObjects::Ne o->compAllocator->comp->compContainer = o.get(); } -void CanvasComponentContainer::delay_post_assignment_update(DrawingProgram& drawP, CanvasComponent& comp) { - comp.compContainer->commit_update(drawP); -} - void CanvasComponentContainer::save_file(cereal::PortableBinaryOutputArchive& a) const { a(coords); get_comp().save_file(a); diff --git a/src/CanvasComponents/CanvasComponentContainer.hpp b/src/CanvasComponents/CanvasComponentContainer.hpp index a32ecdb..9d4ef25 100644 --- a/src/CanvasComponents/CanvasComponentContainer.hpp +++ b/src/CanvasComponents/CanvasComponentContainer.hpp @@ -13,7 +13,7 @@ class DrawingProgramCacheBVHNode; class CanvasComponentContainer { public: typedef NetworkingObjects::NetObjOrderedList NetList; - typedef NetworkingObjects::NetObjOwnerPtr> NetListOwnerPtr; + typedef NetworkingObjects::NetObjOwnerPtr NetListOwnerPtr; typedef NetworkingObjects::NetObjOrderedListObjectInfo ObjInfo; typedef std::shared_ptr ObjInfoSharedPtr; typedef std::weak_ptr ObjInfoWeakPtr; @@ -28,7 +28,6 @@ class CanvasComponentContainer { CanvasComponentContainer(); CanvasComponentContainer(NetworkingObjects::NetObjManager& objMan, CanvasComponentType type); static void register_class(NetworkingObjects::NetObjManager& t); - static void delay_post_assignment_update(DrawingProgram& drawP, CanvasComponent& comp); void save_file(cereal::PortableBinaryOutputArchive& a) const; void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version); CanvasComponent& get_comp() const; diff --git a/src/DrawingProgram/Layers/DrawingProgramLayer.hpp b/src/DrawingProgram/Layers/DrawingProgramLayer.hpp new file mode 100644 index 0000000..7b98fc9 --- /dev/null +++ b/src/DrawingProgram/Layers/DrawingProgramLayer.hpp @@ -0,0 +1,10 @@ +#pragma once +#include +#include "../../CanvasComponents/CanvasComponent.hpp" + +class DrawingProgramLayerListItem; + +class DrawingProgramLayer { + public: + CanvasComponentContainer::NetListOwnerPtr components; +}; diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerFolder.hpp b/src/DrawingProgram/Layers/DrawingProgramLayerFolder.hpp new file mode 100644 index 0000000..cd11c27 --- /dev/null +++ b/src/DrawingProgram/Layers/DrawingProgramLayerFolder.hpp @@ -0,0 +1,10 @@ +#pragma once +#include + +class DrawingProgramLayerListItem; + +class DrawingProgramLayerFolder { + public: + NetworkingObjects::NetObjOwnerPtr> folderList; + bool isFolderOpen = false; +}; diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerListItem.cpp b/src/DrawingProgram/Layers/DrawingProgramLayerListItem.cpp new file mode 100644 index 0000000..7537480 --- /dev/null +++ b/src/DrawingProgram/Layers/DrawingProgramLayerListItem.cpp @@ -0,0 +1,115 @@ +#include "DrawingProgramLayerListItem.hpp" +#include "DrawingProgramLayerFolder.hpp" +#include +#include "DrawingProgramLayer.hpp" +#include "../../World.hpp" + +using namespace NetworkingObjects; + +DrawingProgramLayerListItem::DrawingProgramLayerListItem() {} + +DrawingProgramLayerListItem::DrawingProgramLayerListItem(NetworkingObjects::NetObjManager& netObjMan, const std::string& initName, bool isFolder) { + if(isFolder) { + folderData = std::make_unique(); + folderData->folderList = netObjMan.make_obj>(); + } + else { + layerData = std::make_unique(); + layerData->components = netObjMan.make_obj(); + } + nameData = netObjMan.make_obj(); + nameData->name = initName; + displayData = netObjMan.make_obj(); +} + +void DrawingProgramLayerListItem::reassign_netobj_ids_call() { + if(folderData) + folderData->folderList.reassign_ids(); + else + layerData->components.reassign_ids(); + nameData.reassign_ids(); + displayData.reassign_ids(); +} + +bool DrawingProgramLayerListItem::is_folder() const { + return folderData != nullptr; +} + +DrawingProgramLayerFolder& DrawingProgramLayerListItem::get_folder() const { + return *folderData; +} + +DrawingProgramLayer& DrawingProgramLayerListItem::get_layer() const { + return *layerData; +} + +void DrawingProgramLayerListItem::set_name(NetworkingObjects::DelayUpdateSerializedClassManager& delayedNetObjMan, const std::string& newName) const { + if(nameData && nameData->name != newName) { + nameData->name = newName; + delayedNetObjMan.send_update_to_all(nameData, false); + } +} + +const std::string& DrawingProgramLayerListItem::get_name() const { + return nameData->name; +} + +void DrawingProgramLayerListItem::set_alpha(NetworkingObjects::DelayUpdateSerializedClassManager& delayedNetObjMan, float newAlpha) const { + if(displayData && displayData->alpha != newAlpha) { + displayData->alpha = newAlpha; + delayedNetObjMan.send_update_to_all(displayData, false); + } +} + +float DrawingProgramLayerListItem::get_alpha() const { + return displayData->alpha; +} + +void DrawingProgramLayerListItem::set_visible(NetworkingObjects::DelayUpdateSerializedClassManager& delayedNetObjMan, bool newVisible) const { + if(displayData && displayData->visible != newVisible) { + displayData->visible = newVisible; + delayedNetObjMan.send_update_to_all(displayData, false); + } +} + +bool DrawingProgramLayerListItem::get_visible() const { + return displayData->visible; +} + +void DrawingProgramLayerListItem::register_class(World& w) { + w.netObjMan.register_class({ + .writeConstructorFuncClient = write_constructor_func, + .readConstructorFuncClient = read_constructor_func, + .readUpdateFuncClient = nullptr, + .writeConstructorFuncServer = write_constructor_func, + .readConstructorFuncServer = read_constructor_func, + .readUpdateFuncServer = nullptr, + }); + w.delayedUpdateObjectManager.register_class(w.netObjMan); + w.delayedUpdateObjectManager.register_class(w.netObjMan); +} + +void DrawingProgramLayerListItem::write_constructor_func(const NetworkingObjects::NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a) { + a(o->is_folder()); + if(o->is_folder()) + o->folderData->folderList.write_create_message(a); + else + o->layerData->components.write_create_message(a); + o->nameData.write_create_message(a); + o->displayData.write_create_message(a); +} + +void DrawingProgramLayerListItem::read_constructor_func(const NetworkingObjects::NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) { + bool isFolder; + a(isFolder); + if(isFolder) { + o->folderData = std::make_unique(); + o->folderData->folderList = o.get_obj_man()->read_create_message>(a, c); + } + else { + o->layerData = std::make_unique(); + o->layerData->components = o.get_obj_man()->read_create_message(a, c); + } + o->nameData = o.get_obj_man()->read_create_message(a, c); + o->displayData = o.get_obj_man()->read_create_message(a, c); +} diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerListItem.hpp b/src/DrawingProgram/Layers/DrawingProgramLayerListItem.hpp new file mode 100644 index 0000000..9dd0396 --- /dev/null +++ b/src/DrawingProgram/Layers/DrawingProgramLayerListItem.hpp @@ -0,0 +1,50 @@ +#pragma once +#include +#include +#include +#include "DrawingProgramLayerFolder.hpp" +#include "DrawingProgramLayer.hpp" + +class DrawingProgramLayerFolder; +class DrawingProgramLayer; +class World; + +class DrawingProgramLayerListItem { + public: + DrawingProgramLayerListItem(); + DrawingProgramLayerListItem(NetworkingObjects::NetObjManager& netObjMan, const std::string& initName, bool isFolder); + bool is_folder() const; + DrawingProgramLayerFolder& get_folder() const; + DrawingProgramLayer& get_layer() const; + static void register_class(World& w); + void reassign_netobj_ids_call(); + + void set_name(NetworkingObjects::DelayUpdateSerializedClassManager& delayedNetObjMan, const std::string& newName) const; + const std::string& get_name() const; + + void set_alpha(NetworkingObjects::DelayUpdateSerializedClassManager& delayedNetObjMan, float newAlpha) const; + float get_alpha() const; + + void set_visible(NetworkingObjects::DelayUpdateSerializedClassManager& delayedNetObjMan, bool newVisible) const; + bool get_visible() const; + private: + static void write_constructor_func(const NetworkingObjects::NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive& a); + static void read_constructor_func(const NetworkingObjects::NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c); + std::unique_ptr folderData; + std::unique_ptr layerData; + struct NameData { + std::string name; + template void serialize(Archive& a) { + a(name); + } + }; + struct DisplayData { + float alpha = 1.0f; + bool visible = true; + template void serialize(Archive& a) { + a(alpha, visible); + } + }; + NetworkingObjects::NetObjOwnerPtr nameData; + NetworkingObjects::NetObjOwnerPtr displayData; +}; diff --git a/src/World.cpp b/src/World.cpp index 6021b14..ab9ebc0 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -110,11 +110,10 @@ void World::init_client_data_list_callbacks() { } void World::init_net_obj_type_list() { - BookmarkListItem::register_class(netObjMan); - NetworkingObjects::register_ordered_list_class(netObjMan); + BookmarkListItem::register_class(*this); delayedUpdateObjectManager.register_class(netObjMan); NetworkingObjects::register_ordered_list_class(netObjMan); - CanvasComponentAllocator::register_class(*this, netObjMan); + CanvasComponentAllocator::register_class(*this); CanvasComponentContainer::register_class(netObjMan); NetworkingObjects::register_ordered_list_class(netObjMan); canvasTheme.register_class();