scene.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "editor/scene/scene.h"
  8. #include "editor/scene/scene_item_canvas.h"
  9. #include "editor/scene/scene_item_line.h"
  10. #include "editor/scene/scene_item_sticker.h"
  11. #include "ui/rp_widget.h"
  12. #include <QGraphicsSceneMouseEvent>
  13. namespace Editor {
  14. namespace {
  15. using ItemPtr = std::shared_ptr<NumberedItem>;
  16. bool SkipMouseEvent(not_null<QGraphicsSceneMouseEvent*> event) {
  17. return event->isAccepted() || (event->button() == Qt::RightButton);
  18. }
  19. } // namespace
  20. Scene::Scene(const QRectF &rect)
  21. : QGraphicsScene(rect)
  22. , _canvas(std::make_shared<ItemCanvas>())
  23. , _lastZ(std::make_shared<float64>(9000.)) {
  24. QGraphicsScene::addItem(_canvas.get());
  25. _canvas->clearPixmap();
  26. _canvas->grabContentRequests(
  27. ) | rpl::start_with_next([=](ItemCanvas::Content &&content) {
  28. const auto item = std::make_shared<ItemLine>(
  29. std::move(content.pixmap));
  30. item->setPos(content.position);
  31. addItem(item);
  32. _canvas->setZValue(++_lastLineZ);
  33. }, _lifetime);
  34. }
  35. void Scene::cancelDrawing() {
  36. _canvas->cancelDrawing();
  37. }
  38. void Scene::addItem(ItemPtr item) {
  39. if (!item) {
  40. return;
  41. }
  42. item->setNumber(_itemNumber++);
  43. QGraphicsScene::addItem(item.get());
  44. _items.push_back(std::move(item));
  45. _addsItem.fire({});
  46. }
  47. void Scene::removeItem(not_null<QGraphicsItem*> item) {
  48. const auto it = ranges::find_if(_items, [&](const ItemPtr &i) {
  49. return i.get() == item;
  50. });
  51. if (it == end(_items)) {
  52. return;
  53. }
  54. removeItem(*it);
  55. }
  56. void Scene::removeItem(const ItemPtr &item) {
  57. item->setStatus(NumberedItem::Status::Removed);
  58. _removesItem.fire({});
  59. }
  60. void Scene::mousePressEvent(QGraphicsSceneMouseEvent *event) {
  61. QGraphicsScene::mousePressEvent(event);
  62. if (SkipMouseEvent(event)) {
  63. return;
  64. }
  65. _canvas->handleMousePressEvent(event);
  66. }
  67. void Scene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
  68. QGraphicsScene::mouseReleaseEvent(event);
  69. if (SkipMouseEvent(event)) {
  70. return;
  71. }
  72. _canvas->handleMouseReleaseEvent(event);
  73. }
  74. void Scene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
  75. QGraphicsScene::mouseMoveEvent(event);
  76. if (SkipMouseEvent(event)) {
  77. return;
  78. }
  79. _canvas->handleMouseMoveEvent(event);
  80. }
  81. void Scene::applyBrush(const QColor &color, float size) {
  82. _canvas->applyBrush(color, size);
  83. }
  84. rpl::producer<> Scene::addsItem() const {
  85. return _addsItem.events();
  86. }
  87. rpl::producer<> Scene::removesItem() const {
  88. return _removesItem.events();
  89. }
  90. std::vector<ItemPtr> Scene::items(
  91. Qt::SortOrder order) const {
  92. auto copyItems = _items;
  93. ranges::sort(copyItems, [&](ItemPtr a, ItemPtr b) {
  94. const auto numA = a->number();
  95. const auto numB = b->number();
  96. return (order == Qt::AscendingOrder) ? (numA < numB) : (numA > numB);
  97. });
  98. return copyItems;
  99. }
  100. std::shared_ptr<float64> Scene::lastZ() const {
  101. return _lastZ;
  102. }
  103. void Scene::updateZoom(float64 zoom) {
  104. for (const auto &item : items()) {
  105. if (item->type() >= ItemBase::Type) {
  106. static_cast<ItemBase*>(item.get())->updateZoom(zoom);
  107. }
  108. }
  109. }
  110. bool Scene::hasUndo() const {
  111. return ranges::any_of(_items, &NumberedItem::isNormalStatus);
  112. }
  113. bool Scene::hasRedo() const {
  114. return ranges::any_of(_items, &NumberedItem::isUndidStatus);
  115. }
  116. void Scene::performUndo() {
  117. const auto filtered = items(Qt::DescendingOrder);
  118. const auto it = ranges::find_if(filtered, &NumberedItem::isNormalStatus);
  119. if (it != filtered.end()) {
  120. (*it)->setStatus(NumberedItem::Status::Undid);
  121. }
  122. }
  123. void Scene::performRedo() {
  124. const auto filtered = items(Qt::AscendingOrder);
  125. const auto it = ranges::find_if(filtered, &NumberedItem::isUndidStatus);
  126. if (it != filtered.end()) {
  127. (*it)->setStatus(NumberedItem::Status::Normal);
  128. }
  129. }
  130. void Scene::removeIf(Fn<bool(const ItemPtr &)> proj) {
  131. auto copy = std::vector<ItemPtr>();
  132. for (const auto &item : _items) {
  133. const auto toRemove = proj(item);
  134. if (toRemove) {
  135. // Scene loses ownership of an item.
  136. // It seems for some reason this line causes a crash. =(
  137. // QGraphicsScene::removeItem(item.get());
  138. } else {
  139. copy.push_back(item);
  140. }
  141. }
  142. _items = std::move(copy);
  143. }
  144. void Scene::clearRedoList() {
  145. for (const auto &item : _items) {
  146. if (item->isUndidStatus()) {
  147. item->setStatus(NumberedItem::Status::Removed);
  148. }
  149. }
  150. }
  151. void Scene::save(SaveState state) {
  152. removeIf([](const ItemPtr &item) {
  153. return item->isRemovedStatus()
  154. && !item->hasState(SaveState::Keep)
  155. && !item->hasState(SaveState::Save);
  156. });
  157. for (const auto &item : _items) {
  158. item->save(state);
  159. }
  160. clearSelection();
  161. cancelDrawing();
  162. }
  163. void Scene::restore(SaveState state) {
  164. removeIf([=](const ItemPtr &item) {
  165. return !item->hasState(state);
  166. });
  167. for (const auto &item : _items) {
  168. item->restore(state);
  169. }
  170. clearSelection();
  171. cancelDrawing();
  172. }
  173. Scene::~Scene() {
  174. // Prevent destroying by scene of all items.
  175. QGraphicsScene::removeItem(_canvas.get());
  176. for (const auto &item : items()) {
  177. // Scene loses ownership of an item.
  178. QGraphicsScene::removeItem(item.get());
  179. }
  180. }
  181. } // namespace Editor