photo_editor_content.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  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/photo_editor_content.h"
  8. #include "editor/editor_crop.h"
  9. #include "editor/editor_paint.h"
  10. #include "history/history_drag_area.h"
  11. #include "media/view/media_view_pip.h"
  12. #include "storage/storage_media_prepare.h"
  13. namespace Editor {
  14. using Media::View::FlipSizeByRotation;
  15. using Media::View::RotatedRect;
  16. PhotoEditorContent::PhotoEditorContent(
  17. not_null<Ui::RpWidget*> parent,
  18. std::shared_ptr<Image> photo,
  19. PhotoModifications modifications,
  20. std::shared_ptr<Controllers> controllers,
  21. EditorData data)
  22. : RpWidget(parent)
  23. , _photoSize(photo->size())
  24. , _paint(base::make_unique_q<Paint>(
  25. this,
  26. modifications,
  27. _photoSize,
  28. std::move(controllers)))
  29. , _crop(base::make_unique_q<Crop>(
  30. this,
  31. modifications,
  32. _photoSize,
  33. std::move(data)))
  34. , _photo(std::move(photo))
  35. , _modifications(modifications) {
  36. rpl::combine(
  37. _modifications.value(),
  38. sizeValue()
  39. ) | rpl::start_with_next([=](
  40. const PhotoModifications &mods, const QSize &size) {
  41. if (size.isEmpty()) {
  42. return;
  43. }
  44. const auto imageSizeF = [&] {
  45. const auto rotatedSize
  46. = FlipSizeByRotation(size, mods.angle);
  47. const auto m = _crop->cropMargins();
  48. const auto sizeForCrop = rotatedSize
  49. - QSize(m.left() + m.right(), m.top() + m.bottom());
  50. const auto originalSize = QSizeF(_photoSize);
  51. if ((originalSize.width() > sizeForCrop.width())
  52. || (originalSize.height() > sizeForCrop.height())) {
  53. return originalSize.scaled(
  54. sizeForCrop,
  55. Qt::KeepAspectRatio);
  56. }
  57. return originalSize;
  58. }();
  59. const auto imageSize = QSize(imageSizeF.width(), imageSizeF.height());
  60. _imageRect = QRect(
  61. QPoint(-imageSize.width() / 2, -imageSize.height() / 2),
  62. imageSize);
  63. _imageMatrix.reset();
  64. _imageMatrix.translate(size.width() / 2, size.height() / 2);
  65. if (mods.flipped) {
  66. _imageMatrix.scale(-1, 1);
  67. }
  68. _imageMatrix.rotate(mods.angle);
  69. const auto geometry = _imageMatrix.mapRect(_imageRect);
  70. _crop->applyTransform(
  71. geometry + _crop->cropMargins(),
  72. mods.angle,
  73. mods.flipped, imageSizeF);
  74. _paint->applyTransform(geometry, mods.angle, mods.flipped);
  75. _innerRect = geometry;
  76. }, lifetime());
  77. paintRequest(
  78. ) | rpl::start_with_next([=](const QRect &clip) {
  79. auto p = QPainter(this);
  80. p.fillRect(clip, Qt::transparent);
  81. p.setTransform(_imageMatrix);
  82. p.drawPixmap(_imageRect, _photo->pix(_imageRect.size()));
  83. }, lifetime());
  84. setupDragArea();
  85. }
  86. void PhotoEditorContent::applyModifications(
  87. PhotoModifications modifications) {
  88. _modifications = std::move(modifications);
  89. update();
  90. }
  91. void PhotoEditorContent::save(PhotoModifications &modifications) {
  92. modifications.crop = _crop->saveCropRect();
  93. _paint->keepResult();
  94. const auto savedScene = _paint->saveScene();
  95. if (!modifications.paint) {
  96. modifications.paint = savedScene;
  97. }
  98. }
  99. void PhotoEditorContent::applyMode(const PhotoEditorMode &mode) {
  100. if (mode.mode == PhotoEditorMode::Mode::Out) {
  101. if (mode.action == PhotoEditorMode::Action::Discard) {
  102. _paint->restoreScene();
  103. }
  104. return;
  105. }
  106. const auto isTransform = (mode.mode == PhotoEditorMode::Mode::Transform);
  107. _crop->setVisible(isTransform);
  108. _paint->setAttribute(Qt::WA_TransparentForMouseEvents, isTransform);
  109. if (!isTransform) {
  110. _paint->updateUndoState();
  111. }
  112. if (mode.action == PhotoEditorMode::Action::Discard) {
  113. _paint->cancel();
  114. } else if (mode.action == PhotoEditorMode::Action::Save) {
  115. _paint->keepResult();
  116. }
  117. _mode = mode;
  118. }
  119. void PhotoEditorContent::applyBrush(const Brush &brush) {
  120. _paint->applyBrush(brush);
  121. }
  122. bool PhotoEditorContent::handleKeyPress(not_null<QKeyEvent*> e) const {
  123. return false;
  124. }
  125. void PhotoEditorContent::setupDragArea() {
  126. auto dragEnterFilter = [=](const QMimeData *data) {
  127. return (_mode.mode == PhotoEditorMode::Mode::Paint)
  128. ? Storage::ValidatePhotoEditorMediaDragData(data)
  129. : false;
  130. };
  131. const auto areas = DragArea::SetupDragAreaToContainer(
  132. this,
  133. std::move(dragEnterFilter),
  134. nullptr,
  135. nullptr,
  136. [](const QMimeData *d) { return Storage::MimeDataState::Image; },
  137. true);
  138. areas.photo->setDroppedCallback([=](const QMimeData *data) {
  139. _paint->handleMimeData(data);
  140. });
  141. }
  142. } // namespace Editor