From d9761a84b5561804d2810c0976cde45f467a1876 Mon Sep 17 00:00:00 2001 From: Yousef Khadadeh Date: Mon, 28 Jul 2025 11:09:59 +0300 Subject: [PATCH] Readded clipboard --- src/CollabList.hpp | 23 ++++++ src/DrawingProgram/DrawingProgram.cpp | 55 ++++++++++++--- src/DrawingProgram/DrawingProgram.hpp | 3 + .../DrawingProgramSelection.cpp | 70 +++++++++++++++++-- .../DrawingProgramSelection.hpp | 3 + 5 files changed, 140 insertions(+), 14 deletions(-) diff --git a/src/CollabList.hpp b/src/CollabList.hpp index feaa5d9..7f81c54 100644 --- a/src/CollabList.hpp +++ b/src/CollabList.hpp @@ -77,6 +77,29 @@ template class CollabList { return newObj; } + std::vector client_insert_ordered_vector_items(uint64_t pos, const std::vector& items) { + std::vector itemsToPushIn; + for(auto& item : items) { + auto& newObj = itemsToPushIn.emplace_back(std::make_shared()); + newObj->syncIgnore = true; + newObj->id = getNewIDFunc(); + newObj->obj = item; + item->collabListInfo = newObj; + idToObjectMap.emplace(newObj->id, newObj); + } + + clientSideList.insert(clientSideList.begin() + pos, itemsToPushIn.begin(), itemsToPushIn.end()); + + complete_client_pos_refresh(false); + + if(clientInsertOrderedVectorCallback) + clientInsertOrderedVectorCallback(itemsToPushIn); + if(updateCallback) + updateCallback(); + + return itemsToPushIn; + } + IDType client_insert(const ObjectInfoPtr& objInfoToInsert) { objInfoToInsert->syncIgnore = true; objInfoToInsert->id = getNewIDFunc(); diff --git a/src/DrawingProgram/DrawingProgram.cpp b/src/DrawingProgram/DrawingProgram.cpp index 2cd5579..81a939d 100644 --- a/src/DrawingProgram/DrawingProgram.cpp +++ b/src/DrawingProgram/DrawingProgram.cpp @@ -46,7 +46,8 @@ DrawingProgram::DrawingProgram(World& initWorld): world.main.drawProgCache.refresh = true; }; components.clientInsertCallback = [&](const CollabListType::ObjectInfoPtr& c) { - compCache.add_component(c); + if(addToCompCacheOnInsert) + compCache.add_component(c); DrawComponentType t = c->obj->get_type(); if(t == DRAWCOMPONENT_IMAGE || t == DRAWCOMPONENT_TEXTBOX) updateableComponents.emplace(c->obj); @@ -547,10 +548,48 @@ void DrawingProgram::add_undo_place_component(const CollabListType::ObjectInfoPt }); } -void DrawingProgram::add_undo_erase_components(const std::unordered_set& erasedComponents) { +void DrawingProgram::add_undo_place_components(const std::unordered_set& objSetToUndo) { world.undo.push(UndoManager::UndoRedoPair{ - [&, erasedComponents = erasedComponents]() { - std::vector sortedObjects(erasedComponents.begin(), erasedComponents.end()); + [&, objSetToUndo = objSetToUndo]() { + for(auto& comp : objSetToUndo) + if(!comp->obj->collabListInfo.lock()) + return false; + + std::unordered_set idsToErase; + for(auto& c : objSetToUndo) + idsToErase.emplace(c->id); + + DrawComponent::client_send_erase_set(*this, idsToErase); + components.client_erase_set(objSetToUndo); + + reset_tools(); + + return true; + }, + [&, objSetToUndo = objSetToUndo]() { + std::vector sortedObjects(objSetToUndo.begin(), objSetToUndo.end()); + std::sort(sortedObjects.begin(), sortedObjects.end(), [](auto& a, auto& b) { + return a->pos < b->pos; + }); + + for(auto& comp : sortedObjects) + if(comp->obj->collabListInfo.lock()) + return false; + + components.client_insert_ordered_vector(sortedObjects); + DrawComponent::client_send_place_many(*this, sortedObjects); + + reset_tools(); + + return true; + } + }); +} + +void DrawingProgram::add_undo_erase_components(const std::unordered_set& objSetToUndo) { + world.undo.push(UndoManager::UndoRedoPair{ + [&, objSetToUndo = objSetToUndo]() { + std::vector sortedObjects(objSetToUndo.begin(), objSetToUndo.end()); std::sort(sortedObjects.begin(), sortedObjects.end(), [](auto& a, auto& b) { return a->pos < b->pos; }); @@ -566,17 +605,17 @@ void DrawingProgram::add_undo_erase_components(const std::unordered_setobj->collabListInfo.lock()) return false; std::unordered_set idsToErase; - for(auto& c : erasedComponents) + for(auto& c : objSetToUndo) idsToErase.emplace(c->id); DrawComponent::client_send_erase_set(*this, idsToErase); - components.client_erase_set(erasedComponents); + components.client_erase_set(objSetToUndo); reset_tools(); diff --git a/src/DrawingProgram/DrawingProgram.hpp b/src/DrawingProgram/DrawingProgram.hpp index c669c4a..e5a6d97 100644 --- a/src/DrawingProgram/DrawingProgram.hpp +++ b/src/DrawingProgram/DrawingProgram.hpp @@ -68,6 +68,8 @@ class DrawingProgram { void force_rebuild_cache(); + bool addToCompCacheOnInsert = true; + std::atomic addFileInNextFrame = false; std::pair addFileInfo; @@ -80,6 +82,7 @@ class DrawingProgram { void draw_drag_circle(SkCanvas* canvas, const Vector2f& pos, const SkColor4f& c, const DrawData& drawData, float radiusMultiplier = 1.0f); void add_undo_place_component(const CollabListType::ObjectInfoPtr& objToUndo); + void add_undo_place_components(const std::unordered_set& objSetToUndo); void add_undo_erase_components(const std::unordered_set& objSetToUndo); BrushTool brushTool; diff --git a/src/DrawingProgram/DrawingProgramSelection.cpp b/src/DrawingProgram/DrawingProgramSelection.cpp index aa4a237..b50104f 100644 --- a/src/DrawingProgram/DrawingProgramSelection.cpp +++ b/src/DrawingProgram/DrawingProgramSelection.cpp @@ -59,7 +59,11 @@ void DrawingProgramSelection::add_from_cam_coord_collider_to_selection(const SCo return false; }); - selectedSet = selectedComponents; + set_to_selection(selectedComponents); +} + +void DrawingProgramSelection::set_to_selection(const std::unordered_set& newSelection) { + selectedSet = newSelection; for(auto& obj : selectedSet) cache.add_component(obj); calculate_aabb(); @@ -178,16 +182,27 @@ void DrawingProgramSelection::delete_all() { } } +// NOTE: Only run this if no transformations happened +void DrawingProgramSelection::selection_to_clipboard() { + auto& clipboard = drawP.world.main.clipboard; + std::unordered_set resourceSet; + for(auto& c : selectedSet) + c->obj->get_used_resources(resourceSet); + std::vector compVecSort(selectedSet.begin(), selectedSet.end()); + std::sort(compVecSort.begin(), compVecSort.end(), [&](auto& a, auto& b) { + return a->pos < b->pos; + }); + clipboard.components.clear(); + for(auto& c : compVecSort) + clipboard.components.emplace_back(c->obj); + clipboard.pos = initialSelectionAABB.center(); +} + void DrawingProgramSelection::update() { if(is_something_selected()) { if(cache.check_if_rebuild_should_occur()) cache.test_rebuild(std::vector(selectedSet.begin(), selectedSet.end()), true); - if(drawP.world.main.input.key(InputManager::KEY_DRAW_UNSELECT).pressed) - deselect_all(); - else if(drawP.world.main.input.key(InputManager::KEY_DRAW_DELETE).pressed) - delete_all(); - selectionRectPoints[0] = selectionTransformCoords.from_space_world(initialSelectionAABB.min); selectionRectPoints[1] = selectionTransformCoords.from_space_world(initialSelectionAABB.bottom_left()); selectionRectPoints[2] = selectionTransformCoords.from_space_world(initialSelectionAABB.max); @@ -280,7 +295,50 @@ void DrawingProgramSelection::update() { transformOpHappening = TransformOperation::NONE; break; } + + if(drawP.world.main.input.key(InputManager::KEY_DRAW_UNSELECT).pressed) + deselect_all(); + else if(drawP.world.main.input.key(InputManager::KEY_DRAW_DELETE).pressed) + delete_all(); + else if(drawP.world.main.input.key(InputManager::KEY_COPY).pressed && startingSelectionTransformCoords == CoordSpaceHelper()) + selection_to_clipboard(); + else if(drawP.world.main.input.key(InputManager::KEY_CUT).pressed && startingSelectionTransformCoords == CoordSpaceHelper()) { + selection_to_clipboard(); + delete_all(); + } + else if(drawP.world.main.input.key(InputManager::KEY_PASTE).pressed) { + deselect_all(); + paste_clipboard(); + } } + else if(drawP.world.main.input.key(InputManager::KEY_PASTE).pressed && !drawP.prevent_undo_or_redo()) + paste_clipboard(); +} + +void DrawingProgramSelection::paste_clipboard() { + auto& clipboard = drawP.world.main.clipboard; + drawP.reset_tools(); + drawP.controls.selectedTool = DrawingProgram::TOOL_RECTSELECT; + drawP.controls.previousSelected = DrawingProgram::TOOL_RECTSELECT; + uint64_t allPlacement = drawP.components.client_list().size(); + std::vector> placedComponents; + WorldVec mousePos = drawP.world.get_mouse_world_pos(); + WorldVec moveVec = drawP.world.main.clipboard.pos - mousePos; + std::unordered_map resourceRemapIDs; + for(auto& r : clipboard.resources) + resourceRemapIDs[r.first] = drawP.world.rMan.add_resource(r.second); + for(auto& c : clipboard.components) { + auto& newC = placedComponents.emplace_back(c->copy()); + newC->remap_resource_ids(resourceRemapIDs); + newC->coords.translate(-moveVec); + newC->final_update(drawP, false); + } + drawP.addToCompCacheOnInsert = false; + auto compListInserted = drawP.components.client_insert_ordered_vector_items(allPlacement, placedComponents); + drawP.addToCompCacheOnInsert = true; + std::unordered_set compSetInserted(compListInserted.begin(), compListInserted.end()); + set_to_selection(compSetInserted); + drawP.add_undo_place_components(compSetInserted); } void DrawingProgramSelection::rebuild_cam_space() { diff --git a/src/DrawingProgram/DrawingProgramSelection.hpp b/src/DrawingProgram/DrawingProgramSelection.hpp index 8553f30..0225fd6 100644 --- a/src/DrawingProgram/DrawingProgramSelection.hpp +++ b/src/DrawingProgram/DrawingProgramSelection.hpp @@ -22,6 +22,9 @@ class DrawingProgramSelection { bool mouse_collided_with_scale_point(); bool mouse_collided_with_rotate_center_handle_point(); bool mouse_collided_with_rotate_handle_point(); + void selection_to_clipboard(); + void paste_clipboard(); + void set_to_selection(const std::unordered_set& newSelection); void calculate_aabb(); void calculate_initial_rotate_center_location();