From 0821f0840e9f76b218c0491203ed320575417abe Mon Sep 17 00:00:00 2001 From: Yousef Khadadeh Date: Tue, 20 Jan 2026 11:59:03 +0300 Subject: [PATCH] Added bring to front and send to back --- src/DrawingProgram/DrawingProgram.cpp | 8 ++ .../DrawingProgramSelection.cpp | 12 ++ .../DrawingProgramSelection.hpp | 2 + .../Layers/DrawingProgramLayerManager.cpp | 120 ++++++++++++++++++ .../Layers/DrawingProgramLayerManager.hpp | 1 + 5 files changed, 143 insertions(+) diff --git a/src/DrawingProgram/DrawingProgram.cpp b/src/DrawingProgram/DrawingProgram.cpp index 31093f3..804c966 100644 --- a/src/DrawingProgram/DrawingProgram.cpp +++ b/src/DrawingProgram/DrawingProgram.cpp @@ -186,6 +186,14 @@ bool DrawingProgram::selection_action_menu(Vector2f popupPos) { selection.delete_all(); shouldClose = true; } + if(t.gui.text_button_left_transparent("Bring to front of layer", "Bring to front of layer")) { + selection.push_selection_to_front(); + shouldClose = true; + } + if(t.gui.text_button_left_transparent("Send to back of layer", "Send to back of layer")) { + selection.push_selection_to_back(); + shouldClose = true; + } } }); return !shouldClose; diff --git a/src/DrawingProgram/DrawingProgramSelection.cpp b/src/DrawingProgram/DrawingProgramSelection.cpp index b276e0d..495a96f 100644 --- a/src/DrawingProgram/DrawingProgramSelection.cpp +++ b/src/DrawingProgram/DrawingProgramSelection.cpp @@ -369,6 +369,18 @@ void DrawingProgramSelection::deselect_all() { } } +void DrawingProgramSelection::push_selection_to_front() { + auto selectedVec = selectedSet; + deselect_all(); + drawP.layerMan.push_components_to(selectedVec, false); +} + +void DrawingProgramSelection::push_selection_to_back() { + auto selectedVec = selectedSet; + deselect_all(); + drawP.layerMan.push_components_to(selectedVec, true); +} + void DrawingProgramSelection::delete_all() { if(is_something_selected()) { auto selectedSetTemp = selectedSet; diff --git a/src/DrawingProgram/DrawingProgramSelection.hpp b/src/DrawingProgram/DrawingProgramSelection.hpp index 1ae6a94..59cac7b 100644 --- a/src/DrawingProgram/DrawingProgramSelection.hpp +++ b/src/DrawingProgram/DrawingProgramSelection.hpp @@ -21,6 +21,8 @@ class DrawingProgramSelection { void paste_clipboard(Vector2f pasteScreenPos); void paste_image(Vector2f pasteScreenPos); std::unordered_set get_selection_as_set(); + void push_selection_to_front(); + void push_selection_to_back(); void delete_all(); void selection_to_clipboard(); CanvasComponentContainer::ObjInfo* get_front_object_colliding_with_in_editing_layer(const SCollision::ColliderCollection& cC); diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp b/src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp index c96b048..861700c 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp @@ -95,6 +95,126 @@ bool DrawingProgramLayerManager::component_passes_layer_selector(CanvasComponent return false; } +void DrawingProgramLayerManager::push_components_to(const std::vector& objs, bool beginIfTrueEndIfFalse) { + using namespace NetworkingObjects; + + if(objs.empty()) + return; + + struct MoveUndoLayerData { + std::vector oldPos; + std::vector objs; + }; + std::unordered_map toMoveMapUndo; + + auto& undoMan = drawP.world.undo; + + drawP.world.netObjMan.send_multi_update_messsage([&]() { + std::unordered_map> toEraseMap; + std::vector> toInsertObjPtrs; + + DrawingProgramLayerListItem* parentLayer = nullptr; + std::vector toEraseList; + + auto commitMoveOnLayer = [&]() { + if(toEraseList.empty()) + return; + { + MoveUndoLayerData moveUndoData; + uint32_t i = 0; + for(auto& e : toEraseList) { + moveUndoData.objs.emplace_back(drawP.world.undo.get_undoid_from_netid(e->obj.get_net_id())); + moveUndoData.oldPos.emplace_back(e->pos - i); + ++i; + } + toMoveMapUndo[undoMan.get_undoid_from_netid(parentLayer->get_layer().components.get_net_id())] = moveUndoData; + } + + std::vector> erasedObjects; + auto& components = parentLayer->get_layer().components; + components->erase_list(components, toEraseList, &erasedObjects); + std::vector>> toInsert; + auto insertIt = beginIfTrueEndIfFalse ? components->begin() : components->end(); + for(auto& e : erasedObjects) { + e.reassign_ids(); + toInsert.emplace_back(insertIt, std::move(e)); + } + components->insert_ordered_list_and_send_create(components, toInsert); + }; + for(auto& obj : objs) { + if(parentLayer != obj->obj->parentLayer) { + commitMoveOnLayer(); + parentLayer = obj->obj->parentLayer; + } + toEraseList.emplace_back(obj->obj->objInfo); + } + commitMoveOnLayer(); + }, NetObjManager::SendUpdateType::SEND_TO_ALL, nullptr); + + class MoveComponentsUndoAction : public WorldUndoAction { + public: + MoveComponentsUndoAction(std::unordered_map initToMoveMapUndo): + toMoveMapUndo(std::move(initToMoveMapUndo)) + {} + std::string get_name() const override { + return "Move Components"; + } + bool undo(WorldUndoManager& undoMan) override { + return undo_redo(undoMan); + } + bool redo(WorldUndoManager& undoMan) override { + return undo_redo(undoMan); + } + bool undo_redo(WorldUndoManager& undoMan) { + struct MoveLayerData { + std::vector* oldPos; + std::vector objs; + }; + std::unordered_map toMoveObjs; + + { + for(auto& [undoID, moveUndoData] : toMoveMapUndo) { + std::optional netID = undoMan.get_netid_from_undoid(undoID); + if(!netID.has_value()) + return false; + auto& moveMapEntry = toMoveObjs[netID.value()]; + moveMapEntry.oldPos = &moveUndoData.oldPos; + if(!undoMan.fill_netid_list_from_undoid_list(moveMapEntry.objs, moveUndoData.objs)) + return false; + } + } + + undoMan.world.netObjMan.send_multi_update_messsage([&]() { + for(auto& [compNetID, moveData] : toMoveObjs) { + auto components = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(compNetID); + std::vector>> toInsert; + std::vector> toErase = components->get_list(moveData.objs); + std::vector> erasedObjs; + std::vector newPos; + { + uint32_t i = 0; + for(auto& it : toErase) { + newPos.emplace_back(it->pos - i); + ++i; + } + } + components->erase_list(components, toErase, &erasedObjs); + std::vector> insertIteratorList = components->at_ordered_indices(*moveData.oldPos); + for(uint32_t i = 0; i < toErase.size(); i++) + toInsert.emplace_back(insertIteratorList[i], std::move(erasedObjs[i])); + components->insert_ordered_list_and_send_create(components, toInsert); + *moveData.oldPos = newPos; + } + }, NetObjManager::SendUpdateType::SEND_TO_ALL, nullptr); + return true; + } + ~MoveComponentsUndoAction() {} + + std::unordered_map toMoveMapUndo; + }; + undoMan.push(std::make_unique(std::move(toMoveMapUndo))); +} + std::vector DrawingProgramLayerManager::add_many_components_to_layer_being_edited(const std::vector>& newObjs) { if(!newObjs.empty()) { auto editLayerPtr = editingLayer.lock(); diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerManager.hpp b/src/DrawingProgram/Layers/DrawingProgramLayerManager.hpp index 06c9a10..f8c30c4 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayerManager.hpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayerManager.hpp @@ -46,6 +46,7 @@ class DrawingProgramLayerManager { } uint32_t edited_layer_component_count(); CanvasComponentContainer::ObjInfoIterator get_edited_layer_end_iterator(); + void push_components_to(const std::vector& objs, bool beginIfTrueEndIfFalse); bool component_passes_layer_selector(CanvasComponentContainer::ObjInfo* c, LayerSelector layerSelector); void disable_add_to_cache_block(const std::function& toRun); void disable_commit_update_block(const std::function& toRun);