From 6b93d8dc4116f3bb3143b8b00f71c5c70e125208 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Thu, 8 Jul 2021 15:29:04 +0300 Subject: [PATCH] Refactored and fixed saving scene states between modes in photo editor. --- Telegram/SourceFiles/editor/editor_paint.cpp | 66 ++--------------- Telegram/SourceFiles/editor/editor_paint.h | 6 -- .../editor/photo_editor_content.cpp | 4 +- Telegram/SourceFiles/editor/scene/scene.cpp | 72 +++++++++++++------ Telegram/SourceFiles/editor/scene/scene.h | 11 +-- .../editor/scene/scene_item_base.cpp | 23 +++--- .../editor/scene/scene_item_base.h | 4 +- .../editor/scene/scene_item_line.cpp | 23 +++--- .../editor/scene/scene_item_line.h | 5 +- 9 files changed, 97 insertions(+), 117 deletions(-) diff --git a/Telegram/SourceFiles/editor/editor_paint.cpp b/Telegram/SourceFiles/editor/editor_paint.cpp index 3f80c00f4..0dfe2dcbe 100644 --- a/Telegram/SourceFiles/editor/editor_paint.cpp +++ b/Telegram/SourceFiles/editor/editor_paint.cpp @@ -153,86 +153,30 @@ void Paint::applyTransform(QRect geometry, int angle, bool flipped) { } std::shared_ptr Paint::saveScene() const { - _scene->saveItemsState(SaveState::Save); - _scene->clearSelection(); + _scene->save(SaveState::Save); return _scene->items().empty() - ? nullptr - : ranges::none_of(_scene->items(), &QGraphicsItem::isVisible) ? nullptr : _scene; } void Paint::restoreScene() { - _scene->restoreItemsState(SaveState::Save); + _scene->restore(SaveState::Save); } void Paint::cancel() { - _scene->restoreItemsState(SaveState::Keep); - _scene->clearSelection(); - _scene->cancelDrawing(); - - const auto filtered = _scene->items(Qt::AscendingOrder); - if (filtered.empty()) { - return; - } - - for (const auto &item : filtered) { - const auto it = ranges::find( - _previousItems, - item, - &SavedItem::item); - if (it == end(_previousItems)) { - _scene->removeItem(item); - } else { - it->item->setVisible(!it->undid); - } - } - - _itemsToRemove.clear(); + _scene->restore(SaveState::Keep); } void Paint::keepResult() { - _scene->saveItemsState(SaveState::Keep); - _scene->clearSelection(); - _scene->cancelDrawing(); - - for (const auto &item : _itemsToRemove) { - _scene->removeItem(item); - } - _itemsToRemove.clear(); - - const auto items = _scene->items(); - _previousItems = ranges::views::all( - items - ) | ranges::views::transform([=](ItemPtr i) -> SavedItem { - return { i, !i->isVisible() }; - }) | ranges::to_vector; + _scene->save(SaveState::Keep); } void Paint::clearRedoList() { - const auto items = _scene->items(Qt::AscendingOrder); - auto &&filtered = ranges::views::all( - items - ) | ranges::views::filter( - [=](const ItemPtr &i) { return isItemHidden(i); } - ); - - ranges::for_each(std::move(filtered), [&](ItemPtr item) { - item->hide(); - _itemsToRemove.push_back(item); - }); + _scene->clearRedoList(); _hasRedo = false; } -bool Paint::isItemHidden(const ItemPtr &item) const { - return !item->isVisible() && !isItemToRemove(item); -} - -bool Paint::isItemToRemove(const ItemPtr &item) const { - return ranges::contains(_itemsToRemove, item); -} - void Paint::updateUndoState() { _hasUndo = _scene->hasUndo(); _hasRedo = _scene->hasRedo(); diff --git a/Telegram/SourceFiles/editor/editor_paint.h b/Telegram/SourceFiles/editor/editor_paint.h index 80b3b2b87..8100d79ed 100644 --- a/Telegram/SourceFiles/editor/editor_paint.h +++ b/Telegram/SourceFiles/editor/editor_paint.h @@ -51,9 +51,6 @@ private: void clearRedoList(); - bool isItemToRemove(const std::shared_ptr &item) const; - bool isItemHidden(const std::shared_ptr &item) const; - const std::shared_ptr _controllers; const std::shared_ptr _scene; const base::unique_qptr _view; @@ -65,9 +62,6 @@ private: float64 zoom = 0.; } _transform; - std::vector _previousItems; - std::vector> _itemsToRemove; - rpl::variable _hasUndo = true; rpl::variable _hasRedo = true; diff --git a/Telegram/SourceFiles/editor/photo_editor_content.cpp b/Telegram/SourceFiles/editor/photo_editor_content.cpp index 8a217940d..da24431cf 100644 --- a/Telegram/SourceFiles/editor/photo_editor_content.cpp +++ b/Telegram/SourceFiles/editor/photo_editor_content.cpp @@ -107,8 +107,10 @@ void PhotoEditorContent::applyModifications( void PhotoEditorContent::save(PhotoModifications &modifications) { modifications.crop = _crop->saveCropRect(); _paint->keepResult(); + + const auto savedScene = _paint->saveScene(); if (!modifications.paint) { - modifications.paint = _paint->saveScene(); + modifications.paint = savedScene; } } diff --git a/Telegram/SourceFiles/editor/scene/scene.cpp b/Telegram/SourceFiles/editor/scene/scene.cpp index b5378ee64..4a878b85c 100644 --- a/Telegram/SourceFiles/editor/scene/scene.cpp +++ b/Telegram/SourceFiles/editor/scene/scene.cpp @@ -66,11 +66,8 @@ void Scene::removeItem(not_null item) { removeItem(*it); } -void Scene::removeItem(const std::shared_ptr &item) { - // Scene loses ownership of an item. - QGraphicsScene::removeItem(item.get()); - - _items.erase(ranges::remove(_items, item), end(_items)); +void Scene::removeItem(const ItemPtr &item) { + item->setStatus(NumberedItem::Status::Removed); _removesItem.fire({}); } @@ -147,22 +144,6 @@ void Scene::updateZoom(float64 zoom) { } } -void Scene::saveItemsState(SaveState state) { - for (const auto &item : items()) { - if (item->type() >= ItemBase::Type) { - static_cast(item.get())->save(state); - } - } -} - -void Scene::restoreItemsState(SaveState state) { - for (const auto &item : items()) { - if (item->type() >= ItemBase::Type) { - static_cast(item.get())->restore(state); - } - } -} - bool Scene::hasUndo() const { return ranges::any_of(_items, &NumberedItem::isNormalStatus); } @@ -189,6 +170,55 @@ void Scene::performRedo() { } } +void Scene::removeIf(Fn proj) { + auto copy = std::vector(); + for (const auto &item : _items) { + const auto toRemove = proj(item); + if (toRemove) { + // Scene loses ownership of an item. + // It seems for some reason this line causes a crash. =( + // QGraphicsScene::removeItem(item.get()); + } else { + copy.push_back(item); + } + } + _items = std::move(copy); +} + +void Scene::clearRedoList() { + for (const auto &item : _items) { + if (item->isUndidStatus()) { + item->setStatus(NumberedItem::Status::Removed); + } + } +} + +void Scene::save(SaveState state) { + removeIf([](const ItemPtr &item) { + return item->isRemovedStatus() + && !item->hasState(SaveState::Keep) + && !item->hasState(SaveState::Save); + }); + + for (const auto &item : _items) { + item->save(state); + } + clearSelection(); + cancelDrawing(); +} + +void Scene::restore(SaveState state) { + removeIf([=](const ItemPtr &item) { + return !item->hasState(state); + }); + + for (const auto &item : _items) { + item->restore(state); + } + clearSelection(); + cancelDrawing(); +} + Scene::~Scene() { // Prevent destroying by scene of all items. QGraphicsScene::removeItem(_canvas.get()); diff --git a/Telegram/SourceFiles/editor/scene/scene.h b/Telegram/SourceFiles/editor/scene/scene.h index 731632ebd..bbee707d3 100644 --- a/Telegram/SourceFiles/editor/scene/scene.h +++ b/Telegram/SourceFiles/editor/scene/scene.h @@ -35,7 +35,7 @@ public: Qt::SortOrder order = Qt::DescendingOrder) const; void addItem(ItemPtr item); void removeItem(not_null item); - void removeItem(const std::shared_ptr &item); + void removeItem(const ItemPtr &item); [[nodiscard]] rpl::producer<> addsItem() const; [[nodiscard]] rpl::producer<> removesItem() const; @@ -47,19 +47,22 @@ public: void cancelDrawing(); - void saveItemsState(SaveState state); - void restoreItemsState(SaveState state); - [[nodiscard]] bool hasUndo() const; [[nodiscard]] bool hasRedo() const; void performUndo(); void performRedo(); + + void save(SaveState state); + void restore(SaveState state); + + void clearRedoList(); protected: void mousePressEvent(QGraphicsSceneMouseEvent *event) override; void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; private: + void removeIf(Fn proj); const std::shared_ptr _canvas; const std::shared_ptr _lastZ; diff --git a/Telegram/SourceFiles/editor/scene/scene_item_base.cpp b/Telegram/SourceFiles/editor/scene/scene_item_base.cpp index cceff0689..0aaac899b 100644 --- a/Telegram/SourceFiles/editor/scene/scene_item_base.cpp +++ b/Telegram/SourceFiles/editor/scene/scene_item_base.cpp @@ -60,6 +60,10 @@ bool NumberedItem::isUndidStatus() const { return _status == Status::Undid; } +bool NumberedItem::isRemovedStatus() const { + return _status == Status::Removed; +} + void NumberedItem::save(SaveState state) { } @@ -413,16 +417,13 @@ void ItemBase::applyData(const Data &data) { } void ItemBase::save(SaveState state) { - if (state == SaveState::Keep) { - const auto z = zValue(); - _keeped = { - .data = generateData(), - .zValue = z, - .visible = isVisible(), - }; - } else if (state == SaveState::Save) { - _saved = _keeped; - } + const auto z = zValue(); + auto &saved = (state == SaveState::Keep) ? _keeped : _saved; + saved = { + .data = generateData(), + .zValue = z, + .status = status(), + }; } void ItemBase::restore(SaveState state) { @@ -432,7 +433,7 @@ void ItemBase::restore(SaveState state) { const auto &saved = (state == SaveState::Keep) ? _keeped : _saved; applyData(saved.data); setZValue(saved.zValue); - setVisible(saved.visible); + setStatus(saved.status); } bool ItemBase::hasState(SaveState state) const { diff --git a/Telegram/SourceFiles/editor/scene/scene_item_base.h b/Telegram/SourceFiles/editor/scene/scene_item_base.h index bb16a8dea..3ee271ad2 100644 --- a/Telegram/SourceFiles/editor/scene/scene_item_base.h +++ b/Telegram/SourceFiles/editor/scene/scene_item_base.h @@ -27,6 +27,7 @@ public: enum class Status { Normal, Undid, + Removed, }; enum { Type = UserType + 1 }; @@ -40,6 +41,7 @@ public: void setStatus(Status status); [[nodiscard]] bool isNormalStatus() const; [[nodiscard]] bool isUndidStatus() const; + [[nodiscard]] bool isRemovedStatus() const; virtual void save(SaveState state); virtual void restore(SaveState state); @@ -135,7 +137,7 @@ private: struct { Data data; float64 zValue = 0.; - bool visible = true; + NumberedItem::Status status; } _saved, _keeped; struct { diff --git a/Telegram/SourceFiles/editor/scene/scene_item_line.cpp b/Telegram/SourceFiles/editor/scene/scene_item_line.cpp index 9635cc1b0..3ebf394a5 100644 --- a/Telegram/SourceFiles/editor/scene/scene_item_line.cpp +++ b/Telegram/SourceFiles/editor/scene/scene_item_line.cpp @@ -39,23 +39,24 @@ bool ItemLine::collidesWithPath( } void ItemLine::save(SaveState state) { - if (state == SaveState::Keep) { - _keeped = true; - } else if (state == SaveState::Save) { - _saved = true; - } + auto &saved = (state == SaveState::Keep) ? _keeped : _saved; + saved = { + .saved = true, + .status = status(), + }; } void ItemLine::restore(SaveState state) { + if (!hasState(state)) { + return; + } + const auto &saved = (state == SaveState::Keep) ? _keeped : _saved; + setStatus(saved.status); } bool ItemLine::hasState(SaveState state) const { - if (state == SaveState::Keep) { - return _keeped; - } else if (state == SaveState::Save) { - return _saved; - } - return false; + const auto &saved = (state == SaveState::Keep) ? _keeped : _saved; + return saved.saved; } } // namespace Editor diff --git a/Telegram/SourceFiles/editor/scene/scene_item_line.h b/Telegram/SourceFiles/editor/scene/scene_item_line.h index da594775d..d4746c8e3 100644 --- a/Telegram/SourceFiles/editor/scene/scene_item_line.h +++ b/Telegram/SourceFiles/editor/scene/scene_item_line.h @@ -34,7 +34,10 @@ private: const QPixmap _pixmap; const QRectF _rect; - bool _saved, _keeped = false; + struct { + bool saved = false; + NumberedItem::Status status; + } _saved, _keeped; };