diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index de9569656..0c4f1fda0 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1433,41 +1433,12 @@ int HistoryWidget::itemTopForHighlight( const auto heightLeft = (visibleAreaHeight - viewHeight); if (heightLeft >= 0) { return std::max(itemTop - (heightLeft / 2), 0); - } else if (const auto sel = itemHighlight(item).range; !sel.empty()) { - auto request = HistoryView::StateRequest(); - request.flags = Ui::Text::StateRequest::Flag::LookupSymbol; + } else if (const auto sel = itemHighlight(item).range + ; !sel.empty() && !IsSubGroupSelection(sel)) { const auto single = st::messageTextStyle.font->height; - const auto findy = [&](int symbol, int yfrom = 0) { - const auto fory = [&](int y) { - return view->textState(QPoint(0, y), request).symbol; - }; - auto ytill = view->height() - 1; - auto symbolfrom = fory(yfrom); - auto symboltill = fory(ytill); - if ((yfrom >= ytill) || (symbolfrom >= symbol)) { - return yfrom; - } else if (symboltill <= symbol) { - return ytill; - } - while (ytill - yfrom >= 2 * single) { - const auto middle = (yfrom + ytill) / 2; - const auto found = fory(middle); - if (found == symbol - || symbolfrom > found - || symboltill < found) { - return middle; - } else if (found < symbol) { - yfrom = middle; - symbolfrom = found; - } else { - ytill = middle; - symboltill = found; - } - } - return (yfrom + ytill) / 2; - }; - const auto begin = findy(sel.from) - single; - const auto end = findy(sel.to, begin + single) + 2 * single; + const auto begin = HistoryView::FindViewY(view, sel.from) - single; + const auto end = HistoryView::FindViewY(view, sel.to, begin + single) + + 2 * single; auto result = itemTop; if (end > visibleAreaHeight) { result = std::max(result, itemTop + end - visibleAreaHeight); diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 794ec5665..3bee997aa 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -2015,4 +2015,37 @@ void Element::ClearGlobal() { MousedElement = nullptr; } +int FindViewY(not_null view, uint16 symbol, int yfrom) { + auto request = HistoryView::StateRequest(); + request.flags = Ui::Text::StateRequest::Flag::LookupSymbol; + const auto single = st::messageTextStyle.font->height; + const auto fory = [&](int y) { + return view->textState(QPoint(0, y), request).symbol; + }; + auto ytill = view->height() - 1; + auto symbolfrom = fory(yfrom); + auto symboltill = fory(ytill); + if ((yfrom >= ytill) || (symbolfrom >= symbol)) { + return yfrom; + } else if (symboltill <= symbol) { + return ytill; + } + while (ytill - yfrom >= 2 * single) { + const auto middle = (yfrom + ytill) / 2; + const auto found = fory(middle); + if (found == symbol + || symbolfrom > found + || symboltill < found) { + return middle; + } else if (found < symbol) { + yfrom = middle; + symbolfrom = found; + } else { + ytill = middle; + symboltill = found; + } + } + return (yfrom + ytill) / 2; +} + } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h index e8a5a1c53..3f688d9d3 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.h +++ b/Telegram/SourceFiles/history/view/history_view_element.h @@ -668,4 +668,9 @@ private: }; +[[nodiscard]] int FindViewY( + not_null view, + uint16 symbol, + int yfrom = 0); + } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 35d0d8073..d4ae98e67 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -711,7 +711,25 @@ std::optional ListWidget::scrollTopForView( const auto top = view->y(); const auto height = view->height(); const auto available = _visibleBottom - _visibleTop; - return top - std::max((available - height) / 2, 0); + const auto heightLeft = (available - height); + if (heightLeft >= 0) { + return std::max(top - (heightLeft / 2), 0); + } else if (const auto sel = _highlighter.state(view->data()).range + ; !sel.empty() && !IsSubGroupSelection(sel)) { + const auto single = st::messageTextStyle.font->height; + const auto begin = HistoryView::FindViewY(view, sel.from) - single; + const auto end = HistoryView::FindViewY(view, sel.to, begin + single) + + 2 * single; + auto result = top; + if (end > available) { + result = std::max(result, top + end - available); + } + if (top + begin < result) { + result = top + begin; + } + return result; + } + return top; } void ListWidget::scrollTo( @@ -873,24 +891,31 @@ bool ListWidget::showAtPositionNow( Data::MessagePosition position, const Window::SectionShow ¶ms, Fn done) { - if (const auto scrollTop = scrollTopForPosition(position)) { - computeScrollTo(*scrollTop, position, params.animated); - if (position != Data::MaxMessagePosition - && position != Data::UnreadMessagePosition) { - highlightMessage( - position.fullId, - params.highlightPart, - params.highlightPartOffsetHint); - } - if (done) { - const auto found = !position.fullId.peer - || !IsServerMsgId(position.fullId.msg) - || viewForItem(position.fullId); - done(found); - } - return true; + auto scrollTop = scrollTopForPosition(position); + if (!scrollTop.has_value()) { + return false; } - return false; + if (position != Data::MaxMessagePosition + && position != Data::UnreadMessagePosition) { + const auto hasHighlight = !params.highlightPart.empty(); + highlightMessage( + position.fullId, + params.highlightPart, + params.highlightPartOffsetHint); + if (hasHighlight) { + // We may want to scroll to a different part of the message. + scrollTop = scrollTopForPosition(position); + Assert(scrollTop.has_value()); + } + } + computeScrollTo(*scrollTop, position, params.animated); + if (done) { + const auto found = !position.fullId.peer + || !IsServerMsgId(position.fullId.msg) + || viewForItem(position.fullId); + done(found); + } + return true; } void ListWidget::computeScrollTo(