Moved out highlight scroll logic from sections to single place.

This commit is contained in:
23rd
2026-03-29 23:16:47 +03:00
parent 59bf5515c3
commit cec81616a4
6 changed files with 106 additions and 113 deletions
@@ -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;
@@ -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<Element*> 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<ClickHandlerContext>();
if (const auto controller = my.sessionWindow.get()) {
@@ -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<Element*> view,
const Ui::ChatPaintHighlight &highlight);
[[nodiscard]] int AdjustScrollForRange(
int viewTop,
int available,
HighlightYRange range);
[[nodiscard]] Window::SessionController *ExtractController(
const ClickContext &context);
@@ -769,60 +769,10 @@ std::optional<int> 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;
}
@@ -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)
@@ -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);