From 6e682643df5711a61b5acf0cf116e7bd8a0233ff Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 29 Oct 2020 19:12:43 +0300 Subject: [PATCH] Fix captions selection in column albums. --- .../SourceFiles/history/history_item_text.cpp | 32 ++++++- .../view/media/history_view_document.cpp | 6 +- .../view/media/history_view_document.h | 6 +- .../history/view/media/history_view_gif.cpp | 6 +- .../history/view/media/history_view_gif.h | 6 +- .../history/view/media/history_view_media.cpp | 3 +- .../history/view/media/history_view_media.h | 6 +- .../view/media/history_view_media_grouped.cpp | 84 ++++++++++++++++--- .../view/media/history_view_media_grouped.h | 8 +- .../history/view/media/history_view_photo.cpp | 6 +- .../history/view/media/history_view_photo.h | 6 +- 11 files changed, 119 insertions(+), 50 deletions(-) diff --git a/Telegram/SourceFiles/history/history_item_text.cpp b/Telegram/SourceFiles/history/history_item_text.cpp index 3af55f05c2..5a1d9adfb8 100644 --- a/Telegram/SourceFiles/history/history_item_text.cpp +++ b/Telegram/SourceFiles/history/history_item_text.cpp @@ -108,12 +108,38 @@ TextForMimeData HistoryItemText(not_null item) { TextForMimeData HistoryGroupText(not_null group) { Expects(!group->items.empty()); + const auto columnAlbum = [&] { + const auto item = group->items.front(); + if (const auto media = item->media()) { + if (const auto document = media->document()) { + return !document->isVideoFile(); + } + } + return false; + }(); + const auto hasCaption = [](not_null item) { + return !item->clipboardText().empty(); + }; + if (columnAlbum) { + const auto simple = !ranges::any_of(group->items, hasCaption); + if (!simple) { + auto result = TextForMimeData(); + for (const auto &item : group->items) { + if (result.empty()) { + result = HistoryItemText(item); + } else { + result.append(qstr("\n\n")).append(HistoryItemText(item)); + } + } + return result; + } + } auto caption = [&] { auto &&nonempty = ranges::view::all( group->items - ) | ranges::view::filter([](not_null item) { - return !item->clipboardText().empty(); - }) | ranges::view::take(2); + ) | ranges::view::filter( + hasCaption + ) | ranges::view::take(2); auto first = nonempty.begin(); auto end = nonempty.end(); if (first == end) { diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index 67691a00ab..2dcb0f1b43 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -908,8 +908,7 @@ void Document::drawGrouped( RectParts sides, RectParts corners, not_null cacheKey, - not_null cache, - bool last) const { + not_null cache) const { p.translate(geometry.topLeft()); draw( p, @@ -924,8 +923,7 @@ TextState Document::getStateGrouped( const QRect &geometry, RectParts sides, QPoint point, - StateRequest request, - bool last) const { + StateRequest request) const { point -= geometry.topLeft(); return textState( point, diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.h b/Telegram/SourceFiles/history/view/media/history_view_document.h index 7171babbca..d50d7e0ed6 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.h +++ b/Telegram/SourceFiles/history/view/media/history_view_document.h @@ -73,14 +73,12 @@ public: RectParts sides, RectParts corners, not_null cacheKey, - not_null cache, - bool last) const override; + not_null cache) const override; TextState getStateGrouped( const QRect &geometry, RectParts sides, QPoint point, - StateRequest request, - bool last) const override; + StateRequest request) const override; bool voiceProgressAnimationCallback(crl::time now); diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index dcf2d0db3f..883e324073 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -902,8 +902,7 @@ void Gif::drawGrouped( RectParts sides, RectParts corners, not_null cacheKey, - not_null cache, - bool last) const { + not_null cache) const { ensureDataMediaCreated(); const auto item = _parent->data(); const auto loaded = dataLoaded(); @@ -1091,8 +1090,7 @@ TextState Gif::getStateGrouped( const QRect &geometry, RectParts sides, QPoint point, - StateRequest request, - bool last) const { + StateRequest request) const { if (!geometry.contains(point)) { return {}; } diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.h b/Telegram/SourceFiles/history/view/media/history_view_gif.h index 89487c01d6..e5bfcc30cd 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.h +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.h @@ -80,14 +80,12 @@ public: RectParts sides, RectParts corners, not_null cacheKey, - not_null cache, - bool last) const override; + not_null cache) const override; TextState getStateGrouped( const QRect &geometry, RectParts sides, QPoint point, - StateRequest request, - bool last) const override; + StateRequest request) const override; void stopAnimation() override; void checkAnimation() override; diff --git a/Telegram/SourceFiles/history/view/media/history_view_media.cpp b/Telegram/SourceFiles/history/view/media/history_view_media.cpp index 5b243babed..64eb1ff5dd 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media.cpp @@ -182,8 +182,7 @@ TextState Media::getStateGrouped( const QRect &geometry, RectParts sides, QPoint point, - StateRequest request, - bool last) const { + StateRequest request) const { Unexpected("Grouping method call."); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_media.h b/Telegram/SourceFiles/history/view/media/history_view_media.h index abde5adb8a..82df073bfa 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media.h +++ b/Telegram/SourceFiles/history/view/media/history_view_media.h @@ -178,16 +178,14 @@ public: RectParts sides, RectParts corners, not_null cacheKey, - not_null cache, - bool last) const { + not_null cache) const { Unexpected("Grouping method call."); } [[nodiscard]] virtual TextState getStateGrouped( const QRect &geometry, RectParts sides, QPoint point, - StateRequest request, - bool last) const; + StateRequest request) const; [[nodiscard]] virtual bool animating() const { return false; diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp index 0395a027dd..a2ea6af931 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp @@ -254,14 +254,21 @@ void GroupedMedia::draw( TextSelection selection, crl::time ms) const { const auto groupPadding = groupedPadding(); + const auto fullSelection = (selection == FullSelection); + const auto textSelection = !fullSelection + && !IsSubGroupSelection(selection); for (auto i = 0, count = int(_parts.size()); i != count; ++i) { const auto &part = _parts[i]; - const auto partSelection = (selection == FullSelection) + const auto partSelection = fullSelection ? FullSelection + : textSelection + ? selection : IsGroupItemSelection(selection, i) ? FullSelection : TextSelection(); - const auto last = (i + 1 == count); + if (textSelection) { + selection = part.content->skipSelection(selection); + } part.content->drawGrouped( p, clip, @@ -271,8 +278,7 @@ void GroupedMedia::draw( part.sides, cornersFromSides(part.sides), &part.cacheKey, - &part.cache, - last); + &part.cache); } // date @@ -303,20 +309,19 @@ void GroupedMedia::draw( TextState GroupedMedia::getPartState( QPoint point, StateRequest request) const { - auto index = 0; + auto shift = 0; for (const auto &part : _parts) { - ++index; if (part.geometry.contains(point)) { - const auto last = (index == _parts.size()); auto result = part.content->getStateGrouped( part.geometry, part.sides, point, - request, - last); + request); + result.symbol += shift; result.itemId = part.item->fullId(); return result; } + shift += part.content->fullSelectionLength(); } return TextState(_parent->data()); } @@ -389,12 +394,69 @@ bool GroupedMedia::dragItemByHandler(const ClickHandlerPtr &p) const { TextSelection GroupedMedia::adjustSelection( TextSelection selection, TextSelectType type) const { - return _caption.adjustSelection(selection, type); + if (_mode != Mode::Column) { + return _caption.adjustSelection(selection, type); + } + auto checked = 0; + for (const auto &part : _parts) { + const auto modified = ShiftItemSelection( + part.content->adjustSelection( + UnshiftItemSelection(selection, checked), + type), + checked); + const auto till = checked + part.content->fullSelectionLength(); + if (selection.from >= checked && selection.from < till) { + selection.from = modified.from; + } + if (selection.to <= till) { + selection.to = modified.to; + return selection; + } + } + return selection; +} + +uint16 GroupedMedia::fullSelectionLength() const { + if (_mode != Mode::Column) { + return _caption.length(); + } + auto result = 0; + for (const auto &part : _parts) { + result += part.content->fullSelectionLength(); + } + return result; +} + +bool GroupedMedia::hasTextForCopy() const { + if (_mode != Mode::Column) { + return !_caption.isEmpty(); + } + for (const auto &part : _parts) { + if (part.content->hasTextForCopy()) { + return true; + } + } + return false; } TextForMimeData GroupedMedia::selectedText( TextSelection selection) const { - return _caption.toTextForMimeData(selection); + if (_mode != Mode::Column) { + return _caption.toTextForMimeData(selection); + } + auto result = TextForMimeData(); + for (const auto &part : _parts) { + auto text = part.content->selectedText(selection); + if (!text.empty()) { + if (result.empty()) { + result = std::move(text); + } else { + result.append(qstr("\n\n")).append(std::move(text)); + } + } + selection = part.content->skipSelection(selection); + } + return result; } auto GroupedMedia::getBubbleSelectionIntervals( diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h index 615c037725..ee24c61f82 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h +++ b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h @@ -48,12 +48,8 @@ public: [[nodiscard]] TextSelection adjustSelection( TextSelection selection, TextSelectType type) const override; - uint16 fullSelectionLength() const override { - return _caption.length(); - } - bool hasTextForCopy() const override { - return !_caption.isEmpty(); - } + uint16 fullSelectionLength() const override; + bool hasTextForCopy() const override; PhotoData *getPhoto() const override; DocumentData *getDocument() const override; diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp index 3d7541d098..ebb7fd3186 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp @@ -486,8 +486,7 @@ void Photo::drawGrouped( RectParts sides, RectParts corners, not_null cacheKey, - not_null cache, - bool last) const { + not_null cache) const { ensureDataMediaCreated(); _dataMedia->automaticLoad(_realParent->fullId(), _parent->data()); @@ -587,8 +586,7 @@ TextState Photo::getStateGrouped( const QRect &geometry, RectParts sides, QPoint point, - StateRequest request, - bool last) const { + StateRequest request) const { if (!geometry.contains(point)) { return {}; } diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.h b/Telegram/SourceFiles/history/view/media/history_view_photo.h index 1f3038da79..234843cf01 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.h +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.h @@ -69,14 +69,12 @@ public: RectParts sides, RectParts corners, not_null cacheKey, - not_null cache, - bool last) const override; + not_null cache) const override; TextState getStateGrouped( const QRect &geometry, RectParts sides, QPoint point, - StateRequest request, - bool last) const override; + StateRequest request) const override; TextWithEntities getCaption() const override { return _caption.toTextWithEntities();