mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-31 07:52:06 +00:00
Allow to select and copy text in the events log.
Also better handle window resize in the events log.
This commit is contained in:
parent
693c30d264
commit
624f33c5e2
@ -94,6 +94,23 @@ TextWithTags::Tags ConvertEntitiesToTextTags(const EntitiesInText &entities) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<QMimeData> MimeDataFromTextWithEntities(const TextWithEntities &forClipboard) {
|
||||
if (forClipboard.text.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto result = std::make_unique<QMimeData>();
|
||||
result->setText(forClipboard.text);
|
||||
auto tags = ConvertEntitiesToTextTags(forClipboard.entities);
|
||||
if (!tags.isEmpty()) {
|
||||
for (auto &tag : tags) {
|
||||
tag.id = ConvertTagToMimeTag(tag.id);
|
||||
}
|
||||
result->setData(Ui::FlatTextarea::tagsMimeType(), Ui::FlatTextarea::serializeTagsList(tags));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
MessageField::MessageField(QWidget *parent, gsl::not_null<Window::Controller*> controller, const style::FlatTextarea &st, base::lambda<QString()> placeholderFactory, const QString &val) : Ui::FlatTextarea(parent, st, std::move(placeholderFactory), val)
|
||||
, _controller(controller) {
|
||||
setMinHeight(st::historySendSize.height() - 2 * st::historySendPadding);
|
||||
|
@ -31,6 +31,7 @@ QString ConvertTagToMimeTag(const QString &tagId);
|
||||
|
||||
EntitiesInText ConvertTextTagsToEntities(const TextWithTags::Tags &tags);
|
||||
TextWithTags::Tags ConvertEntitiesToTextTags(const EntitiesInText &entities);
|
||||
std::unique_ptr<QMimeData> MimeDataFromTextWithEntities(const TextWithEntities &forClipboard);
|
||||
|
||||
class MessageField final : public Ui::FlatTextarea {
|
||||
Q_OBJECT
|
||||
|
@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
#include "history/history_message.h"
|
||||
#include "history/history_service_layout.h"
|
||||
#include "history/history_admin_log_section.h"
|
||||
#include "chat_helpers/message_field.h"
|
||||
#include "mainwindow.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "auth_session.h"
|
||||
@ -234,16 +235,20 @@ void InnerWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) {
|
||||
}
|
||||
|
||||
void InnerWidget::updateVisibleTopItem() {
|
||||
auto begin = std::rbegin(_items), end = std::rend(_items);
|
||||
auto from = std::lower_bound(begin, end, _visibleTop, [this](auto &elem, int top) {
|
||||
return itemTop(elem) + elem->height() <= top;
|
||||
});
|
||||
if (from != end) {
|
||||
_visibleTopItem = *from;
|
||||
_visibleTopFromItem = _visibleTop - _visibleTopItem->y();
|
||||
} else {
|
||||
if (_visibleBottom == height()) {
|
||||
_visibleTopItem = nullptr;
|
||||
_visibleTopFromItem = _visibleTop;
|
||||
} else {
|
||||
auto begin = std::rbegin(_items), end = std::rend(_items);
|
||||
auto from = std::lower_bound(begin, end, _visibleTop, [this](auto &elem, int top) {
|
||||
return itemTop(elem) + elem->height() <= top;
|
||||
});
|
||||
if (from != end) {
|
||||
_visibleTopItem = *from;
|
||||
_visibleTopFromItem = _visibleTop - _visibleTopItem->y();
|
||||
} else {
|
||||
_visibleTopItem = nullptr;
|
||||
_visibleTopFromItem = _visibleTop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -447,8 +452,7 @@ void InnerWidget::itemsAdded(Direction direction) {
|
||||
|
||||
void InnerWidget::updateSize() {
|
||||
TWidget::resizeToWidth(width());
|
||||
auto newVisibleTop = _visibleTopItem ? (itemTop(_visibleTopItem) + _visibleTopFromItem) : ScrollMax;
|
||||
_scrollTo(newVisibleTop);
|
||||
restoreScrollPosition();
|
||||
updateVisibleTopItem();
|
||||
checkPreloadMore();
|
||||
}
|
||||
@ -466,6 +470,11 @@ int InnerWidget::resizeGetHeight(int newWidth) {
|
||||
return _itemsTop + _itemsHeight + st::historyPaddingBottom;
|
||||
}
|
||||
|
||||
void InnerWidget::restoreScrollPosition() {
|
||||
auto newVisibleTop = _visibleTopItem ? (itemTop(_visibleTopItem) + _visibleTopFromItem) : ScrollMax;
|
||||
_scrollTo(newVisibleTop);
|
||||
}
|
||||
|
||||
void InnerWidget::paintEvent(QPaintEvent *e) {
|
||||
if (Ui::skipPaintEvent(this, e)) {
|
||||
return;
|
||||
@ -490,7 +499,8 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
|
||||
auto top = itemTop(from->get());
|
||||
p.translate(0, top);
|
||||
for (auto i = from; i != to; ++i) {
|
||||
(*i)->draw(p, clip.translated(0, -top), TextSelection(), ms);
|
||||
auto selection = (*i == _selectedItem) ? _selectedText : TextSelection();
|
||||
(*i)->draw(p, clip.translated(0, -top), selection, ms);
|
||||
auto height = (*i)->height();
|
||||
top += height;
|
||||
p.translate(0, height);
|
||||
@ -562,9 +572,37 @@ void InnerWidget::paintEmpty(Painter &p) {
|
||||
//p.drawText(tr.left() + st::msgPadding.left(), tr.top() + st::msgServicePadding.top() + 1 + font->ascent, lang(lng_willbe_history));
|
||||
}
|
||||
|
||||
TextWithEntities InnerWidget::getSelectedText() const {
|
||||
return _selectedItem ? _selectedItem->selectedText(_selectedText) : TextWithEntities();
|
||||
}
|
||||
|
||||
void InnerWidget::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Escape && _cancelledCallback) {
|
||||
_cancelledCallback();
|
||||
} else if (e == QKeySequence::Copy && _selectedItem != nullptr) {
|
||||
copySelectedText();
|
||||
#ifdef Q_OS_MAC
|
||||
} else if (e->key() == Qt::Key_E && e->modifiers().testFlag(Qt::ControlModifier)) {
|
||||
setToClipboard(getSelectedText(), QClipboard::FindBuffer);
|
||||
#endif // Q_OS_MAC
|
||||
} else {
|
||||
e->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
void InnerWidget::copySelectedText() {
|
||||
setToClipboard(getSelectedText());
|
||||
}
|
||||
|
||||
void InnerWidget::copyContextUrl() {
|
||||
//if (_contextMenuLnk) {
|
||||
// _contextMenuLnk->copyToClipboard();
|
||||
//}
|
||||
}
|
||||
|
||||
void InnerWidget::setToClipboard(const TextWithEntities &forClipboard, QClipboard::Mode mode) {
|
||||
if (auto data = MimeDataFromTextWithEntities(forClipboard)) {
|
||||
QApplication::clipboard()->setMimeData(data.release(), mode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -826,7 +864,10 @@ void InnerWidget::updateSelected() {
|
||||
if (dragState.afterSymbol && _mouseSelectType == TextSelectType::Letters) {
|
||||
++second;
|
||||
}
|
||||
auto selection = _mouseActionItem->adjustSelection({ qMin(second, _mouseTextSymbol), qMax(second, _mouseTextSymbol) }, _mouseSelectType);
|
||||
auto selection = TextSelection { qMin(second, _mouseTextSymbol), qMax(second, _mouseTextSymbol) };
|
||||
if (_mouseSelectType != TextSelectType::Letters) {
|
||||
_mouseActionItem->adjustSelection(selection, _mouseSelectType);
|
||||
}
|
||||
if (_selectedText != selection) {
|
||||
_selectedText = selection;
|
||||
repaintItem(_mouseActionItem);
|
||||
|
@ -68,6 +68,9 @@ public:
|
||||
// Updates the area that is visible inside the scroll container.
|
||||
void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
|
||||
|
||||
// Set the correct scroll position after being resized.
|
||||
void restoreScrollPosition();
|
||||
|
||||
void resizeToWidth(int newWidth, int minHeight) {
|
||||
_minHeight = minHeight;
|
||||
return TWidget::resizeToWidth(newWidth);
|
||||
@ -141,6 +144,11 @@ private:
|
||||
void scrollDateCheck();
|
||||
void scrollDateHideByTimer();
|
||||
|
||||
TextWithEntities getSelectedText() const;
|
||||
void copySelectedText();
|
||||
void copyContextUrl();
|
||||
void setToClipboard(const TextWithEntities &forClipboard, QClipboard::Mode mode = QClipboard::Clipboard);
|
||||
|
||||
// This function finds all history items that are displayed and calls template method
|
||||
// for each found message (in given direction) in the passed history with passed top offset.
|
||||
//
|
||||
|
@ -219,6 +219,7 @@ void Widget::resizeEvent(QResizeEvent *e) {
|
||||
if (_scroll->size() != scrollSize) {
|
||||
_scroll->resize(scrollSize);
|
||||
_inner->resizeToWidth(scrollSize.width(), _scroll->height());
|
||||
_inner->restoreScrollPosition();
|
||||
}
|
||||
|
||||
if (!_scroll->isHidden()) {
|
||||
|
@ -78,23 +78,6 @@ int BinarySearchBlocksOrItems(const T &list, int edge) {
|
||||
return start;
|
||||
}
|
||||
|
||||
std::unique_ptr<QMimeData> MimeDataFromTextWithEntities(const TextWithEntities &forClipboard) {
|
||||
if (forClipboard.text.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto result = std::make_unique<QMimeData>();
|
||||
result->setText(forClipboard.text);
|
||||
auto tags = ConvertEntitiesToTextTags(forClipboard.entities);
|
||||
if (!tags.isEmpty()) {
|
||||
for (auto &tag : tags) {
|
||||
tag.id = ConvertTagToMimeTag(tag.id);
|
||||
}
|
||||
result->setData(Ui::FlatTextarea::tagsMimeType(), Ui::FlatTextarea::serializeTagsList(tags));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
|
||||
@ -2143,7 +2126,10 @@ void HistoryInner::onUpdateSelected() {
|
||||
if (dragState.afterSymbol && _mouseSelectType == TextSelectType::Letters) {
|
||||
++second;
|
||||
}
|
||||
auto selState = _mouseActionItem->adjustSelection({ qMin(second, _mouseTextSymbol), qMax(second, _mouseTextSymbol) }, _mouseSelectType);
|
||||
auto selState = TextSelection { qMin(second, _mouseTextSymbol), qMax(second, _mouseTextSymbol) };
|
||||
if (_mouseSelectType != TextSelectType::Letters) {
|
||||
_mouseActionItem->adjustSelection(selState, _mouseSelectType);
|
||||
}
|
||||
if (_selected[_mouseActionItem] != selState) {
|
||||
_selected[_mouseActionItem] = selState;
|
||||
repaintItem(_mouseActionItem);
|
||||
|
@ -584,18 +584,18 @@ HistoryMediaPtr::~HistoryMediaPtr() {
|
||||
|
||||
namespace internal {
|
||||
|
||||
TextSelection unshiftSelection(TextSelection selection, const Text &byText) {
|
||||
TextSelection unshiftSelection(TextSelection selection, uint16 byLength) {
|
||||
if (selection == FullSelection) {
|
||||
return selection;
|
||||
}
|
||||
return ::unshiftSelection(selection, byText);
|
||||
return ::unshiftSelection(selection, byLength);
|
||||
}
|
||||
|
||||
TextSelection shiftSelection(TextSelection selection, const Text &byText) {
|
||||
TextSelection shiftSelection(TextSelection selection, uint16 byLength) {
|
||||
if (selection == FullSelection) {
|
||||
return selection;
|
||||
}
|
||||
return ::shiftSelection(selection, byText);
|
||||
return ::shiftSelection(selection, byLength);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
@ -465,8 +465,14 @@ private:
|
||||
|
||||
namespace internal {
|
||||
|
||||
TextSelection unshiftSelection(TextSelection selection, const Text &byText);
|
||||
TextSelection shiftSelection(TextSelection selection, const Text &byText);
|
||||
TextSelection unshiftSelection(TextSelection selection, uint16 byLength);
|
||||
TextSelection shiftSelection(TextSelection selection, uint16 byLength);
|
||||
inline TextSelection unshiftSelection(TextSelection selection, const Text &byText) {
|
||||
return ::internal::unshiftSelection(selection, byText.length());
|
||||
}
|
||||
inline TextSelection shiftSelection(TextSelection selection, const Text &byText) {
|
||||
return ::internal::shiftSelection(selection, byText.length());
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
@ -984,10 +990,10 @@ protected:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TextSelection toMediaSelection(TextSelection selection) const {
|
||||
TextSelection skipTextSelection(TextSelection selection) const {
|
||||
return internal::unshiftSelection(selection, _text);
|
||||
}
|
||||
TextSelection fromMediaSelection(TextSelection selection) const {
|
||||
TextSelection unskipTextSelection(TextSelection selection) const {
|
||||
return internal::shiftSelection(selection, _text);
|
||||
}
|
||||
|
||||
|
@ -90,6 +90,15 @@ public:
|
||||
virtual bool consumeMessageText(const TextWithEntities &textWithEntities) {
|
||||
return false;
|
||||
}
|
||||
virtual uint16 fullSelectionLength() const {
|
||||
return 0;
|
||||
}
|
||||
TextSelection skipSelection(TextSelection selection) const {
|
||||
return internal::unshiftSelection(selection, fullSelectionLength());
|
||||
}
|
||||
TextSelection unskipSelection(TextSelection selection) const {
|
||||
return internal::shiftSelection(selection, fullSelectionLength());
|
||||
}
|
||||
|
||||
// if we press and drag this link should we drag the item
|
||||
virtual bool dragItemByHandler(const ClickHandlerPtr &p) const = 0;
|
||||
|
@ -139,6 +139,9 @@ public:
|
||||
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override {
|
||||
return _caption.adjustSelection(selection, type);
|
||||
}
|
||||
uint16 fullSelectionLength() const override {
|
||||
return _caption.length();
|
||||
}
|
||||
bool hasTextForCopy() const override {
|
||||
return !_caption.isEmpty();
|
||||
}
|
||||
@ -221,6 +224,9 @@ public:
|
||||
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override {
|
||||
return _caption.adjustSelection(selection, type);
|
||||
}
|
||||
uint16 fullSelectionLength() const override {
|
||||
return _caption.length();
|
||||
}
|
||||
bool hasTextForCopy() const override {
|
||||
return !_caption.isEmpty();
|
||||
}
|
||||
@ -372,6 +378,12 @@ public:
|
||||
}
|
||||
return selection;
|
||||
}
|
||||
uint16 fullSelectionLength() const override {
|
||||
if (auto captioned = Get<HistoryDocumentCaptioned>()) {
|
||||
return captioned->_caption.length();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
bool hasTextForCopy() const override {
|
||||
return Has<HistoryDocumentCaptioned>();
|
||||
}
|
||||
@ -475,6 +487,9 @@ public:
|
||||
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override {
|
||||
return _caption.adjustSelection(selection, type);
|
||||
}
|
||||
uint16 fullSelectionLength() const override {
|
||||
return _caption.length();
|
||||
}
|
||||
bool hasTextForCopy() const override {
|
||||
return !_caption.isEmpty();
|
||||
}
|
||||
@ -769,6 +784,9 @@ public:
|
||||
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override;
|
||||
|
||||
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override;
|
||||
uint16 fullSelectionLength() const override {
|
||||
return _title.length() + _description.length();
|
||||
}
|
||||
bool hasTextForCopy() const override {
|
||||
return false; // we do not add _title and _description in FullSelection text copy.
|
||||
}
|
||||
@ -869,6 +887,9 @@ public:
|
||||
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override;
|
||||
|
||||
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override;
|
||||
uint16 fullSelectionLength() const override {
|
||||
return _title.length() + _description.length();
|
||||
}
|
||||
bool isAboveMessage() const override {
|
||||
return true;
|
||||
}
|
||||
@ -977,6 +998,9 @@ public:
|
||||
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override;
|
||||
|
||||
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override;
|
||||
uint16 fullSelectionLength() const override {
|
||||
return _title.length() + _description.length();
|
||||
}
|
||||
bool hasTextForCopy() const override {
|
||||
return false; // we do not add _title and _description in FullSelection text copy.
|
||||
}
|
||||
@ -1060,6 +1084,9 @@ public:
|
||||
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override;
|
||||
|
||||
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override;
|
||||
uint16 fullSelectionLength() const override {
|
||||
return _title.length() + _description.length();
|
||||
}
|
||||
bool hasTextForCopy() const override {
|
||||
return !_title.isEmpty() || !_description.isEmpty();
|
||||
}
|
||||
|
@ -1058,24 +1058,33 @@ void HistoryMessage::eraseFromOverview() {
|
||||
}
|
||||
|
||||
TextWithEntities HistoryMessage::selectedText(TextSelection selection) const {
|
||||
TextWithEntities result, textResult, mediaResult;
|
||||
TextWithEntities textResult, mediaResult, logEntryOriginalResult;
|
||||
if (selection == FullSelection) {
|
||||
textResult = _text.originalTextWithEntities(AllTextSelection, ExpandLinksAll);
|
||||
} else {
|
||||
textResult = _text.originalTextWithEntities(selection, ExpandLinksAll);
|
||||
}
|
||||
if (_media) {
|
||||
mediaResult = _media->selectedText(toMediaSelection(selection));
|
||||
auto skipped = skipTextSelection(selection);
|
||||
auto mediaDisplayed = (_media && _media->isDisplayed());
|
||||
if (mediaDisplayed) {
|
||||
mediaResult = _media->selectedText(skipped);
|
||||
}
|
||||
if (textResult.text.isEmpty()) {
|
||||
result = mediaResult;
|
||||
} else if (mediaResult.text.isEmpty()) {
|
||||
result = textResult;
|
||||
} else {
|
||||
result.text = textResult.text + qstr("\n\n");
|
||||
result.entities = textResult.entities;
|
||||
if (auto entry = Get<HistoryMessageLogEntryOriginal>()) {
|
||||
logEntryOriginalResult = entry->_page->selectedText(mediaDisplayed ? _media->skipSelection(skipped) : skipped);
|
||||
}
|
||||
auto result = textResult;
|
||||
if (result.text.isEmpty()) {
|
||||
result = std::move(mediaResult);
|
||||
} else if (!mediaResult.text.isEmpty()) {
|
||||
result.text += qstr("\n\n");
|
||||
appendTextWithEntities(result, std::move(mediaResult));
|
||||
}
|
||||
if (result.text.isEmpty()) {
|
||||
result = std::move(logEntryOriginalResult);
|
||||
} else if (!logEntryOriginalResult.text.isEmpty()) {
|
||||
result.text += qstr("\n\n");
|
||||
appendTextWithEntities(result, std::move(logEntryOriginalResult));
|
||||
}
|
||||
if (auto forwarded = Get<HistoryMessageForwarded>()) {
|
||||
if (selection == FullSelection) {
|
||||
auto fwdinfo = forwarded->_text.originalTextWithEntities(AllTextSelection, ExpandLinksAll);
|
||||
@ -1138,7 +1147,8 @@ void HistoryMessage::setText(const TextWithEntities &textWithEntities) {
|
||||
if (mediaDisplayed && _media->consumeMessageText(textWithEntities)) {
|
||||
setEmptyText();
|
||||
} else {
|
||||
if (_media && _media->isDisplayed() && !_media->isAboveMessage()) {
|
||||
auto mediaOnBottom = (_media && _media->isDisplayed() && _media->isBubbleBottom()) || Has<HistoryMessageLogEntryOriginal>();
|
||||
if (mediaOnBottom) {
|
||||
_text.setMarkedText(st::messageTextStyle, textWithEntities, itemTextOptions(this));
|
||||
} else {
|
||||
_text.setMarkedText(st::messageTextStyle, { textWithEntities.text + skipBlock(), textWithEntities.entities }, itemTextOptions(this));
|
||||
@ -1442,7 +1452,7 @@ void HistoryMessage::draw(Painter &p, QRect clip, TextSelection selection, TimeM
|
||||
paintText(p, trect, selection);
|
||||
}
|
||||
p.translate(mediaLeft, mediaTop);
|
||||
_media->draw(p, clip.translated(-mediaLeft, -mediaTop), toMediaSelection(selection), ms);
|
||||
_media->draw(p, clip.translated(-mediaLeft, -mediaTop), skipTextSelection(selection), ms);
|
||||
p.translate(-mediaLeft, -mediaTop);
|
||||
|
||||
if (mediaAboveText) {
|
||||
@ -1458,7 +1468,11 @@ void HistoryMessage::draw(Painter &p, QRect clip, TextSelection selection, TimeM
|
||||
auto entryLeft = g.left();
|
||||
auto entryTop = trect.y() + trect.height();
|
||||
p.translate(entryLeft, entryTop);
|
||||
entry->_page->draw(p, clip.translated(-entryLeft, -entryTop), TextSelection(), ms);
|
||||
auto entrySelection = skipTextSelection(selection);
|
||||
if (mediaDisplayed) {
|
||||
entrySelection = _media->skipSelection(entrySelection);
|
||||
}
|
||||
entry->_page->draw(p, clip.translated(-entryLeft, -entryTop), entrySelection, ms);
|
||||
p.translate(-entryLeft, -entryTop);
|
||||
}
|
||||
if (needDrawInfo) {
|
||||
@ -1466,7 +1480,7 @@ void HistoryMessage::draw(Painter &p, QRect clip, TextSelection selection, TimeM
|
||||
}
|
||||
} else if (_media) {
|
||||
p.translate(g.topLeft());
|
||||
_media->draw(p, clip.translated(-g.topLeft()), toMediaSelection(selection), ms);
|
||||
_media->draw(p, clip.translated(-g.topLeft()), skipTextSelection(selection), ms);
|
||||
p.translate(-g.topLeft());
|
||||
}
|
||||
|
||||
@ -1749,7 +1763,7 @@ HistoryTextState HistoryMessage::getState(QPoint point, HistoryStateRequest requ
|
||||
auto entryTop = trect.y() + trect.height();
|
||||
if (point.y() >= entryTop && point.y() < entryTop + entryHeight) {
|
||||
result = entry->_page->getState(point - QPoint(entryLeft, entryTop), request);
|
||||
result.symbol += _text.length();
|
||||
result.symbol += _text.length() + (mediaDisplayed ? _media->fullSelectionLength() : 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1926,15 +1940,38 @@ bool HistoryMessage::getStateText(QPoint point, QRect &trect, HistoryTextState *
|
||||
}
|
||||
|
||||
TextSelection HistoryMessage::adjustSelection(TextSelection selection, TextSelectType type) const {
|
||||
if (!_media || selection.to <= _text.length()) {
|
||||
return _text.adjustSelection(selection, type);
|
||||
auto result = _text.adjustSelection(selection, type);
|
||||
auto beforeMediaLength = _text.length();
|
||||
if (selection.to <= beforeMediaLength) {
|
||||
return result;
|
||||
}
|
||||
auto mediaSelection = _media->adjustSelection(toMediaSelection(selection), type);
|
||||
if (selection.from >= _text.length()) {
|
||||
return fromMediaSelection(mediaSelection);
|
||||
auto mediaDisplayed = _media && _media->isDisplayed();
|
||||
if (mediaDisplayed) {
|
||||
auto mediaSelection = unskipTextSelection(_media->adjustSelection(skipTextSelection(selection), type));
|
||||
if (selection.from >= beforeMediaLength) {
|
||||
result = mediaSelection;
|
||||
} else {
|
||||
result.to = mediaSelection.to;
|
||||
}
|
||||
}
|
||||
auto textSelection = _text.adjustSelection(selection, type);
|
||||
return { textSelection.from, fromMediaSelection(mediaSelection).to };
|
||||
auto beforeEntryLength = beforeMediaLength + (mediaDisplayed ? _media->fullSelectionLength() : 0);
|
||||
if (selection.to <= beforeEntryLength) {
|
||||
return result;
|
||||
}
|
||||
if (auto entry = Get<HistoryMessageLogEntryOriginal>()) {
|
||||
auto entrySelection = mediaDisplayed ? _media->skipSelection(skipTextSelection(selection)) : skipTextSelection(selection);
|
||||
auto logEntryOriginalSelection = entry->_page->adjustSelection(entrySelection, type);
|
||||
if (mediaDisplayed) {
|
||||
logEntryOriginalSelection = _media->unskipSelection(logEntryOriginalSelection);
|
||||
}
|
||||
logEntryOriginalSelection = unskipTextSelection(logEntryOriginalSelection);
|
||||
if (selection.from >= beforeEntryLength) {
|
||||
result = logEntryOriginalSelection;
|
||||
} else {
|
||||
result.to = logEntryOriginalSelection.to;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void HistoryMessage::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
|
||||
|
@ -218,7 +218,7 @@ void ServiceMessagePainter::paint(Painter &p, const HistoryService *message, con
|
||||
height -= st::msgServiceMargin.top() + media->height();
|
||||
auto left = st::msgServiceMargin.left() + (g.width() - media->maxWidth()) / 2, top = st::msgServiceMargin.top() + height + st::msgServiceMargin.top();
|
||||
p.translate(left, top);
|
||||
media->draw(p, context.clip.translated(-left, -top), message->toMediaSelection(context.selection), context.ms);
|
||||
media->draw(p, context.clip.translated(-left, -top), message->skipTextSelection(context.selection), context.ms);
|
||||
p.translate(-left, -top);
|
||||
}
|
||||
|
||||
|
@ -245,13 +245,17 @@ private:
|
||||
inline TextSelection snapSelection(int from, int to) {
|
||||
return { static_cast<uint16>(snap(from, 0, 0xFFFF)), static_cast<uint16>(snap(to, 0, 0xFFFF)) };
|
||||
}
|
||||
inline TextSelection shiftSelection(TextSelection selection, uint16 byLength) {
|
||||
return snapSelection(int(selection.from) + byLength, int(selection.to) + byLength);
|
||||
}
|
||||
inline TextSelection unshiftSelection(TextSelection selection, uint16 byLength) {
|
||||
return snapSelection(int(selection.from) - int(byLength), int(selection.to) - int(byLength));
|
||||
}
|
||||
inline TextSelection shiftSelection(TextSelection selection, const Text &byText) {
|
||||
int len = byText.length();
|
||||
return snapSelection(int(selection.from) + len, int(selection.to) + len);
|
||||
return shiftSelection(selection, byText.length());
|
||||
}
|
||||
inline TextSelection unshiftSelection(TextSelection selection, const Text &byText) {
|
||||
int len = byText.length();
|
||||
return snapSelection(int(selection.from) - len, int(selection.to) - len);
|
||||
return unshiftSelection(selection, byText.length());
|
||||
}
|
||||
|
||||
void initLinkSets();
|
||||
|
Loading…
Reference in New Issue
Block a user