diff --git a/src/Bookmarks/BookmarkManager.cpp b/src/Bookmarks/BookmarkManager.cpp index ca33d30..a8b2151 100644 --- a/src/Bookmarks/BookmarkManager.cpp +++ b/src/Bookmarks/BookmarkManager.cpp @@ -44,7 +44,7 @@ NetworkingObjects::NetObjTemporaryPtr BookmarkManager::get_boo return toRet; } -void BookmarkManager::setup_list_gui(const char* id) { +void BookmarkManager::setup_list_gui() { using namespace NetworkingObjects; using namespace GUIStuff; using namespace ElementHelpers; @@ -439,6 +439,7 @@ NetworkingObjects::NetObjOrderedListIterator BookmarkManager:: auto& it = insertedBookmarkPair.second; world.undo.push(std::make_unique(it->pos, world.undo.get_undoid_from_netid(insertedBookmarkPair.first), world.undo.get_undoid_from_netid(it->obj.get_net_id()))); world.main.g.gui.set_to_layout(); + refresh_gui_data(); return it; } diff --git a/src/Bookmarks/BookmarkManager.hpp b/src/Bookmarks/BookmarkManager.hpp index fb8fe3b..bb3f30d 100644 --- a/src/Bookmarks/BookmarkManager.hpp +++ b/src/Bookmarks/BookmarkManager.hpp @@ -13,7 +13,7 @@ class BookmarkManager { BookmarkManager(World& w); void server_init_no_file(); void scale_up(const WorldScalar& scaleUpAmount); - void setup_list_gui(const char* id); + void setup_list_gui(); void refresh_gui_data(); void save_file(cereal::PortableBinaryOutputArchive& a) const; void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version); diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp b/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp index 9cd867d..c09f7bc 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp @@ -8,546 +8,600 @@ #include "Helpers/NetworkingObjects/NetObjOrderedList.hpp" #include "SerializedBlendMode.hpp" +#include "../../GUIStuff/ElementHelpers/TextLabelHelpers.hpp" +#include "../../GUIStuff/ElementHelpers/ButtonHelpers.hpp" +#include "../../GUIStuff/ElementHelpers/LayoutHelpers.hpp" +#include "../../GUIStuff/ElementHelpers/TextBoxHelpers.hpp" +#include "../../GUIStuff/ElementHelpers/NumberSliderHelpers.hpp" +#include "../../GUIStuff/Elements/SVGIcon.hpp" +#include "../../GUIStuff/Elements/DropDown.hpp" + DrawingProgramLayerManagerGUI::DrawingProgramLayerManagerGUI(DrawingProgramLayerManager& drawLayerMan): layerMan(drawLayerMan) {} void DrawingProgramLayerManagerGUI::refresh_gui_data() { + selectedLayerIndices.clear(); editing_layer_check(); - oldSelection.clear(); nameToEdit.clear(); nameForNew.clear(); - editingData = std::nullopt; + editingLayerOldMetainfo = std::nullopt; alphaValToEdit = 0.0f; blendModeValToEdit = 0; } -void DrawingProgramLayerManagerGUI::setup_list_gui(const char* id, bool& hoveringOverDropdown) { - //using namespace NetworkingObjects; - //auto& world = layerMan.drawP.world; - //if(layerMan.layerTreeRoot) { - // auto& gui = world.main.toolbar.gui; - // gui.push_id(id); - // if(layerMan.layerTreeRoot->get_folder().folderList->empty()) { - // gui.text_label_centered("No layers exist."); - // selectionData = GUIStuff::TreeListing::SelectionData(); - // oldSelection.clear(); - // nameToEdit.clear(); - // } - // else { - // std::optional toDeleteParent; - // std::optional toDeleteObject; - // gui.tree_listing("list", layerMan.layerTreeRoot.get_net_id(), GUIStuff::TreeListing::DisplayData{ - // .getObjInListAtIndex = [&](NetObjID parentId, size_t index) -> std::optional { - // NetObjOrderedList& parentFolder = *world.netObjMan.get_obj_temporary_ref_from_id(parentId)->get_folder().folderList; - // if(parentFolder.size() <= index) - // return std::nullopt; - // return GUIStuff::TreeListing::DisplayData::ObjInList{ - // .id = parentFolder.at(index)->obj.get_net_id(), - // .isDirectory = parentFolder.at(index)->obj->is_folder(), - // .isDirectoryOpen = parentFolder.at(index)->obj->is_folder() ? parentFolder.at(index)->obj->get_folder().isFolderOpen : false - // }; - // }, - // .getIndexOfObjInList = [&](const GUIStuff::TreeListing::ParentObjectIDPair& idPair) { - // return world.netObjMan.get_obj_temporary_ref_from_id(idPair.parent)->get_folder().folderList->get(idPair.object)->pos; - // }, - // .setDirectoryOpen = [&](NetObjID netID, bool newDirectoryOpen) { - // world.netObjMan.get_obj_temporary_ref_from_id(netID)->get_folder().isFolderOpen = 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("ico", "data/icons/layer.svg"); - // } - // return false; - // }, - // .drawObjGUI = [&](const GUIStuff::TreeListing::ParentObjectIDPair& idPair) { - // auto tempPtr = world.netObjMan.get_obj_temporary_ref_from_id(idPair.object); - // bool isButtonClicked = false; - // if(Clay_Hovered() && gui.io->mouse.leftClick >= 2 && !tempPtr->is_folder() && selectionData.objsSelected.contains(idPair.object) && !gui.io->key.leftCtrl && !gui.io->key.leftShift) - // layerMan.editingLayer = tempPtr; - // if(!tempPtr->is_folder()) { - // CLAY_AUTO_ID({ - // .layout = { - // .sizing = {.width = CLAY_SIZING_FIXED(GUIStuff::TreeListing::ENTRY_HEIGHT), .height = CLAY_SIZING_FIXED(GUIStuff::TreeListing::ENTRY_HEIGHT)}, - // .padding = CLAY_PADDING_ALL(2), - // }, - // }) { - // if(tempPtr.get_net_id() == layerMan.editingLayer.get_net_id()) - // gui.svg_icon("edit ico", "data/icons/pencil.svg"); - // } - // } - // 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(gui.svg_icon_button_transparent("edit button", "data/icons/pencil.svg", false, GUIStuff::TreeListing::ENTRY_HEIGHT)) { - // layerMan.editingLayer = tempPtr; - // isButtonClicked = true; - // } - // if(gui.svg_icon_button_transparent("visible button", tempPtr->get_visible() ? "data/icons/eyeopen.svg" : "data/icons/eyeclose.svg", false, GUIStuff::TreeListing::ENTRY_HEIGHT)) { - // tempPtr->set_visible(layerMan, !tempPtr->get_visible()); - // isButtonClicked = true; - // } - // if(gui.svg_icon_button_transparent("delete button", "data/icons/trash.svg", false, GUIStuff::TreeListing::ENTRY_HEIGHT)) { - // toDeleteParent = idPair.parent; - // toDeleteObject = idPair.object; - // isButtonClicked = true; - // } - // return isButtonClicked; - // }, - // .moveObjectsToListAtIndex = [&](NetObjID listObj, size_t index, const std::vector& objsToInsert) { - // std::unordered_map, std::vector>> toEraseMapUndo; - // WorldUndoManager::UndoObjectID insertParentUndoID; - // uint32_t insertUndoPosition; - // std::vector insertedUndoIDs; +NetworkingObjects::NetObjTemporaryPtr DrawingProgramLayerManagerGUI::get_layer_parent_from_obj_index(const GUIStuff::TreeListingObjIndexList& objIndex) { + if(objIndex.empty()) + throw std::runtime_error("[DrawingProgramLayerManagerGUI::get_layer_parent_from_obj_index] Called on empty objIndex"); + NetworkingObjects::NetObjTemporaryPtr toRet = layerMan.layerTreeRoot; + for(size_t i = 0; i < objIndex.size() - 1; i++) + toRet = toRet->get_folder().folderList->at(objIndex[i])->obj; + return toRet; +} - // 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().folderList; +NetworkingObjects::NetObjTemporaryPtr DrawingProgramLayerManagerGUI::get_layer_from_obj_index(const GUIStuff::TreeListingObjIndexList& objIndex) { + NetworkingObjects::NetObjTemporaryPtr toRet = layerMan.layerTreeRoot; + for(size_t i : objIndex) + toRet = toRet->get_folder().folderList->at(i)->obj; + return toRet; +} - // // Map parent folders to list of objects that should be erased from them - // for(size_t i = 0; i < objsToInsert.size(); i++) { - // auto& parentListPtr = world.netObjMan.get_obj_temporary_ref_from_id(objsToInsert[i].parent)->get_folder().folderList; - // toEraseMap[objsToInsert[i].parent].emplace_back(parentListPtr->get(objsToInsert[i].object)); - // if(newIndex != 0 && objsToInsert[i].parent == listObj && listPtr->get(objsToInsert[i].object)->pos <= index) - // newIndex--; - // } +void DrawingProgramLayerManagerGUI::setup_list_gui() { + using namespace NetworkingObjects; + using namespace GUIStuff; + using namespace ElementHelpers; - // // Prepare erase map for undo - // for(auto& [parentNetID, objsToEraseList] : toEraseMap) { - // auto& undoEraseListPairForParent = toEraseMapUndo[world.undo.get_undoid_from_netid(parentNetID)]; - // uint32_t i = 0; - // for(auto& objToErase : objsToEraseList) { - // undoEraseListPairForParent.first.emplace_back(objToErase->pos - i); - // undoEraseListPairForParent.second.emplace_back(world.undo.get_undoid_from_netid(objToErase->obj.get_net_id())); - // i++; - // } - // } + auto& world = layerMan.drawP.world; + if(layerMan.layerTreeRoot) { + auto& gui = world.main.g.gui; + if(layerMan.layerTreeRoot->get_folder().folderList->empty()) { + text_label_centered(gui, "No layers exist."); + selectedLayerIndices.clear(); + nameToEdit.clear(); + } + else { + gui.element("list", TreeListing::Data { + .selectedIndices = &selectedLayerIndices, + .dirInfo = [&](const TreeListingObjIndexList& objIndex) -> std::optional { + auto layer = get_layer_from_obj_index(objIndex); + if(!layer->is_folder()) + return std::nullopt; + else + return TreeListing::DirectoryInfo{ + .dirSize = layer->get_folder().folderList->size(), + .isOpen = layer->get_folder().isFolderOpen + }; + }, + .setDirectoryOpen = [&](const TreeListingObjIndexList& objIndex, bool newDirectoryOpen) { + get_layer_from_obj_index(objIndex)->get_folder().isFolderOpen = newDirectoryOpen; + }, + .drawNonDirectoryObjIconGUI = [&](const TreeListingObjIndexList& objIndex) { + CLAY_AUTO_ID({ + .layout = { + .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}, + .padding = CLAY_PADDING_ALL(2), + }, + }) { + gui.element("layer ico", "data/icons/layer.svg"); + } + }, + .drawObjGUI = [&](const TreeListingObjIndexList& objIndex) { + auto layer = get_layer_from_obj_index(objIndex); + 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} + }, + }) { + text_label(gui, layer->get_name()); + } + if(!layer->is_folder()) { + gui.set_z_index_keep_clipping_region(gui.get_z_index() + 1, [&] { + svg_icon_button(gui, "edit button", "data/icons/pencil.svg", { + .drawType = SelectableButton::DrawType::TRANSPARENT_ALL, + .size = TreeListing::ENTRY_HEIGHT, + .onClick = [&, layer] { + layerMan.editingLayer = layer; + } + }); + }); + } + gui.set_z_index_keep_clipping_region(gui.get_z_index() + 1, [&] { + svg_icon_button(gui, "visible button", layer->get_visible() ? "data/icons/eyeopen.svg" : "data/icons/eyeclose.svg", { + .drawType = SelectableButton::DrawType::TRANSPARENT_ALL, + .size = TreeListing::ENTRY_HEIGHT, + .onClick = [&, layer] { + layer->set_visible(layerMan, !layer->get_visible()); + } + }); + }); + gui.set_z_index_keep_clipping_region(gui.get_z_index() + 1, [&] { + svg_icon_button(gui, "delete button", "data/icons/trash.svg", { + .drawType = SelectableButton::DrawType::TRANSPARENT_ALL, + .size = TreeListing::ENTRY_HEIGHT, + .onClick = [&, objIndex] { + remove_layer(objIndex); + } + }); + }); + }, + .onDoubleClick = [&](const TreeListingObjIndexList& objIndex) { + layerMan.editingLayer = get_layer_from_obj_index(objIndex); + }, + .onSelectChange = [&] { + editing_layer_check(); + if(selectedLayerIndices.size() == 1) { + const TreeListingObjIndexList& objIndex = *selectedLayerIndices.begin(); + NetObjTemporaryPtr tempPtr = get_layer_from_obj_index(objIndex); + if(tempPtr) { + nameToEdit = tempPtr->get_name(); + alphaValToEdit = tempPtr->get_alpha(); + auto it = std::find(get_blend_mode_useful_list().begin(), get_blend_mode_useful_list().end(), tempPtr->get_blend_mode()); + blendModeValToEdit = (it == get_blend_mode_useful_list().end()) ? 0 : (it - get_blend_mode_useful_list().begin()); + } + else { + nameToEdit.clear(); + alphaValToEdit = 0.0f; + blendModeValToEdit = 0; + } + } + else { + nameToEdit.clear(); + alphaValToEdit = 0.0f; + blendModeValToEdit = 0; + } + }, + .moveObj = [&](const std::vector& objectIndicesTreeListing, const TreeListingObjIndexList& newObjIndexTreeListing) { + NetObjID listObj; + size_t index; + struct ParentObjectIDPair { + NetObjID parent; + NetObjID object; + }; + std::vector objsToInsert; - // // Erase the list of objects we previously mapped to each parent, and move the erased objects to vector toInsertObjPtrs - // for(auto& [listToEraseFrom, setToErase] : toEraseMap) { - // auto& listToEraseFromPtr = world.netObjMan.get_obj_temporary_ref_from_id(listToEraseFrom)->get_folder().folderList; - // listToEraseFromPtr->erase_list(listToEraseFromPtr, setToErase, &toInsertObjPtrs); - // } + { + listObj = get_layer_parent_from_obj_index(newObjIndexTreeListing).get_net_id(); + index = newObjIndexTreeListing.back(); + for(auto& objIndex : objectIndicesTreeListing) + objsToInsert.emplace_back(get_layer_parent_from_obj_index(objIndex).get_net_id(), get_layer_from_obj_index(objIndex).get_net_id()); + } - // // Insert objects in toInsertObjPtrs into the folder we have selected - // std::vector, NetObjOwnerPtr>> toInsert; - // auto insertIt = listPtr->at(newIndex); - // 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(insertIt, std::move(*it)); - // toInsert.back().second.reassign_ids(); - // } - // std::vector> insertedIterators = listPtr->insert_sorted_list_and_send_create(listPtr, toInsert); + std::unordered_map, std::vector>> toEraseMapUndo; + WorldUndoManager::UndoObjectID insertParentUndoID; + uint32_t insertUndoPosition; + std::vector insertedUndoIDs; - // // Prepare insert list for undo - // insertParentUndoID = world.undo.get_undoid_from_netid(listObj); - // insertUndoPosition = newIndex; - // for(auto& it : insertedIterators) - // insertedUndoIDs.emplace_back(world.undo.get_undoid_from_netid(it->obj.get_net_id())); - // }, NetObjManager::SendUpdateType::SEND_TO_ALL, nullptr); + 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().folderList; - // class MoveLayersWorldUndoAction : public WorldUndoAction { - // public: - // // If the undo ID maps to the net id, we can also assume that the object is definitely inside the list we want to move it from, and not inside some other list - // // If it was moved to another list, there would be an undo move that would move it back to this list, and if it was moved by another player the undo id wouldnt map back to the net id, and the undo would fail - // // We can also assume all objects in all lists remain in the same order for the same reason, so no need to sort anything if it was sorted when the undo action was generated - // MoveLayersWorldUndoAction(const std::unordered_map, std::vector>>& initUndoEraseMap, - // WorldUndoManager::UndoObjectID initInsertParentUndoID, - // uint32_t initInsertPosition, - // std::vector initInsertedUndoIDs): - // undoEraseMap(initUndoEraseMap), - // insertParentUndoID(initInsertParentUndoID), - // insertPosition(initInsertPosition), - // insertedUndoIDs(initInsertedUndoIDs) - // {} - // std::string get_name() const override { - // return "Move Layers"; - // } - // bool undo(WorldUndoManager& undoMan) override { - // std::vector> toMoveObjs; - // std::vector> toEraseList; - // NetObjTemporaryPtr> eraseListPtr; - // std::unordered_map*, std::vector>> toInsertToMap; + // Map parent folders to list of objects that should be erased from them + for(size_t i = 0; i < objsToInsert.size(); i++) { + auto& parentListPtr = world.netObjMan.get_obj_temporary_ref_from_id(objsToInsert[i].parent)->get_folder().folderList; + toEraseMap[objsToInsert[i].parent].emplace_back(parentListPtr->get(objsToInsert[i].object)); + if(newIndex != 0 && objsToInsert[i].parent == listObj && listPtr->get(objsToInsert[i].object)->pos <= index) + newIndex--; + } - // { - // std::optional eraseListNetID = undoMan.get_netid_from_undoid(insertParentUndoID); - // if(!eraseListNetID.has_value()) - // return false; - // eraseListPtr = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(eraseListNetID.value())->get_folder().folderList; - // } + // Prepare erase map for undo + for(auto& [parentNetID, objsToEraseList] : toEraseMap) { + auto& undoEraseListPairForParent = toEraseMapUndo[world.undo.get_undoid_from_netid(parentNetID)]; + uint32_t i = 0; + for(auto& objToErase : objsToEraseList) { + undoEraseListPairForParent.first.emplace_back(objToErase->pos - i); + undoEraseListPairForParent.second.emplace_back(world.undo.get_undoid_from_netid(objToErase->obj.get_net_id())); + i++; + } + } - // { - // std::vector toEraseNetIDList; - // if(!undoMan.fill_netid_list_from_undoid_list(toEraseNetIDList, insertedUndoIDs)) - // return false; - // toEraseList = eraseListPtr->get_list(toEraseNetIDList); - // } + // Erase the list of objects we previously mapped to each parent, and move the erased objects to vector toInsertObjPtrs + for(auto& [listToEraseFrom, setToErase] : toEraseMap) { + auto& listToEraseFromPtr = world.netObjMan.get_obj_temporary_ref_from_id(listToEraseFrom)->get_folder().folderList; + listToEraseFromPtr->erase_list(listToEraseFromPtr, setToErase, &toInsertObjPtrs); + } - // { - // for(auto& [undoID, indexUndoIdListPair] : undoEraseMap) { - // std::optional netID = undoMan.get_netid_from_undoid(undoID); - // if(!netID.has_value()) - // return false; - // auto& insertMapEntry = toInsertToMap[netID.value()]; - // insertMapEntry.first = &indexUndoIdListPair.first; - // if(!undoMan.fill_netid_list_from_undoid_list(insertMapEntry.second, indexUndoIdListPair.second)) - // return false; - // } - // } + // Insert objects in toInsertObjPtrs into the folder we have selected + std::vector, NetObjOwnerPtr>> toInsert; + auto insertIt = listPtr->at(newIndex); + 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(insertIt, std::move(*it)); + toInsert.back().second.reassign_ids(); + } + std::vector> insertedIterators = listPtr->insert_sorted_list_and_send_create(listPtr, toInsert); - // undoMan.world.netObjMan.send_multi_update_messsage([&]() { - // eraseListPtr->erase_list(eraseListPtr, toEraseList, &toMoveObjs); + // Prepare insert list for undo + insertParentUndoID = world.undo.get_undoid_from_netid(listObj); + insertUndoPosition = newIndex; + for(auto& it : insertedIterators) + insertedUndoIDs.emplace_back(world.undo.get_undoid_from_netid(it->obj.get_net_id())); + }, NetObjManager::SendUpdateType::SEND_TO_ALL, nullptr); - // for(auto& [parentNetID, indexNetIDListPair] : toInsertToMap) { - // auto& parentListPtr = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(parentNetID)->get_folder().folderList; - // std::vector> insertIteratorList = parentListPtr->at_ordered_indices(*indexNetIDListPair.first); - // auto& insertNetIDList = indexNetIDListPair.second; - // std::vector, NetObjOwnerPtr>> toInsert; - // for(auto [insertIt, netID] : std::views::zip(insertIteratorList, insertNetIDList)) { - // auto it = std::find_if(toMoveObjs.begin(), toMoveObjs.end(), [id = netID](NetObjOwnerPtr& objPtr) { - // return objPtr.get_net_id() == id; - // }); - // toInsert.emplace_back(insertIt, std::move(*it)); - // toInsert.back().second.reassign_ids(); - // } - // parentListPtr->insert_sorted_list_and_send_create(parentListPtr, toInsert); - // } - // }, NetObjManager::SendUpdateType::SEND_TO_ALL, nullptr); - // return true; - // } - // bool redo(WorldUndoManager& undoMan) override { - // std::unordered_map> toEraseMap; - // NetObjTemporaryPtr> listPtr; - // std::vector objsToInsert; + class MoveLayersWorldUndoAction : public WorldUndoAction { + public: + // If the undo ID maps to the net id, we can also assume that the object is definitely inside the list we want to move it from, and not inside some other list + // If it was moved to another list, there would be an undo move that would move it back to this list, and if it was moved by another player the undo id wouldnt map back to the net id, and the undo would fail + // We can also assume all objects in all lists remain in the same order for the same reason, so no need to sort anything if it was sorted when the undo action was generated + MoveLayersWorldUndoAction(const std::unordered_map, std::vector>>& initUndoEraseMap, + WorldUndoManager::UndoObjectID initInsertParentUndoID, + uint32_t initInsertPosition, + std::vector initInsertedUndoIDs): + undoEraseMap(initUndoEraseMap), + insertParentUndoID(initInsertParentUndoID), + insertPosition(initInsertPosition), + insertedUndoIDs(initInsertedUndoIDs) + {} + std::string get_name() const override { + return "Move Layers"; + } + bool undo(WorldUndoManager& undoMan) override { + std::vector> toMoveObjs; + std::vector> toEraseList; + NetObjTemporaryPtr> eraseListPtr; + std::unordered_map*, std::vector>> toInsertToMap; - // { - // for(auto& [undoID, indexUndoIDListPair] : undoEraseMap) { - // std::optional netID = undoMan.get_netid_from_undoid(undoID); - // if(!netID.has_value()) - // return false; - // if(!undoMan.fill_netid_list_from_undoid_list(toEraseMap[netID.value()], indexUndoIDListPair.second)) - // return false; - // } - // } + { + std::optional eraseListNetID = undoMan.get_netid_from_undoid(insertParentUndoID); + if(!eraseListNetID.has_value()) + return false; + eraseListPtr = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(eraseListNetID.value())->get_folder().folderList; + } - // { - // std::optional netID = undoMan.get_netid_from_undoid(insertParentUndoID); - // if(!netID.has_value()) - // return false; - // listPtr = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(netID.value())->get_folder().folderList; - // } + { + std::vector toEraseNetIDList; + if(!undoMan.fill_netid_list_from_undoid_list(toEraseNetIDList, insertedUndoIDs)) + return false; + toEraseList = eraseListPtr->get_list(toEraseNetIDList); + } - // { - // if(!undoMan.fill_netid_list_from_undoid_list(objsToInsert, insertedUndoIDs)) - // return false; - // } + { + for(auto& [undoID, indexUndoIdListPair] : undoEraseMap) { + std::optional netID = undoMan.get_netid_from_undoid(undoID); + if(!netID.has_value()) + return false; + auto& insertMapEntry = toInsertToMap[netID.value()]; + insertMapEntry.first = &indexUndoIdListPair.first; + if(!undoMan.fill_netid_list_from_undoid_list(insertMapEntry.second, indexUndoIdListPair.second)) + return false; + } + } - // undoMan.world.netObjMan.send_multi_update_messsage([&]() { - // std::vector> toInsertObjPtrs; + undoMan.world.netObjMan.send_multi_update_messsage([&]() { + eraseListPtr->erase_list(eraseListPtr, toEraseList, &toMoveObjs); - // for(auto& [listToEraseFrom, setToErase] : toEraseMap) { - // auto& listToEraseFromPtr = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(listToEraseFrom)->get_folder().folderList; - // listToEraseFromPtr->erase_list(listToEraseFromPtr, listToEraseFromPtr->get_list(setToErase), &toInsertObjPtrs); - // } + for(auto& [parentNetID, indexNetIDListPair] : toInsertToMap) { + auto& parentListPtr = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(parentNetID)->get_folder().folderList; + std::vector> insertIteratorList = parentListPtr->at_ordered_indices(*indexNetIDListPair.first); + auto& insertNetIDList = indexNetIDListPair.second; + std::vector, NetObjOwnerPtr>> toInsert; + for(auto [insertIt, netID] : std::views::zip(insertIteratorList, insertNetIDList)) { + auto it = std::find_if(toMoveObjs.begin(), toMoveObjs.end(), [id = netID](NetObjOwnerPtr& objPtr) { + return objPtr.get_net_id() == id; + }); + toInsert.emplace_back(insertIt, std::move(*it)); + toInsert.back().second.reassign_ids(); + } + parentListPtr->insert_sorted_list_and_send_create(parentListPtr, toInsert); + } + }, NetObjManager::SendUpdateType::SEND_TO_ALL, nullptr); + return true; + } + bool redo(WorldUndoManager& undoMan) override { + std::unordered_map> toEraseMap; + NetObjTemporaryPtr> listPtr; + std::vector objsToInsert; - // std::vector, NetObjOwnerPtr>> toInsert; - // auto insertIt = listPtr->at(insertPosition); - // for(uint32_t i = 0; i < objsToInsert.size(); i++) { - // auto it = std::find_if(toInsertObjPtrs.begin(), toInsertObjPtrs.end(), [id = objsToInsert[i]](NetObjOwnerPtr& objPtr) { - // return objPtr.get_net_id() == id; - // }); - // toInsert.emplace_back(insertIt, std::move(*it)); - // toInsert.back().second.reassign_ids(); - // } - // listPtr->insert_sorted_list_and_send_create(listPtr, toInsert); - // }, NetObjManager::SendUpdateType::SEND_TO_ALL, nullptr); + { + for(auto& [undoID, indexUndoIDListPair] : undoEraseMap) { + std::optional netID = undoMan.get_netid_from_undoid(undoID); + if(!netID.has_value()) + return false; + if(!undoMan.fill_netid_list_from_undoid_list(toEraseMap[netID.value()], indexUndoIDListPair.second)) + return false; + } + } - // return true; - // } - // ~MoveLayersWorldUndoAction() {} + { + std::optional netID = undoMan.get_netid_from_undoid(insertParentUndoID); + if(!netID.has_value()) + return false; + listPtr = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(netID.value())->get_folder().folderList; + } - // std::unordered_map, std::vector>> undoEraseMap; - // WorldUndoManager::UndoObjectID insertParentUndoID; - // uint32_t insertPosition; - // std::vector insertedUndoIDs; - // }; - // world.undo.push(std::make_unique(toEraseMapUndo, insertParentUndoID, insertUndoPosition, insertedUndoIDs)); - // } - // }, selectionData); + { + if(!undoMan.fill_netid_list_from_undoid_list(objsToInsert, insertedUndoIDs)) + return false; + } + undoMan.world.netObjMan.send_multi_update_messsage([&]() { + std::vector> toInsertObjPtrs; - // if(selectionData.objsSelected != oldSelection) { - // editing_layer_check(); - // 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(); - // alphaValToEdit = tempPtr->get_alpha(); - // auto it = std::find(get_blend_mode_useful_list().begin(), get_blend_mode_useful_list().end(), tempPtr->get_blend_mode()); - // blendModeValToEdit = (it == get_blend_mode_useful_list().end()) ? 0 : (it - get_blend_mode_useful_list().begin()); - // } - // else { - // nameToEdit.clear(); - // alphaValToEdit = 0.0f; - // blendModeValToEdit = 0; - // } - // } - // else { - // nameToEdit.clear(); - // alphaValToEdit = 0.0f; - // blendModeValToEdit = 0; - // } - // } + for(auto& [listToEraseFrom, setToErase] : toEraseMap) { + auto& listToEraseFromPtr = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(listToEraseFrom)->get_folder().folderList; + listToEraseFromPtr->erase_list(listToEraseFromPtr, listToEraseFromPtr->get_list(setToErase), &toInsertObjPtrs); + } - // if(toDeleteObject.has_value()) - // remove_layer(toDeleteParent.value(), toDeleteObject.value()); - // } + std::vector, NetObjOwnerPtr>> toInsert; + auto insertIt = listPtr->at(insertPosition); + for(uint32_t i = 0; i < objsToInsert.size(); i++) { + auto it = std::find_if(toInsertObjPtrs.begin(), toInsertObjPtrs.end(), [id = objsToInsert[i]](NetObjOwnerPtr& objPtr) { + return objPtr.get_net_id() == id; + }); + toInsert.emplace_back(insertIt, std::move(*it)); + toInsert.back().second.reassign_ids(); + } + listPtr->insert_sorted_list_and_send_create(listPtr, toInsert); + }, NetObjManager::SendUpdateType::SEND_TO_ALL, nullptr); - // gui.left_to_right_line_layout([&]() { - // bool addByEnter = false; - // gui.input_text("input new name", &nameForNew, true, [&](GUIStuff::SelectionHelper& s) { - // addByEnter = s.selected && gui.io->key.enter; - // }); - // - // if(gui.svg_icon_button("create new layer", "data/icons/plusbold.svg", false, gui.SMALL_BUTTON_SIZE) || addByEnter) { - // auto newLayerObjInfo = create_layer(new DrawingProgramLayerListItem(world.netObjMan, nameForNew, false)); - // layerMan.editingLayer = newLayerObjInfo->obj; - // } - // else if(gui.svg_icon_button("create new folder", "data/icons/folderbold.svg", false, gui.SMALL_BUTTON_SIZE)) { - // auto newFolderObjInfo = create_layer(new DrawingProgramLayerListItem(world.netObjMan, nameForNew, true)); - // newFolderObjInfo->obj->get_folder().isFolderOpen = true; - // } - // }); + return true; + } + ~MoveLayersWorldUndoAction() {} - // if(selectionData.objsSelected.size() == 1) { - // NetObjTemporaryPtr tempPtr = world.netObjMan.get_obj_temporary_ref_from_id(*selectionData.objsSelected.begin()); - // if(tempPtr) { - // gui.text_label_centered(tempPtr->is_folder() ? "Edit Layer Folder" : "Edit Layer"); - // gui.input_text_field("input edit name", "Name", &nameToEdit); - // tempPtr->set_name(world.delayedUpdateObjectManager, nameToEdit); - // gui.slider_scalar_field("input alpha slider", "Alpha", &alphaValToEdit, 0.0f, 1.0f, 2); - // tempPtr->set_alpha(layerMan, alphaValToEdit); - // gui.left_to_right_line_layout([&]() { - // gui.text_label("Blend Mode"); - // gui.dropdown_select("input blend mode", &blendModeValToEdit, get_blend_mode_useful_name_list(), 190.0f, [&hoveringOverDropdown]() { - // if(Clay_Hovered()) - // hoveringOverDropdown = true; - // }); - // }); - // tempPtr->set_blend_mode(layerMan, get_blend_mode_useful_list()[blendModeValToEdit]); - // } - // } + std::unordered_map, std::vector>> undoEraseMap; + WorldUndoManager::UndoObjectID insertParentUndoID; + uint32_t insertPosition; + std::vector insertedUndoIDs; + }; + world.undo.push(std::make_unique(toEraseMapUndo, insertParentUndoID, insertUndoPosition, insertedUndoIDs)); + } + }); + } - // gui.pop_id(); - //} + left_to_right_line_layout(gui, [&]() { + input_text(gui, "input new name", &nameForNew, { + .onEnter = [&] { + auto newLayerObjInfo = create_layer(new DrawingProgramLayerListItem(world.netObjMan, nameForNew, false)); + layerMan.editingLayer = newLayerObjInfo->obj; + } + }); + + svg_icon_button(gui, "create new layer", "data/icons/plusbold.svg", { + .size = SMALL_BUTTON_SIZE, + .onClick = [&] { + auto newLayerObjInfo = create_layer(new DrawingProgramLayerListItem(world.netObjMan, nameForNew, false)); + layerMan.editingLayer = newLayerObjInfo->obj; + } + }); + + svg_icon_button(gui, "create new folder", "data/icons/folderbold.svg", { + .size = SMALL_BUTTON_SIZE, + .onClick = [&] { + auto newFolderObjInfo = create_layer(new DrawingProgramLayerListItem(world.netObjMan, nameForNew, true)); + newFolderObjInfo->obj->get_folder().isFolderOpen = true; + } + }); + }); + + if(editingLayer) { + text_label_centered(gui, editingLayer->is_folder() ? "Edit Layer Folder" : "Edit Layer"); + input_text_field(gui, "input edit name", "Name", &nameToEdit, { + .onEdit = [&] { + if(editingLayer) { // This can be set to null on the way here (close layer popup when textbox is selected) + editingLayer->set_name(world.delayedUpdateObjectManager, nameToEdit); + world.main.g.gui.set_to_layout(); + } + } + }); + slider_scalar_field(gui, "input alpha slider", "Alpha", &alphaValToEdit, 0.0f, 1.0f, { + .decimalPrecision = 2, + .onEdit = [&] { + if(editingLayer) { + editingLayer->set_name(world.delayedUpdateObjectManager, nameToEdit); + editingLayer->set_alpha(layerMan, alphaValToEdit); + } + } + }); + left_to_right_line_layout(gui, [&]() { + text_label(gui, "Blend Mode"); + gui.element>("input blend mode", &blendModeValToEdit, get_blend_mode_useful_name_list(), DropdownOptions{ + .width = 190.0f, + .onClick = [&] { + if(editingLayer) + editingLayer->set_blend_mode(layerMan, get_blend_mode_useful_list()[blendModeValToEdit]); + } + }); + }); + } + } } std::optional>> DrawingProgramLayerManagerGUI::try_to_create_in_proper_position(DrawingProgramLayerListItem* newItem) { - //using namespace NetworkingObjects; - //auto& world = layerMan.drawP.world; - //if(selectionData.orderedObjsSelected.empty()) - // return std::nullopt; - //auto& backObjParentObjectPair = selectionData.orderedObjsSelected.back(); - //NetObjTemporaryPtr parentPtr = world.netObjMan.get_obj_temporary_ref_from_id(backObjParentObjectPair.parent); - //if(!parentPtr) - // return std::nullopt; - //NetObjTemporaryPtr objectPtr = world.netObjMan.get_obj_temporary_ref_from_id(backObjParentObjectPair.object); - //if(!objectPtr) - // return std::nullopt; - //if(objectPtr->is_folder()) { - // objectPtr->get_folder().isFolderOpen = true; - // return std::pair>{objectPtr.get_net_id(), objectPtr->get_folder().folderList->insert_and_send_create(objectPtr->get_folder().folderList, objectPtr->get_folder().folderList->begin(), newItem)}; - //} - //return std::pair>{parentPtr.get_net_id(), parentPtr->get_folder().folderList->insert_and_send_create(parentPtr->get_folder().folderList, parentPtr->get_folder().folderList->get(objectPtr.get_net_id()), newItem)}; + using namespace NetworkingObjects; + if(selectedLayerIndices.empty()) + return std::nullopt; + auto& lastObjSelected = *selectedLayerIndices.rbegin(); + NetObjTemporaryPtr objectPtr = get_layer_from_obj_index(lastObjSelected); + if(objectPtr->is_folder()) { + objectPtr->get_folder().isFolderOpen = true; + return std::pair>{objectPtr.get_net_id(), objectPtr->get_folder().folderList->insert_and_send_create(objectPtr->get_folder().folderList, objectPtr->get_folder().folderList->begin(), newItem)}; + } + NetObjTemporaryPtr parentPtr = get_layer_parent_from_obj_index(lastObjSelected); + return std::pair>{parentPtr.get_net_id(), parentPtr->get_folder().folderList->insert_and_send_create(parentPtr->get_folder().folderList, parentPtr->get_folder().folderList->get(objectPtr.get_net_id()), newItem)}; } std::pair> DrawingProgramLayerManagerGUI::create_in_proper_position(DrawingProgramLayerListItem* newItem) { - //auto toRet = try_to_create_in_proper_position(newItem); - //if(!toRet) - // return {layerMan.layerTreeRoot.get_net_id(), layerMan.layerTreeRoot->get_folder().folderList->insert_and_send_create(layerMan.layerTreeRoot->get_folder().folderList, layerMan.layerTreeRoot->get_folder().folderList->begin(), newItem)}; - //return toRet.value(); + auto toRet = try_to_create_in_proper_position(newItem); + if(!toRet) + return {layerMan.layerTreeRoot.get_net_id(), layerMan.layerTreeRoot->get_folder().folderList->insert_and_send_create(layerMan.layerTreeRoot->get_folder().folderList, layerMan.layerTreeRoot->get_folder().folderList->begin(), newItem)}; + return toRet.value(); } NetworkingObjects::NetObjOrderedListIterator DrawingProgramLayerManagerGUI::create_layer(DrawingProgramLayerListItem* newItem) { - //auto& world = layerMan.drawP.world; - //class AddLayerWorldUndoAction : public WorldUndoAction { - // public: - // AddLayerWorldUndoAction(std::unique_ptr initLayerData, uint32_t newPos, WorldUndoManager::UndoObjectID initParentUndoID, WorldUndoManager::UndoObjectID initUndoID): - // layerData(std::move(initLayerData)), - // pos(newPos), - // parentUndoID(initParentUndoID), - // undoID(initUndoID) - // {} - // std::string get_name() const override { - // return "Add Layer Item"; - // } - // bool undo(WorldUndoManager& undoMan) override { - // std::optional toEraseParentID = undoMan.get_netid_from_undoid(parentUndoID); - // if(!toEraseParentID.has_value()) - // return false; - // std::optional toEraseID = undoMan.get_netid_from_undoid(undoID); - // if(!toEraseID.has_value()) - // return false; + auto& world = layerMan.drawP.world; + class AddLayerWorldUndoAction : public WorldUndoAction { + public: + AddLayerWorldUndoAction(std::unique_ptr initLayerData, uint32_t newPos, WorldUndoManager::UndoObjectID initParentUndoID, WorldUndoManager::UndoObjectID initUndoID): + layerData(std::move(initLayerData)), + pos(newPos), + parentUndoID(initParentUndoID), + undoID(initUndoID) + {} + std::string get_name() const override { + return "Add Layer Item"; + } + bool undo(WorldUndoManager& undoMan) override { + std::optional toEraseParentID = undoMan.get_netid_from_undoid(parentUndoID); + if(!toEraseParentID.has_value()) + return false; + std::optional toEraseID = undoMan.get_netid_from_undoid(undoID); + if(!toEraseID.has_value()) + return false; - // auto& layerList = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(toEraseParentID.value())->get_folder().folderList; - // auto it = layerList->get(toEraseID.value()); - // layerData = std::make_unique(it->obj->get_undo_data(undoMan)); - // layerList->erase(layerList, it); - // return true; - // } - // bool redo(WorldUndoManager& undoMan) override { - // std::optional toInsertParentID = undoMan.get_netid_from_undoid(parentUndoID); - // if(!toInsertParentID.has_value()) - // return false; - // std::optional toInsertID = undoMan.get_netid_from_undoid(undoID); - // if(toInsertID.has_value()) - // return false; + auto& layerList = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(toEraseParentID.value())->get_folder().folderList; + auto it = layerList->get(toEraseID.value()); + layerData = std::make_unique(it->obj->get_undo_data(undoMan)); + layerList->erase(layerList, it); + return true; + } + bool redo(WorldUndoManager& undoMan) override { + std::optional toInsertParentID = undoMan.get_netid_from_undoid(parentUndoID); + if(!toInsertParentID.has_value()) + return false; + std::optional toInsertID = undoMan.get_netid_from_undoid(undoID); + if(toInsertID.has_value()) + return false; - // auto& layerList = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(toInsertParentID.value())->get_folder().folderList; - // auto insertedIt = layerList->emplace_direct(layerList, layerList->at(pos), undoMan.world, *layerData); - // undoMan.register_new_netid_to_existing_undoid(undoID, insertedIt->obj.get_net_id()); - // layerData = nullptr; - // return true; - // } - // void scale_up(const WorldScalar& scaleAmount) override { - // if(layerData) - // layerData->scale_up(scaleAmount); - // } - // ~AddLayerWorldUndoAction() {} + auto& layerList = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(toInsertParentID.value())->get_folder().folderList; + auto insertedIt = layerList->emplace_direct(layerList, layerList->at(pos), undoMan.world, *layerData); + undoMan.register_new_netid_to_existing_undoid(undoID, insertedIt->obj.get_net_id()); + layerData = nullptr; + return true; + } + void scale_up(const WorldScalar& scaleAmount) override { + if(layerData) + layerData->scale_up(scaleAmount); + } + ~AddLayerWorldUndoAction() {} - // std::unique_ptr layerData; - // uint32_t pos; - // WorldUndoManager::UndoObjectID parentUndoID; - // WorldUndoManager::UndoObjectID undoID; - //}; + std::unique_ptr layerData; + uint32_t pos; + WorldUndoManager::UndoObjectID parentUndoID; + WorldUndoManager::UndoObjectID undoID; + }; - //auto insertedLayerPair = create_in_proper_position(newItem); - //auto& it = insertedLayerPair.second; - //world.undo.push(std::make_unique(std::make_unique(it->obj->get_undo_data(world.undo)), it->pos, world.undo.get_undoid_from_netid(insertedLayerPair.first), world.undo.get_undoid_from_netid(it->obj.get_net_id()))); - //return it; + auto insertedLayerPair = create_in_proper_position(newItem); + auto& it = insertedLayerPair.second; + world.undo.push(std::make_unique(std::make_unique(it->obj->get_undo_data(world.undo)), it->pos, world.undo.get_undoid_from_netid(insertedLayerPair.first), world.undo.get_undoid_from_netid(it->obj.get_net_id()))); + world.main.g.gui.set_to_layout(); + refresh_gui_data(); + return it; } -void DrawingProgramLayerManagerGUI::remove_layer(const NetworkingObjects::NetObjID& parentID, const NetworkingObjects::NetObjID& objectID) { - //auto& world = layerMan.drawP.world; - //class DeleteLayerWorldUndoAction : public WorldUndoAction { - // public: - // DeleteLayerWorldUndoAction(std::unique_ptr initLayerData, uint32_t newPos, WorldUndoManager::UndoObjectID initParentUndoID, WorldUndoManager::UndoObjectID initUndoID): - // layerData(std::move(initLayerData)), - // pos(newPos), - // parentUndoID(initParentUndoID), - // undoID(initUndoID) - // {} - // std::string get_name() const override { - // return "Delete Layer Item"; - // } - // bool undo(WorldUndoManager& undoMan) override { - // std::optional toInsertParentID = undoMan.get_netid_from_undoid(parentUndoID); - // if(!toInsertParentID.has_value()) - // return false; - // std::optional toInsertID = undoMan.get_netid_from_undoid(undoID); - // if(toInsertID.has_value()) - // return false; +void DrawingProgramLayerManagerGUI::remove_layer(const GUIStuff::TreeListingObjIndexList& objIndex) { + refresh_gui_data(); - // auto& layerList = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(toInsertParentID.value())->get_folder().folderList; - // auto insertedIt = layerList->emplace_direct(layerList, layerList->at(pos), undoMan.world, *layerData); - // undoMan.register_new_netid_to_existing_undoid(undoID, insertedIt->obj.get_net_id()); - // layerData = nullptr; - // return true; - // } - // bool redo(WorldUndoManager& undoMan) override { - // std::optional toEraseParentID = undoMan.get_netid_from_undoid(parentUndoID); - // if(!toEraseParentID.has_value()) - // return false; - // std::optional toEraseID = undoMan.get_netid_from_undoid(undoID); - // if(!toEraseID.has_value()) - // return false; + auto& world = layerMan.drawP.world; + class DeleteLayerWorldUndoAction : public WorldUndoAction { + public: + DeleteLayerWorldUndoAction(std::unique_ptr initLayerData, uint32_t newPos, WorldUndoManager::UndoObjectID initParentUndoID, WorldUndoManager::UndoObjectID initUndoID): + layerData(std::move(initLayerData)), + pos(newPos), + parentUndoID(initParentUndoID), + undoID(initUndoID) + {} + std::string get_name() const override { + return "Delete Layer Item"; + } + bool undo(WorldUndoManager& undoMan) override { + std::optional toInsertParentID = undoMan.get_netid_from_undoid(parentUndoID); + if(!toInsertParentID.has_value()) + return false; + std::optional toInsertID = undoMan.get_netid_from_undoid(undoID); + if(toInsertID.has_value()) + return false; - // auto& layerList = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(toEraseParentID.value())->get_folder().folderList; - // auto it = layerList->get(toEraseID.value()); - // layerData = std::make_unique(it->obj->get_undo_data(undoMan)); - // layerList->erase(layerList, it); - // return true; - // } - // void scale_up(const WorldScalar& scaleAmount) override { - // if(layerData) - // layerData->scale_up(scaleAmount); - // } - // ~DeleteLayerWorldUndoAction() {} + auto& layerList = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(toInsertParentID.value())->get_folder().folderList; + auto insertedIt = layerList->emplace_direct(layerList, layerList->at(pos), undoMan.world, *layerData); + undoMan.register_new_netid_to_existing_undoid(undoID, insertedIt->obj.get_net_id()); + layerData = nullptr; + return true; + } + bool redo(WorldUndoManager& undoMan) override { + std::optional toEraseParentID = undoMan.get_netid_from_undoid(parentUndoID); + if(!toEraseParentID.has_value()) + return false; + std::optional toEraseID = undoMan.get_netid_from_undoid(undoID); + if(!toEraseID.has_value()) + return false; - // std::unique_ptr layerData; - // uint32_t pos; - // WorldUndoManager::UndoObjectID parentUndoID; - // WorldUndoManager::UndoObjectID undoID; - //}; + auto& layerList = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(toEraseParentID.value())->get_folder().folderList; + auto it = layerList->get(toEraseID.value()); + layerData = std::make_unique(it->obj->get_undo_data(undoMan)); + layerList->erase(layerList, it); + return true; + } + void scale_up(const WorldScalar& scaleAmount) override { + if(layerData) + layerData->scale_up(scaleAmount); + } + ~DeleteLayerWorldUndoAction() {} - //auto& folderList = world.netObjMan.get_obj_temporary_ref_from_id(parentID)->get_folder().folderList; - //auto it = folderList->get(objectID); - //world.undo.push(std::make_unique(std::make_unique(it->obj->get_undo_data(world.undo)), it->pos, world.undo.get_undoid_from_netid(parentID), world.undo.get_undoid_from_netid(objectID))); - //folderList->erase(folderList, it); + std::unique_ptr layerData; + uint32_t pos; + WorldUndoManager::UndoObjectID parentUndoID; + WorldUndoManager::UndoObjectID undoID; + }; + + + auto parentPtr = get_layer_parent_from_obj_index(objIndex); + auto layerPtr = get_layer_from_obj_index(objIndex); + auto it = parentPtr->get_folder().folderList->get(layerPtr.get_net_id()); + world.undo.push(std::make_unique(std::make_unique(layerPtr->get_undo_data(world.undo)), it->pos, world.undo.get_undoid_from_netid(parentPtr.get_net_id()), world.undo.get_undoid_from_netid(layerPtr.get_net_id()))); + parentPtr->get_folder().folderList->erase(parentPtr->get_folder().folderList, it); + world.main.g.gui.set_to_layout(); } void DrawingProgramLayerManagerGUI::editing_layer_check() { - //auto& world = layerMan.drawP.world; - //class EditLayerWorldUndoAction : public WorldUndoAction { - // public: - // EditLayerWorldUndoAction(std::unique_ptr initData, WorldUndoManager::UndoObjectID initUndoID): - // data(std::move(initData)), - // undoID(initUndoID) - // {} - // std::string get_name() const override { - // return "Edit Layer"; - // } - // bool undo(WorldUndoManager& undoMan) override { - // return undo_redo(undoMan); - // } - // bool redo(WorldUndoManager& undoMan) override { - // return undo_redo(undoMan); - // } - // bool undo_redo(WorldUndoManager& undoMan) { - // std::optional toModifyID = undoMan.get_netid_from_undoid(undoID); - // if(!toModifyID.has_value()) - // return false; - // auto objPtr = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(toModifyID.value()); - // auto newData = std::make_unique(objPtr->get_metainfo()); - // objPtr->set_metainfo(undoMan.world.drawProg.layerMan, *data); - // data = std::move(newData); - // return true; - // } - // ~EditLayerWorldUndoAction() {} + auto& world = layerMan.drawP.world; + class EditLayerWorldUndoAction : public WorldUndoAction { + public: + EditLayerWorldUndoAction(std::unique_ptr initData, WorldUndoManager::UndoObjectID initUndoID): + data(std::move(initData)), + undoID(initUndoID) + {} + std::string get_name() const override { + return "Edit Layer"; + } + bool undo(WorldUndoManager& undoMan) override { + return undo_redo(undoMan); + } + bool redo(WorldUndoManager& undoMan) override { + return undo_redo(undoMan); + } + bool undo_redo(WorldUndoManager& undoMan) { + std::optional toModifyID = undoMan.get_netid_from_undoid(undoID); + if(!toModifyID.has_value()) + return false; + auto objPtr = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(toModifyID.value()); + auto newData = std::make_unique(objPtr->get_metainfo()); + objPtr->set_metainfo(undoMan.world.drawProg.layerMan, *data); + data = std::move(newData); + return true; + } + ~EditLayerWorldUndoAction() {} - // std::unique_ptr data; - // WorldUndoManager::UndoObjectID undoID; - //}; + std::unique_ptr data; + WorldUndoManager::UndoObjectID undoID; + }; - //if(oldSelection.size() == 1 && editingData.has_value()) { - // const NetworkingObjects::NetObjID& oldNetObjID = *oldSelection.begin(); - // auto tempPtr = world.netObjMan.get_obj_temporary_ref_from_id(oldNetObjID); - // if(tempPtr) { - // const DrawingProgramLayerListItemMetaInfo& currentMetaData = tempPtr->get_metainfo(); - // if(currentMetaData != editingData.value()) - // world.undo.push(std::make_unique(std::make_unique(editingData.value()), world.undo.get_undoid_from_netid(oldNetObjID))); - // } - //} - //editingData = std::nullopt; - //if(selectionData.objsSelected.size() == 1) { - // auto tempPtr = world.netObjMan.get_obj_temporary_ref_from_id(*selectionData.objsSelected.begin()); - // if(tempPtr) - // editingData = tempPtr->get_metainfo(); - //} - //oldSelection = selectionData.objsSelected; + + if(editingLayer) { + const DrawingProgramLayerListItemMetaInfo& currentMetaData = editingLayer->get_metainfo(); + if(currentMetaData != editingLayerOldMetainfo.value()) + world.undo.push(std::make_unique(std::make_unique(editingLayerOldMetainfo.value()), world.undo.get_undoid_from_netid(editingLayer.get_net_id()))); + } + + if(selectedLayerIndices.size() == 1) { + editingLayer = get_layer_from_obj_index(*selectedLayerIndices.begin()); + editingLayerOldMetainfo = editingLayer->get_metainfo(); + } + else { + editingLayer = NetworkingObjects::NetObjTemporaryPtr(); + editingLayerOldMetainfo = std::nullopt; + } } diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.hpp b/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.hpp index e2d3b94..e148f30 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.hpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.hpp @@ -12,21 +12,26 @@ class DrawingProgramLayerManagerGUI { public: DrawingProgramLayerManagerGUI(DrawingProgramLayerManager& layerManager); void refresh_gui_data(); - void setup_list_gui(const char* id, bool& hoveringOverDropdown); + void setup_list_gui(); private: std::optional>> try_to_create_in_proper_position(DrawingProgramLayerListItem* newItem); std::pair> create_in_proper_position(DrawingProgramLayerListItem* newItem); NetworkingObjects::NetObjOrderedListIterator create_layer(DrawingProgramLayerListItem* newItem); - void remove_layer(const NetworkingObjects::NetObjID& parentID, const NetworkingObjects::NetObjID& objectID); + void remove_layer(const GUIStuff::TreeListingObjIndexList& objIndex); void editing_layer_check(); - std::unordered_set oldSelection; + NetworkingObjects::NetObjTemporaryPtr get_layer_parent_from_obj_index(const GUIStuff::TreeListingObjIndexList& objIndex); + NetworkingObjects::NetObjTemporaryPtr get_layer_from_obj_index(const GUIStuff::TreeListingObjIndexList& objIndex); + std::string nameToEdit; std::string nameForNew; float alphaValToEdit = 0.0f; size_t blendModeValToEdit = 0; - std::optional editingData; + std::set selectedLayerIndices; + NetworkingObjects::NetObjTemporaryPtr editingLayer; + + std::optional editingLayerOldMetainfo; DrawingProgramLayerManager& layerMan; }; diff --git a/src/GUIStuff/Elements/ColorPickerButton.impl.hpp b/src/GUIStuff/Elements/ColorPickerButton.impl.hpp index 610590d..26b6e47 100644 --- a/src/GUIStuff/Elements/ColorPickerButton.impl.hpp +++ b/src/GUIStuff/Elements/ColorPickerButton.impl.hpp @@ -12,6 +12,7 @@ template void ColorPickerButton::layout(const Clay_ElementId& id GUIStuff::ElementHelpers::color_button(gui, "Color Picker Button", val, { .isSelected = isOpen, + .hasAlpha = data.hasAlpha, .onClick = [&]{ isOpen = !isOpen; gui.set_to_layout(); diff --git a/src/Toolbar.cpp b/src/Toolbar.cpp index 74a3aa0..423a62d 100644 --- a/src/Toolbar.cpp +++ b/src/Toolbar.cpp @@ -545,15 +545,11 @@ void Toolbar::top_toolbar() { else gridMenu.popupOpen = true; }); - icon_button_top_toolbar("Layer Menu Button", "data/icons/layer.svg", layerMenuPopupOpen, [&] { - if(layerMenuPopupOpen) { - main.world->drawProg.layerMan.listGUI.refresh_gui_data(); - layerMenuPopupOpen = false; - } - else { + Element* layerMenuButton = icon_button_top_toolbar("Layer Menu Button", "data/icons/layer.svg", layerMenuPopupOpen, [&] { + if(layerMenuPopupOpen) + stop_displaying_layer_menu(); + else layerMenuPopupOpen = true; - layerMenuPopUpJustOpen = true; - } }); Element* bookmarkMenuButton = icon_button_top_toolbar("Bookmark Menu Button", "data/icons/bookmark.svg", bookmarkMenuPopupOpen, [&] { if(bookmarkMenuPopupOpen) @@ -567,7 +563,7 @@ void Toolbar::top_toolbar() { if(bookmarkMenuPopupOpen) bookmark_menu(bookmarkMenuButton); if(layerMenuPopupOpen) - layer_menu(layerMenuPopUpJustOpen); + layer_menu(layerMenuButton); } if(menuPopUpOpen) { gui.set_z_index(5, [&] { @@ -959,12 +955,18 @@ void Toolbar::stop_displaying_bookmark_menu() { main.g.gui.set_to_layout(); } +void Toolbar::stop_displaying_layer_menu() { + main.world->drawProg.layerMan.listGUI.refresh_gui_data(); + layerMenuPopupOpen = false; + main.g.gui.set_to_layout(); +} + void Toolbar::bookmark_menu(Element* bookmarkMenuButton) { auto& gui = main.g.gui; auto& io = gui.io; gui.set_z_index(gui.get_z_index() + 1, [&] { - gui.element("grid menu", [&] (LayoutElement*, const Clay_ElementId& lId) { + gui.element("bookmark menu", [&] (LayoutElement*, const Clay_ElementId& lId) { CLAY(lId, { .layout = { .sizing = {.width = CLAY_SIZING_FIT(300), .height = CLAY_SIZING_FIT(0, 600) }, @@ -978,7 +980,7 @@ void Toolbar::bookmark_menu(Element* bookmarkMenuButton) { .floating = {.offset = {.x = 0, .y = static_cast(io.theme->padding1)}, .zIndex = gui.get_z_index(), .attachPoints = {.element = CLAY_ATTACH_POINT_RIGHT_TOP, .parent = CLAY_ATTACH_POINT_RIGHT_BOTTOM}, .attachTo = CLAY_ATTACH_TO_PARENT} }) { text_label_centered(gui, "Bookmarks"); - main.world->bMan.setup_list_gui("bookmark menu list"); + main.world->bMan.setup_list_gui(); } }, LayoutElement::Callbacks { .mouseButton = [&, bookmarkMenuButton] (LayoutElement* l, const InputManager::MouseButtonCallbackArgs& button) { @@ -989,33 +991,33 @@ void Toolbar::bookmark_menu(Element* bookmarkMenuButton) { }); } -void Toolbar::layer_menu(bool justOpened) { +void Toolbar::layer_menu(Element* layerMenuButton) { auto& gui = main.g.gui; auto& io = gui.io; - gui.new_id("layer menu", [&] { - //Clay_ElementId localId = CLAY_ID_LOCAL("INFINIPAINT LAYER MENU"); - //CLAY(localId, { - // .layout = { - // .sizing = {.width = CLAY_SIZING_FIT(300), .height = CLAY_SIZING_FIT(0, 600) }, - // .padding = CLAY_PADDING_ALL(io.theme->padding1), - // .childGap = io.theme->childGap1, - // .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_TOP}, - // .layoutDirection = CLAY_TOP_TO_BOTTOM - // }, - // .backgroundColor = convert_vec4(io.theme->backColor1), - // .cornerRadius = CLAY_CORNER_RADIUS(io.theme->windowCorners1), - // .floating = {.offset = {.x = 0, .y = static_cast(io.theme->padding1)}, .attachPoints = {.element = CLAY_ATTACH_POINT_RIGHT_TOP, .parent = CLAY_ATTACH_POINT_RIGHT_BOTTOM}, .attachTo = CLAY_ATTACH_TO_PARENT} - //}) { - // gui.obstructing_window(localId); - // text_label_centered(gui, "Layers"); - // bool hoveringOverDropdown = false; - // main.world->drawProg.layerMan.listGUI.setup_list_gui("layer menu list", hoveringOverDropdown); - // if(io.mouse.leftClick && !Clay_Hovered() && !justOpened && !hoveringOverDropdown) { - // layerMenuPopupOpen = false; - // main.world->drawProg.layerMan.listGUI.refresh_gui_data(); - // } - //} + gui.set_z_index(gui.get_z_index() + 1, [&] { + gui.element("layer menu", [&] (LayoutElement*, const Clay_ElementId& lId) { + CLAY(lId, { + .layout = { + .sizing = {.width = CLAY_SIZING_FIT(300), .height = CLAY_SIZING_FIT(0, 600) }, + .padding = CLAY_PADDING_ALL(io.theme->padding1), + .childGap = io.theme->childGap1, + .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_TOP}, + .layoutDirection = CLAY_TOP_TO_BOTTOM + }, + .backgroundColor = convert_vec4(io.theme->backColor1), + .cornerRadius = CLAY_CORNER_RADIUS(io.theme->windowCorners1), + .floating = {.offset = {.x = 0, .y = static_cast(io.theme->padding1)}, .zIndex = gui.get_z_index(), .attachPoints = {.element = CLAY_ATTACH_POINT_RIGHT_TOP, .parent = CLAY_ATTACH_POINT_RIGHT_BOTTOM}, .attachTo = CLAY_ATTACH_TO_PARENT} + }) { + text_label_centered(gui, "Layers"); + main.world->drawProg.layerMan.listGUI.setup_list_gui(); + } + }, LayoutElement::Callbacks { + .mouseButton = [&, layerMenuButton] (LayoutElement* l, const InputManager::MouseButtonCallbackArgs& button) { + if(!l->mouseHovering && !l->childMouseHovering && !layerMenuButton->mouseHovering && button.down) + stop_displaying_layer_menu(); + } + }); }); } diff --git a/src/Toolbar.hpp b/src/Toolbar.hpp index c0c7587..d93b165 100644 --- a/src/Toolbar.hpp +++ b/src/Toolbar.hpp @@ -95,8 +95,9 @@ class Toolbar { void add_grid(); void stop_displaying_grid_menu(); void stop_displaying_bookmark_menu(); + void stop_displaying_layer_menu(); void bookmark_menu(GUIStuff::Element* bookmarkMenuButton); - void layer_menu(bool justOpened); + void layer_menu(GUIStuff::Element* layerMenuButton); void drawing_program_gui(); void options_menu(); void file_picker_gui_refresh_entries();