From 624f33c5e2ec4bce2b47ad31b2efa23991a4e917 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 23 Jun 2017 22:28:42 +0300 Subject: [PATCH] Allow to select and copy text in the events log. Also better handle window resize in the events log. --- .../chat_helpers/message_field.cpp | 17 ++++ .../SourceFiles/chat_helpers/message_field.h | 1 + .../history/history_admin_log_inner.cpp | 67 ++++++++++++--- .../history/history_admin_log_inner.h | 8 ++ .../history/history_admin_log_section.cpp | 1 + .../history/history_inner_widget.cpp | 22 +---- Telegram/SourceFiles/history/history_item.cpp | 8 +- Telegram/SourceFiles/history/history_item.h | 14 +++- Telegram/SourceFiles/history/history_media.h | 9 +++ .../SourceFiles/history/history_media_types.h | 27 +++++++ .../SourceFiles/history/history_message.cpp | 81 ++++++++++++++----- .../history/history_service_layout.cpp | 2 +- Telegram/SourceFiles/ui/text/text.h | 12 ++- 13 files changed, 203 insertions(+), 66 deletions(-) diff --git a/Telegram/SourceFiles/chat_helpers/message_field.cpp b/Telegram/SourceFiles/chat_helpers/message_field.cpp index 3d742e0c0..207a3bba4 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.cpp +++ b/Telegram/SourceFiles/chat_helpers/message_field.cpp @@ -94,6 +94,23 @@ TextWithTags::Tags ConvertEntitiesToTextTags(const EntitiesInText &entities) { return result; } +std::unique_ptr MimeDataFromTextWithEntities(const TextWithEntities &forClipboard) { + if (forClipboard.text.isEmpty()) { + return nullptr; + } + + auto result = std::make_unique(); + 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 controller, const style::FlatTextarea &st, base::lambda placeholderFactory, const QString &val) : Ui::FlatTextarea(parent, st, std::move(placeholderFactory), val) , _controller(controller) { setMinHeight(st::historySendSize.height() - 2 * st::historySendPadding); diff --git a/Telegram/SourceFiles/chat_helpers/message_field.h b/Telegram/SourceFiles/chat_helpers/message_field.h index 5cd97c1e5..88cee7f9d 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.h +++ b/Telegram/SourceFiles/chat_helpers/message_field.h @@ -31,6 +31,7 @@ QString ConvertTagToMimeTag(const QString &tagId); EntitiesInText ConvertTextTagsToEntities(const TextWithTags::Tags &tags); TextWithTags::Tags ConvertEntitiesToTextTags(const EntitiesInText &entities); +std::unique_ptr MimeDataFromTextWithEntities(const TextWithEntities &forClipboard); class MessageField final : public Ui::FlatTextarea { Q_OBJECT diff --git a/Telegram/SourceFiles/history/history_admin_log_inner.cpp b/Telegram/SourceFiles/history/history_admin_log_inner.cpp index 338f177ac..670bfb30d 100644 --- a/Telegram/SourceFiles/history/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/history_admin_log_inner.cpp @@ -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); diff --git a/Telegram/SourceFiles/history/history_admin_log_inner.h b/Telegram/SourceFiles/history/history_admin_log_inner.h index 7aa1b18c2..3c0ac7252 100644 --- a/Telegram/SourceFiles/history/history_admin_log_inner.h +++ b/Telegram/SourceFiles/history/history_admin_log_inner.h @@ -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. // diff --git a/Telegram/SourceFiles/history/history_admin_log_section.cpp b/Telegram/SourceFiles/history/history_admin_log_section.cpp index fed64fd84..78c17e91b 100644 --- a/Telegram/SourceFiles/history/history_admin_log_section.cpp +++ b/Telegram/SourceFiles/history/history_admin_log_section.cpp @@ -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()) { diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index b338f9e46..730de50ba 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -78,23 +78,6 @@ int BinarySearchBlocksOrItems(const T &list, int edge) { return start; } -std::unique_ptr MimeDataFromTextWithEntities(const TextWithEntities &forClipboard) { - if (forClipboard.text.isEmpty()) { - return nullptr; - } - - auto result = std::make_unique(); - 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); diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index b9fbf6bd6..7ed230ec5 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -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 diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index f4e72599a..24df6d942 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -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); } diff --git a/Telegram/SourceFiles/history/history_media.h b/Telegram/SourceFiles/history/history_media.h index 1a7bb8e99..636cd019d 100644 --- a/Telegram/SourceFiles/history/history_media.h +++ b/Telegram/SourceFiles/history/history_media.h @@ -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; diff --git a/Telegram/SourceFiles/history/history_media_types.h b/Telegram/SourceFiles/history/history_media_types.h index fb7de919d..65bfeba57 100644 --- a/Telegram/SourceFiles/history/history_media_types.h +++ b/Telegram/SourceFiles/history/history_media_types.h @@ -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()) { + return captioned->_caption.length(); + } + return 0; + } bool hasTextForCopy() const override { return Has(); } @@ -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(); } diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index f70b62fe9..a94b04449 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -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()) { + 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()) { 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(); + 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()) { + 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) { diff --git a/Telegram/SourceFiles/history/history_service_layout.cpp b/Telegram/SourceFiles/history/history_service_layout.cpp index d60ce5ed5..4a43b0f0f 100644 --- a/Telegram/SourceFiles/history/history_service_layout.cpp +++ b/Telegram/SourceFiles/history/history_service_layout.cpp @@ -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); } diff --git a/Telegram/SourceFiles/ui/text/text.h b/Telegram/SourceFiles/ui/text/text.h index bbaa9d894..7698da1b1 100644 --- a/Telegram/SourceFiles/ui/text/text.h +++ b/Telegram/SourceFiles/ui/text/text.h @@ -245,13 +245,17 @@ private: inline TextSelection snapSelection(int from, int to) { return { static_cast(snap(from, 0, 0xFFFF)), static_cast(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();