Fix undo/redo problem with erase, added send_multi_update_message blocks

This commit is contained in:
Yousef Khadadeh 2026-05-28 21:55:30 +03:00
parent afc672210c
commit 8e4732c1e0
11 changed files with 102 additions and 72 deletions

View file

@ -218,7 +218,7 @@ void DrawingProgramSelection::check_add_stroke_color_change_undo() {
if(!undoMan.fill_netid_list_from_undoid_list(netIDs, undoIDs))
return false;
undoMan.world.netObjMan.send_multi_update_messsage([&]() {
{
for(size_t i = 0; i < netIDs.size(); i++) {
auto objPtr = undoMan.world.netObjMan.get_obj_temporary_ref_from_id<CanvasComponentContainer>(netIDs[i]);
if(objPtr) {
@ -229,7 +229,7 @@ void DrawingProgramSelection::check_add_stroke_color_change_undo() {
objPtr->send_comp_update(undoMan.world.drawProg, true);
}
}
}, NetworkingObjects::NetObjManager::SendUpdateType::SEND_TO_ALL, nullptr);
}
return true;
}

View file

@ -203,12 +203,12 @@ void DrawingProgramLayerManager::push_components_to(const std::vector<CanvasComp
}
}
undoMan.world.netObjMan.send_multi_update_messsage([&]() {
{
for(auto& [compNetID, moveData] : toMoveObjs) {
auto components = undoMan.world.netObjMan.get_obj_temporary_ref_from_id<CanvasComponentContainer::NetList>(compNetID);
std::vector<std::pair<CanvasComponentContainer::ObjInfoIterator, NetObjOwnerPtr<CanvasComponentContainer>>> toInsert;
std::vector<NetObjOrderedListIterator<CanvasComponentContainer>> toErase = components->get_list(moveData.objs);
components->sort_it_list(toErase); // There's a chance that objects could have changed order on the client side, so sort them
components->sort_netobj_ordered_list_iterator_list(components, toErase); // There's a chance that objects could have changed order on the client side, so sort them
std::vector<NetObjOwnerPtr<CanvasComponentContainer>> erasedObjs;
std::vector<uint32_t> newPos;
@ -228,7 +228,7 @@ void DrawingProgramLayerManager::push_components_to(const std::vector<CanvasComp
components->insert_sorted_list_and_send_create(components, toInsert);
*moveData.oldPos = newPos;
}
}, NetObjManager::SendUpdateType::SEND_TO_ALL, nullptr);
}
return true;
}
~MoveComponentsUndoAction() {}
@ -423,7 +423,7 @@ void DrawingProgramLayerManager::add_undo_erase_components(const std::unordered_
}
}
undoMan.world.netObjMan.send_multi_update_messsage([&]() {
{
for(auto& [parentNetID, insertData] : insertMap) {
auto parentListPtr = undoMan.world.netObjMan.get_obj_temporary_ref_from_id<NetObjOrderedList<CanvasComponentContainer>>(parentNetID);
std::vector<std::pair<NetObjOrderedListIterator<CanvasComponentContainer>, NetObjOwnerPtr<CanvasComponentContainer>>> toInsert(insertData.it.size());
@ -435,7 +435,7 @@ void DrawingProgramLayerManager::add_undo_erase_components(const std::unordered_
parentListPtr->insert_sorted_list_and_send_create(parentListPtr, toInsert);
insertData.copyData->clear();
}
}, NetworkingObjects::NetObjManager::SendUpdateType::SEND_TO_ALL, nullptr);
}
return true;
}
@ -458,12 +458,12 @@ void DrawingProgramLayerManager::add_undo_erase_components(const std::unordered_
}
}
undoMan.world.netObjMan.send_multi_update_messsage([&]() {
{
for(auto& [parentNetID, eData] : eraseMap) {
auto parentListPtr = undoMan.world.netObjMan.get_obj_temporary_ref_from_id<NetObjOrderedList<CanvasComponentContainer>>(parentNetID);
parentListPtr->erase_list(parentListPtr, eData);
}
}, NetworkingObjects::NetObjManager::SendUpdateType::SEND_TO_ALL, nullptr);
}
return true;
}
@ -543,6 +543,8 @@ void DrawingProgramLayerManager::add_undo_place_components(DrawingProgramLayerLi
bool redo(WorldUndoManager& undoMan) override {
std::vector<NetObjOrderedListIterator<CanvasComponentContainer>> it;
NetObjTemporaryPtr<NetObjOrderedList<CanvasComponentContainer>> parentListPtr;
auto p = std::chrono::steady_clock::now();
{
std::optional<NetObjID> parentNetID = undoMan.get_netid_from_undoid(parentUndoID);
@ -551,18 +553,27 @@ void DrawingProgramLayerManager::add_undo_place_components(DrawingProgramLayerLi
parentListPtr = undoMan.world.netObjMan.get_obj_temporary_ref_from_id<NetObjOrderedList<CanvasComponentContainer>>(parentNetID.value());
}
p = std::chrono::steady_clock::now();
{
it = parentListPtr->at_ordered_indices(undoPlaceData.pos);
}
p = std::chrono::steady_clock::now();
std::vector<std::pair<NetObjOrderedListIterator<CanvasComponentContainer>, NetObjOwnerPtr<CanvasComponentContainer>>> toInsert(it.size());
for(size_t i = 0; i < it.size(); i++) {
toInsert[i].first = it[i];
toInsert[i].second = undoMan.world.netObjMan.make_obj_direct<CanvasComponentContainer>(undoMan.world.netObjMan, *undoPlaceData.copyData.at(i));
undoMan.register_new_netid_to_existing_undoid(undoPlaceData.undoID.at(i), toInsert[i].second.get_net_id());
}
p = std::chrono::steady_clock::now();
parentListPtr->insert_sorted_list_and_send_create(parentListPtr, toInsert);
p = std::chrono::steady_clock::now();
undoPlaceData.copyData.clear();
return true;
}

View file

@ -79,6 +79,7 @@ class DrawingProgramLayerManager {
uint32_t total_component_count();
CanvasComponentContainer::ObjInfo* add_component_to_layer_being_edited(CanvasComponentContainer* newObj);
// BOTH add_many_components_to_layer CALLS REQUIRE A SORTED INSERT LIST
std::vector<CanvasComponentContainer::ObjInfoIterator> add_many_components_to_layer_being_edited(const std::vector<std::pair<CanvasComponentContainer::ObjInfoIterator, CanvasComponentContainer*>>& newObjs);
std::vector<CanvasComponentContainer::ObjInfoIterator> add_many_components_to_layer(DrawingProgramLayerListItem* layer, const std::vector<std::pair<CanvasComponentContainer::ObjInfoIterator, CanvasComponentContainer*>>& newObjs, bool newUndo = true);
std::vector<CanvasComponentContainer::ObjInfo*> get_flattened_component_list() const;

View file

@ -202,7 +202,7 @@ void DrawingProgramLayerManagerGUI::setup_list_gui() {
uint32_t insertUndoPosition;
std::vector<WorldUndoManager::UndoObjectID> insertedUndoIDs;
world.netObjMan.send_multi_update_messsage([&]() {
{
std::unordered_map<NetObjID, std::vector<NetObjOrderedListIterator<DrawingProgramLayerListItem>>> toEraseMap;
uint32_t newIndex = index;
std::vector<NetObjOwnerPtr<DrawingProgramLayerListItem>> toInsertObjPtrs;
@ -250,7 +250,7 @@ void DrawingProgramLayerManagerGUI::setup_list_gui() {
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 MoveLayersWorldUndoAction : public WorldUndoAction {
public:
@ -301,7 +301,7 @@ void DrawingProgramLayerManagerGUI::setup_list_gui() {
}
}
undoMan.world.netObjMan.send_multi_update_messsage([&]() {
{
eraseListPtr->erase_list(eraseListPtr, toEraseList, &toMoveObjs);
for(auto& [parentNetID, indexNetIDListPair] : toInsertToMap) {
@ -318,7 +318,7 @@ void DrawingProgramLayerManagerGUI::setup_list_gui() {
}
parentListPtr->insert_sorted_list_and_send_create(parentListPtr, toInsert);
}
}, NetObjManager::SendUpdateType::SEND_TO_ALL, nullptr);
}
return true;
}
bool redo(WorldUndoManager& undoMan) override {
@ -348,7 +348,7 @@ void DrawingProgramLayerManagerGUI::setup_list_gui() {
return false;
}
undoMan.world.netObjMan.send_multi_update_messsage([&]() {
{
std::vector<NetObjOwnerPtr<DrawingProgramLayerListItem>> toInsertObjPtrs;
for(auto& [listToEraseFrom, setToErase] : toEraseMap) {
@ -366,7 +366,7 @@ void DrawingProgramLayerManagerGUI::setup_list_gui() {
toInsert.back().second.reassign_ids();
}
listPtr->insert_sorted_list_and_send_create(listPtr, toInsert);
}, NetObjManager::SendUpdateType::SEND_TO_ALL, nullptr);
}
return true;
}

View file

@ -87,9 +87,13 @@ void BrushTool::commit_data(bool final) {
std::optional<SkPath> simplified = Simplify(newMesh.d.meshPath);
if(simplified.has_value())
newMesh.d.meshPath = simplified.value();
containerPtr->normalize_object_coordinates();
}
containerPtr->commit_update(drawP);
containerPtr->send_comp_update(drawP, final);
drawP.world.netObjMan.send_multi_update_messsage([&]() {
drawP.send_transforms_for({objInfoBeingEdited});
containerPtr->send_comp_update(drawP, final);
}, NetworkingObjects::NetObjManager::SendUpdateType::SEND_TO_ALL, nullptr);
}
commitUpdate = false;
}

View file

@ -29,6 +29,7 @@
#include "../../GUIStuff/ElementHelpers/TextLabelHelpers.hpp"
#include "../../GUIStuff/ElementHelpers/RadioButtonHelpers.hpp"
#include "../../GUIStuff/ElementHelpers/CheckBoxHelpers.hpp"
#include "Helpers/NetworkingObjects/NetObjOrderedList.hpp"
EraserTool::EraserTool(DrawingProgram& initDrawP):
DrawingProgramToolBase(initDrawP)
@ -224,26 +225,32 @@ void EraserTool::commit_erase() {
}
return false;
});
bool firstPlacement = true;
for(auto& [layer, compMap] : newObjectsToPlace) {
drawP.layerMan.add_many_components_to_layer(layer, compMap, firstPlacement);
firstPlacement = false;
}
bool objectsToErase = !erasedComponents.empty();
if(objectsToErase)
drawP.layerMan.erase_component_container(erasedComponents, !placedNewObject);
bool first = !objectsToErase && !placedNewObject;
for(auto& [comp, oldData] : updatedComponents) {
comp->obj->get_comp().simplify_paths();
comp->obj->commit_update_dont_invalidate_cache(drawP);
comp->obj->send_comp_update(drawP, true);
if(first) {
first = false;
drawP.world.undo.push(std::make_unique<EditCanvasComponentWorldUndoAction>(std::move(oldData), drawP.world.undo.get_undoid_from_netid(comp->obj.get_net_id())));
drawP.world.netObjMan.send_multi_update_messsage([&]() {
bool firstPlacement = true;
for(auto& [layer, compMap] : newObjectsToPlace) {
layer->get_layer().components->sort_netobj_ordered_list_iterator_insert_list(layer->get_layer().components, compMap);
drawP.layerMan.add_many_components_to_layer(layer, compMap, firstPlacement);
firstPlacement = false;
}
else
drawP.world.undo.push_on_last(std::make_unique<EditCanvasComponentWorldUndoAction>(std::move(oldData), drawP.world.undo.get_undoid_from_netid(comp->obj.get_net_id())));
}
bool objectsToErase = !erasedComponents.empty();
if(objectsToErase)
drawP.layerMan.erase_component_container(erasedComponents, !placedNewObject);
bool first = !objectsToErase && !placedNewObject;
for(auto& [comp, oldData] : updatedComponents) {
comp->obj->get_comp().simplify_paths();
comp->obj->normalize_object_coordinates();
comp->obj->commit_update_dont_invalidate_cache(drawP);
drawP.send_transforms_for({comp});
comp->obj->send_comp_update(drawP, true);
if(first) {
first = false;
drawP.world.undo.push(std::make_unique<EditCanvasComponentWorldUndoAction>(std::move(oldData), drawP.world.undo.get_undoid_from_netid(comp->obj.get_net_id())));
}
else
drawP.world.undo.push_on_last(std::make_unique<EditCanvasComponentWorldUndoAction>(std::move(oldData), drawP.world.undo.get_undoid_from_netid(comp->obj.get_net_id())));
}
}, NetworkingObjects::NetObjManager::SendUpdateType::SEND_TO_ALL, nullptr);
erasedComponents.clear();
updatedComponents.clear();
}