diff --git a/include/Helpers/MathExtras.hpp b/include/Helpers/MathExtras.hpp index 79557ee..16314a8 100644 --- a/include/Helpers/MathExtras.hpp +++ b/include/Helpers/MathExtras.hpp @@ -300,6 +300,8 @@ template std::array, 4> triangle_from_rect_points(cons } template std::string vec_pretty(const T& a) { + if(a.size() == 0) + return "[]"; std::stringstream ss; ss << "["; for(size_t i = 0; i < a.size(); i++) { diff --git a/src/Bookmarks/BookmarkManager.cpp b/src/Bookmarks/BookmarkManager.cpp index d14fd1e..332ef60 100644 --- a/src/Bookmarks/BookmarkManager.cpp +++ b/src/Bookmarks/BookmarkManager.cpp @@ -6,6 +6,12 @@ #include "Helpers/NetworkingObjects/NetObjTemporaryPtr.decl.hpp" #include +#include "../GUIStuff/ElementHelpers/TextLabelHelpers.hpp" +#include "../GUIStuff/ElementHelpers/ButtonHelpers.hpp" +#include "../GUIStuff/ElementHelpers/LayoutHelpers.hpp" +#include "../GUIStuff/ElementHelpers/TextBoxHelpers.hpp" +#include "../GUIStuff/Elements/SVGIcon.hpp" + BookmarkManager::BookmarkManager(World& w): world(w) {} @@ -15,326 +21,345 @@ void BookmarkManager::server_init_no_file() { } void BookmarkManager::refresh_gui_data() { - selectionData = GUIStuff::TreeListing::SelectionData(); + selectedBookmarkIndices.clear(); editing_bookmark_check(); - oldSelection.clear(); - editingBookmarkName = std::nullopt; nameToEdit.clear(); nameForNew.clear(); + world.main.g.gui.set_to_layout(); +} + +NetworkingObjects::NetObjTemporaryPtr BookmarkManager::get_bookmark_parent_from_obj_index(const GUIStuff::TreeListingObjIndexList& objIndex) { + if(objIndex.empty()) + throw std::runtime_error("[BookmarkManager::get_bookmark_parent_from_obj_index] Called on empty objIndex"); + NetworkingObjects::NetObjTemporaryPtr toRet = bookmarkListRoot; + for(size_t i = 0; i < objIndex.size() - 1; i++) + toRet = toRet->get_folder_list()->at(objIndex[i])->obj; + return toRet; +} + +NetworkingObjects::NetObjTemporaryPtr BookmarkManager::get_bookmark_from_obj_index(const GUIStuff::TreeListingObjIndexList& objIndex) { + NetworkingObjects::NetObjTemporaryPtr toRet = bookmarkListRoot; + for(size_t i : objIndex) + toRet = toRet->get_folder_list()->at(i)->obj; + return toRet; } void BookmarkManager::setup_list_gui(const char* id) { - //using namespace NetworkingObjects; - //if(bookmarkListRoot) { - // auto& gui = world.main.toolbar.gui; - // gui.push_id(id); - // 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; - // auto itemAtIndex = bookmarkParentFolder.at(index); - // return GUIStuff::TreeListing::DisplayData::ObjInList{ - // .id = itemAtIndex->obj.get_net_id(), - // .isDirectory = itemAtIndex->obj->is_folder(), - // .isDirectoryOpen = itemAtIndex->obj->is_folder() ? itemAtIndex->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); - // 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) - // 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); - // 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; + using namespace NetworkingObjects; + using namespace GUIStuff; + using namespace ElementHelpers; + if(bookmarkListRoot) { + auto& gui = world.main.g.gui; + if(bookmarkListRoot->get_folder_list()->empty()) + text_label_centered(gui, "No bookmarks yet..."); + else { + gui.element("bookmark list", TreeListing::Data { + .selectedIndices = &selectedBookmarkIndices, + .dirInfo = [&](const TreeListingObjIndexList& objIndex) -> std::optional { + auto bookmark = get_bookmark_from_obj_index(objIndex); + if(!bookmark->is_folder()) + return std::nullopt; + else + return TreeListing::DirectoryInfo{ + .dirSize = bookmark->get_folder_list()->size(), + .isOpen = bookmark->is_folder_open() + }; + }, + .setDirectoryOpen = [&](const TreeListingObjIndexList& objIndex, bool newDirectoryOpen) { + get_bookmark_from_obj_index(objIndex)->set_folder_open(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("bookmark ico", "data/icons/bookmark.svg"); + } + }, + .drawObjGUI = [&](const TreeListingObjIndexList& objIndex) { + auto bookmark = get_bookmark_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, bookmark->get_name()); + } + if(!bookmark->is_folder()) { + gui.set_z_index_keep_clipping_region(gui.get_z_index() + 1, [&] { + svg_icon_button(gui, "jump button", "data/icons/jump.svg", { + .drawType = SelectableButton::DrawType::TRANSPARENT_ALL, + .size = TreeListing::ENTRY_HEIGHT, + .onClick = [&, bookmark] { + bookmark->get_bookmark_data().jump_to(world); + } + }); + }); + } + 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_bookmark(objIndex); + } + }); + }); + }, + .onDoubleClick = [&](const TreeListingObjIndexList& objIndex) { + get_bookmark_from_obj_index(objIndex)->get_bookmark_data().jump_to(world); + }, + .onSelectChange = [&] { + editing_bookmark_check(); + if(selectedBookmarkIndices.size() == 1) { + const TreeListingObjIndexList& objIndex = *selectedBookmarkIndices.begin(); + NetObjTemporaryPtr tempPtr = get_bookmark_from_obj_index(objIndex); + if(tempPtr) + nameToEdit = tempPtr->get_name(); + else + nameToEdit.clear(); + } + else + nameToEdit.clear(); + }, + .moveObj = [&](const std::vector& objectIndices, const TreeListingObjIndexList& newObjIndex) { + std::unordered_map, std::vector>> toEraseMapUndo; + WorldUndoManager::UndoObjectID insertParentUndoID; + uint32_t insertUndoPosition; + std::vector insertedUndoIDs; - // 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(); + world.netObjMan.send_multi_update_messsage([&]() { + std::unordered_map>> toEraseMap; + uint32_t newIndex = newObjIndex.back(); + std::vector> toInsertObjPtrs; + auto& listPtr = get_bookmark_parent_from_obj_index(newObjIndex)->get_folder_list(); - // // 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_list(); - // 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--; - // } + // Map parent folders to list of objects that should be erased from them + for(size_t i = 0; i < objectIndices.size(); i++) { + auto parentBookmarkList = get_bookmark_parent_from_obj_index(objectIndices[i]); + toEraseMap[parentBookmarkList.get_net_id()].emplace_back(parentBookmarkList->get_folder_list()->at(objectIndices[i].back())); + if(newIndex != 0 && parentBookmarkList == listPtr && objectIndices[i].back() <= newObjIndex.back()) + newIndex--; + } - // // 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++; - // } - // } + // 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++; + } + } - // // 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_list(); - // listToEraseFromPtr->erase_list(listToEraseFromPtr, setToErase, &toInsertObjPtrs); - // } + // 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_list(); + listToEraseFromPtr->erase_list(listToEraseFromPtr, setToErase, &toInsertObjPtrs); + } - // // 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); + // 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 < objectIndices.size(); i++) { + auto o = get_bookmark_from_obj_index(objectIndices[i]); + auto it = std::find_if(toInsertObjPtrs.begin(), toInsertObjPtrs.end(), [&o](NetObjOwnerPtr& objPtr) { + return objPtr == o; + }); + toInsert.emplace_back(insertIt, std::move(*it)); + toInsert.back().second.reassign_ids(); + } + std::vector> insertedIterators = listPtr->insert_sorted_list_and_send_create(listPtr, toInsert); - // // 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); + // Prepare insert list for undo + insertParentUndoID = world.undo.get_undoid_from_netid(listPtr.get_net_id()); + 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); - // class MoveBookmarksWorldUndoAction : 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 - // MoveBookmarksWorldUndoAction(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 Bookmarks"; - // } - // bool undo(WorldUndoManager& undoMan) override { - // std::vector> toMoveObjs; - // std::vector> toEraseList; - // NetObjTemporaryPtr> eraseListPtr; - // std::unordered_map*, std::vector>> toInsertToMap; + class MoveBookmarksWorldUndoAction : 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 + MoveBookmarksWorldUndoAction(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 Bookmarks"; + } + bool undo(WorldUndoManager& undoMan) override { + std::vector> toMoveObjs; + std::vector> toEraseList; + NetObjTemporaryPtr> eraseListPtr; + std::unordered_map*, std::vector>> toInsertToMap; - // { - // 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_list(); - // } + { + 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_list(); + } - // { - // std::vector toEraseNetIDList; - // if(!undoMan.fill_netid_list_from_undoid_list(toEraseNetIDList, insertedUndoIDs)) - // return false; - // toEraseList = eraseListPtr->get_list(toEraseNetIDList); - // } + { + std::vector toEraseNetIDList; + if(!undoMan.fill_netid_list_from_undoid_list(toEraseNetIDList, insertedUndoIDs)) + return false; + toEraseList = eraseListPtr->get_list(toEraseNetIDList); + } - // { - // 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; - // } - // } + { + 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([&]() { - // eraseListPtr->erase_list(eraseListPtr, toEraseList, &toMoveObjs); + undoMan.world.netObjMan.send_multi_update_messsage([&]() { + eraseListPtr->erase_list(eraseListPtr, toEraseList, &toMoveObjs); - // for(auto& [parentNetID, indexNetIDListPair] : toInsertToMap) { - // auto& parentListPtr = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(parentNetID)->get_folder_list(); - // 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; + for(auto& [parentNetID, indexNetIDListPair] : toInsertToMap) { + auto& parentListPtr = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(parentNetID)->get_folder_list(); + 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; - // { - // 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; - // } - // } + { + 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 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_list(); - // } + { + 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_list(); + } - // { - // if(!undoMan.fill_netid_list_from_undoid_list(objsToInsert, insertedUndoIDs)) - // return false; - // } + { + if(!undoMan.fill_netid_list_from_undoid_list(objsToInsert, insertedUndoIDs)) + return false; + } - // undoMan.world.netObjMan.send_multi_update_messsage([&]() { - // std::vector> toInsertObjPtrs; + undoMan.world.netObjMan.send_multi_update_messsage([&]() { + std::vector> toInsertObjPtrs; - // for(auto& [listToEraseFrom, setToErase] : toEraseMap) { - // auto& listToEraseFromPtr = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(listToEraseFrom)->get_folder_list(); - // listToEraseFromPtr->erase_list(listToEraseFromPtr, listToEraseFromPtr->get_list(setToErase), &toInsertObjPtrs); - // } + for(auto& [listToEraseFrom, setToErase] : toEraseMap) { + auto& listToEraseFromPtr = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(listToEraseFrom)->get_folder_list(); + listToEraseFromPtr->erase_list(listToEraseFromPtr, listToEraseFromPtr->get_list(setToErase), &toInsertObjPtrs); + } - // 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); + 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); + return true; + } + ~MoveBookmarksWorldUndoAction() {} - // return true; - // } - // ~MoveBookmarksWorldUndoAction() {} + 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)); + } + }); - // 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); + } + left_to_right_line_layout(gui, [&]() { + input_text(gui, "input new name", &nameForNew, { + .onEnter = [&] { + create_bookmark(new BookmarkListItem(world.netObjMan, nameForNew, false, {world.drawData.cam.c, world.main.window.size.cast()})); + } + }); - // if(selectionData.objsSelected != oldSelection) { - // editing_bookmark_check(); - // 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(); - // } + svg_icon_button(gui, "create new bookmark", "data/icons/plusbold.svg", { + .size = SMALL_BUTTON_SIZE, + .onClick = [&] { + create_bookmark(new BookmarkListItem(world.netObjMan, nameForNew, false, {world.drawData.cam.c, world.main.window.size.cast()})); + } + }); - // if(toDeleteObject.has_value()) - // remove_bookmark(toDeleteParent.value(), toDeleteObject.value()); - // } + svg_icon_button(gui, "create new folder", "data/icons/folderbold.svg", { + .size = SMALL_BUTTON_SIZE, + .onClick = [&] { + auto newFolderObjInfo = create_bookmark(new BookmarkListItem(world.netObjMan, nameForNew, true, {})); + newFolderObjInfo->obj->set_folder_open(true); + } + }); + }); - // 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 bookmark", "data/icons/plusbold.svg", false, gui.SMALL_BUTTON_SIZE) || addByEnter) - // create_bookmark(new BookmarkListItem(world.netObjMan, nameForNew, false, {world.drawData.cam.c, world.main.window.size.cast()})); - // else if(gui.svg_icon_button("create new folder", "data/icons/folderbold.svg", false, gui.SMALL_BUTTON_SIZE)) { - // auto newFolderObjInfo = create_bookmark(new BookmarkListItem(world.netObjMan, nameForNew, true, {})); - // newFolderObjInfo->obj->set_folder_open(true); - // } - // }); - - // 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 Bookmark Folder" : "Edit Bookmark"); - // gui.input_text_field("input edit name", "Name", &nameToEdit); - // tempPtr->set_name(world.delayedUpdateObjectManager, nameToEdit); - // } - // } - - // gui.pop_id(); - //} + if(editingBookmark) { + text_label_centered(gui, editingBookmark->is_folder() ? "Edit Bookmark Folder" : "Edit Bookmark"); + input_text_field(gui, "input edit name", "Name", &nameToEdit, { + .onEdit = [&] { + if(editingBookmark) { // This can be set to null on the way here (close bookmark popup when textbox is selected) + editingBookmark->set_name(world.delayedUpdateObjectManager, nameToEdit); + world.main.g.gui.set_to_layout(); + } + } + }); + } + } } std::optional>> BookmarkManager::try_to_create_in_proper_position(BookmarkListItem* newItem) { using namespace NetworkingObjects; - 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) + if(selectedBookmarkIndices.empty()) return std::nullopt; + auto& lastObjSelected = *selectedBookmarkIndices.rbegin(); + NetObjTemporaryPtr objectPtr = get_bookmark_from_obj_index(lastObjSelected); if(objectPtr->is_folder()) { objectPtr->set_folder_open(true); return std::pair>{objectPtr.get_net_id(), objectPtr->get_folder_list()->push_back_and_send_create(objectPtr->get_folder_list(), newItem)}; } + NetObjTemporaryPtr parentPtr = get_bookmark_parent_from_obj_index(lastObjSelected); return std::pair>{parentPtr.get_net_id(), parentPtr->get_folder_list()->insert_and_send_create(parentPtr->get_folder_list(), std::next(parentPtr->get_folder_list()->get(objectPtr.get_net_id())), newItem)}; } @@ -399,10 +424,13 @@ NetworkingObjects::NetObjOrderedListIterator BookmarkManager:: auto insertedBookmarkPair = create_in_proper_position(newItem); 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(); return it; } -void BookmarkManager::remove_bookmark(const NetworkingObjects::NetObjID& parentID, const NetworkingObjects::NetObjID& objectID) { +void BookmarkManager::remove_bookmark(const GUIStuff::TreeListingObjIndexList& objIndex) { + editing_bookmark_check(); + class DeleteBookmarkWorldUndoAction : public WorldUndoAction { public: DeleteBookmarkWorldUndoAction(std::unique_ptr initBookmarkData, uint32_t newPos, WorldUndoManager::UndoObjectID initParentUndoID, WorldUndoManager::UndoObjectID initUndoID): @@ -454,10 +482,12 @@ void BookmarkManager::remove_bookmark(const NetworkingObjects::NetObjID& parentI WorldUndoManager::UndoObjectID undoID; }; - auto& folderList = world.netObjMan.get_obj_temporary_ref_from_id(parentID)->get_folder_list(); - auto it = folderList->get(objectID); - world.undo.push(std::make_unique(std::make_unique(it->obj->get_complete_undo_data(world.undo)), it->pos, world.undo.get_undoid_from_netid(parentID), world.undo.get_undoid_from_netid(objectID))); - folderList->erase(folderList, it); + auto parentPtr = get_bookmark_parent_from_obj_index(objIndex); + auto bookmarkPtr = get_bookmark_from_obj_index(objIndex); + auto it = parentPtr->get_folder_list()->get(bookmarkPtr.get_net_id()); + world.undo.push(std::make_unique(std::make_unique(bookmarkPtr->get_complete_undo_data(world.undo)), it->pos, world.undo.get_undoid_from_netid(parentPtr.get_net_id()), world.undo.get_undoid_from_netid(bookmarkPtr.get_net_id()))); + parentPtr->get_folder_list()->erase(parentPtr->get_folder_list(), it); + world.main.g.gui.set_to_layout(); } void BookmarkManager::scale_up(const WorldScalar& scaleUpAmount) { @@ -520,20 +550,18 @@ void BookmarkManager::editing_bookmark_check() { WorldUndoManager::UndoObjectID undoID; }; - if(oldSelection.size() == 1 && editingBookmarkName.has_value()) { - const NetworkingObjects::NetObjID& oldNetObjID = *oldSelection.begin(); - auto tempPtr = world.netObjMan.get_obj_temporary_ref_from_id(oldNetObjID); - if(tempPtr) { - const std::string& currentNameData = tempPtr->get_name(); - if(currentNameData != editingBookmarkName.value()) - world.undo.push(std::make_unique(editingBookmarkName.value(), world.undo.get_undoid_from_netid(oldNetObjID))); - } + if(editingBookmark) { + const std::string& currentNameData = editingBookmark->get_name(); + if(currentNameData != editingBookmarkOldName.value()) + world.undo.push(std::make_unique(editingBookmarkOldName.value(), world.undo.get_undoid_from_netid(editingBookmark.get_net_id()))); } - editingBookmarkName = std::nullopt; - if(selectionData.objsSelected.size() == 1) { - auto tempPtr = world.netObjMan.get_obj_temporary_ref_from_id(*selectionData.objsSelected.begin()); - if(tempPtr) - editingBookmarkName = tempPtr->get_name(); + + if(selectedBookmarkIndices.size() == 1) { + editingBookmark = get_bookmark_from_obj_index(*selectedBookmarkIndices.begin()); + editingBookmarkOldName = editingBookmark->get_name(); + } + else { + editingBookmark = NetworkingObjects::NetObjTemporaryPtr(); + editingBookmarkOldName = std::nullopt; } - oldSelection = selectionData.objsSelected; } diff --git a/src/Bookmarks/BookmarkManager.hpp b/src/Bookmarks/BookmarkManager.hpp index f41b2ec..fb8fe3b 100644 --- a/src/Bookmarks/BookmarkManager.hpp +++ b/src/Bookmarks/BookmarkManager.hpp @@ -20,17 +20,20 @@ class BookmarkManager { NetworkingObjects::NetObjOwnerPtr bookmarkListRoot; private: + NetworkingObjects::NetObjTemporaryPtr get_bookmark_parent_from_obj_index(const GUIStuff::TreeListingObjIndexList& objIndex); + NetworkingObjects::NetObjTemporaryPtr get_bookmark_from_obj_index(const GUIStuff::TreeListingObjIndexList& objIndex); std::pair> create_in_proper_position(BookmarkListItem* newItem); std::optional>> try_to_create_in_proper_position(BookmarkListItem* newItem); NetworkingObjects::NetObjOrderedListIterator create_bookmark(BookmarkListItem* newItem); - void remove_bookmark(const NetworkingObjects::NetObjID& parentID, const NetworkingObjects::NetObjID& objectID); + void remove_bookmark(const GUIStuff::TreeListingObjIndexList& objIndex); - GUIStuff::TreeListing::SelectionData selectionData; - std::unordered_set oldSelection; std::string nameToEdit; std::string nameForNew; - std::optional editingBookmarkName; + std::set selectedBookmarkIndices; + + NetworkingObjects::NetObjTemporaryPtr editingBookmark; + std::optional editingBookmarkOldName; void editing_bookmark_check(); diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp b/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp index 77be32e..9cd867d 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp @@ -13,7 +13,6 @@ DrawingProgramLayerManagerGUI::DrawingProgramLayerManagerGUI(DrawingProgramLayer {} void DrawingProgramLayerManagerGUI::refresh_gui_data() { - selectionData = GUIStuff::TreeListing::SelectionData(); editing_layer_check(); oldSelection.clear(); nameToEdit.clear(); @@ -359,196 +358,196 @@ void DrawingProgramLayerManagerGUI::setup_list_gui(const char* id, bool& hoverin } 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; + //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)}; } 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()))); + //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; + //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(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& 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& 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(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() {} - 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& 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); + //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); } 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(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; } diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.hpp b/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.hpp index c3ae558..e2d3b94 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.hpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.hpp @@ -20,7 +20,6 @@ class DrawingProgramLayerManagerGUI { void remove_layer(const NetworkingObjects::NetObjID& parentID, const NetworkingObjects::NetObjID& objectID); void editing_layer_check(); - GUIStuff::TreeListing::SelectionData selectionData; std::unordered_set oldSelection; std::string nameToEdit; std::string nameForNew; diff --git a/src/GUIStuff/Elements/TreeListing.cpp b/src/GUIStuff/Elements/TreeListing.cpp index f9a079d..73e0d39 100644 --- a/src/GUIStuff/Elements/TreeListing.cpp +++ b/src/GUIStuff/Elements/TreeListing.cpp @@ -1,284 +1,147 @@ #include "TreeListing.hpp" -#include "../GUIManager.hpp" #include "Helpers/ConvertVec.hpp" -#include -#include "../../TimePoint.hpp" +#include "ScrollArea.hpp" #include "../GUIManager.hpp" +#include "../ElementHelpers/ScrollAreaHelpers.hpp" +#include "../ElementHelpers/ButtonHelpers.hpp" +#include "LayoutElement.hpp" + #define TIME_TO_HOVER_TO_OPEN_DIRECTORY std::chrono::milliseconds(700) +bool operator<(const GUIStuff::TreeListingObjIndexList& a, const GUIStuff::TreeListingObjIndexList& b) { + size_t biggestIndexSize = std::max(a.size(), b.size()); + for(size_t i = 0; i < biggestIndexSize; i++) { + if(i == a.size()) + return true; + else if(i == b.size()) + return false; + else if(a[i] < b[i]) + return true; + else if(a[i] > b[i]) + return false; + } + return false; +} + namespace GUIStuff { +using namespace ElementHelpers; + TreeListing::TreeListing(GUIManager& gui): Element(gui) {} -void TreeListing::layout(const Clay_ElementId& id, NetworkingObjects::NetObjID rootObjID, const DisplayData& displayData, SelectionData& selectionData) { - //auto& io = *gui.io; +void TreeListing::layout(const Clay_ElementId& id, const Data& newDisplayData) { + d = newDisplayData; - //if(!io.mouse.leftHeld) - // dragHoldSelected = false; + flattenedIndexList.clear(); + recursive_visible_flattened_obj_list(flattenedIndexList, {}); - //selectionData.orderedObjsSelected.clear(); - //std::optional hoveredObject; + CLAY(id, { + .layout = {.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}} + }) { + scroll_area_many_entries(gui, "scroll", { + .entryHeight = ENTRY_HEIGHT, + .entryCount = flattenedIndexList.size(), + .elementContent = [&](size_t i) { + const ObjInfo& objInfo = flattenedIndexList[i]; + gui.element("elem", [&](LayoutElement*, const Clay_ElementId& lId) { + SkColor4f backgroundColor; + if(d.selectedIndices && d.selectedIndices->contains(flattenedIndexList[i].objIndex)) + backgroundColor = gui.io.theme->backColor1; + else + backgroundColor = gui.io.theme->backColor2; - //CLAY_AUTO_ID({ - // .layout = {.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}} - //}) { - // Clay_ElementId localID = CLAY_ID_LOCAL("scroll area"); - // float setScrollAmount; - // float setScrollContentHeight; - // CLAY(localID, { - // .layout = {.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}} - // }) { - // gui.scroll_bar_area("scroll area", true, [&](float scrollContentHeight, float containerHeight, float& scrollAmount) { - // setScrollAmount = scrollAmount; - // setScrollContentHeight = scrollContentHeight; - // size_t itemCount = 0; - // size_t itemCountToStartAt = -scrollAmount / ENTRY_HEIGHT; - // size_t itemCountToEndAt = (containerHeight - scrollAmount) / ENTRY_HEIGHT; - // itemCountToEndAt++; - // std::vector parentIDStack; - // CLAY_AUTO_ID({ - // .layout = { - // .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(ENTRY_HEIGHT * itemCountToStartAt)} - // } - // }) {} - // recursive_gui(io, gui, displayData, selectionData, rootObjID, itemCount, itemCountToStartAt, itemCountToEndAt, 0, hoveredObject, parentIDStack, false); - // if(itemCount > itemCountToEndAt) { - // CLAY_AUTO_ID({ - // .layout = { - // .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(ENTRY_HEIGHT * (itemCount - itemCountToEndAt))} - // } - // }) {} - // } - // }, false); - // } - // Clay_ElementData scrollAreaBB = Clay_GetElementData(localID); - // if(scrollAreaBB.found) { - // // Clamp by fabs(scrollcontentheight - 3), small offset is added to account for error (when youre at the very edge it might assume youre at the top of an element) - // float mouseRelativeYPos = std::clamp(std::fabs(io.mouse.pos.y() - scrollAreaBB.boundingBox.y - setScrollAmount), 0.0f, std::fabs(setScrollContentHeight - 3.0f)); - // topHalfOfHovered = std::fmod(mouseRelativeYPos, ENTRY_HEIGHT) < (ENTRY_HEIGHT / 2.0f); - // } - //} + CLAY(lId, { + .layout = { + .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}, + .childAlignment = {.x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER} + }, + .backgroundColor = convert_vec4(backgroundColor) + }) { + if(objInfo.objIndex.size() > 1) { + CLAY_AUTO_ID({ + .layout = {.sizing = {.width = CLAY_SIZING_FIXED((objInfo.objIndex.size() - 1) * ICON_SIZE), .height = CLAY_SIZING_GROW(0)}} + }) {} + } + CLAY_AUTO_ID({ + .layout = {.sizing = {.width = CLAY_SIZING_FIXED(ICON_SIZE), .height = CLAY_SIZING_FIXED(ICON_SIZE)}} + }) { + if(!objInfo.isDirectory) + d.drawNonDirectoryObjIconGUI(objInfo.objIndex); + else { + gui.set_z_index_keep_clipping_region(gui.get_z_index() + 1, [&] { + svg_icon_button(gui, "open dir button", objInfo.isOpen ? "data/icons/droparrow.svg" : "data/icons/droparrowclose.svg", { + .drawType = SelectableButton::DrawType::TRANSPARENT_ALL, + .size = ICON_SIZE, + .onClick = [&] { + d.setDirectoryOpen(objInfo.objIndex, !objInfo.isOpen); + if(d.selectedIndices) { + d.selectedIndices->clear(); + if(d.onSelectChange) d.onSelectChange(); + } + } + }); + }); + } + } + d.drawObjGUI(objInfo.objIndex); + } + }, LayoutElement::Callbacks { + .mouseButton = [&, i] (LayoutElement* l, const InputManager::MouseButtonCallbackArgs& button) { + if(l->mouseHovering && button.button == InputManager::MouseButton::LEFT && button.down) { + gui.set_post_callback_func([&]{ + auto& objIndex = flattenedIndexList[i].objIndex; + if(d.selectedIndices) { + auto it = d.selectedIndices->find(objIndex); + bool wasSelected = it != d.selectedIndices->end(); - //// Any objects that were part of a collapsed directory will be unselected - //selectionData.objsSelected.clear(); - //for(auto& [parent, object] : selectionData.orderedObjsSelected) - // selectionData.objsSelected.emplace(object); - - //if(objDragged.has_value()) { - // if(hoveredObject.has_value() && !selectionData.objsSelected.contains(hoveredObject.value().object) && (std::chrono::steady_clock::now() - timeStartedHoveringOverObject) >= TIME_TO_HOVER_TO_OPEN_DIRECTORY) { - // ParentObjectIDStack& hoveredObjVal = hoveredObject.value(); - // size_t hoveredObjIndex = displayData.getIndexOfObjInList({hoveredObjVal.parents.back(), hoveredObjVal.object}); - // std::optional objHoveringOver = displayData.getObjInListAtIndex(hoveredObjVal.parents.back(), hoveredObjIndex); - // if(objHoveringOver.value().isDirectory && !objHoveringOver.value().isDirectoryOpen) - // displayData.setDirectoryOpen(hoveredObjVal.object, true); - // } - - // ParentObjectIDPair& objDraggedVal = objDragged.value(); - // if(!selectionData.objsSelected.contains(objDraggedVal.object)) - // objDragged = std::nullopt; - // else if(!io.mouse.leftHeld) { - // if(!hoveredObject.has_value()) - // set_single_selected_object(selectionData); - // else { - // ParentObjectIDStack hoveredObjValToUse = hoveredObject.value(); // By value since it'll be edited - // size_t indexToMoveFrom = displayData.getIndexOfObjInList(objDraggedVal); - // size_t indexToMoveTo = displayData.getIndexOfObjInList({hoveredObjValToUse.parents.back(), hoveredObjValToUse.object}); - // std::optional objHoveringOver = displayData.getObjInListAtIndex(hoveredObjValToUse.parents.back(), indexToMoveTo); - // if(objHoveringOver.value().isDirectoryOpen && !topHalfOfHovered) { // Move to front of the directory object - // hoveredObjValToUse.parents.emplace_back(hoveredObjValToUse.object); - // indexToMoveTo = 0; - // } - // else if(!topHalfOfHovered) - // indexToMoveTo++; - // if((indexToMoveFrom == indexToMoveTo || (indexToMoveFrom + 1) == indexToMoveTo) && objDraggedVal.parent == hoveredObjValToUse.parents.back()) - // set_single_selected_object(selectionData); - // else { - // bool wrongMovement = false; - // // Check if object is about to move into itself - // for(const NetworkingObjects::NetObjID& parent : hoveredObjValToUse.parents) { - // if(selectionData.objsSelected.contains(parent)) { - // wrongMovement = true; - // break; - // } - // } - // if(!wrongMovement) { - // displayData.moveObjectsToListAtIndex(hoveredObjValToUse.parents.back(), indexToMoveTo, selectionData.orderedObjsSelected); - // selectionData.objsSelected.clear(); - // selectionData.orderedObjsSelected.clear(); - // } - // else - // set_single_selected_object(selectionData); - // } - // } - // objDragged = std::nullopt; - // } - //} - - //oldHoveredObject = hoveredObject; + if(gui.io.input->key(InputManager::KEY_GENERIC_LSHIFT).held) { + if(!wasSelected) { + d.selectedIndices->emplace(objIndex); + if(d.onSelectChange) d.onSelectChange(); + } + } + else if(gui.io.input->key(InputManager::KEY_GENERIC_LCTRL).held) { + if(!wasSelected) + d.selectedIndices->emplace(objIndex); + else + d.selectedIndices->erase(it); + if(d.onSelectChange) d.onSelectChange(); + } + else if(!wasSelected || d.selectedIndices->size() != 1) { + d.selectedIndices->clear(); + d.selectedIndices->emplace(objIndex); + if(d.onSelectChange) d.onSelectChange(); + } + else if(button.clicks == 2) + if(d.onDoubleClick) d.onDoubleClick(objIndex); + } + else if(button.clicks == 2) + if(d.onDoubleClick) d.onDoubleClick(objIndex); + }); + gui.set_to_layout(); + } + } + }); + } + }); + } } -void TreeListing::set_single_selected_object(SelectionData& selectionData) { - //selectionData.objsSelected.clear(); - //selectionData.orderedObjsSelected.clear(); - //selectionData.objsSelected.emplace(objDragged.value().object); - //selectionData.orderedObjsSelected.emplace_back(objDragged.value()); -} - -void TreeListing::recursive_gui(UpdateInputData& io, GUIManager& gui, const DisplayData& displayData, SelectionData& selectionData, NetworkingObjects::NetObjID objID, size_t& itemCount, size_t itemCountToStartAt, size_t itemCountToEndAt, size_t listDepth, std::optional& hoveredObject, std::vector& parentIDStack, bool parentJustSelected) { - //parentIDStack.emplace_back(objID); - //for(size_t i = 0;; i++) { - // std::optional objInListOptional = displayData.getObjInListAtIndex(objID, i); - // if(!objInListOptional.has_value()) - // break; - // else { - // auto& objInList = objInListOptional.value(); - // bool selfJustSelected = false; - // if(itemCount >= itemCountToStartAt && itemCount < itemCountToEndAt) { - // gui.push_id(itemCount); - // bool buttonClicked = false; - // uint16_t topOutlineWidth = 0; - // uint16_t bottomOutlineWidth = 0; - - // bool isOldHoveredObject = oldHoveredObject.has_value() && oldHoveredObject.value().object == objInList.id; - // SkColor4f backgroundColor; - // if(selectionData.objsSelected.contains(objInList.id)) - // backgroundColor = io.theme->backColor1; - // else if(isOldHoveredObject && objInList.isDirectory && !objInList.isDirectoryOpen && objDragged.has_value()) - // backgroundColor = lerp_vec(io.theme->backColor2, io.theme->fillColor1, std::clamp(std::chrono::duration(std::chrono::steady_clock::now() - timeStartedHoveringOverObject) / TIME_TO_HOVER_TO_OPEN_DIRECTORY, 0.0f, 1.0f)); - // else - // backgroundColor = io.theme->backColor2; - - // if(oldHoveredObject.has_value() && oldHoveredObject.value().object == objInList.id) { - // if(objDragged.has_value()) { - // ParentObjectIDPair& objDraggedVal = objDragged.value(); - // if(objDraggedVal.object != objInList.id) { - // if(topHalfOfHovered) - // topOutlineWidth = 1; - // else - // bottomOutlineWidth = 1; - // } - // } - // } - // CLAY_AUTO_ID({ - // .layout = { - // .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(ENTRY_HEIGHT)}, - // .childAlignment = {.x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER} - // }, - // .backgroundColor = convert_vec4(backgroundColor) - // }) { - // if(listDepth != 0) { - // CLAY_AUTO_ID({ - // .layout = { - // .sizing = {.width = CLAY_SIZING_FIXED(ENTRY_HEIGHT * listDepth), .height = CLAY_SIZING_FIXED(ENTRY_HEIGHT)} - // }, - // }) {} - // } - // CLAY_AUTO_ID({ - // .layout = { - // .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)} - // }, - // .border = { - // .color = convert_vec4(io.theme->frontColor1), - // .width = { - // .left = 0, - // .right = 0, - // .top = topOutlineWidth, - // .bottom = bottomOutlineWidth, - // .betweenChildren = 0 - // } - // } - // }) { - // if(objInList.isDirectory) { - // if(gui.svg_icon_button_transparent("ico", objInList.isDirectoryOpen ? "data/icons/droparrow.svg" : "data/icons/droparrowclose.svg", false, ENTRY_HEIGHT)) { - // displayData.setDirectoryOpen(objInList.id, !objInList.isDirectoryOpen); - // buttonClicked = true; - // } - // } - // else { - // CLAY_AUTO_ID({ - // .layout = { - // .sizing = {.width = CLAY_SIZING_FIXED(ENTRY_HEIGHT), .height = CLAY_SIZING_FIXED(ENTRY_HEIGHT)}, - // .childAlignment = {.x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER} - // }, - // }) { - // buttonClicked |= displayData.drawNonDirectoryObjIconGUI(objInList.id); - // } - // } - // 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} - // } - // }) { - // buttonClicked |= displayData.drawObjGUI({objID, objInList.id}); - // } - // } - // - // if(Clay_Hovered()) { - // hoveredObject = {parentIDStack, objInList.id}; - // if(!isOldHoveredObject) - // timeStartedHoveringOverObject = std::chrono::steady_clock::now(); - // if(io.mouse.leftClick && !buttonClicked && !parentJustSelected) { - // if(io.key.leftShift) - // dragHoldSelected = true; - // else if(io.key.leftCtrl) { - // bool alreadySelected = selectionData.objsSelected.contains(objInList.id); - // if(alreadySelected) - // selectionData.objsSelected.erase(objInList.id); - // else { - // select_and_unselect_parents(parentIDStack, objInList.id, selectionData); - // selfJustSelected = true; - // } - // } - // else { - // if(!selectionData.objsSelected.contains(objInList.id)) { - // selectionData.objsSelected.clear(); - // selectionData.orderedObjsSelected.clear(); - // selectionData.objsSelected.emplace(objInList.id); - // selfJustSelected = true; - // } - // objDragged = {objID, objInList.id}; - // } - // } - // if(io.key.leftShift && dragHoldSelected && !parentJustSelected) { - // select_and_unselect_parents(parentIDStack, objInList.id, selectionData); - // selfJustSelected = true; - // } - // } - // } - // gui.pop_id(); - // } - // if(!parentJustSelected) { - // if(selectionData.objsSelected.contains(objInList.id)) - // selectionData.orderedObjsSelected.emplace_back(objID, objInList.id); - // } - // else - // unselect_object(objInList.id, selectionData); - // itemCount++; - // if(objInList.isDirectoryOpen) - // recursive_gui(io, gui, displayData, selectionData, objInList.id, itemCount, itemCountToStartAt, itemCountToEndAt, listDepth + 1, hoveredObject, parentIDStack, selfJustSelected | parentJustSelected); - // } - //} - //parentIDStack.pop_back(); -} - -void TreeListing::unselect_object(NetworkingObjects::NetObjID id, SelectionData& selectionData) { - //selectionData.objsSelected.erase(id); - //std::erase_if(selectionData.orderedObjsSelected, [&id](const auto& p) { - // return p.object == id; - //}); -} - -void TreeListing::select_and_unselect_parents(const std::vector& parentIDStack, NetworkingObjects::NetObjID newSelectedObj, SelectionData& selectionData) { - //for(const NetworkingObjects::NetObjID& parent : parentIDStack) { - // if(selectionData.objsSelected.contains(parent)) { - // unselect_object(parent, selectionData); - // break; - // } - //} - //selectionData.objsSelected.emplace(newSelectedObj); +void TreeListing::recursive_visible_flattened_obj_list(std::vector& objs, const TreeListingObjIndexList& objIndex) { + std::optional dirInfo = d.dirInfo(objIndex); + bool isRoot = objIndex.empty(); + if(!isRoot) + objs.emplace_back(objIndex, dirInfo.has_value(), dirInfo.has_value() ? dirInfo.value().isOpen : false); + if(dirInfo.has_value() && (dirInfo.value().isOpen || isRoot)) { + TreeListingObjIndexList childObjIndex = objIndex; + childObjIndex.emplace_back(); + for(size_t i = 0; i < dirInfo.value().dirSize; i++) { + childObjIndex.back() = i; + recursive_visible_flattened_obj_list(objs, childObjIndex); + } + } } } diff --git a/src/GUIStuff/Elements/TreeListing.hpp b/src/GUIStuff/Elements/TreeListing.hpp index 4add69d..d356539 100644 --- a/src/GUIStuff/Elements/TreeListing.hpp +++ b/src/GUIStuff/Elements/TreeListing.hpp @@ -1,6 +1,13 @@ #pragma once #include "Element.hpp" #include +#include + +namespace GUIStuff { +typedef std::vector TreeListingObjIndexList; +} + +bool operator<(const GUIStuff::TreeListingObjIndexList& a, const GUIStuff::TreeListingObjIndexList& b); namespace GUIStuff { @@ -9,54 +16,37 @@ class GUIManager; class TreeListing : public Element { public: static constexpr float ENTRY_HEIGHT = 25.0f; + static constexpr float ICON_SIZE = 25.0f; - struct ParentObjectIDPair { - NetworkingObjects::NetObjID parent; - NetworkingObjects::NetObjID object; - bool operator==(const ParentObjectIDPair&) const = default; + struct ObjInfo { + TreeListingObjIndexList objIndex; + bool isDirectory = false; + bool isOpen = false; }; - struct ParentObjectIDStack { - std::vector parents; - NetworkingObjects::NetObjID object; + struct DirectoryInfo { + size_t dirSize; + bool isOpen; }; - struct DisplayData { - struct ObjInList { - NetworkingObjects::NetObjID id; - bool isDirectory = false; - bool isDirectoryOpen = false; - }; - std::function(NetworkingObjects::NetObjID, size_t)> getObjInListAtIndex; - std::function getIndexOfObjInList; - std::function setDirectoryOpen; - std::function drawNonDirectoryObjIconGUI; - std::function drawObjGUI; - std::function&)> moveObjectsToListAtIndex; - }; - - struct SelectionData { - std::vector orderedObjsSelected; - std::unordered_set objsSelected; + struct Data { + std::set* selectedIndices = nullptr; + std::function(const TreeListingObjIndexList& objIndex)> dirInfo; + std::function setDirectoryOpen; + std::function drawNonDirectoryObjIconGUI; + std::function drawObjGUI; + std::function onDoubleClick; + std::function onSelectChange; + std::function& objIndices, const TreeListingObjIndexList& newObjIndex)> moveObj; }; TreeListing(GUIManager& gui); - void layout(const Clay_ElementId& id, NetworkingObjects::NetObjID rootObjID, const DisplayData& displayData, SelectionData& selectionData); + void layout(const Clay_ElementId& id, const Data& newDisplayData); private: - bool dragHoldSelected = false; + void recursive_visible_flattened_obj_list(std::vector& objs, const TreeListingObjIndexList& objIndex); - void set_single_selected_object(SelectionData& selectionData); - - void recursive_gui(UpdateInputData& io, GUIManager& gui, const DisplayData& displayData, SelectionData& selectionData, NetworkingObjects::NetObjID objID, size_t& itemCount, size_t itemCountToStartAt, size_t itemCountToEndAt, size_t listDepth, std::optional& hoveredObject, std::vector& parentIDStack, bool parentJustSelected); - - void select_and_unselect_parents(const std::vector& parentIDStack, NetworkingObjects::NetObjID newSelectedObj, SelectionData& selectionData); - - void unselect_object(NetworkingObjects::NetObjID id, SelectionData& selectionData); - - bool topHalfOfHovered = false; - std::optional objDragged; - std::optional oldHoveredObject; - std::chrono::steady_clock::time_point timeStartedHoveringOverObject; + std::vector flattenedIndexList; + Data d; }; } diff --git a/src/Toolbar.cpp b/src/Toolbar.cpp index f51bb67..74a3aa0 100644 --- a/src/Toolbar.cpp +++ b/src/Toolbar.cpp @@ -492,7 +492,6 @@ void Toolbar::top_toolbar() { .cornerRadius = CLAY_CORNER_RADIUS(io.theme->windowCorners1) }) { global_log(); - bool bookmarkMenuPopUpJustOpen = false; bool layerMenuPopUpJustOpen = false; auto icon_button_top_toolbar = [&](const char* id, const std::string& svgPath, bool isSelected, const std::function& onClick) { @@ -556,21 +555,17 @@ void Toolbar::top_toolbar() { layerMenuPopUpJustOpen = true; } }); - icon_button_top_toolbar("Bookmark Menu Button", "data/icons/bookmark.svg", bookmarkMenuPopupOpen, [&] { - if(bookmarkMenuPopupOpen) { - main.world->bMan.refresh_gui_data(); - bookmarkMenuPopupOpen = false; - } - else { + Element* bookmarkMenuButton = icon_button_top_toolbar("Bookmark Menu Button", "data/icons/bookmark.svg", bookmarkMenuPopupOpen, [&] { + if(bookmarkMenuPopupOpen) + stop_displaying_bookmark_menu(); + else bookmarkMenuPopupOpen = true; - bookmarkMenuPopUpJustOpen = true; - } }); if(gridMenu.popupOpen) grid_menu(gridMenuButton); if(bookmarkMenuPopupOpen) - bookmark_menu(bookmarkMenuPopUpJustOpen); + bookmark_menu(bookmarkMenuButton); if(layerMenuPopupOpen) layer_menu(layerMenuPopUpJustOpen); } @@ -855,7 +850,7 @@ void Toolbar::grid_menu(Element* gridMenuButton) { }, .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} + .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, "Grids"); float ENTRY_HEIGHT = 25.0f; @@ -958,32 +953,39 @@ void Toolbar::stop_displaying_grid_menu() { main.g.gui.set_to_layout(); } -void Toolbar::bookmark_menu(bool justOpened) { +void Toolbar::stop_displaying_bookmark_menu() { + main.world->bMan.refresh_gui_data(); + bookmarkMenuPopupOpen = false; + main.g.gui.set_to_layout(); +} + +void Toolbar::bookmark_menu(Element* bookmarkMenuButton) { auto& gui = main.g.gui; auto& io = gui.io; - gui.new_id("bookmark menu", [&] { - //Clay_ElementId localId = CLAY_ID_LOCAL("INFINIPAINT BOOKMARK 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, "Bookmarks"); - // main.world->bMan.setup_list_gui("bookmark menu list"); - // if(io.mouse.leftClick && !Clay_Hovered() && !justOpened) { - // bookmarkMenuPopupOpen = false; - // main.world->bMan.refresh_gui_data(); - // } - //} + gui.set_z_index(gui.get_z_index() + 1, [&] { + gui.element("grid 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, "Bookmarks"); + main.world->bMan.setup_list_gui("bookmark menu list"); + } + }, LayoutElement::Callbacks { + .mouseButton = [&, bookmarkMenuButton] (LayoutElement* l, const InputManager::MouseButtonCallbackArgs& button) { + if(!l->mouseHovering && !l->childMouseHovering && !bookmarkMenuButton->mouseHovering && button.down) + stop_displaying_bookmark_menu(); + } + }); }); } diff --git a/src/Toolbar.hpp b/src/Toolbar.hpp index 7389556..c0c7587 100644 --- a/src/Toolbar.hpp +++ b/src/Toolbar.hpp @@ -94,7 +94,8 @@ class Toolbar { void grid_menu(GUIStuff::Element* gridMenuButton); void add_grid(); void stop_displaying_grid_menu(); - void bookmark_menu(bool justOpened); + void stop_displaying_bookmark_menu(); + void bookmark_menu(GUIStuff::Element* bookmarkMenuButton); void layer_menu(bool justOpened); void drawing_program_gui(); void options_menu(); diff --git a/src/WorldUndoManager.cpp b/src/WorldUndoManager.cpp index d365eb1..efdb28a 100644 --- a/src/WorldUndoManager.cpp +++ b/src/WorldUndoManager.cpp @@ -1,5 +1,6 @@ #include "WorldUndoManager.hpp" #include "World.hpp" +#include "MainProgram.hpp" void WorldUndoAction::scale_up(const WorldScalar& scaleAmount) {} WorldUndoAction::~WorldUndoAction() {} @@ -42,6 +43,9 @@ void WorldUndoManager::push_redo(std::unique_ptr undoAction) { void WorldUndoManager::undo() { if(undoQueue.empty()) return; + + world.bMan.refresh_gui_data(); + if(!undoQueue.back()->undo(*this)) clear(); else { @@ -50,11 +54,16 @@ void WorldUndoManager::undo() { } set_world_has_unsaved_local_changes(); + + world.main.g.gui.set_to_layout(); } void WorldUndoManager::redo() { if(redoQueue.empty()) return; + + world.bMan.refresh_gui_data(); + if(!redoQueue.back()->redo(*this)) clear(); else { @@ -63,6 +72,8 @@ void WorldUndoManager::redo() { } set_world_has_unsaved_local_changes(); + + world.main.g.gui.set_to_layout(); } void WorldUndoManager::clear() {