From b688c39e688fb5f8f902bf7af92f26e214e749c8 Mon Sep 17 00:00:00 2001 From: Yousef Khadadeh Date: Wed, 31 Dec 2025 10:06:26 +0300 Subject: [PATCH] Fixed selected object ordering --- src/DrawingProgram/DrawingProgram.cpp | 5 +- .../DrawingProgramSelection.cpp | 81 ++++++++----------- .../DrawingProgramSelection.hpp | 12 +-- .../Layers/DrawingProgramLayerManager.cpp | 10 --- .../Layers/DrawingProgramLayerManager.hpp | 10 ++- src/DrawingProgram/Tools/EraserTool.cpp | 2 +- 6 files changed, 52 insertions(+), 68 deletions(-) diff --git a/src/DrawingProgram/DrawingProgram.cpp b/src/DrawingProgram/DrawingProgram.cpp index 5ad1a10..cd6e228 100644 --- a/src/DrawingProgram/DrawingProgram.cpp +++ b/src/DrawingProgram/DrawingProgram.cpp @@ -348,9 +348,8 @@ void DrawingProgram::rebuild_cache() { EraserTool* eraserTool = static_cast(drawTool.get()); drawCache.build(eraserTool->erasedComponents); } - else if(is_selection_allowing_tool(drawTool->get_type())) { - drawCache.build(selection.get_selected_set()); - } + else if(is_selection_allowing_tool(drawTool->get_type())) + drawCache.build(selection.get_selection_as_set()); else drawCache.build({}); } diff --git a/src/DrawingProgram/DrawingProgramSelection.cpp b/src/DrawingProgram/DrawingProgramSelection.cpp index 85c3920..d35bd75 100644 --- a/src/DrawingProgram/DrawingProgramSelection.cpp +++ b/src/DrawingProgram/DrawingProgramSelection.cpp @@ -23,11 +23,11 @@ DrawingProgramSelection::DrawingProgramSelection(DrawingProgram& initDrawP): {} void DrawingProgramSelection::add_from_cam_coord_collider_to_selection(const SCollision::ColliderCollection& cC, DrawingProgramLayerManager::LayerSelector layerSelector, bool frontObjectOnly) { - std::unordered_set selectedComponents; + std::vector selectedComponents; if(frontObjectOnly) { CanvasComponentContainer::ObjInfo* a = drawP.drawCache.get_front_object_colliding_with_in_editing_layer(cC); if(a) { - selectedComponents.emplace(a); + selectedComponents.emplace_back(a); drawP.drawCache.erase_component(a); } } @@ -43,7 +43,7 @@ void DrawingProgramSelection::remove_from_cam_coord_collider_to_selection(const CanvasComponentContainer::ObjInfo* p = get_front_object_colliding_with_in_editing_layer(cC); if(p) { drawP.drawCache.add_component(p); - selectedSet.erase(p); + std::erase(selectedSet, p); } } else { @@ -60,7 +60,7 @@ void DrawingProgramSelection::remove_from_cam_coord_collider_to_selection(const calculate_aabb(); } -std::function&)> DrawingProgramSelection::erase_select_objects_in_bvh_func(std::unordered_set& selectedComponents, const SCollision::ColliderCollection& cC, const SCollision::ColliderCollection& cCWorld, DrawingProgramLayerManager::LayerSelector layerSelector) { +std::function&)> DrawingProgramSelection::erase_select_objects_in_bvh_func(std::vector& selectedComponents, const SCollision::ColliderCollection& cC, const SCollision::ColliderCollection& cCWorld, DrawingProgramLayerManager::LayerSelector layerSelector) { auto toRet = [&](const auto& bvhNode) { if(bvhNode && (bvhNode->coords.inverseScale << 9) < drawP.world.drawData.cam.c.inverseScale && SCollision::collide(cC, drawP.world.drawData.cam.c.to_space(bvhNode->bounds.min)) && @@ -71,7 +71,7 @@ std::function&)> DrawingP drawP.drawCache.traverse_bvh_run_function_starting_at_node_no_collision_check(bvhNode, [&](const auto& bvhNodeChild) { drawP.drawCache.node_loop_erase_if_components(bvhNodeChild, [&](auto c) { if(drawP.layerMan.component_passes_layer_selector(c, drawP.controls.layerSelector)) { - selectedComponents.emplace(c); + selectedComponents.emplace_back(c); return true; } return false; @@ -82,7 +82,7 @@ std::function&)> DrawingP } drawP.drawCache.node_loop_erase_if_components(bvhNode, [&](auto c) { if(drawP.layerMan.component_passes_layer_selector(c, drawP.controls.layerSelector) && c->obj->collides_with(drawP.world.drawData.cam.c, cCWorld, cC)) { - selectedComponents.emplace(c); + selectedComponents.emplace_back(c); drawP.drawCache.invalidate_cache_at_aabb(c->obj->get_world_bounds()); return true; } @@ -94,16 +94,28 @@ std::function&)> DrawingP return toRet; } -void DrawingProgramSelection::add_to_selection(const std::unordered_set& newSelection) { - selectedSet.insert(newSelection.begin(), newSelection.end()); +void DrawingProgramSelection::add_to_selection(const std::vector& newSelection) { + selectedSet.insert(selectedSet.end(), newSelection.begin(), newSelection.end()); + sort_selection(); calculate_aabb(); } -void DrawingProgramSelection::set_to_selection(const std::unordered_set& newSelection) { +void DrawingProgramSelection::set_to_selection(const std::vector& newSelection) { selectedSet = newSelection; + sort_selection(); calculate_aabb(); } +void DrawingProgramSelection::sort_selection() { + std::vector flattenedLayerList = drawP.layerMan.get_flattened_layer_list(); + std::unordered_map flattenedLayerListOrder; + for(size_t i = 0; i < flattenedLayerList.size(); i++) + flattenedLayerListOrder[flattenedLayerList[i]] = i; + std::sort(selectedSet.begin(), selectedSet.end(), [&](auto& a, auto& b) { + return (flattenedLayerListOrder[a->obj->parentLayer] < flattenedLayerListOrder[b->obj->parentLayer]) || (a->obj->parentLayer == b->obj->parentLayer && a->pos < b->pos); + }); +} + void DrawingProgramSelection::calculate_aabb() { if(is_something_selected()) { initialSelectionAABB = (*selectedSet.begin())->obj->get_world_bounds(); @@ -118,7 +130,7 @@ bool DrawingProgramSelection::is_something_selected() { } bool DrawingProgramSelection::is_selected(CanvasComponentContainer::ObjInfo* objToCheck) { - return selectedSet.contains(objToCheck); + return std::find(selectedSet.begin(), selectedSet.end(), objToCheck) != selectedSet.end(); } void DrawingProgramSelection::reset_all() { @@ -292,13 +304,13 @@ void DrawingProgramSelection::delete_all() { if(is_something_selected()) { auto selectedSetTemp = selectedSet; reset_all(); // Clear set before erasing, since calling erase_component_set will run a check to see if each object is selected and erase them one by one, which is slower - drawP.layerMan.erase_component_set(selectedSetTemp); + drawP.layerMan.erase_component_container(selectedSetTemp); } } void DrawingProgramSelection::erase_component(CanvasComponentContainer::ObjInfo* objToCheck) { if(is_selected(objToCheck)) { - selectedSet.erase(objToCheck); + std::erase(selectedSet, objToCheck); if(selectedSet.empty()) reset_all(); } @@ -319,16 +331,8 @@ void DrawingProgramSelection::selection_to_clipboard() { std::unordered_set resourceSet; for(auto& c : selectedSet) c->obj->get_comp().get_used_resources(resourceSet); - std::vector compVecSort(selectedSet.begin(), selectedSet.end()); - std::vector flattenedLayerList = drawP.layerMan.get_flattened_layer_list(); - std::unordered_map flattenedLayerListOrder; - for(size_t i = 0; i < flattenedLayerList.size(); i++) - flattenedLayerListOrder[flattenedLayerList[i]] = i; - std::sort(compVecSort.begin(), compVecSort.end(), [&](auto& a, auto& b) { - return (flattenedLayerListOrder[a->obj->parentLayer] < flattenedLayerListOrder[b->obj->parentLayer]) || (a->obj->parentLayer == b->obj->parentLayer && a->pos < b->pos); - }); clipboard.components.clear(); - for(auto& c : compVecSort) + for(auto& c : selectedSet) clipboard.components.emplace_back(c->obj->get_data_copy()); clipboard.pos = initialSelectionAABB.center(); clipboard.inverseScale = drawP.world.drawData.cam.c.inverseScale; @@ -365,9 +369,11 @@ void DrawingProgramSelection::paste_clipboard(Vector2f pasteScreenPos) { placedComponents.emplace_back(drawP.layerMan.get_edited_layer_end_iterator(), newComponentContainer); } auto newlyInsertedObjectIts = drawP.layerMan.add_many_components_to_layer_being_edited(placedComponents); - std::unordered_set compSetInserted; - for(auto& it : newlyInsertedObjectIts) - compSetInserted.emplace(&(*it)); + std::vector compSetInserted; + for(auto& it : newlyInsertedObjectIts) { + drawP.drawCache.erase_component(&(*it)); + compSetInserted.emplace_back(&(*it)); + } set_to_selection(compSetInserted); //drawP.add_undo_place_components(compSetInserted); } @@ -377,8 +383,8 @@ bool DrawingProgramSelection::is_being_transformed() { return transformOpHappening != TransformOperation::NONE; } -const std::unordered_set& DrawingProgramSelection::get_selected_set() { - return selectedSet; +std::unordered_set DrawingProgramSelection::get_selection_as_set() { + return std::unordered_set(selectedSet.begin(), selectedSet.end()); } void DrawingProgramSelection::rebuild_cam_space() { @@ -422,7 +428,8 @@ void DrawingProgramSelection::draw_components(SkCanvas* canvas, const DrawData& if(!surface) throw std::runtime_error("[DrawingProgramSelection::draw_components] Could not make temporary surface"); - draw_components_recursive(drawP.layerMan.get_layer_root(), surface->getCanvas(), selectionDrawData); + for(auto& c : selectedSet) + c->obj->draw(canvas, selectionDrawData); SkPaint glowBlurP; glowBlurP.setImageFilter(SkImageFilters::Blur(5, 5, nullptr)); @@ -453,23 +460,3 @@ void DrawingProgramSelection::draw_gui(SkCanvas* canvas, const DrawData& drawDat } } } - -void DrawingProgramSelection::draw_components_recursive(const DrawingProgramLayerListItem& layerItem, SkCanvas* canvas, const DrawData& drawData) { - if(layerItem.get_visible()) { - SkPaint layerPaint; - layerPaint.setAlphaf(layerItem.get_alpha()); - //layerPaint.setBlendMode(serialized_blend_mode_to_sk_blend_mode(displayData->blendMode)); // For selection, everything should just be in default blend mode (SrcOver) - canvas->saveLayer(nullptr, &layerPaint); - if(layerItem.is_folder()) { - for(auto& p : *layerItem.get_folder().folderList | std::views::reverse) - draw_components_recursive(*p.obj, canvas, drawData); - } - else { - for(auto& c : selectedSet) { // Loop on selected set and not layer component list, since i'm assuming selected set will be small - if(c->obj->parentLayer == &layerItem) - c->obj->draw(canvas, drawData); - } - } - canvas->restore(); - } -} diff --git a/src/DrawingProgram/DrawingProgramSelection.hpp b/src/DrawingProgram/DrawingProgramSelection.hpp index 75bf1fa..62ef915 100644 --- a/src/DrawingProgram/DrawingProgramSelection.hpp +++ b/src/DrawingProgram/DrawingProgramSelection.hpp @@ -19,12 +19,11 @@ class DrawingProgramSelection { void update(); void deselect_all(); void paste_clipboard(Vector2f pasteScreenPos); - const std::unordered_set& get_selected_set(); + std::unordered_set get_selection_as_set(); void delete_all(); void selection_to_clipboard(); CanvasComponentContainer::ObjInfo* get_front_object_colliding_with_in_editing_layer(const SCollision::ColliderCollection& cC); private: - void draw_components_recursive(const DrawingProgramLayerListItem& layerItem, SkCanvas* canvas, const DrawData& drawData); bool mouse_collided_with_selection_aabb(); bool mouse_collided_with_scale_point(); bool mouse_collided_with_rotate_center_handle_point(); @@ -34,16 +33,17 @@ class DrawingProgramSelection { void rebuild_cam_space(); Vector2f get_rotation_point_pos_from_angle(double angle); - void set_to_selection(const std::unordered_set& newSelection); - void add_to_selection(const std::unordered_set& newSelection); + void set_to_selection(const std::vector& newSelection); + void add_to_selection(const std::vector& newSelection); + void sort_selection(); void calculate_aabb(); void reset_all(); - std::function&)> erase_select_objects_in_bvh_func(std::unordered_set& selectedComponents, const SCollision::ColliderCollection& cC, const SCollision::ColliderCollection& cCWorld, DrawingProgramLayerManager::LayerSelector layerSelector); + std::function&)> erase_select_objects_in_bvh_func(std::vector& selectedComponents, const SCollision::ColliderCollection& cC, const SCollision::ColliderCollection& cCWorld, DrawingProgramLayerManager::LayerSelector layerSelector); SCollision::ColliderCollection camSpaceSelection; std::array selectionRectPoints; CoordSpaceHelperTransform selectionTransformCoords; - std::unordered_set selectedSet; + std::vector selectedSet; SCollision::AABB initialSelectionAABB; DrawingProgram& drawP; diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp b/src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp index 0b1012f..45f6c00 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp @@ -62,16 +62,6 @@ const DrawingProgramLayerListItem& DrawingProgramLayerManager::get_layer_root() return *layerTreeRoot; } -void DrawingProgramLayerManager::erase_component_set(const std::unordered_set& compsToErase) { - std::unordered_map> idsToEraseInSpecificLayers; - for(auto& c : compsToErase) - idsToEraseInSpecificLayers[c->obj->parentLayer].emplace_back(c->obj->objInfo); - for(auto& [layerListItem, netObjSetToErase] : idsToEraseInSpecificLayers) { - auto& layerComponentList = layerListItem->get_layer().components; - layerComponentList->erase_list(layerComponentList, netObjSetToErase); - } -} - bool DrawingProgramLayerManager::component_passes_layer_selector(CanvasComponentContainer::ObjInfo* c, LayerSelector layerSelector) { switch(layerSelector) { case LayerSelector::ALL_VISIBLE_LAYERS: diff --git a/src/DrawingProgram/Layers/DrawingProgramLayerManager.hpp b/src/DrawingProgram/Layers/DrawingProgramLayerManager.hpp index 104ad4a..72a267f 100644 --- a/src/DrawingProgram/Layers/DrawingProgramLayerManager.hpp +++ b/src/DrawingProgram/Layers/DrawingProgramLayerManager.hpp @@ -24,7 +24,15 @@ class DrawingProgramLayerManager { void write_components_server(cereal::PortableBinaryOutputArchive& a); void read_components_client(cereal::PortableBinaryInputArchive& a); bool is_a_layer_being_edited(); - void erase_component_set(const std::unordered_set& compsToErase); + template void erase_component_container(const List& compsToErase) { + std::unordered_map> idsToEraseInSpecificLayers; + for(auto& c : compsToErase) + idsToEraseInSpecificLayers[c->obj->parentLayer].emplace_back(c->obj->objInfo); + for(auto& [layerListItem, netObjSetToErase] : idsToEraseInSpecificLayers) { + auto& layerComponentList = layerListItem->get_layer().components; + layerComponentList->erase_list(layerComponentList, netObjSetToErase); + } + } uint32_t edited_layer_component_count(); CanvasComponentContainer::ObjInfoIterator get_edited_layer_end_iterator(); bool component_passes_layer_selector(CanvasComponentContainer::ObjInfo* c, LayerSelector layerSelector); diff --git a/src/DrawingProgram/Tools/EraserTool.cpp b/src/DrawingProgram/Tools/EraserTool.cpp index bbe4077..003c7a0 100644 --- a/src/DrawingProgram/Tools/EraserTool.cpp +++ b/src/DrawingProgram/Tools/EraserTool.cpp @@ -36,7 +36,7 @@ void EraserTool::erase_component(CanvasComponentContainer::ObjInfo* erasedComp) } void EraserTool::switch_tool(DrawingProgramToolType newTool) { - drawP.layerMan.erase_component_set(erasedComponents); + drawP.layerMan.erase_component_container(erasedComponents); } void EraserTool::tool_update() {