Fixed bugs with undo and redo of multiple objects
This commit is contained in:
parent
2de5c90006
commit
9aa41ddb7f
7 changed files with 74 additions and 52 deletions
|
|
@ -519,6 +519,15 @@ void DrawingProgram::initialize_draw_data(cereal::PortableBinaryInputArchive& a)
|
|||
compCache.test_rebuild(components.client_list(), true);
|
||||
}
|
||||
|
||||
void DrawingProgram::client_erase_set(std::unordered_set<CollabListType::ObjectInfoPtr> erasedComponents) {
|
||||
std::unordered_set<ServerClientID> idsToErase;
|
||||
for(auto& c : erasedComponents)
|
||||
idsToErase.emplace(c->id);
|
||||
DrawComponent::client_send_erase_set(*this, idsToErase);
|
||||
components.client_erase_set(erasedComponents);
|
||||
add_undo_erase_components(erasedComponents);
|
||||
}
|
||||
|
||||
void DrawingProgram::add_undo_place_component(const CollabListType::ObjectInfoPtr& objToUndo) {
|
||||
world.undo.push(UndoManager::UndoRedoPair{
|
||||
[&, objToUndo]() {
|
||||
|
|
@ -531,7 +540,6 @@ void DrawingProgram::add_undo_place_component(const CollabListType::ObjectInfoPt
|
|||
if(objToUndo->obj->collabListInfo.lock())
|
||||
return false;
|
||||
components.client_insert(objToUndo);
|
||||
objToUndo->obj->final_update(*this); // Method to recover after an undo that happened while drawing a component
|
||||
objToUndo->obj->client_send_place(*this);
|
||||
reset_tools();
|
||||
return true;
|
||||
|
|
@ -539,6 +547,44 @@ void DrawingProgram::add_undo_place_component(const CollabListType::ObjectInfoPt
|
|||
});
|
||||
}
|
||||
|
||||
void DrawingProgram::add_undo_erase_components(const std::unordered_set<CollabListType::ObjectInfoPtr>& erasedComponents) {
|
||||
world.undo.push(UndoManager::UndoRedoPair{
|
||||
[&, erasedComponents = erasedComponents]() {
|
||||
std::vector<CollabListType::ObjectInfoPtr> sortedObjects(erasedComponents.begin(), erasedComponents.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;
|
||||
},
|
||||
[&, erasedComponents = erasedComponents]() {
|
||||
for(auto& comp : erasedComponents)
|
||||
if(!comp->obj->collabListInfo.lock())
|
||||
return false;
|
||||
|
||||
std::unordered_set<ServerClientID> idsToErase;
|
||||
for(auto& c : erasedComponents)
|
||||
idsToErase.emplace(c->id);
|
||||
|
||||
DrawComponent::client_send_erase_set(*this, idsToErase);
|
||||
components.client_erase_set(erasedComponents);
|
||||
|
||||
reset_tools();
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ClientPortionID DrawingProgram::get_max_id(ServerPortionID serverID) {
|
||||
ClientPortionID maxClientID = 0;
|
||||
auto& cList = components.client_list();
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ class DrawingProgram {
|
|||
|
||||
Vector4f* get_foreground_color_ptr();
|
||||
private:
|
||||
void client_erase_set(std::unordered_set<CollabListType::ObjectInfoPtr> erasedComponents); // The set might be modified while this is being called, so dont pass by reference
|
||||
|
||||
void check_delayed_update_timers();
|
||||
void check_updateable_components();
|
||||
|
|
@ -79,6 +80,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_erase_components(const std::unordered_set<CollabListType::ObjectInfoPtr>& objSetToUndo);
|
||||
|
||||
BrushTool brushTool;
|
||||
EraserTool eraserTool;
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ void DrawingProgramCache::clear_own_cached_surfaces() {
|
|||
}
|
||||
|
||||
bool DrawingProgramCache::check_if_rebuild_should_occur() {
|
||||
return (unsortedComponents.size() >= MINIMUM_COMPONENTS_TO_START_REBUILD && (std::chrono::steady_clock::now() - lastBvhBuildTime) >= std::chrono::seconds(5));
|
||||
return (unsortedComponents.size() >= MINIMUM_COMPONENTS_TO_START_REBUILD);
|
||||
}
|
||||
|
||||
void DrawingProgramCache::test_rebuild(const std::vector<CollabListType::ObjectInfoPtr>& comps, bool force) {
|
||||
|
|
@ -105,10 +105,7 @@ const std::chrono::steady_clock::time_point& DrawingProgramCache::get_last_bvh_b
|
|||
|
||||
void DrawingProgramCache::add_component(const CollabListType::ObjectInfoPtr& c) {
|
||||
unsortedComponents.emplace_back(c);
|
||||
if(c->obj->worldAABB)
|
||||
invalidate_cache_at_aabb_before_pos(c->obj->worldAABB.value(), c->pos);
|
||||
else
|
||||
invalidate_cache_before_pos(c->pos);
|
||||
invalidate_cache_at_optional_aabb_before_pos(c->obj->worldAABB, c->pos);
|
||||
}
|
||||
|
||||
void DrawingProgramCache::erase_component(const CollabListType::ObjectInfoPtr& c) {
|
||||
|
|
@ -119,7 +116,7 @@ void DrawingProgramCache::erase_component(const CollabListType::ObjectInfoPtr& c
|
|||
}
|
||||
else
|
||||
std::erase(unsortedComponents, c);
|
||||
invalidate_cache_before_pos(c->pos);
|
||||
invalidate_cache_at_optional_aabb_before_pos(c->obj->worldAABB, c->pos);
|
||||
}
|
||||
|
||||
std::pair<std::shared_ptr<DrawingProgramCacheBVHNode>, std::vector<CollabListType::ObjectInfoPtr>::iterator> DrawingProgramCache::get_bvh_node_fully_containing_recursive(const std::shared_ptr<DrawingProgramCacheBVHNode>& bvhNode, DrawComponent* c) {
|
||||
|
|
@ -261,6 +258,13 @@ void DrawingProgramCache::invalidate_cache_before_pos(uint64_t placementToInvali
|
|||
});
|
||||
}
|
||||
|
||||
void DrawingProgramCache::invalidate_cache_at_optional_aabb_before_pos(const std::optional<SCollision::AABB<WorldScalar>>& aabb, uint64_t placementToInvalidateAt) {
|
||||
if(aabb)
|
||||
invalidate_cache_at_aabb_before_pos(aabb.value(), placementToInvalidateAt);
|
||||
else
|
||||
invalidate_cache_before_pos(placementToInvalidateAt);
|
||||
}
|
||||
|
||||
void DrawingProgramCache::invalidate_cache_at_aabb_before_pos(const SCollision::AABB<WorldScalar>& aabb, uint64_t placementToInvalidateAt) {
|
||||
std::erase_if(nodesWithCachedSurfaces, [&](auto& n) {
|
||||
if(placementToInvalidateAt <= n->drawCache.value().lastDrawnComponentPlacement && SCollision::collide(aabb, n->bounds)) {
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ class DrawingProgramCache {
|
|||
void preupdate_component(const CollabListType::ObjectInfoPtr& c);
|
||||
void invalidate_cache_before_pos(uint64_t placementToInvalidateAt);
|
||||
void invalidate_cache_at_aabb_before_pos(const SCollision::AABB<WorldScalar>& aabb, uint64_t placementToInvalidateAt);
|
||||
void invalidate_cache_at_optional_aabb_before_pos(const std::optional<SCollision::AABB<WorldScalar>>& aabb, uint64_t placementToInvalidateAt);
|
||||
void clear();
|
||||
void draw_components_to_canvas(SkCanvas* canvas, const DrawData& drawData, uint64_t* lastDrawnComponentPlacement = nullptr);
|
||||
const std::vector<CollabListType::ObjectInfoPtr>& get_unsorted_component_list() const;
|
||||
|
|
|
|||
|
|
@ -172,14 +172,25 @@ bool DrawingProgramSelection::is_selected(const CollabListType::ObjectInfoPtr& o
|
|||
return selectedSet.contains(objToCheck);
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::delete_all() {
|
||||
if(is_something_selected()) {
|
||||
drawP.client_erase_set(selectedSet);
|
||||
selectedSet.clear();
|
||||
cache.clear();
|
||||
transformOpHappening = TransformOperation::NONE;
|
||||
selectionTransformCoords = CoordSpaceHelper();
|
||||
}
|
||||
}
|
||||
|
||||
void DrawingProgramSelection::update() {
|
||||
if(is_something_selected()) {
|
||||
|
||||
if(cache.check_if_rebuild_should_occur())
|
||||
cache.test_rebuild(std::vector<CollabListType::ObjectInfoPtr>(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());
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ class DrawingProgramSelection {
|
|||
bool is_selected(const CollabListType::ObjectInfoPtr& objToCheck);
|
||||
const std::unordered_set<CollabListType::ObjectInfoPtr>& get_selected_set();
|
||||
private:
|
||||
void delete_all();
|
||||
bool mouse_collided_with_selection_aabb();
|
||||
bool mouse_collided_with_scale_point();
|
||||
bool mouse_collided_with_rotate_center_handle_point();
|
||||
|
|
|
|||
|
|
@ -23,50 +23,7 @@ void EraserTool::gui_toolbox() {
|
|||
void EraserTool::reset_tool() {
|
||||
if(!erasedComponents.empty()) {
|
||||
DrawingProgramCache::move_components_from_bvh_nodes_to_set(erasedComponents, erasedBVHNodes);
|
||||
|
||||
std::unordered_set<ServerClientID> idsToErase1;
|
||||
for(auto& c : erasedComponents)
|
||||
idsToErase1.emplace(c->id);
|
||||
DrawComponent::client_send_erase_set(drawP, idsToErase1);
|
||||
drawP.components.client_erase_set(erasedComponents);
|
||||
|
||||
drawP.world.undo.push(UndoManager::UndoRedoPair{
|
||||
[&, erasedComponents = erasedComponents]() {
|
||||
std::vector<CollabListType::ObjectInfoPtr> sortedObjects(erasedComponents.begin(), erasedComponents.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;
|
||||
|
||||
drawP.components.client_insert_ordered_vector(sortedObjects);
|
||||
DrawComponent::client_send_place_many(drawP, sortedObjects);
|
||||
|
||||
drawP.reset_tools();
|
||||
|
||||
return true;
|
||||
},
|
||||
[&, erasedComponents = erasedComponents]() {
|
||||
for(auto& comp : erasedComponents)
|
||||
if(!comp->obj->collabListInfo.lock())
|
||||
return false;
|
||||
|
||||
std::unordered_set<ServerClientID> idsToErase;
|
||||
for(auto& c : erasedComponents)
|
||||
idsToErase.emplace(c->id);
|
||||
|
||||
DrawComponent::client_send_erase_set(drawP, idsToErase);
|
||||
drawP.components.client_erase_set(erasedComponents);
|
||||
|
||||
drawP.reset_tools();
|
||||
|
||||
drawP.force_rebuild_cache();
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
drawP.client_erase_set(erasedComponents);
|
||||
}
|
||||
erasedComponents.clear();
|
||||
erasedBVHNodes.clear();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue