From cec81616a44957e9709caece577db42e46090766 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 29 Mar 2026 23:16:47 +0300 Subject: [PATCH] Moved out highlight scroll logic from sections to single place. --- .../SourceFiles/history/history_widget.cpp | 65 +++---------------- .../history/view/history_view_element.cpp | 56 ++++++++++++++++ .../history/view/history_view_element.h | 19 ++++++ .../history/view/history_view_list_widget.cpp | 58 ++--------------- .../SourceFiles/layout/layout_selection.cpp | 18 ++++- .../SourceFiles/layout/layout_selection.h | 3 + 6 files changed, 106 insertions(+), 113 deletions(-) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 59fac6634d..51b7551f9e 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1595,62 +1595,15 @@ int HistoryWidget::itemTopForHighlight( const auto heightLeft = (visibleAreaHeight - viewHeight); if (heightLeft >= 0) { return std::max(itemTop - (heightLeft / 2), 0); - } else if (const auto highlight = itemHighlight(item) - ; (!highlight.range.empty() - || highlight.todoItemId - || !highlight.pollOption.isEmpty()) - && !IsSubGroupSelection(highlight.range)) { - const auto sel = highlight.range; - const auto single = st::messageTextStyle.font->height; - const auto todoy = sel.empty() - ? (highlight.todoItemId - ? HistoryView::FindViewTaskY(view, highlight.todoItemId) - : !highlight.pollOption.isEmpty() - ? HistoryView::FindViewPollOptionY(view, highlight.pollOption) - : 0) - : 0; - const auto begin = sel.empty() - ? (todoy - 4 * single) - : HistoryView::FindViewY(view, sel.from) - single; - const auto end = sel.empty() - ? (todoy + 4 * single) - : (HistoryView::FindViewY(view, sel.to, begin + single) - + 2 * single); - auto result = itemTop; - if (end > visibleAreaHeight) { - result = std::max(result, itemTop + end - visibleAreaHeight); - } - if (itemTop + begin < result) { - result = itemTop + begin; - } - return result; - } else if (IsSubGroupSelection(highlight.range)) { - if (const auto media = view->media()) { - for (auto i = 0; i != 15; ++i) { - if (!IsGroupItemSelection(highlight.range, i)) { - continue; - } - const auto rect = media->groupItemRect(i); - if (rect.isEmpty()) { - break; - } - const auto inner = view->innerGeometry(); - const auto single = st::messageTextStyle.font->height; - const auto begin = inner.y() + rect.y() - 2 * single; - const auto end = inner.y() + rect.y() - + rect.height() + 2 * single; - auto result = itemTop; - if (end > visibleAreaHeight) { - result = std::max( - result, - itemTop + end - visibleAreaHeight); - } - if (itemTop + begin < result) { - result = itemTop + begin; - } - return result; - } - } + } + const auto highlight = itemHighlight(item); + if (const auto range = HistoryView::FindHighlightYRange( + view, + highlight)) { + return HistoryView::AdjustScrollForRange( + itemTop, + visibleAreaHeight, + range); } else if (reactionCenter >= 0) { const auto maxSize = st::reactionInlineImage; diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index a56b578fdd..1a21b0750b 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -39,6 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "chat_helpers/stickers_emoji_pack.h" #include "payments/payments_reaction_process.h" // TryAddingPaidReaction. #include "window/window_session_controller.h" +#include "ui/chat/chat_style.h" #include "ui/effects/glare.h" #include "ui/effects/path_shift_gradient.h" #include "ui/effects/reaction_fly_animation.h" @@ -3139,6 +3140,61 @@ int FindViewPollOptionY( return origin.y() + (yfrom + ytill) / 2; } +HighlightYRange FindHighlightYRange( + not_null view, + const Ui::ChatPaintHighlight &highlight) { + const auto sel = highlight.range; + const auto single = st::messageTextStyle.font->height; + if (IsSubGroupSelection(sel)) { + const auto index = FirstGroupItemIndex(sel); + if (index < 0) { + return {}; + } + const auto media = view->media(); + if (!media) { + return {}; + } + const auto rect = media->groupItemRect(index); + if (rect.isEmpty()) { + return {}; + } + const auto inner = view->innerGeometry(); + return { + inner.y() + rect.y() - 2 * single, + inner.y() + rect.y() + rect.height() + 2 * single, + }; + } + if (highlight.todoItemId) { + const auto y = FindViewTaskY(view, highlight.todoItemId); + return { y - 4 * single, y + 4 * single }; + } + if (!highlight.pollOption.isEmpty()) { + const auto y = FindViewPollOptionY(view, highlight.pollOption); + return { y - 4 * single, y + 4 * single }; + } + if (!sel.empty()) { + const auto begin = FindViewY(view, sel.from) - single; + const auto end = FindViewY(view, sel.to, begin + single) + + 2 * single; + return { begin, end }; + } + return {}; +} + +int AdjustScrollForRange( + int viewTop, + int available, + HighlightYRange range) { + auto result = viewTop; + if (range.end > available) { + result = std::max(result, viewTop + range.end - available); + } + if (viewTop + range.begin < result) { + result = viewTop + range.begin; + } + return result; +} + Window::SessionController *ExtractController(const ClickContext &context) { const auto my = context.other.value(); if (const auto controller = my.sessionWindow.get()) { diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h index b0307e71fc..08a1e3d55e 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.h +++ b/Telegram/SourceFiles/history/view/history_view_element.h @@ -34,6 +34,7 @@ namespace Ui { class PathShiftGradient; struct BubblePattern; struct ChatPaintContext; +struct ChatPaintHighlight; class ChatStyle; struct ReactionFlyAnimationArgs; class ReactionFlyAnimation; @@ -807,6 +808,24 @@ private: const QByteArray &option, int yfrom = 0); +struct HighlightYRange { + int begin = 0; + int end = 0; + + explicit operator bool() const { + return begin != end; + } +}; + +[[nodiscard]] HighlightYRange FindHighlightYRange( + not_null view, + const Ui::ChatPaintHighlight &highlight); + +[[nodiscard]] int AdjustScrollForRange( + int viewTop, + int available, + HighlightYRange range); + [[nodiscard]] Window::SessionController *ExtractController( const ClickContext &context); diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 62b970f598..cdc1840367 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -769,60 +769,10 @@ std::optional ListWidget::scrollTopForView( const auto heightLeft = (available - height); if (heightLeft >= 0) { return std::max(top - (heightLeft / 2), 0); - } else if (const auto highlight = _highlighter.state(view->data()) - ; (!highlight.range.empty() - || highlight.todoItemId - || !highlight.pollOption.isEmpty()) - && !IsSubGroupSelection(highlight.range)) { - const auto sel = highlight.range; - const auto single = st::messageTextStyle.font->height; - const auto todoy = sel.empty() - ? (highlight.todoItemId - ? HistoryView::FindViewTaskY(view, highlight.todoItemId) - : !highlight.pollOption.isEmpty() - ? HistoryView::FindViewPollOptionY(view, highlight.pollOption) - : 0) - : 0; - const auto begin = sel.empty() - ? (todoy - 4 * single) - : HistoryView::FindViewY(view, sel.from) - single; - const auto end = sel.empty() - ? (todoy + 4 * single) - : (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; - } else if (IsSubGroupSelection(highlight.range)) { - if (const auto media = view->media()) { - for (auto i = 0; i != 15; ++i) { - if (!IsGroupItemSelection(highlight.range, i)) { - continue; - } - const auto rect = media->groupItemRect(i); - if (rect.isEmpty()) { - break; - } - const auto inner = view->innerGeometry(); - const auto single = st::messageTextStyle.font->height; - const auto begin = inner.y() + rect.y() - 2 * single; - const auto end = inner.y() + rect.y() - + rect.height() + 2 * single; - auto result = top; - if (end > available) { - result = std::max(result, top + end - available); - } - if (top + begin < result) { - result = top + begin; - } - return result; - } - } + } + const auto highlight = _highlighter.state(view->data()); + if (const auto range = FindHighlightYRange(view, highlight)) { + return AdjustScrollForRange(top, available, range); } return top; } diff --git a/Telegram/SourceFiles/layout/layout_selection.cpp b/Telegram/SourceFiles/layout/layout_selection.cpp index 32f48b20fb..52d0b3f099 100644 --- a/Telegram/SourceFiles/layout/layout_selection.cpp +++ b/Telegram/SourceFiles/layout/layout_selection.cpp @@ -14,15 +14,27 @@ bool IsSubGroupSelection(TextSelection selection) { bool IsGroupItemSelection( TextSelection selection, int index) { - Expects(index >= 0 && index < 0x0F); + Expects(index >= 0 && index < kMaxGroupSelectionItems); return IsSubGroupSelection(selection) && (selection.to & (1 << index)); } +int FirstGroupItemIndex(TextSelection selection) { + if (!IsSubGroupSelection(selection)) { + return -1; + } + for (auto i = 0; i != kMaxGroupSelectionItems; ++i) { + if (selection.to & (1 << i)) { + return i; + } + } + return -1; +} + TextSelection AddGroupItemSelection( TextSelection selection, int index) { - Expects(index >= 0 && index < 0x0F); + Expects(index >= 0 && index < kMaxGroupSelectionItems); const auto bit = uint16(1U << index); return TextSelection( @@ -33,7 +45,7 @@ TextSelection AddGroupItemSelection( TextSelection RemoveGroupItemSelection( TextSelection selection, int index) { - Expects(index >= 0 && index < 0x0F); + Expects(index >= 0 && index < kMaxGroupSelectionItems); const auto bit = uint16(1U << index); return IsSubGroupSelection(selection) diff --git a/Telegram/SourceFiles/layout/layout_selection.h b/Telegram/SourceFiles/layout/layout_selection.h index 726fc19c52..3a7be49fca 100644 --- a/Telegram/SourceFiles/layout/layout_selection.h +++ b/Telegram/SourceFiles/layout/layout_selection.h @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/text/text.h" constexpr auto FullSelection = TextSelection { 0xFFFF, 0xFFFF }; +constexpr auto kMaxGroupSelectionItems = 0x0F; [[nodiscard]] bool IsSubGroupSelection(TextSelection selection); @@ -17,6 +18,8 @@ constexpr auto FullSelection = TextSelection { 0xFFFF, 0xFFFF }; TextSelection selection, int index); +[[nodiscard]] int FirstGroupItemIndex(TextSelection selection); + [[nodiscard]] TextSelection AddGroupItemSelection( TextSelection selection, int index);