mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Removed using of raw pointers for QGraphicsItem in photo editor.
Now all items are wrapped in the shared_ptr, and the Scene loses ownership of all items before being destroyed.
This commit is contained in:
parent
2791f89f30
commit
fde7cef9c8
5 changed files with 76 additions and 44 deletions
|
@ -12,7 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "editor/scene_item_canvas.h"
|
#include "editor/scene_item_canvas.h"
|
||||||
#include "editor/scene_item_sticker.h"
|
#include "editor/scene_item_sticker.h"
|
||||||
#include "editor/controllers.h"
|
#include "editor/controllers.h"
|
||||||
#include "base/event_filter.h"
|
#include "lottie/lottie_single_player.h"
|
||||||
|
|
||||||
#include <QGraphicsView>
|
#include <QGraphicsView>
|
||||||
|
|
||||||
|
@ -38,6 +38,8 @@ std::shared_ptr<Scene> EnsureScene(
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
using ItemPtr = Scene::ItemPtr;
|
||||||
|
|
||||||
Paint::Paint(
|
Paint::Paint(
|
||||||
not_null<Ui::RpWidget*> parent,
|
not_null<Ui::RpWidget*> parent,
|
||||||
PhotoModifications &modifications,
|
PhotoModifications &modifications,
|
||||||
|
@ -71,7 +73,7 @@ Paint::Paint(
|
||||||
? Qt::DescendingOrder
|
? Qt::DescendingOrder
|
||||||
: Qt::AscendingOrder);
|
: Qt::AscendingOrder);
|
||||||
|
|
||||||
auto proj = [&](QGraphicsItem *i) {
|
auto proj = [&](const ItemPtr &i) {
|
||||||
return isUndo ? i->isVisible() : isItemHidden(i);
|
return isUndo ? i->isVisible() : isItemHidden(i);
|
||||||
};
|
};
|
||||||
const auto it = ranges::find_if(filtered, std::move(proj));
|
const auto it = ranges::find_if(filtered, std::move(proj));
|
||||||
|
@ -108,7 +110,7 @@ Paint::Paint(
|
||||||
const auto size = std::min(s.width(), s.height()) / 2;
|
const auto size = std::min(s.width(), s.height()) / 2;
|
||||||
const auto x = s.width() / 2;
|
const auto x = s.width() / 2;
|
||||||
const auto y = s.height() / 2;
|
const auto y = s.height() / 2;
|
||||||
const auto item = new ItemSticker(
|
const auto item = std::make_shared<ItemSticker>(
|
||||||
document,
|
document,
|
||||||
_zoom.value(),
|
_zoom.value(),
|
||||||
_lastZ,
|
_lastZ,
|
||||||
|
@ -169,13 +171,13 @@ void Paint::cancel() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &group : filtered) {
|
for (const auto &item : filtered) {
|
||||||
const auto it = ranges::find(
|
const auto it = ranges::find(
|
||||||
_previousItems,
|
_previousItems,
|
||||||
group,
|
item,
|
||||||
&SavedItem::item);
|
&SavedItem::item);
|
||||||
if (it == end(_previousItems)) {
|
if (it == end(_previousItems)) {
|
||||||
_scene->removeItem(group);
|
_scene->removeItem(item);
|
||||||
} else {
|
} else {
|
||||||
it->item->setVisible(!it->undid);
|
it->item->setVisible(!it->undid);
|
||||||
}
|
}
|
||||||
|
@ -188,11 +190,12 @@ void Paint::keepResult() {
|
||||||
for (const auto &item : _itemsToRemove) {
|
for (const auto &item : _itemsToRemove) {
|
||||||
_scene->removeItem(item);
|
_scene->removeItem(item);
|
||||||
}
|
}
|
||||||
|
_itemsToRemove.clear();
|
||||||
|
|
||||||
const auto items = _scene->items();
|
const auto items = _scene->items();
|
||||||
_previousItems = ranges::views::all(
|
_previousItems = ranges::views::all(
|
||||||
items
|
items
|
||||||
) | ranges::views::transform([=](QGraphicsItem *i) -> SavedItem {
|
) | ranges::views::transform([=](ItemPtr i) -> SavedItem {
|
||||||
return { i, !i->isVisible() };
|
return { i, !i->isVisible() };
|
||||||
}) | ranges::to_vector;
|
}) | ranges::to_vector;
|
||||||
}
|
}
|
||||||
|
@ -204,7 +207,7 @@ bool Paint::hasUndo() const {
|
||||||
bool Paint::hasRedo() const {
|
bool Paint::hasRedo() const {
|
||||||
return ranges::any_of(
|
return ranges::any_of(
|
||||||
_scene->items(),
|
_scene->items(),
|
||||||
[=](QGraphicsItem *i) { return isItemHidden(i); });
|
[=](const ItemPtr &i) { return isItemHidden(i); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Paint::clearRedoList() {
|
void Paint::clearRedoList() {
|
||||||
|
@ -212,10 +215,10 @@ void Paint::clearRedoList() {
|
||||||
auto &&filtered = ranges::views::all(
|
auto &&filtered = ranges::views::all(
|
||||||
items
|
items
|
||||||
) | ranges::views::filter(
|
) | ranges::views::filter(
|
||||||
[=](QGraphicsItem *i) { return isItemHidden(i); }
|
[=](const ItemPtr &i) { return isItemHidden(i); }
|
||||||
);
|
);
|
||||||
|
|
||||||
ranges::for_each(std::move(filtered), [&](QGraphicsItem *item) {
|
ranges::for_each(std::move(filtered), [&](ItemPtr item) {
|
||||||
item->hide();
|
item->hide();
|
||||||
_itemsToRemove.push_back(item);
|
_itemsToRemove.push_back(item);
|
||||||
});
|
});
|
||||||
|
@ -223,12 +226,12 @@ void Paint::clearRedoList() {
|
||||||
_hasRedo = false;
|
_hasRedo = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Paint::isItemHidden(not_null<QGraphicsItem*> item) const {
|
bool Paint::isItemHidden(const ItemPtr &item) const {
|
||||||
return !item->isVisible() && !isItemToRemove(item);
|
return !item->isVisible() && !isItemToRemove(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Paint::isItemToRemove(not_null<QGraphicsItem*> item) const {
|
bool Paint::isItemToRemove(const ItemPtr &item) const {
|
||||||
return ranges::contains(_itemsToRemove, item.get());
|
return ranges::contains(_itemsToRemove, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Paint::updateUndoState() {
|
void Paint::updateUndoState() {
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct SavedItem {
|
struct SavedItem {
|
||||||
QGraphicsItem *item;
|
std::shared_ptr<QGraphicsItem> item;
|
||||||
bool undid = false;
|
bool undid = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -47,8 +47,8 @@ private:
|
||||||
bool hasRedo() const;
|
bool hasRedo() const;
|
||||||
void clearRedoList();
|
void clearRedoList();
|
||||||
|
|
||||||
bool isItemToRemove(not_null<QGraphicsItem*> item) const;
|
bool isItemToRemove(const std::shared_ptr<QGraphicsItem> &item) const;
|
||||||
bool isItemHidden(not_null<QGraphicsItem*> item) const;
|
bool isItemHidden(const std::shared_ptr<QGraphicsItem> &item) const;
|
||||||
|
|
||||||
const std::shared_ptr<float64> _lastZ;
|
const std::shared_ptr<float64> _lastZ;
|
||||||
const std::shared_ptr<Scene> _scene;
|
const std::shared_ptr<Scene> _scene;
|
||||||
|
@ -56,7 +56,7 @@ private:
|
||||||
const QSize _imageSize;
|
const QSize _imageSize;
|
||||||
|
|
||||||
std::vector<SavedItem> _previousItems;
|
std::vector<SavedItem> _previousItems;
|
||||||
QList<QGraphicsItem*> _itemsToRemove;
|
std::vector<std::shared_ptr<QGraphicsItem>> _itemsToRemove;
|
||||||
|
|
||||||
rpl::variable<bool> _hasUndo = true;
|
rpl::variable<bool> _hasUndo = true;
|
||||||
rpl::variable<bool> _hasRedo = true;
|
rpl::variable<bool> _hasRedo = true;
|
||||||
|
|
|
@ -17,6 +17,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace Editor {
|
namespace Editor {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using ItemPtr = Scene::ItemPtr;
|
||||||
|
|
||||||
bool SkipMouseEvent(not_null<QGraphicsSceneMouseEvent*> event) {
|
bool SkipMouseEvent(not_null<QGraphicsSceneMouseEvent*> event) {
|
||||||
return event->isAccepted() || (event->button() == Qt::RightButton);
|
return event->isAccepted() || (event->button() == Qt::RightButton);
|
||||||
}
|
}
|
||||||
|
@ -25,25 +27,44 @@ bool SkipMouseEvent(not_null<QGraphicsSceneMouseEvent*> event) {
|
||||||
|
|
||||||
Scene::Scene(const QRectF &rect)
|
Scene::Scene(const QRectF &rect)
|
||||||
: QGraphicsScene(rect)
|
: QGraphicsScene(rect)
|
||||||
, _canvas(new ItemCanvas) {
|
, _canvas(std::make_shared<ItemCanvas>()) {
|
||||||
QGraphicsScene::addItem(_canvas);
|
QGraphicsScene::addItem(_canvas.get());
|
||||||
_canvas->clearPixmap();
|
_canvas->clearPixmap();
|
||||||
|
|
||||||
_canvas->grabContentRequests(
|
_canvas->grabContentRequests(
|
||||||
) | rpl::start_with_next([=](ItemCanvas::Content &&content) {
|
) | rpl::start_with_next([=](ItemCanvas::Content &&content) {
|
||||||
const auto item = new ItemLine(std::move(content.pixmap));
|
const auto item = std::make_shared<ItemLine>(
|
||||||
|
std::move(content.pixmap));
|
||||||
item->setPos(content.position);
|
item->setPos(content.position);
|
||||||
addItem(item);
|
addItem(item);
|
||||||
_canvas->setZValue(++_lastLineZ);
|
_canvas->setZValue(++_lastLineZ);
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::addItem(not_null<NumberedItem*> item) {
|
void Scene::addItem(std::shared_ptr<NumberedItem> item) {
|
||||||
|
if (!item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
item->setNumber(_itemNumber++);
|
item->setNumber(_itemNumber++);
|
||||||
QGraphicsScene::addItem(item);
|
QGraphicsScene::addItem(item.get());
|
||||||
|
_items.push_back(std::move(item));
|
||||||
_addsItem.fire({});
|
_addsItem.fire({});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Scene::removeItem(not_null<QGraphicsItem*> item) {
|
||||||
|
const auto it = ranges::find_if(_items, [&](const ItemPtr &i) {
|
||||||
|
return i.get() == item;
|
||||||
|
});
|
||||||
|
if (it == end(_items)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
removeItem(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::removeItem(const ItemPtr &item) {
|
||||||
|
_items.erase(ranges::remove(_items, item), end(_items));
|
||||||
|
}
|
||||||
|
|
||||||
void Scene::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
void Scene::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
||||||
QGraphicsScene::mousePressEvent(event);
|
QGraphicsScene::mousePressEvent(event);
|
||||||
if (SkipMouseEvent(event)) {
|
if (SkipMouseEvent(event)) {
|
||||||
|
@ -81,23 +102,19 @@ rpl::producer<> Scene::addsItem() const {
|
||||||
return _addsItem.events();
|
return _addsItem.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<QGraphicsItem*> Scene::items(Qt::SortOrder order) const {
|
std::vector<ItemPtr> Scene::items(
|
||||||
using Item = QGraphicsItem;
|
Qt::SortOrder order) const {
|
||||||
auto rawItems = QGraphicsScene::items();
|
auto copyItems = _items;
|
||||||
|
|
||||||
auto filteredItems = ranges::views::all(
|
ranges::sort(copyItems, [&](ItemPtr a, ItemPtr b) {
|
||||||
rawItems
|
const auto numA = qgraphicsitem_cast<NumberedItem*>(
|
||||||
) | ranges::views::filter([](Item *i) {
|
a.get())->number();
|
||||||
return i->type() != ItemCanvas::Type;
|
const auto numB = qgraphicsitem_cast<NumberedItem*>(
|
||||||
}) | ranges::to_vector;
|
b.get())->number();
|
||||||
|
|
||||||
ranges::sort(filteredItems, [&](not_null<Item*> a, not_null<Item*> b) {
|
|
||||||
const auto numA = qgraphicsitem_cast<NumberedItem*>(a)->number();
|
|
||||||
const auto numB = qgraphicsitem_cast<NumberedItem*>(b)->number();
|
|
||||||
return (order == Qt::AscendingOrder) ? (numA < numB) : (numA > numB);
|
return (order == Qt::AscendingOrder) ? (numA < numB) : (numA > numB);
|
||||||
});
|
});
|
||||||
|
|
||||||
return filteredItems;
|
return copyItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<MTPInputDocument> Scene::attachedStickers() const {
|
std::vector<MTPInputDocument> Scene::attachedStickers() const {
|
||||||
|
@ -105,14 +122,20 @@ std::vector<MTPInputDocument> Scene::attachedStickers() const {
|
||||||
|
|
||||||
return ranges::views::all(
|
return ranges::views::all(
|
||||||
allItems
|
allItems
|
||||||
) | ranges::views::filter([](QGraphicsItem *i) {
|
) | ranges::views::filter([](const ItemPtr &i) {
|
||||||
return i->isVisible() && (i->type() == ItemSticker::Type);
|
return i->isVisible() && (i->type() == ItemSticker::Type);
|
||||||
}) | ranges::views::transform([](QGraphicsItem *i) {
|
}) | ranges::views::transform([](const ItemPtr &i) {
|
||||||
return qgraphicsitem_cast<ItemSticker*>(i)->sticker();
|
return qgraphicsitem_cast<ItemSticker*>(i.get())->sticker();
|
||||||
}) | ranges::to_vector;
|
}) | ranges::to_vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
Scene::~Scene() {
|
Scene::~Scene() {
|
||||||
|
// Prevent destroying by scene of all items.
|
||||||
|
QGraphicsScene::removeItem(_canvas.get());
|
||||||
|
for (const auto &item : items()) {
|
||||||
|
// Scene loses ownership of an item.
|
||||||
|
QGraphicsScene::removeItem(item.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Editor
|
} // namespace Editor
|
||||||
|
|
|
@ -24,13 +24,17 @@ class NumberedItem;
|
||||||
|
|
||||||
class Scene final : public QGraphicsScene {
|
class Scene final : public QGraphicsScene {
|
||||||
public:
|
public:
|
||||||
|
using ItemPtr = std::shared_ptr<QGraphicsItem>;
|
||||||
|
|
||||||
Scene(const QRectF &rect);
|
Scene(const QRectF &rect);
|
||||||
~Scene();
|
~Scene();
|
||||||
void applyBrush(const QColor &color, float size);
|
void applyBrush(const QColor &color, float size);
|
||||||
|
|
||||||
[[nodiscard]] std::vector<QGraphicsItem*> items(
|
[[nodiscard]] std::vector<ItemPtr> items(
|
||||||
Qt::SortOrder order = Qt::DescendingOrder) const;
|
Qt::SortOrder order = Qt::DescendingOrder) const;
|
||||||
void addItem(not_null<NumberedItem*> item);
|
void addItem(std::shared_ptr<NumberedItem> item);
|
||||||
|
void removeItem(not_null<QGraphicsItem*> item);
|
||||||
|
void removeItem(const ItemPtr &item);
|
||||||
[[nodiscard]] rpl::producer<> addsItem() const;
|
[[nodiscard]] rpl::producer<> addsItem() const;
|
||||||
[[nodiscard]] rpl::producer<> mousePresses() const;
|
[[nodiscard]] rpl::producer<> mousePresses() const;
|
||||||
|
|
||||||
|
@ -40,7 +44,9 @@ protected:
|
||||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
|
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
|
||||||
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
|
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
|
||||||
private:
|
private:
|
||||||
const not_null<ItemCanvas*> _canvas;
|
const std::shared_ptr<ItemCanvas> _canvas;
|
||||||
|
|
||||||
|
std::vector<ItemPtr> _items;
|
||||||
|
|
||||||
float64 _lastLineZ = 0.;
|
float64 _lastLineZ = 0.;
|
||||||
int _itemNumber = 0;
|
int _itemNumber = 0;
|
||||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "editor/scene_item_base.h"
|
#include "editor/scene_item_base.h"
|
||||||
|
|
||||||
|
#include "editor/scene.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "ui/widgets/popup_menu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
#include "styles/style_editor.h"
|
#include "styles/style_editor.h"
|
||||||
|
@ -179,9 +180,8 @@ void ItemBase::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
|
||||||
|
|
||||||
_menu = base::make_unique_q<Ui::PopupMenu>(nullptr);
|
_menu = base::make_unique_q<Ui::PopupMenu>(nullptr);
|
||||||
_menu->addAction(tr::lng_selected_delete(tr::now), [=] {
|
_menu->addAction(tr::lng_selected_delete(tr::now), [=] {
|
||||||
if (scene()) {
|
if (const auto s = static_cast<Scene*>(scene())) {
|
||||||
scene()->removeItem(this); // Scene loses ownership of item.
|
s->removeItem(this);
|
||||||
delete this;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue