2020-10-13 15:11:53 +00:00
|
|
|
/*
|
|
|
|
This file is part of Telegram Desktop,
|
|
|
|
the official desktop application for the Telegram messaging service.
|
|
|
|
|
|
|
|
For license and copyright information please follow this link:
|
|
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
|
|
*/
|
|
|
|
#include "ui/chat/attach/attach_album_preview.h"
|
|
|
|
|
|
|
|
#include "ui/chat/attach/attach_album_thumbnail.h"
|
|
|
|
#include "ui/chat/attach/attach_prepare.h"
|
|
|
|
#include "styles/style_chat.h"
|
|
|
|
#include "styles/style_boxes.h"
|
|
|
|
#include "styles/style_layers.h"
|
|
|
|
|
2021-04-25 22:50:16 +00:00
|
|
|
#include <QtWidgets/QApplication>
|
|
|
|
|
2020-10-13 15:11:53 +00:00
|
|
|
namespace Ui {
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
constexpr auto kDragDuration = crl::time(200);
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
AlbumPreview::AlbumPreview(
|
|
|
|
QWidget *parent,
|
2020-10-16 10:38:12 +00:00
|
|
|
gsl::span<Ui::PreparedFile> items,
|
2020-10-13 15:11:53 +00:00
|
|
|
SendFilesWay way)
|
|
|
|
: RpWidget(parent)
|
2021-04-25 22:50:16 +00:00
|
|
|
, _sendWay(way)
|
|
|
|
, _dragTimer([=] { switchToDrag(); }) {
|
2020-10-13 15:11:53 +00:00
|
|
|
setMouseTracking(true);
|
2020-10-16 10:38:12 +00:00
|
|
|
prepareThumbs(items);
|
2020-10-13 15:11:53 +00:00
|
|
|
updateSize();
|
|
|
|
updateFileRows();
|
|
|
|
}
|
|
|
|
|
|
|
|
AlbumPreview::~AlbumPreview() = default;
|
|
|
|
|
|
|
|
void AlbumPreview::setSendWay(SendFilesWay way) {
|
|
|
|
if (_sendWay != way) {
|
|
|
|
cancelDrag();
|
|
|
|
_sendWay = way;
|
|
|
|
}
|
|
|
|
updateSize();
|
|
|
|
updateFileRows();
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumPreview::updateFileRows() {
|
|
|
|
Expects(_order.size() == _thumbs.size());
|
2020-10-15 14:27:16 +00:00
|
|
|
|
|
|
|
const auto isFile = !_sendWay.sendImagesAsPhotos();
|
2020-10-13 15:11:53 +00:00
|
|
|
for (auto i = 0; i < _order.size(); i++) {
|
|
|
|
_thumbs[i]->updateFileRow(isFile ? _order[i] : -1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<int> AlbumPreview::takeOrder() {
|
2020-10-17 17:09:06 +00:00
|
|
|
//Expects(_thumbs.size() == _order.size());
|
|
|
|
//Expects(_itemsShownDimensions.size() == _order.size());
|
2020-10-16 10:38:12 +00:00
|
|
|
|
2020-10-13 15:11:53 +00:00
|
|
|
auto reordered = std::vector<std::unique_ptr<AlbumThumbnail>>();
|
2020-10-16 10:38:12 +00:00
|
|
|
auto reorderedShownDimensions = std::vector<QSize>();
|
2020-10-13 15:11:53 +00:00
|
|
|
reordered.reserve(_thumbs.size());
|
2020-10-16 10:38:12 +00:00
|
|
|
reorderedShownDimensions.reserve(_itemsShownDimensions.size());
|
2020-10-13 15:11:53 +00:00
|
|
|
for (auto index : _order) {
|
|
|
|
reordered.push_back(std::move(_thumbs[index]));
|
2020-10-16 10:38:12 +00:00
|
|
|
reorderedShownDimensions.push_back(_itemsShownDimensions[index]);
|
2020-10-13 15:11:53 +00:00
|
|
|
}
|
|
|
|
_thumbs = std::move(reordered);
|
2020-10-16 10:38:12 +00:00
|
|
|
_itemsShownDimensions = std::move(reorderedShownDimensions);
|
2020-10-13 15:11:53 +00:00
|
|
|
return std::exchange(_order, defaultOrder());
|
|
|
|
}
|
|
|
|
|
|
|
|
auto AlbumPreview::generateOrderedLayout() const
|
|
|
|
-> std::vector<GroupMediaLayout> {
|
|
|
|
auto layout = LayoutMediaGroup(
|
2020-10-16 10:38:12 +00:00
|
|
|
_itemsShownDimensions,
|
2020-10-13 15:11:53 +00:00
|
|
|
st::sendMediaPreviewSize,
|
|
|
|
st::historyGroupWidthMin / 2,
|
|
|
|
st::historyGroupSkip / 2);
|
|
|
|
Assert(layout.size() == _order.size());
|
|
|
|
return layout;
|
|
|
|
}
|
|
|
|
|
2020-10-16 10:38:12 +00:00
|
|
|
std::vector<int> AlbumPreview::defaultOrder(int count) const {
|
|
|
|
if (count < 0) {
|
|
|
|
count = _order.size();
|
|
|
|
}
|
2021-03-13 12:12:08 +00:00
|
|
|
return ranges::views::ints(0, count) | ranges::to_vector;
|
2020-10-13 15:11:53 +00:00
|
|
|
}
|
|
|
|
|
2020-10-16 10:38:12 +00:00
|
|
|
void AlbumPreview::prepareThumbs(gsl::span<Ui::PreparedFile> items) {
|
|
|
|
_order = defaultOrder(items.size());
|
2021-03-13 12:12:08 +00:00
|
|
|
_itemsShownDimensions = ranges::views::all(
|
2020-10-16 10:38:12 +00:00
|
|
|
_order
|
2021-03-13 12:12:08 +00:00
|
|
|
) | ranges::views::transform([&](int index) {
|
2020-10-16 10:38:12 +00:00
|
|
|
return items[index].shownDimensions;
|
|
|
|
}) | ranges::to_vector;
|
2020-10-13 15:11:53 +00:00
|
|
|
|
2020-10-16 10:38:12 +00:00
|
|
|
const auto count = int(_order.size());
|
2020-10-13 15:11:53 +00:00
|
|
|
const auto layout = generateOrderedLayout();
|
|
|
|
_thumbs.reserve(count);
|
|
|
|
for (auto i = 0; i != count; ++i) {
|
|
|
|
_thumbs.push_back(std::make_unique<AlbumThumbnail>(
|
2020-10-16 10:38:12 +00:00
|
|
|
items[i],
|
2020-10-13 15:11:53 +00:00
|
|
|
layout[i],
|
|
|
|
this,
|
|
|
|
[=] { changeThumbByIndex(thumbIndex(thumbUnderCursor())); },
|
|
|
|
[=] { deleteThumbByIndex(thumbIndex(thumbUnderCursor())); }));
|
|
|
|
}
|
|
|
|
_thumbsHeight = countLayoutHeight(layout);
|
2021-03-13 12:12:08 +00:00
|
|
|
_photosHeight = ranges::accumulate(ranges::views::all(
|
2020-10-13 15:11:53 +00:00
|
|
|
_thumbs
|
2021-03-13 12:12:08 +00:00
|
|
|
) | ranges::views::transform([](const auto &thumb) {
|
2020-10-13 15:11:53 +00:00
|
|
|
return thumb->photoHeight();
|
2020-10-19 15:37:59 +00:00
|
|
|
}), 0) + (count - 1) * st::sendMediaRowSkip;
|
2020-10-13 15:11:53 +00:00
|
|
|
|
2020-10-19 15:37:59 +00:00
|
|
|
const auto &st = st::attachPreviewThumbLayout;
|
|
|
|
_filesHeight = count * st.thumbSize
|
|
|
|
+ (count - 1) * st::sendMediaRowSkip;
|
2020-10-13 15:11:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int AlbumPreview::contentLeft() const {
|
|
|
|
return (st::boxWideWidth - st::sendMediaPreviewSize) / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
int AlbumPreview::contentTop() const {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
AlbumThumbnail *AlbumPreview::findThumb(QPoint position) const {
|
|
|
|
position -= QPoint(contentLeft(), contentTop());
|
|
|
|
|
|
|
|
auto top = 0;
|
2020-10-15 14:27:16 +00:00
|
|
|
const auto isPhotosWay = _sendWay.sendImagesAsPhotos();
|
2020-10-19 15:37:59 +00:00
|
|
|
const auto skip = st::sendMediaRowSkip;
|
2020-10-13 15:11:53 +00:00
|
|
|
auto find = [&](const auto &thumb) {
|
2020-10-17 09:51:55 +00:00
|
|
|
if (_sendWay.groupFiles() && _sendWay.sendImagesAsPhotos()) {
|
2020-10-13 15:11:53 +00:00
|
|
|
return thumb->containsPoint(position);
|
2020-10-15 14:27:16 +00:00
|
|
|
} else {
|
2020-10-13 15:11:53 +00:00
|
|
|
const auto bottom = top + (isPhotosWay
|
|
|
|
? thumb->photoHeight()
|
2020-10-19 15:37:59 +00:00
|
|
|
: st::attachPreviewThumbLayout.thumbSize);
|
2020-10-13 15:11:53 +00:00
|
|
|
const auto isUnderTop = (position.y() > top);
|
|
|
|
top = bottom + skip;
|
|
|
|
return isUnderTop && (position.y() < bottom);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
|
|
|
const auto i = ranges::find_if(_thumbs, std::move(find));
|
|
|
|
return (i == _thumbs.end()) ? nullptr : i->get();
|
|
|
|
}
|
|
|
|
|
|
|
|
not_null<AlbumThumbnail*> AlbumPreview::findClosestThumb(
|
|
|
|
QPoint position) const {
|
|
|
|
Expects(_draggedThumb != nullptr);
|
|
|
|
|
|
|
|
if (const auto exact = findThumb(position)) {
|
|
|
|
return exact;
|
|
|
|
}
|
|
|
|
auto result = _draggedThumb;
|
|
|
|
auto distance = _draggedThumb->distanceTo(position);
|
|
|
|
for (const auto &thumb : _thumbs) {
|
|
|
|
const auto check = thumb->distanceTo(position);
|
|
|
|
if (check < distance) {
|
|
|
|
distance = check;
|
|
|
|
result = thumb.get();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int AlbumPreview::orderIndex(
|
|
|
|
not_null<AlbumThumbnail*> thumb) const {
|
|
|
|
const auto i = ranges::find_if(_order, [&](int index) {
|
|
|
|
return (_thumbs[index].get() == thumb);
|
|
|
|
});
|
|
|
|
Assert(i != _order.end());
|
|
|
|
return int(i - _order.begin());
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumPreview::cancelDrag() {
|
|
|
|
_thumbsHeightAnimation.stop();
|
|
|
|
_finishDragAnimation.stop();
|
|
|
|
_shrinkAnimation.stop();
|
|
|
|
if (_draggedThumb) {
|
|
|
|
_draggedThumb->moveInAlbum({ 0, 0 });
|
|
|
|
_draggedThumb = nullptr;
|
|
|
|
}
|
|
|
|
if (_suggestedThumb) {
|
|
|
|
const auto suggestedIndex = orderIndex(_suggestedThumb);
|
|
|
|
if (suggestedIndex > 0) {
|
|
|
|
_thumbs[_order[suggestedIndex - 1]]->suggestMove(0., [] {});
|
|
|
|
}
|
|
|
|
if (suggestedIndex < int(_order.size() - 1)) {
|
|
|
|
_thumbs[_order[suggestedIndex + 1]]->suggestMove(0., [] {});
|
|
|
|
}
|
|
|
|
_suggestedThumb->suggestMove(0., [] {});
|
|
|
|
_suggestedThumb->finishAnimations();
|
|
|
|
_suggestedThumb = nullptr;
|
|
|
|
}
|
|
|
|
_paintedAbove = nullptr;
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumPreview::finishDrag() {
|
|
|
|
Expects(_draggedThumb != nullptr);
|
|
|
|
Expects(_suggestedThumb != nullptr);
|
|
|
|
|
|
|
|
if (_suggestedThumb != _draggedThumb) {
|
|
|
|
const auto currentIndex = orderIndex(_draggedThumb);
|
|
|
|
const auto newIndex = orderIndex(_suggestedThumb);
|
|
|
|
const auto delta = (currentIndex < newIndex) ? 1 : -1;
|
|
|
|
const auto realIndex = _order[currentIndex];
|
|
|
|
for (auto i = currentIndex; i != newIndex; i += delta) {
|
|
|
|
_order[i] = _order[i + delta];
|
|
|
|
}
|
|
|
|
_order[newIndex] = realIndex;
|
|
|
|
const auto layout = generateOrderedLayout();
|
|
|
|
for (auto i = 0, count = int(_order.size()); i != count; ++i) {
|
|
|
|
_thumbs[_order[i]]->moveToLayout(layout[i]);
|
|
|
|
}
|
|
|
|
_finishDragAnimation.start([=] { update(); }, 0., 1., kDragDuration);
|
|
|
|
|
|
|
|
updateSizeAnimated(layout);
|
|
|
|
} else {
|
|
|
|
for (const auto &thumb : _thumbs) {
|
|
|
|
thumb->resetLayoutAnimation();
|
|
|
|
}
|
|
|
|
_draggedThumb->animateLayoutToInitial();
|
|
|
|
_finishDragAnimation.start([=] { update(); }, 0., 1., kDragDuration);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int AlbumPreview::countLayoutHeight(
|
|
|
|
const std::vector<GroupMediaLayout> &layout) const {
|
|
|
|
const auto accumulator = [](int current, const auto &item) {
|
|
|
|
return std::max(current, item.geometry.y() + item.geometry.height());
|
|
|
|
};
|
|
|
|
return ranges::accumulate(layout, 0, accumulator);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumPreview::updateSizeAnimated(
|
|
|
|
const std::vector<GroupMediaLayout> &layout) {
|
|
|
|
const auto newHeight = countLayoutHeight(layout);
|
|
|
|
if (newHeight != _thumbsHeight) {
|
|
|
|
_thumbsHeightAnimation.start(
|
|
|
|
[=] { updateSize(); },
|
|
|
|
_thumbsHeight,
|
|
|
|
newHeight,
|
|
|
|
kDragDuration);
|
|
|
|
_thumbsHeight = newHeight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumPreview::updateSize() {
|
|
|
|
const auto newHeight = [&] {
|
2020-10-17 09:51:55 +00:00
|
|
|
if (!_sendWay.sendImagesAsPhotos()) {
|
|
|
|
return _filesHeight;
|
|
|
|
} else if (!_sendWay.groupFiles()) {
|
2020-10-15 14:27:16 +00:00
|
|
|
return _photosHeight;
|
|
|
|
} else {
|
2021-09-27 08:13:57 +00:00
|
|
|
return int(base::SafeRound(_thumbsHeightAnimation.value(
|
2020-10-17 09:51:55 +00:00
|
|
|
_thumbsHeight)));
|
2020-10-13 15:11:53 +00:00
|
|
|
}
|
|
|
|
}();
|
|
|
|
if (height() != newHeight) {
|
|
|
|
resize(st::boxWideWidth, newHeight);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumPreview::paintEvent(QPaintEvent *e) {
|
|
|
|
Painter p(this);
|
|
|
|
|
2020-10-17 09:51:55 +00:00
|
|
|
if (!_sendWay.sendImagesAsPhotos()) {
|
|
|
|
paintFiles(p, e->rect());
|
|
|
|
} else if (!_sendWay.groupFiles()) {
|
2020-10-15 14:27:16 +00:00
|
|
|
paintPhotos(p, e->rect());
|
|
|
|
} else {
|
2020-10-17 09:51:55 +00:00
|
|
|
paintAlbum(p);
|
2020-10-13 15:11:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumPreview::paintAlbum(Painter &p) const {
|
|
|
|
const auto shrink = _shrinkAnimation.value(_draggedThumb ? 1. : 0.);
|
|
|
|
const auto moveProgress = _finishDragAnimation.value(1.);
|
|
|
|
const auto left = contentLeft();
|
|
|
|
const auto top = contentTop();
|
|
|
|
for (const auto &thumb : _thumbs) {
|
|
|
|
if (thumb.get() != _paintedAbove) {
|
|
|
|
thumb->paintInAlbum(p, left, top, shrink, moveProgress);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (_paintedAbove) {
|
|
|
|
_paintedAbove->paintInAlbum(p, left, top, shrink, moveProgress);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumPreview::paintPhotos(Painter &p, QRect clip) const {
|
|
|
|
const auto left = (st::boxWideWidth - st::sendMediaPreviewSize) / 2;
|
|
|
|
auto top = 0;
|
|
|
|
const auto outerWidth = width();
|
|
|
|
for (const auto &thumb : _thumbs) {
|
|
|
|
const auto bottom = top + thumb->photoHeight();
|
|
|
|
const auto guard = gsl::finally([&] {
|
2020-10-19 15:37:59 +00:00
|
|
|
top = bottom + st::sendMediaRowSkip;
|
2020-10-13 15:11:53 +00:00
|
|
|
});
|
|
|
|
if (top >= clip.y() + clip.height()) {
|
|
|
|
break;
|
|
|
|
} else if (bottom <= clip.y()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
thumb->paintPhoto(p, left, top, outerWidth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumPreview::paintFiles(Painter &p, QRect clip) const {
|
2020-10-19 15:37:59 +00:00
|
|
|
const auto fileHeight = st::attachPreviewThumbLayout.thumbSize
|
|
|
|
+ st::sendMediaRowSkip;
|
2020-10-13 15:11:53 +00:00
|
|
|
const auto bottom = clip.y() + clip.height();
|
|
|
|
const auto from = std::clamp(clip.y() / fileHeight, 0, int(_thumbs.size()));
|
|
|
|
const auto till = std::clamp((bottom + fileHeight - 1) / fileHeight, 0, int(_thumbs.size()));
|
|
|
|
const auto left = (st::boxWideWidth - st::sendMediaPreviewSize) / 2;
|
|
|
|
const auto outerWidth = width();
|
|
|
|
|
|
|
|
auto top = from * fileHeight;
|
|
|
|
for (auto i = from; i != till; ++i) {
|
|
|
|
_thumbs[i]->paintFile(p, left, top, outerWidth);
|
|
|
|
top += fileHeight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int AlbumPreview::thumbIndex(AlbumThumbnail *thumb) {
|
|
|
|
if (!thumb) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
const auto thumbIt = ranges::find_if(_thumbs, [&](auto &t) {
|
|
|
|
return t.get() == thumb;
|
|
|
|
});
|
|
|
|
Expects(thumbIt != _thumbs.end());
|
|
|
|
return std::distance(_thumbs.begin(), thumbIt);
|
|
|
|
}
|
|
|
|
|
|
|
|
AlbumThumbnail *AlbumPreview::thumbUnderCursor() {
|
|
|
|
return findThumb(mapFromGlobal(QCursor::pos()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumPreview::deleteThumbByIndex(int index) {
|
|
|
|
if (index < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const auto orderIt = ranges::find(_order, index);
|
|
|
|
Expects(orderIt != _order.end());
|
|
|
|
|
|
|
|
_order.erase(orderIt);
|
|
|
|
ranges::for_each(_order, [=](auto &i) {
|
|
|
|
if (i > index) {
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
_thumbDeleted.fire(std::move(index));
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumPreview::changeThumbByIndex(int index) {
|
|
|
|
if (index < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_thumbChanged.fire(std::move(index));
|
|
|
|
}
|
|
|
|
|
2021-04-25 22:50:16 +00:00
|
|
|
void AlbumPreview::modifyThumbByIndex(int index) {
|
|
|
|
if (index < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_thumbModified.fire(std::move(index));
|
|
|
|
}
|
|
|
|
|
2020-10-13 15:11:53 +00:00
|
|
|
void AlbumPreview::thumbButtonsCallback(
|
|
|
|
not_null<AlbumThumbnail*> thumb,
|
|
|
|
AttachButtonType type) {
|
|
|
|
const auto index = thumbIndex(thumb);
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case AttachButtonType::None: return;
|
|
|
|
case AttachButtonType::Edit: changeThumbByIndex(index); break;
|
|
|
|
case AttachButtonType::Delete: deleteThumbByIndex(index); break;
|
2021-04-25 22:50:16 +00:00
|
|
|
case AttachButtonType::Modify:
|
|
|
|
cancelDrag();
|
|
|
|
modifyThumbByIndex(index);
|
|
|
|
break;
|
2020-10-13 15:11:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumPreview::mousePressEvent(QMouseEvent *e) {
|
|
|
|
if (_finishDragAnimation.animating()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const auto position = e->pos();
|
|
|
|
cancelDrag();
|
|
|
|
if (const auto thumb = findThumb(position)) {
|
2021-04-25 22:50:16 +00:00
|
|
|
_draggedStartPosition = position;
|
|
|
|
_pressedThumb = thumb;
|
|
|
|
_pressedButtonType = thumb->buttonTypeFromPoint(position);
|
|
|
|
|
|
|
|
const auto isAlbum = _sendWay.sendImagesAsPhotos()
|
|
|
|
&& _sendWay.groupFiles();
|
|
|
|
if (!isAlbum) {
|
2020-10-13 15:11:53 +00:00
|
|
|
return;
|
|
|
|
}
|
2021-04-25 22:50:16 +00:00
|
|
|
|
|
|
|
if (_pressedButtonType == AttachButtonType::None) {
|
|
|
|
switchToDrag();
|
|
|
|
} else if (_pressedButtonType == AttachButtonType::Modify) {
|
|
|
|
_dragTimer.callOnce(QApplication::startDragTime());
|
|
|
|
}
|
2020-10-13 15:11:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumPreview::mouseMoveEvent(QMouseEvent *e) {
|
2020-10-15 14:27:16 +00:00
|
|
|
if (!_sendWay.sendImagesAsPhotos()) {
|
2020-10-13 15:11:53 +00:00
|
|
|
applyCursor(style::cur_default);
|
|
|
|
return;
|
|
|
|
}
|
2021-04-25 22:50:16 +00:00
|
|
|
if (_dragTimer.isActive()) {
|
|
|
|
_dragTimer.cancel();
|
|
|
|
switchToDrag();
|
|
|
|
}
|
2020-10-17 09:51:55 +00:00
|
|
|
const auto isAlbum = _sendWay.sendImagesAsPhotos()
|
|
|
|
&& _sendWay.groupFiles();
|
2020-10-13 15:11:53 +00:00
|
|
|
if (isAlbum && _draggedThumb) {
|
|
|
|
const auto position = e->pos();
|
|
|
|
_draggedThumb->moveInAlbum(position - _draggedStartPosition);
|
|
|
|
updateSuggestedDrag(_draggedThumb->center());
|
|
|
|
update();
|
|
|
|
} else {
|
|
|
|
const auto thumb = findThumb(e->pos());
|
|
|
|
const auto regularCursor = isAlbum
|
2021-04-25 22:50:16 +00:00
|
|
|
? style::cur_pointer
|
2020-10-13 15:11:53 +00:00
|
|
|
: style::cur_default;
|
|
|
|
const auto cursor = thumb
|
|
|
|
? (thumb->buttonsContainPoint(e->pos())
|
|
|
|
? style::cur_pointer
|
|
|
|
: regularCursor)
|
|
|
|
: style::cur_default;
|
|
|
|
applyCursor(cursor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumPreview::applyCursor(style::cursor cursor) {
|
|
|
|
if (_cursor != cursor) {
|
|
|
|
_cursor = cursor;
|
|
|
|
setCursor(_cursor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumPreview::updateSuggestedDrag(QPoint position) {
|
|
|
|
auto closest = findClosestThumb(position);
|
|
|
|
auto closestIndex = orderIndex(closest);
|
|
|
|
|
|
|
|
const auto draggedIndex = orderIndex(_draggedThumb);
|
|
|
|
const auto closestIsBeforePoint = closest->isPointAfter(position);
|
|
|
|
if (closestIndex < draggedIndex && closestIsBeforePoint) {
|
|
|
|
closest = _thumbs[_order[++closestIndex]].get();
|
|
|
|
} else if (closestIndex > draggedIndex && !closestIsBeforePoint) {
|
|
|
|
closest = _thumbs[_order[--closestIndex]].get();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_suggestedThumb == closest) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto last = int(_order.size()) - 1;
|
|
|
|
if (_suggestedThumb) {
|
|
|
|
const auto suggestedIndex = orderIndex(_suggestedThumb);
|
|
|
|
if (suggestedIndex < draggedIndex && suggestedIndex > 0) {
|
|
|
|
const auto previous = _thumbs[_order[suggestedIndex - 1]].get();
|
|
|
|
previous->suggestMove(0., [=] { update(); });
|
|
|
|
} else if (suggestedIndex > draggedIndex && suggestedIndex < last) {
|
|
|
|
const auto next = _thumbs[_order[suggestedIndex + 1]].get();
|
|
|
|
next->suggestMove(0., [=] { update(); });
|
|
|
|
}
|
|
|
|
_suggestedThumb->suggestMove(0., [=] { update(); });
|
|
|
|
}
|
|
|
|
_suggestedThumb = closest;
|
|
|
|
const auto suggestedIndex = closestIndex;
|
|
|
|
if (_suggestedThumb != _draggedThumb) {
|
|
|
|
const auto delta = (suggestedIndex < draggedIndex) ? 1. : -1.;
|
|
|
|
if (delta > 0. && suggestedIndex > 0) {
|
|
|
|
const auto previous = _thumbs[_order[suggestedIndex - 1]].get();
|
|
|
|
previous->suggestMove(-delta, [=] { update(); });
|
|
|
|
} else if (delta < 0. && suggestedIndex < last) {
|
|
|
|
const auto next = _thumbs[_order[suggestedIndex + 1]].get();
|
|
|
|
next->suggestMove(-delta, [=] { update(); });
|
|
|
|
}
|
|
|
|
_suggestedThumb->suggestMove(delta, [=] { update(); });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumPreview::mouseReleaseEvent(QMouseEvent *e) {
|
|
|
|
if (_draggedThumb) {
|
|
|
|
finishDrag();
|
|
|
|
_shrinkAnimation.start(
|
|
|
|
[=] { update(); },
|
|
|
|
1.,
|
|
|
|
0.,
|
|
|
|
AlbumThumbnail::kShrinkDuration);
|
|
|
|
_draggedThumb = nullptr;
|
|
|
|
_suggestedThumb = nullptr;
|
|
|
|
update();
|
2021-04-25 22:50:16 +00:00
|
|
|
} else if (const auto thumb = base::take(_pressedThumb)) {
|
|
|
|
const auto was = _pressedButtonType;
|
|
|
|
const auto now = thumb->buttonTypeFromPoint(e->pos());
|
|
|
|
if (was == now) {
|
|
|
|
thumbButtonsCallback(thumb, now);
|
2021-04-26 10:01:53 +00:00
|
|
|
}
|
2020-10-13 15:11:53 +00:00
|
|
|
}
|
2021-04-26 10:01:53 +00:00
|
|
|
_pressedButtonType = AttachButtonType::None;
|
2020-10-13 15:11:53 +00:00
|
|
|
}
|
|
|
|
|
2021-04-25 22:50:16 +00:00
|
|
|
void AlbumPreview::switchToDrag() {
|
|
|
|
_paintedAbove
|
|
|
|
= _suggestedThumb
|
|
|
|
= _draggedThumb
|
|
|
|
= base::take(_pressedThumb);
|
|
|
|
_shrinkAnimation.start(
|
|
|
|
[=] { update(); },
|
|
|
|
0.,
|
|
|
|
1.,
|
|
|
|
AlbumThumbnail::kShrinkDuration);
|
|
|
|
applyCursor(style::cur_sizeall);
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
2021-02-20 03:30:14 +00:00
|
|
|
rpl::producer<int> AlbumPreview::thumbModified() const {
|
|
|
|
return _thumbModified.events();
|
|
|
|
}
|
|
|
|
|
2020-10-13 15:11:53 +00:00
|
|
|
} // namespace Ui
|