Fix long message parts highlighting in topics.

This commit is contained in:
John Preston 2024-12-23 13:12:29 +04:00
parent 99a7a13218
commit 2b53df98cd
4 changed files with 86 additions and 52 deletions

View file

@ -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);

View file

@ -2015,4 +2015,37 @@ void Element::ClearGlobal() {
MousedElement = nullptr;
}
int FindViewY(not_null<Element*> 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

View file

@ -668,4 +668,9 @@ private:
};
[[nodiscard]] int FindViewY(
not_null<Element*> view,
uint16 symbol,
int yfrom = 0);
} // namespace HistoryView

View file

@ -711,7 +711,25 @@ std::optional<int> 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 &params,
Fn<void(bool found)> 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(