Fix / improve support for album items selection.

This commit is contained in:
John Preston 2018-01-27 16:59:24 +03:00
parent 722264f634
commit 2fdc3169ce
34 changed files with 983 additions and 598 deletions

View File

@ -280,7 +280,7 @@ void BotKeyboard::updateSelected() {
auto p = mapFromGlobal(_lastMousePos); auto p = mapFromGlobal(_lastMousePos);
auto x = rtl() ? st::botKbScroll.width : _st->margin; auto x = rtl() ? st::botKbScroll.width : _st->margin;
auto link = _impl->getState(p - QPoint(x, _st->margin)); auto link = _impl->getLink(p - QPoint(x, _st->margin));
if (ClickHandler::setActive(link, this)) { if (ClickHandler::setActive(link, this)) {
Ui::Tooltip::Hide(); Ui::Tooltip::Hide();
setCursor(link ? style::cur_pointer : style::cur_default); setCursor(link ? style::cur_pointer : style::cur_default);

View File

@ -888,7 +888,7 @@ void GifsListWidget::updateSelected() {
int row = -1, col = -1, sel = -1; int row = -1, col = -1, sel = -1;
ClickHandlerPtr lnk; ClickHandlerPtr lnk;
ClickHandlerHost *lnkhost = nullptr; ClickHandlerHost *lnkhost = nullptr;
HistoryCursorState cursor = HistoryDefaultCursorState; HistoryView::CursorState cursor = HistoryView::CursorState::None;
if (sy >= 0) { if (sy >= 0) {
row = 0; row = 0;
for (int rows = _rows.size(); row < rows; ++row) { for (int rows = _rows.size(); row < rows; ++row) {
@ -913,10 +913,12 @@ void GifsListWidget::updateSelected() {
} }
if (col < inlineItems.size()) { if (col < inlineItems.size()) {
sel = row * MatrixRowShift + col; sel = row * MatrixRowShift + col;
auto result = inlineItems[col]->getState(QPoint(sx, sy), HistoryStateRequest()); auto result = inlineItems[col]->getState(
QPoint(sx, sy),
HistoryView::StateRequest());
lnk = result.link; lnk = result.link;
cursor = result.cursor; cursor = result.cursor;
lnkhost = inlineItems.at(col); lnkhost = inlineItems[col];
} else { } else {
row = col = -1; row = col = -1;
} }

View File

@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/admin_log/history_admin_log_filter.h" #include "history/admin_log/history_admin_log_filter.h"
#include "history/view/history_view_message.h" #include "history/view/history_view_message.h"
#include "history/view/history_view_service_message.h" #include "history/view/history_view_service_message.h"
#include "history/view/history_view_cursor_state.h"
#include "chat_helpers/message_field.h" #include "chat_helpers/message_field.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "mainwidget.h" #include "mainwidget.h"
@ -451,13 +452,15 @@ void InnerWidget::updateEmptyText() {
} }
QString InnerWidget::tooltipText() const { QString InnerWidget::tooltipText() const {
if (_mouseCursorState == HistoryInDateCursorState && _mouseAction == MouseAction::None) { if (_mouseCursorState == CursorState::Date
&& _mouseAction == MouseAction::None) {
if (const auto view = App::hoveredItem()) { if (const auto view = App::hoveredItem()) {
auto dateText = view->data()->date.toString( auto dateText = view->data()->date.toString(
QLocale::system().dateTimeFormat(QLocale::LongFormat)); QLocale::system().dateTimeFormat(QLocale::LongFormat));
return dateText; return dateText;
} }
} else if (_mouseCursorState == HistoryInForwardedCursorState && _mouseAction == MouseAction::None) { } else if (_mouseCursorState == CursorState::Forwarded
&& _mouseAction == MouseAction::None) {
if (const auto view = App::hoveredItem()) { if (const auto view = App::hoveredItem()) {
if (const auto forwarded = view->data()->Get<HistoryMessageForwarded>()) { if (const auto forwarded = view->data()->Get<HistoryMessageForwarded>()) {
return forwarded->text.originalText(AllTextSelection, ExpandLinksNone); return forwarded->text.originalText(AllTextSelection, ExpandLinksNone);
@ -872,10 +875,10 @@ void InnerWidget::keyPressEvent(QKeyEvent *e) {
void InnerWidget::mouseDoubleClickEvent(QMouseEvent *e) { void InnerWidget::mouseDoubleClickEvent(QMouseEvent *e) {
mouseActionStart(e->globalPos(), e->button()); mouseActionStart(e->globalPos(), e->button());
if (((_mouseAction == MouseAction::Selecting && _selectedItem != nullptr) || (_mouseAction == MouseAction::None)) && _mouseSelectType == TextSelectType::Letters && _mouseActionItem) { if (((_mouseAction == MouseAction::Selecting && _selectedItem != nullptr) || (_mouseAction == MouseAction::None)) && _mouseSelectType == TextSelectType::Letters && _mouseActionItem) {
HistoryStateRequest request; StateRequest request;
request.flags |= Text::StateRequest::Flag::LookupSymbol; request.flags |= Text::StateRequest::Flag::LookupSymbol;
auto dragState = _mouseActionItem->getState(_dragStartPosition, request); auto dragState = _mouseActionItem->textState(_dragStartPosition, request);
if (dragState.cursor == HistoryInTextCursorState) { if (dragState.cursor == CursorState::Text) {
_mouseTextSymbol = dragState.symbol; _mouseTextSymbol = dragState.symbol;
_mouseSelectType = TextSelectType::Words; _mouseSelectType = TextSelectType::Words;
if (_mouseAction == MouseAction::None) { if (_mouseAction == MouseAction::None) {
@ -914,10 +917,10 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
auto mousePos = mapPointToItem( auto mousePos = mapPointToItem(
mapFromGlobal(_mousePosition), mapFromGlobal(_mousePosition),
App::mousedItem()); App::mousedItem());
HistoryStateRequest request; StateRequest request;
request.flags |= Text::StateRequest::Flag::LookupSymbol; request.flags |= Text::StateRequest::Flag::LookupSymbol;
auto dragState = App::mousedItem()->getState(mousePos, request); auto dragState = App::mousedItem()->textState(mousePos, request);
if (dragState.cursor == HistoryInTextCursorState if (dragState.cursor == CursorState::Text
&& base::in_range(dragState.symbol, selFrom, selTo)) { && base::in_range(dragState.symbol, selFrom, selTo)) {
isUponSelected = 1; isUponSelected = 1;
} }
@ -1275,12 +1278,12 @@ void InnerWidget::mouseActionStart(const QPoint &screenPos, Qt::MouseButton butt
_mouseAction = MouseAction::PrepareDrag; _mouseAction = MouseAction::PrepareDrag;
} }
if (_mouseAction == MouseAction::None && _mouseActionItem) { if (_mouseAction == MouseAction::None && _mouseActionItem) {
HistoryTextState dragState; TextState dragState;
if (_trippleClickTimer.isActive() && (screenPos - _trippleClickPoint).manhattanLength() < QApplication::startDragDistance()) { if (_trippleClickTimer.isActive() && (screenPos - _trippleClickPoint).manhattanLength() < QApplication::startDragDistance()) {
HistoryStateRequest request; StateRequest request;
request.flags = Text::StateRequest::Flag::LookupSymbol; request.flags = Text::StateRequest::Flag::LookupSymbol;
dragState = _mouseActionItem->getState(_dragStartPosition, request); dragState = _mouseActionItem->textState(_dragStartPosition, request);
if (dragState.cursor == HistoryInTextCursorState) { if (dragState.cursor == CursorState::Text) {
auto selection = TextSelection { dragState.symbol, dragState.symbol }; auto selection = TextSelection { dragState.symbol, dragState.symbol };
repaintItem(std::exchange(_selectedItem, _mouseActionItem)); repaintItem(std::exchange(_selectedItem, _mouseActionItem));
_selectedText = selection; _selectedText = selection;
@ -1291,14 +1294,14 @@ void InnerWidget::mouseActionStart(const QPoint &screenPos, Qt::MouseButton butt
_trippleClickTimer.callOnce(QApplication::doubleClickInterval()); _trippleClickTimer.callOnce(QApplication::doubleClickInterval());
} }
} else if (App::pressedItem()) { } else if (App::pressedItem()) {
HistoryStateRequest request; StateRequest request;
request.flags = Text::StateRequest::Flag::LookupSymbol; request.flags = Text::StateRequest::Flag::LookupSymbol;
dragState = _mouseActionItem->getState(_dragStartPosition, request); dragState = _mouseActionItem->textState(_dragStartPosition, request);
} }
if (_mouseSelectType != TextSelectType::Paragraphs) { if (_mouseSelectType != TextSelectType::Paragraphs) {
if (App::pressedItem()) { if (App::pressedItem()) {
_mouseTextSymbol = dragState.symbol; _mouseTextSymbol = dragState.symbol;
auto uponSelected = (dragState.cursor == HistoryInTextCursorState); auto uponSelected = (dragState.cursor == CursorState::Text);
if (uponSelected) { if (uponSelected) {
if (!_selectedItem || _selectedItem != _mouseActionItem) { if (!_selectedItem || _selectedItem != _mouseActionItem) {
uponSelected = false; uponSelected = false;
@ -1399,7 +1402,7 @@ void InnerWidget::updateSelected() {
if (item) { if (item) {
App::mousedItem(view); App::mousedItem(view);
itemPoint = mapPointToItem(point, view); itemPoint = mapPointToItem(point, view);
if (view->hasPoint(itemPoint)) { if (view->pointState(itemPoint) != PointState::Outside) {
if (App::hoveredItem() != view) { if (App::hoveredItem() != view) {
repaintItem(App::hoveredItem()); repaintItem(App::hoveredItem());
App::hoveredItem(view); App::hoveredItem(view);
@ -1411,7 +1414,7 @@ void InnerWidget::updateSelected() {
} }
} }
HistoryTextState dragState; TextState dragState;
ClickHandlerHost *lnkhost = nullptr; ClickHandlerHost *lnkhost = nullptr;
auto selectingText = _selectedItem auto selectingText = _selectedItem
&& (view == _mouseActionItem) && (view == _mouseActionItem)
@ -1423,13 +1426,13 @@ void InnerWidget::updateSelected() {
InvokeQueued(this, [this] { performDrag(); }); InvokeQueued(this, [this] { performDrag(); });
} }
} }
HistoryStateRequest request; StateRequest request;
if (_mouseAction == MouseAction::Selecting) { if (_mouseAction == MouseAction::Selecting) {
request.flags |= Text::StateRequest::Flag::LookupSymbol; request.flags |= Text::StateRequest::Flag::LookupSymbol;
} else { } else {
selectingText = false; selectingText = false;
} }
dragState = view->getState(itemPoint, request); dragState = view->textState(itemPoint, request);
lnkhost = view; lnkhost = view;
if (!dragState.link && itemPoint.x() >= st::historyPhotoLeft && itemPoint.x() < st::historyPhotoLeft + st::msgPhotoSize) { if (!dragState.link && itemPoint.x() >= st::historyPhotoLeft && itemPoint.x() < st::historyPhotoLeft + st::msgPhotoSize) {
if (auto message = item->toHistoryMessage()) { if (auto message = item->toHistoryMessage()) {
@ -1459,7 +1462,9 @@ void InnerWidget::updateSelected() {
if (lnkChanged || dragState.cursor != _mouseCursorState) { if (lnkChanged || dragState.cursor != _mouseCursorState) {
Ui::Tooltip::Hide(); Ui::Tooltip::Hide();
} }
if (dragState.link || dragState.cursor == HistoryInDateCursorState || dragState.cursor == HistoryInForwardedCursorState) { if (dragState.link
|| dragState.cursor == CursorState::Date
|| dragState.cursor == CursorState::Forwarded) {
Ui::Tooltip::Show(1000, this); Ui::Tooltip::Show(1000, this);
} }
@ -1468,9 +1473,9 @@ void InnerWidget::updateSelected() {
_mouseCursorState = dragState.cursor; _mouseCursorState = dragState.cursor;
if (dragState.link) { if (dragState.link) {
cursor = style::cur_pointer; cursor = style::cur_pointer;
} else if (_mouseCursorState == HistoryInTextCursorState) { } else if (_mouseCursorState == CursorState::Text) {
cursor = style::cur_text; cursor = style::cur_text;
} else if (_mouseCursorState == HistoryInDateCursorState) { } else if (_mouseCursorState == CursorState::Date) {
// cursor = style::cur_cross; // cursor = style::cur_cross;
} }
} else if (item) { } else if (item) {
@ -1530,10 +1535,10 @@ void InnerWidget::performDrag() {
// if (!_selected.isEmpty() && _selected.cbegin().value() == FullSelection) { // if (!_selected.isEmpty() && _selected.cbegin().value() == FullSelection) {
// uponSelected = _selected.contains(_mouseActionItem); // uponSelected = _selected.contains(_mouseActionItem);
// } else { // } else {
// HistoryStateRequest request; // StateRequest request;
// request.flags |= Text::StateRequest::Flag::LookupSymbol; // request.flags |= Text::StateRequest::Flag::LookupSymbol;
// auto dragState = _mouseActionItem->getState(_dragStartPosition.x(), _dragStartPosition.y(), request); // auto dragState = _mouseActionItem->textState(_dragStartPosition.x(), _dragStartPosition.y(), request);
// uponSelected = (dragState.cursor == HistoryInTextCursorState); // uponSelected = (dragState.cursor == CursorState::Text);
// if (uponSelected) { // if (uponSelected) {
// if (_selected.isEmpty() || // if (_selected.isEmpty() ||
// _selected.cbegin().value() == FullSelection || // _selected.cbegin().value() == FullSelection ||
@ -1584,7 +1589,7 @@ void InnerWidget::performDrag() {
// auto pressedMedia = static_cast<HistoryMedia*>(nullptr); // auto pressedMedia = static_cast<HistoryMedia*>(nullptr);
// if (auto pressedItem = App::pressedItem()) { // if (auto pressedItem = App::pressedItem()) {
// pressedMedia = pressedItem->media(); // pressedMedia = pressedItem->media();
// if (_mouseCursorState == HistoryInDateCursorState // if (_mouseCursorState == CursorState::Date
// || (pressedMedia && pressedMedia->dragItem())) { // || (pressedMedia && pressedMedia->dragItem())) {
// forwardMimeType = qsl("application/x-td-forward"); // forwardMimeType = qsl("application/x-td-forward");
// Auth().data().setMimeForwardIds( // Auth().data().setMimeForwardIds(

View File

@ -7,7 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "history/view/history_view_cursor_state.h"
#include "history/view/history_view_element.h" #include "history/view/history_view_element.h"
#include "history/admin_log/history_admin_log_item.h" #include "history/admin_log/history_admin_log_item.h"
#include "history/admin_log/history_admin_log_section.h" #include "history/admin_log/history_admin_log_section.h"
@ -16,6 +15,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/sender.h" #include "mtproto/sender.h"
#include "base/timer.h" #include "base/timer.h"
namespace HistoryView {
class Element;
struct TextState;
struct StateRequest;
enum class CursorState : char;
enum class PointState : char;
} // namespace HistoryView
namespace Ui { namespace Ui {
class PopupMenu; class PopupMenu;
} // namespace Ui } // namespace Ui
@ -115,6 +122,10 @@ private:
TopToBottom, TopToBottom,
BottomToTop, BottomToTop,
}; };
using TextState = HistoryView::TextState;
using CursorState = HistoryView::CursorState;
using PointState = HistoryView::PointState;
using StateRequest = HistoryView::StateRequest;
void mouseActionStart(const QPoint &screenPos, Qt::MouseButton button); void mouseActionStart(const QPoint &screenPos, Qt::MouseButton button);
void mouseActionUpdate(const QPoint &screenPos); void mouseActionUpdate(const QPoint &screenPos);
@ -228,7 +239,7 @@ private:
QPoint _dragStartPosition; QPoint _dragStartPosition;
QPoint _mousePosition; QPoint _mousePosition;
Element *_mouseActionItem = nullptr; Element *_mouseActionItem = nullptr;
HistoryCursorState _mouseCursorState = HistoryDefaultCursorState; CursorState _mouseCursorState = CursorState();
uint16 _mouseTextSymbol = 0; uint16 _mouseTextSymbol = 0;
bool _pressWasInactive = false; bool _pressWasInactive = false;

View File

@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item_text.h" #include "history/history_item_text.h"
#include "history/view/history_view_message.h" #include "history/view/history_view_message.h"
#include "history/view/history_view_service_message.h" #include "history/view/history_view_service_message.h"
#include "history/view/history_view_cursor_state.h"
#include "ui/text_options.h" #include "ui/text_options.h"
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
#include "window/window_controller.h" #include "window/window_controller.h"
@ -131,7 +132,8 @@ HistoryInner::HistoryInner(
, _migrated(history->migrateFrom()) , _migrated(history->migrateFrom())
, _widget(historyWidget) , _widget(historyWidget)
, _scroll(scroll) , _scroll(scroll)
, _scrollDateCheck([this] { onScrollDateCheck(); }) { , _scrollDateCheck([this] { scrollDateCheck(); })
, _scrollDateHideTimer([this] { scrollDateHideByTimer(); }) {
_touchSelectTimer.setSingleShot(true); _touchSelectTimer.setSingleShot(true);
connect(&_touchSelectTimer, SIGNAL(timeout()), this, SLOT(onTouchSelect())); connect(&_touchSelectTimer, SIGNAL(timeout()), this, SLOT(onTouchSelect()));
@ -140,8 +142,6 @@ HistoryInner::HistoryInner(
_trippleClickTimer.setSingleShot(true); _trippleClickTimer.setSingleShot(true);
connect(&_scrollDateHideTimer, SIGNAL(timeout()), this, SLOT(onScrollDateHideByTimer()));
notifyIsBotChanged(); notifyIsBotChanged();
setMouseTracking(true); setMouseTracking(true);
@ -166,9 +166,15 @@ HistoryInner::HistoryInner(
mouseActionCancel(); mouseActionCancel();
}, lifetime()); }, lifetime());
Auth().data().viewRepaintRequest( Auth().data().viewRepaintRequest(
) | rpl::start_with_next( ) | rpl::start_with_next([this](not_null<const Element*> view) {
[this](auto view) { repaintItem(view); }, repaintItem(view);
lifetime()); }, lifetime());
Auth().data().viewLayoutChanged(
) | rpl::filter([](not_null<const Element*> view) {
return (view == view->data()->mainView()) && view->isUnderCursor();
}) | rpl::start_with_next([this](not_null<const Element*> view) {
mouseActionUpdate();
}, lifetime());
} }
void HistoryInner::messagesReceived(PeerData *peer, const QVector<MTPMessage> &messages) { void HistoryInner::messagesReceived(PeerData *peer, const QVector<MTPMessage> &messages) {
@ -423,6 +429,10 @@ void HistoryInner::enumerateDates(Method method) {
TextSelection HistoryInner::computeRenderSelection( TextSelection HistoryInner::computeRenderSelection(
not_null<const SelectedItems*> selected, not_null<const SelectedItems*> selected,
not_null<Element*> view) const { not_null<Element*> view) const {
if (view->isHiddenByGroup()) {
return TextSelection();
}
const auto item = view->data();
const auto itemSelection = [&](not_null<HistoryItem*> item) { const auto itemSelection = [&](not_null<HistoryItem*> item) {
auto i = selected->find(item); auto i = selected->find(item);
if (i != selected->end()) { if (i != selected->end()) {
@ -430,32 +440,30 @@ TextSelection HistoryInner::computeRenderSelection(
} }
return TextSelection(); return TextSelection();
}; };
// #TODO group selection const auto result = itemSelection(item);
//if (const auto group = view->Get<HistoryView::Group>()) { if (result != TextSelection() && result != FullSelection) {
// if (group->leader != view) { return result;
// return TextSelection(); }
// } if (const auto group = Auth().data().groups().find(item)) {
// auto result = TextSelection(); auto parts = TextSelection();
// auto allFullSelected = true; auto allFullSelected = true;
// const auto count = int(group->others.size()); const auto count = int(group->items.size());
// for (auto i = 0; i != count; ++i) { for (auto i = 0; i != count; ++i) {
// if (itemSelection(group->others[i]->data()) == FullSelection) { const auto part = group->items[i];
// result = AddGroupItemSelection(result, i); const auto selection = itemSelection(part);
// } else { if (part == item
// allFullSelected = false; && selection != FullSelection
// } && selection != TextSelection()) {
// } return selection;
// const auto leaderSelection = itemSelection(view->data()); } else if (selection == FullSelection) {
// if (leaderSelection == FullSelection) { parts = AddGroupItemSelection(parts, i);
// return allFullSelected } else {
// ? FullSelection allFullSelected = false;
// : AddGroupItemSelection(result, count); }
// } else if (leaderSelection != TextSelection()) { }
// return leaderSelection; return allFullSelected ? FullSelection : parts;
// } }
// return result; return itemSelection(item);
//}
return itemSelection(view->data());
} }
TextSelection HistoryInner::itemRenderSelection( TextSelection HistoryInner::itemRenderSelection(
@ -894,7 +902,7 @@ void HistoryInner::mouseMoveEvent(QMouseEvent *e) {
void HistoryInner::mouseActionUpdate(const QPoint &screenPos) { void HistoryInner::mouseActionUpdate(const QPoint &screenPos) {
_mousePosition = screenPos; _mousePosition = screenPos;
onUpdateSelected(); mouseActionUpdate();
} }
void HistoryInner::touchScrollUpdated(const QPoint &screenPos) { void HistoryInner::touchScrollUpdated(const QPoint &screenPos) {
@ -958,12 +966,12 @@ void HistoryInner::mouseActionStart(const QPoint &screenPos, Qt::MouseButton but
} }
} }
if (_mouseAction == MouseAction::None && mouseActionView) { if (_mouseAction == MouseAction::None && mouseActionView) {
HistoryTextState dragState; TextState dragState;
if (_trippleClickTimer.isActive() && (screenPos - _trippleClickPoint).manhattanLength() < QApplication::startDragDistance()) { if (_trippleClickTimer.isActive() && (screenPos - _trippleClickPoint).manhattanLength() < QApplication::startDragDistance()) {
HistoryStateRequest request; StateRequest request;
request.flags = Text::StateRequest::Flag::LookupSymbol; request.flags = Text::StateRequest::Flag::LookupSymbol;
dragState = mouseActionView->getState(_dragStartPosition, request); dragState = mouseActionView->textState(_dragStartPosition, request);
if (dragState.cursor == HistoryInTextCursorState) { if (dragState.cursor == CursorState::Text) {
TextSelection selStatus = { dragState.symbol, dragState.symbol }; TextSelection selStatus = { dragState.symbol, dragState.symbol };
if (selStatus != FullSelection && (_selected.empty() || _selected.cbegin()->second != FullSelection)) { if (selStatus != FullSelection && (_selected.empty() || _selected.cbegin()->second != FullSelection)) {
if (!_selected.empty()) { if (!_selected.empty()) {
@ -979,14 +987,14 @@ void HistoryInner::mouseActionStart(const QPoint &screenPos, Qt::MouseButton but
} }
} }
} else if (App::pressedItem()) { } else if (App::pressedItem()) {
HistoryStateRequest request; StateRequest request;
request.flags = Text::StateRequest::Flag::LookupSymbol; request.flags = Text::StateRequest::Flag::LookupSymbol;
dragState = mouseActionView->getState(_dragStartPosition, request); dragState = mouseActionView->textState(_dragStartPosition, request);
} }
if (_mouseSelectType != TextSelectType::Paragraphs) { if (_mouseSelectType != TextSelectType::Paragraphs) {
if (App::pressedItem()) { if (App::pressedItem()) {
_mouseTextSymbol = dragState.symbol; _mouseTextSymbol = dragState.symbol;
bool uponSelected = (dragState.cursor == HistoryInTextCursorState); bool uponSelected = (dragState.cursor == CursorState::Text);
if (uponSelected) { if (uponSelected) {
if (_selected.empty() if (_selected.empty()
|| _selected.cbegin()->second == FullSelection || _selected.cbegin()->second == FullSelection
@ -1002,7 +1010,8 @@ void HistoryInner::mouseActionStart(const QPoint &screenPos, Qt::MouseButton but
if (uponSelected) { if (uponSelected) {
_mouseAction = MouseAction::PrepareDrag; // start text drag _mouseAction = MouseAction::PrepareDrag; // start text drag
} else if (!_pressWasInactive) { } else if (!_pressWasInactive) {
if (dynamic_cast<HistorySticker*>(App::pressedItem()->media()) || _mouseCursorState == HistoryInDateCursorState) { if (dynamic_cast<HistorySticker*>(App::pressedItem()->media())
|| _mouseCursorState == CursorState::Date) {
_mouseAction = MouseAction::PrepareDrag; // start sticker drag or by-date drag _mouseAction = MouseAction::PrepareDrag; // start sticker drag or by-date drag
} else { } else {
if (dragState.afterSymbol) ++_mouseTextSymbol; if (dragState.afterSymbol) ++_mouseTextSymbol;
@ -1055,10 +1064,10 @@ void HistoryInner::performDrag() {
uponSelected = _dragStateItem uponSelected = _dragStateItem
&& (_selected.find(_dragStateItem) != _selected.cend()); && (_selected.find(_dragStateItem) != _selected.cend());
} else { } else {
HistoryStateRequest request; StateRequest request;
request.flags |= Text::StateRequest::Flag::LookupSymbol; request.flags |= Text::StateRequest::Flag::LookupSymbol;
auto dragState = mouseActionView->getState(_dragStartPosition, request); auto dragState = mouseActionView->textState(_dragStartPosition, request);
uponSelected = (dragState.cursor == HistoryInTextCursorState); uponSelected = (dragState.cursor == CursorState::Text);
if (uponSelected) { if (uponSelected) {
if (_selected.empty() if (_selected.empty()
|| _selected.cbegin()->second == FullSelection || _selected.cbegin()->second == FullSelection
@ -1108,7 +1117,7 @@ void HistoryInner::performDrag() {
auto pressedMedia = static_cast<HistoryMedia*>(nullptr); auto pressedMedia = static_cast<HistoryMedia*>(nullptr);
if (auto pressedItem = App::pressedItem()) { if (auto pressedItem = App::pressedItem()) {
pressedMedia = pressedItem->media(); pressedMedia = pressedItem->media();
if (_mouseCursorState == HistoryInDateCursorState if (_mouseCursorState == CursorState::Date
|| (pressedMedia && pressedMedia->dragItem())) { || (pressedMedia && pressedMedia->dragItem())) {
Auth().data().setMimeForwardIds( Auth().data().setMimeForwardIds(
Auth().data().itemOrItsGroup(pressedItem->data())); Auth().data().itemOrItsGroup(pressedItem->data()));
@ -1173,10 +1182,12 @@ void HistoryInner::itemRemoved(not_null<const HistoryItem*> item) {
_dragSelTo = nullptr; _dragSelTo = nullptr;
update(); update();
} }
onUpdateSelected(); mouseActionUpdate();
} }
void HistoryInner::mouseActionFinish(const QPoint &screenPos, Qt::MouseButton button) { void HistoryInner::mouseActionFinish(
const QPoint &screenPos,
Qt::MouseButton button) {
mouseActionUpdate(screenPos); mouseActionUpdate(screenPos);
auto activated = ClickHandler::unpressed(); auto activated = ClickHandler::unpressed();
@ -1290,10 +1301,10 @@ void HistoryInner::mouseDoubleClickEvent(QMouseEvent *e) {
|| (_mouseAction == MouseAction::None || (_mouseAction == MouseAction::None
&& (_selected.empty() && (_selected.empty()
|| _selected.cbegin()->second != FullSelection)))) { || _selected.cbegin()->second != FullSelection)))) {
HistoryStateRequest request; StateRequest request;
request.flags |= Text::StateRequest::Flag::LookupSymbol; request.flags |= Text::StateRequest::Flag::LookupSymbol;
auto dragState = mouseActionView->getState(_dragStartPosition, request); auto dragState = mouseActionView->textState(_dragStartPosition, request);
if (dragState.cursor == HistoryInTextCursorState) { if (dragState.cursor == CursorState::Text) {
_mouseTextSymbol = dragState.symbol; _mouseTextSymbol = dragState.symbol;
_mouseSelectType = TextSelectType::Words; _mouseSelectType = TextSelectType::Words;
if (_mouseAction == MouseAction::None) { if (_mouseAction == MouseAction::None) {
@ -1342,10 +1353,12 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
hasSelected = (selTo > selFrom) ? 1 : 0; hasSelected = (selTo > selFrom) ? 1 : 0;
if (App::mousedItem() && App::mousedItem() == App::hoveredItem()) { if (App::mousedItem() && App::mousedItem() == App::hoveredItem()) {
auto mousePos = mapPointToItem(mapFromGlobal(_mousePosition), App::mousedItem()); auto mousePos = mapPointToItem(mapFromGlobal(_mousePosition), App::mousedItem());
HistoryStateRequest request; StateRequest request;
request.flags |= Text::StateRequest::Flag::LookupSymbol; request.flags |= Text::StateRequest::Flag::LookupSymbol;
auto dragState = App::mousedItem()->getState(mousePos, request); auto dragState = App::mousedItem()->textState(mousePos, request);
if (dragState.cursor == HistoryInTextCursorState && dragState.symbol >= selFrom && dragState.symbol < selTo) { if (dragState.cursor == CursorState::Text
&& dragState.symbol >= selFrom
&& dragState.symbol < selTo) {
isUponSelected = 1; isUponSelected = 1;
} }
} }
@ -1397,7 +1410,11 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
const auto item = _dragStateItem; const auto item = _dragStateItem;
const auto itemId = item ? item->fullId() : FullMsgId(); const auto itemId = item ? item->fullId() : FullMsgId();
if (isUponSelected > 0) { if (isUponSelected > 0) {
_menu->addAction(lang((isUponSelected > 1) ? lng_context_copy_selected_items : lng_context_copy_selected), this, SLOT(copySelectedText())); _menu->addAction(
lang((isUponSelected > 1)
? lng_context_copy_selected_items
: lng_context_copy_selected),
[=] { copySelectedText(); });
} }
addItemActions(item); addItemActions(item);
if (lnkPhoto) { if (lnkPhoto) {
@ -1503,7 +1520,11 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
const auto msg = dynamic_cast<HistoryMessage*>(item); const auto msg = dynamic_cast<HistoryMessage*>(item);
if (isUponSelected > 0) { if (isUponSelected > 0) {
_menu->addAction(lang((isUponSelected > 1) ? lng_context_copy_selected_items : lng_context_copy_selected), this, SLOT(copySelectedText())); _menu->addAction(
lang((isUponSelected > 1)
? lng_context_copy_selected_items
: lng_context_copy_selected),
[=] { copySelectedText(); });
addItemActions(item); addItemActions(item);
} else { } else {
addItemActions(item); addItemActions(item);
@ -1724,7 +1745,7 @@ void HistoryInner::copyContextText(FullMsgId itemId) {
} }
void HistoryInner::resizeEvent(QResizeEvent *e) { void HistoryInner::resizeEvent(QResizeEvent *e) {
onUpdateSelected(); mouseActionUpdate();
} }
TextWithEntities HistoryInner::getSelectedText() const { TextWithEntities HistoryInner::getSelectedText() const {
@ -1986,7 +2007,7 @@ void HistoryInner::visibleAreaUpdated(int top, int bottom) {
if (scrolledUp) { if (scrolledUp) {
_scrollDateCheck.call(); _scrollDateCheck.call();
} else { } else {
onScrollDateHideByTimer(); scrollDateHideByTimer();
} }
} }
@ -1994,7 +2015,7 @@ bool HistoryInner::displayScrollDate() const {
return (_visibleAreaTop <= height() - 2 * (_visibleAreaBottom - _visibleAreaTop)); return (_visibleAreaTop <= height() - 2 * (_visibleAreaBottom - _visibleAreaTop));
} }
void HistoryInner::onScrollDateCheck() { void HistoryInner::scrollDateCheck() {
if (!_history) return; if (!_history) return;
auto newScrollDateItem = _history->scrollTopItem ? _history->scrollTopItem : (_migrated ? _migrated->scrollTopItem : nullptr); auto newScrollDateItem = _history->scrollTopItem ? _history->scrollTopItem : (_migrated ? _migrated->scrollTopItem : nullptr);
@ -2015,12 +2036,12 @@ void HistoryInner::onScrollDateCheck() {
} }
_scrollDateLastItem = newScrollDateItem; _scrollDateLastItem = newScrollDateItem;
_scrollDateLastItemTop = newScrollDateItemTop; _scrollDateLastItemTop = newScrollDateItemTop;
_scrollDateHideTimer.start(kScrollDateHideTimeout); _scrollDateHideTimer.callOnce(kScrollDateHideTimeout);
} }
} }
void HistoryInner::onScrollDateHideByTimer() { void HistoryInner::scrollDateHideByTimer() {
_scrollDateHideTimer.stop(); _scrollDateHideTimer.cancel();
if (!_scrollDateLink || ClickHandler::getPressed() != _scrollDateLink) { if (!_scrollDateLink || ClickHandler::getPressed() != _scrollDateLink) {
scrollDateHide(); scrollDateHide();
} }
@ -2036,7 +2057,7 @@ void HistoryInner::keepScrollDateForNow() {
if (!_scrollDateShown && _scrollDateLastItem && _scrollDateOpacity.animating()) { if (!_scrollDateShown && _scrollDateLastItem && _scrollDateOpacity.animating()) {
toggleScrollDateShown(); toggleScrollDateShown();
} }
_scrollDateHideTimer.start(kScrollDateHideTimeout); _scrollDateHideTimer.callOnce(kScrollDateHideTimeout);
} }
void HistoryInner::toggleScrollDateShown() { void HistoryInner::toggleScrollDateShown() {
@ -2261,7 +2282,7 @@ void HistoryInner::onTouchSelect() {
mouseActionStart(_touchPos, Qt::LeftButton); mouseActionStart(_touchPos, Qt::LeftButton);
} }
void HistoryInner::onUpdateSelected() { void HistoryInner::mouseActionUpdate() {
if (!_history || hasPendingResizedItems()) { if (!_history || hasPendingResizedItems()) {
return; return;
} }
@ -2282,7 +2303,7 @@ void HistoryInner::onUpdateSelected() {
App::mousedItem(view); App::mousedItem(view);
m = mapPointToItem(point, view); m = mapPointToItem(point, view);
if (view->hasPoint(m)) { if (view->pointState(m) != PointState::Outside) {
if (App::hoveredItem() != view) { if (App::hoveredItem() != view) {
repaintItem(App::hoveredItem()); repaintItem(App::hoveredItem());
App::hoveredItem(view); App::hoveredItem(view);
@ -2297,7 +2318,7 @@ void HistoryInner::onUpdateSelected() {
mouseActionCancel(); mouseActionCancel();
} }
HistoryTextState dragState; TextState dragState;
ClickHandlerHost *lnkhost = nullptr; ClickHandlerHost *lnkhost = nullptr;
auto selectingText = (item == _mouseActionItem) auto selectingText = (item == _mouseActionItem)
&& (view == App::hoveredItem()) && (view == App::hoveredItem())
@ -2305,7 +2326,7 @@ void HistoryInner::onUpdateSelected() {
&& (_selected.cbegin()->second != FullSelection); && (_selected.cbegin()->second != FullSelection);
if (point.y() < _historyPaddingTop) { if (point.y() < _historyPaddingTop) {
if (_botAbout && !_botAbout->info->text.isEmpty() && _botAbout->height > 0) { if (_botAbout && !_botAbout->info->text.isEmpty() && _botAbout->height > 0) {
dragState = HistoryTextState(nullptr, _botAbout->info->text.getState( dragState = TextState(nullptr, _botAbout->info->text.getState(
point - _botAbout->rect.topLeft() - QPoint(st::msgPadding.left(), st::msgPadding.top() + st::botDescSkip + st::msgNameFont->height), point - _botAbout->rect.topLeft() - QPoint(st::msgPadding.left(), st::msgPadding.top() + st::botDescSkip + st::msgNameFont->height),
_botAbout->width)); _botAbout->width));
_dragStateItem = App::histItemById(dragState.itemId); _dragStateItem = App::histItemById(dragState.itemId);
@ -2363,7 +2384,7 @@ void HistoryInner::onUpdateSelected() {
} else { } else {
static_cast<DateClickHandler*>(_scrollDateLink.get())->setDate(item->date.date()); static_cast<DateClickHandler*>(_scrollDateLink.get())->setDate(item->date.date());
} }
dragState = HistoryTextState( dragState = TextState(
nullptr, nullptr,
_scrollDateLink); _scrollDateLink);
_dragStateItem = App::histItemById(dragState.itemId); _dragStateItem = App::histItemById(dragState.itemId);
@ -2375,13 +2396,13 @@ void HistoryInner::onUpdateSelected() {
return true; return true;
}); });
if (!dragState.link) { if (!dragState.link) {
HistoryStateRequest request; StateRequest request;
if (_mouseAction == MouseAction::Selecting) { if (_mouseAction == MouseAction::Selecting) {
request.flags |= Text::StateRequest::Flag::LookupSymbol; request.flags |= Text::StateRequest::Flag::LookupSymbol;
} else { } else {
selectingText = false; selectingText = false;
} }
dragState = view->getState(m, request); dragState = view->textState(m, request);
_dragStateItem = App::histItemById(dragState.itemId); _dragStateItem = App::histItemById(dragState.itemId);
lnkhost = view; lnkhost = view;
if (!dragState.link && m.x() >= st::historyPhotoLeft && m.x() < st::historyPhotoLeft + st::msgPhotoSize) { if (!dragState.link && m.x() >= st::historyPhotoLeft && m.x() < st::historyPhotoLeft + st::msgPhotoSize) {
@ -2398,7 +2419,7 @@ void HistoryInner::onUpdateSelected() {
const auto message = view->data()->toHistoryMessage(); const auto message = view->data()->toHistoryMessage();
Assert(message != nullptr); Assert(message != nullptr);
dragState = HistoryTextState( dragState = TextState(
nullptr, nullptr,
message->displayFrom()->openLink()); message->displayFrom()->openLink());
_dragStateItem = App::histItemById(dragState.itemId); _dragStateItem = App::histItemById(dragState.itemId);
@ -2416,7 +2437,9 @@ void HistoryInner::onUpdateSelected() {
if (lnkChanged || dragState.cursor != _mouseCursorState) { if (lnkChanged || dragState.cursor != _mouseCursorState) {
Ui::Tooltip::Hide(); Ui::Tooltip::Hide();
} }
if (dragState.link || dragState.cursor == HistoryInDateCursorState || dragState.cursor == HistoryInForwardedCursorState) { if (dragState.link
|| dragState.cursor == CursorState::Date
|| dragState.cursor == CursorState::Forwarded) {
Ui::Tooltip::Show(1000, this); Ui::Tooltip::Show(1000, this);
} }
@ -2425,9 +2448,9 @@ void HistoryInner::onUpdateSelected() {
_mouseCursorState = dragState.cursor; _mouseCursorState = dragState.cursor;
if (dragState.link) { if (dragState.link) {
cur = style::cur_pointer; cur = style::cur_pointer;
} else if (_mouseCursorState == HistoryInTextCursorState && (_selected.empty() || _selected.cbegin()->second != FullSelection)) { } else if (_mouseCursorState == CursorState::Text && (_selected.empty() || _selected.cbegin()->second != FullSelection)) {
cur = style::cur_text; cur = style::cur_text;
} else if (_mouseCursorState == HistoryInDateCursorState) { } else if (_mouseCursorState == CursorState::Date) {
//cur = style::cur_cross; //cur = style::cur_cross;
} }
} else if (item) { } else if (item) {
@ -2457,7 +2480,8 @@ void HistoryInner::onUpdateSelected() {
auto selectingDown = (itemTop(_mouseActionItem) < itemTop(item)) || (_mouseActionItem == item && _dragStartPosition.y() < m.y()); auto selectingDown = (itemTop(_mouseActionItem) < itemTop(item)) || (_mouseActionItem == item && _dragStartPosition.y() < m.y());
auto dragSelFrom = _mouseActionItem->mainView(); auto dragSelFrom = _mouseActionItem->mainView();
auto dragSelTo = view; auto dragSelTo = view;
if (!dragSelFrom->hasPoint(_dragStartPosition)) { // maybe exclude dragSelFrom // Maybe exclude dragSelFrom.
if (dragSelFrom->pointState(_dragStartPosition) == PointState::Outside) {
if (selectingDown) { if (selectingDown) {
if (_dragStartPosition.y() >= dragSelFrom->height() - dragSelFrom->marginBottom() || ((view == dragSelFrom) && (m.y() < _dragStartPosition.y() + QApplication::startDragDistance() || m.y() < dragSelFrom->marginTop()))) { if (_dragStartPosition.y() >= dragSelFrom->height() - dragSelFrom->marginBottom() || ((view == dragSelFrom) && (m.y() < _dragStartPosition.y() + QApplication::startDragDistance() || m.y() < dragSelFrom->marginTop()))) {
dragSelFrom = (dragSelFrom != dragSelTo) dragSelFrom = (dragSelFrom != dragSelTo)
@ -2743,9 +2767,7 @@ void HistoryInner::changeSelectionAsGroup(
: SelectAction::Select; : SelectAction::Select;
} }
auto total = int(toItems->size()); auto total = int(toItems->size());
const auto add = (action == SelectAction::Select); const auto canSelect = [&] {
const auto adding = [&] {
for (const auto other : group->items) { for (const auto other : group->items) {
if (!goodForSelection(toItems, other, total)) { if (!goodForSelection(toItems, other, total)) {
return false; return false;
@ -2753,7 +2775,7 @@ void HistoryInner::changeSelectionAsGroup(
} }
return (total <= MaxSelectedItems); return (total <= MaxSelectedItems);
}(); }();
if (adding) { if (action == SelectAction::Select && canSelect) {
for (const auto other : group->items) { for (const auto other : group->items) {
addToSelection(toItems, other); addToSelection(toItems, other);
} }
@ -2880,7 +2902,8 @@ void HistoryInner::applyDragSelection(
} }
QString HistoryInner::tooltipText() const { QString HistoryInner::tooltipText() const {
if (_mouseCursorState == HistoryInDateCursorState && _mouseAction == MouseAction::None) { if (_mouseCursorState == CursorState::Date
&& _mouseAction == MouseAction::None) {
if (const auto view = App::hoveredItem()) { if (const auto view = App::hoveredItem()) {
auto dateText = view->data()->date.toString( auto dateText = view->data()->date.toString(
QLocale::system().dateTimeFormat(QLocale::LongFormat)); QLocale::system().dateTimeFormat(QLocale::LongFormat));
@ -2893,7 +2916,8 @@ QString HistoryInner::tooltipText() const {
} }
return dateText; return dateText;
} }
} else if (_mouseCursorState == HistoryInForwardedCursorState && _mouseAction == MouseAction::None) { } else if (_mouseCursorState == CursorState::Forwarded
&& _mouseAction == MouseAction::None) {
if (const auto view = App::hoveredItem()) { if (const auto view = App::hoveredItem()) {
if (const auto forwarded = view->data()->Get<HistoryMessageForwarded>()) { if (const auto forwarded = view->data()->Get<HistoryMessageForwarded>()) {
return forwarded->text.originalText(AllTextSelection, ExpandLinksNone); return forwarded->text.originalText(AllTextSelection, ExpandLinksNone);

View File

@ -7,14 +7,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "base/timer.h"
#include "ui/rp_widget.h" #include "ui/rp_widget.h"
#include "ui/widgets/tooltip.h" #include "ui/widgets/tooltip.h"
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
#include "history/view/history_view_cursor_state.h"
#include "history/view/history_view_top_bar_widget.h" #include "history/view/history_view_top_bar_widget.h"
namespace HistoryView { namespace HistoryView {
class ElementDelegate; class ElementDelegate;
struct TextState;
struct StateRequest;
enum class CursorState : char;
enum class PointState : char;
} // namespace HistoryView } // namespace HistoryView
namespace Window { namespace Window {
@ -113,18 +117,11 @@ protected:
void contextMenuEvent(QContextMenuEvent *e) override; void contextMenuEvent(QContextMenuEvent *e) override;
public slots: public slots:
void onUpdateSelected();
void onParentGeometryChanged(); void onParentGeometryChanged();
void copySelectedText();
void onTouchSelect(); void onTouchSelect();
void onTouchScrollTimer(); void onTouchScrollTimer();
private slots:
void onScrollDateCheck();
void onScrollDateHideByTimer();
private: private:
class BotAbout; class BotAbout;
using SelectedItems = std::map<HistoryItem*, TextSelection, std::less<>>; using SelectedItems = std::map<HistoryItem*, TextSelection, std::less<>>;
@ -144,6 +141,11 @@ private:
TopToBottom, TopToBottom,
BottomToTop, BottomToTop,
}; };
using CursorState = HistoryView::CursorState;
using PointState = HistoryView::PointState;
using TextState = HistoryView::TextState;
using StateRequest = HistoryView::StateRequest;
// This function finds all history items that are displayed and calls template method // 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. // for each found message (in given direction) in the passed history with passed top offset.
// //
@ -180,8 +182,11 @@ private:
template <typename Method> template <typename Method>
void enumerateDates(Method method); void enumerateDates(Method method);
void scrollDateCheck();
void scrollDateHideByTimer();
bool canHaveFromUserpics() const; bool canHaveFromUserpics() const;
void mouseActionStart(const QPoint &screenPos, Qt::MouseButton button); void mouseActionStart(const QPoint &screenPos, Qt::MouseButton button);
void mouseActionUpdate();
void mouseActionUpdate(const QPoint &screenPos); void mouseActionUpdate(const QPoint &screenPos);
void mouseActionFinish(const QPoint &screenPos, Qt::MouseButton button); void mouseActionFinish(const QPoint &screenPos, Qt::MouseButton button);
void mouseActionCancel(); void mouseActionCancel();
@ -265,6 +270,7 @@ private:
void deleteItem(not_null<HistoryItem*> item); void deleteItem(not_null<HistoryItem*> item);
void deleteItem(FullMsgId itemId); void deleteItem(FullMsgId itemId);
void deleteAsGroup(FullMsgId itemId); void deleteAsGroup(FullMsgId itemId);
void copySelectedText();
// Does any of the shown histories has this flag set. // Does any of the shown histories has this flag set.
bool hasPendingResizedItems() const; bool hasPendingResizedItems() const;
@ -301,7 +307,7 @@ private:
QPoint _mousePosition; QPoint _mousePosition;
HistoryItem *_mouseActionItem = nullptr; HistoryItem *_mouseActionItem = nullptr;
HistoryItem *_dragStateItem = nullptr; HistoryItem *_dragStateItem = nullptr;
HistoryCursorState _mouseCursorState = HistoryDefaultCursorState; CursorState _mouseCursorState = CursorState();
uint16 _mouseTextSymbol = 0; uint16 _mouseTextSymbol = 0;
bool _pressWasInactive = false; bool _pressWasInactive = false;
@ -338,7 +344,7 @@ private:
bool _scrollDateShown = false; bool _scrollDateShown = false;
Animation _scrollDateOpacity; Animation _scrollDateOpacity;
SingleQueuedInvokation _scrollDateCheck; SingleQueuedInvokation _scrollDateCheck;
SingleTimer _scrollDateHideTimer; base::Timer _scrollDateHideTimer;
Element *_scrollDateLastItem = nullptr; Element *_scrollDateLastItem = nullptr;
int _scrollDateLastItemTop = 0; int _scrollDateLastItemTop = 0;
ClickHandlerPtr _scrollDateLink; ClickHandlerPtr _scrollDateLink;

View File

@ -10,7 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/runtime_composer.h" #include "base/runtime_composer.h"
#include "base/flags.h" #include "base/flags.h"
#include "base/value_ordering.h" #include "base/value_ordering.h"
#include "history/view/history_view_cursor_state.h"
enum class UnreadMentionType; enum class UnreadMentionType;
struct HistoryMessageReplyMarkup; struct HistoryMessageReplyMarkup;
@ -47,6 +46,10 @@ class Controller;
} // namespace Window } // namespace Window
namespace HistoryView { namespace HistoryView {
struct TextState;
struct StateRequest;
enum class CursorState : char;
enum class PointState : char;
enum class Context : char; enum class Context : char;
class ElementDelegate; class ElementDelegate;
} // namespace HistoryView } // namespace HistoryView

View File

@ -521,7 +521,7 @@ void ReplyKeyboard::paint(Painter &p, int outerWidth, const QRect &clip, TimeMs
} }
} }
ClickHandlerPtr ReplyKeyboard::getState(QPoint point) const { ClickHandlerPtr ReplyKeyboard::getLink(QPoint point) const {
Assert(_width > 0); Assert(_width > 0);
for_const (auto &row, _rows) { for_const (auto &row, _rows) {

View File

@ -274,7 +274,7 @@ public:
int naturalHeight() const; int naturalHeight() const;
void paint(Painter &p, int outerWidth, const QRect &clip, TimeMs ms) const; void paint(Painter &p, int outerWidth, const QRect &clip, TimeMs ms) const;
ClickHandlerPtr getState(QPoint point) const; ClickHandlerPtr getLink(QPoint point) const;
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active); void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active);
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed); void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed);

View File

@ -9,9 +9,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item.h" #include "history/history_item.h"
#include "history/view/history_view_element.h" #include "history/view/history_view_element.h"
#include "history/view/history_view_cursor_state.h"
#include "storage/storage_shared_media.h" #include "storage/storage_shared_media.h"
#include "ui/text_options.h" #include "ui/text_options.h"
namespace {
using PointState = HistoryView::PointState;
using TextState = HistoryView::TextState;
} // namespace
Storage::SharedMediaTypesMask HistoryMedia::sharedMediaTypes() const { Storage::SharedMediaTypesMask HistoryMedia::sharedMediaTypes() const {
return {}; return {};
} }
@ -54,9 +62,15 @@ TextSelection HistoryMedia::unskipSelection(TextSelection selection) const {
fullSelectionLength()); fullSelectionLength());
} }
HistoryTextState HistoryMedia::getStateGrouped( PointState HistoryMedia::pointState(QPoint point) const {
return QRect(0, 0, width(), height()).contains(point)
? PointState::Inside
: PointState::Outside;
}
TextState HistoryMedia::getStateGrouped(
const QRect &geometry, const QRect &geometry,
QPoint point, QPoint point,
HistoryStateRequest request) const { StateRequest request) const {
Unexpected("Grouping method call."); Unexpected("Grouping method call.");
} }

View File

@ -10,8 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_object.h" #include "history/view/history_view_object.h"
struct HistoryMessageEdited; struct HistoryMessageEdited;
struct HistoryTextState;
struct HistoryStateRequest;
struct TextSelection; struct TextSelection;
namespace base { namespace base {
@ -24,6 +22,14 @@ enum class SharedMediaType : char;
using SharedMediaTypesMask = base::enum_mask<SharedMediaType>; using SharedMediaTypesMask = base::enum_mask<SharedMediaType>;
} // namespace Storage } // namespace Storage
namespace HistoryView {
enum class PointState : char;
enum class CursorState : char;
enum class InfoDisplayType : char;
struct TextState;
struct StateRequest;
} // namespace HistoryView
enum class MediaInBubbleState { enum class MediaInBubbleState {
None, None,
Top, Top,
@ -53,6 +59,9 @@ enum HistoryMediaType : char {
class HistoryMedia : public HistoryView::Object { class HistoryMedia : public HistoryView::Object {
public: public:
using Element = HistoryView::Element; using Element = HistoryView::Element;
using PointState = HistoryView::PointState;
using TextState = HistoryView::TextState;
using StateRequest = HistoryView::StateRequest;
HistoryMedia(not_null<Element*> parent) : _parent(parent) { HistoryMedia(not_null<Element*> parent) : _parent(parent) {
} }
@ -63,16 +72,9 @@ public:
return TextWithEntities(); return TextWithEntities();
} }
bool hasPoint(QPoint point) const {
return QRect(0, 0, width(), height()).contains(point);
}
virtual bool isDisplayed() const; virtual bool isDisplayed() const;
virtual void updateNeedBubbleState() { virtual void updateNeedBubbleState() {
} }
virtual bool isAboveMessage() const {
return false;
}
virtual bool hasTextForCopy() const { virtual bool hasTextForCopy() const {
return false; return false;
} }
@ -85,7 +87,8 @@ public:
virtual void refreshParentId(not_null<HistoryItem*> realParent) { virtual void refreshParentId(not_null<HistoryItem*> realParent) {
} }
virtual void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const = 0; virtual void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const = 0;
virtual HistoryTextState getState(QPoint point, HistoryStateRequest request) const = 0; virtual PointState pointState(QPoint point) const;
virtual TextState textState(QPoint point, StateRequest request) const = 0;
virtual void updatePressed(QPoint point) { virtual void updatePressed(QPoint point) {
} }
@ -156,10 +159,10 @@ public:
not_null<QPixmap*> cache) const { not_null<QPixmap*> cache) const {
Unexpected("Grouping method call."); Unexpected("Grouping method call.");
} }
virtual HistoryTextState getStateGrouped( virtual TextState getStateGrouped(
const QRect &geometry, const QRect &geometry,
QPoint point, QPoint point,
HistoryStateRequest request) const; StateRequest request) const;
virtual std::unique_ptr<HistoryMedia> takeLastFromGroup() { virtual std::unique_ptr<HistoryMedia> takeLastFromGroup() {
return nullptr; return nullptr;
} }
@ -236,6 +239,9 @@ public:
virtual ~HistoryMedia() = default; virtual ~HistoryMedia() = default;
protected: protected:
using CursorState = HistoryView::CursorState;
using InfoDisplayType = HistoryView::InfoDisplayType;
QSize countCurrentSize(int newWidth) override; QSize countCurrentSize(int newWidth) override;
Text createCaption(not_null<HistoryItem*> item) const; Text createCaption(not_null<HistoryItem*> item) const;

View File

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_media_types.h" #include "history/history_media_types.h"
#include "history/history_message.h" #include "history/history_message.h"
#include "history/view/history_view_element.h" #include "history/view/history_view_element.h"
#include "history/view/history_view_cursor_state.h"
#include "data/data_media_types.h" #include "data/data_media_types.h"
#include "storage/storage_shared_media.h" #include "storage/storage_shared_media.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
@ -19,6 +20,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_history.h" #include "styles/style_history.h"
#include "layout.h" #include "layout.h"
namespace {
using TextState = HistoryView::TextState;
using PointState = HistoryView::PointState;
} // namespace
HistoryGroupedMedia::Part::Part(not_null<HistoryItem*> item) HistoryGroupedMedia::Part::Part(not_null<HistoryItem*> item)
: item(item) { : item(item) {
} }
@ -176,7 +182,7 @@ void HistoryGroupedMedia::draw(
auto fullRight = width(); auto fullRight = width();
auto fullBottom = height(); auto fullBottom = height();
if (needInfoDisplay()) { if (needInfoDisplay()) {
_parent->drawInfo(p, fullRight, fullBottom, width(), selected, InfoDisplayOverImage); _parent->drawInfo(p, fullRight, fullBottom, width(), selected, InfoDisplayType::Image);
} }
if (!_parent->hasBubble() && _parent->displayRightAction()) { if (!_parent->hasBubble() && _parent->displayRightAction()) {
auto fastShareLeft = (fullRight + st::historyFastShareLeft); auto fastShareLeft = (fullRight + st::historyFastShareLeft);
@ -186,9 +192,9 @@ void HistoryGroupedMedia::draw(
} }
} }
HistoryTextState HistoryGroupedMedia::getPartState( TextState HistoryGroupedMedia::getPartState(
QPoint point, QPoint point,
HistoryStateRequest request) const { StateRequest request) const {
for (const auto &part : _parts) { for (const auto &part : _parts) {
if (part.geometry.contains(point)) { if (part.geometry.contains(point)) {
auto result = part.content->getStateGrouped( auto result = part.content->getStateGrouped(
@ -199,12 +205,24 @@ HistoryTextState HistoryGroupedMedia::getPartState(
return result; return result;
} }
} }
return HistoryTextState(_parent->data()); return TextState(_parent->data());
} }
HistoryTextState HistoryGroupedMedia::getState( PointState HistoryGroupedMedia::pointState(QPoint point) const {
if (!QRect(0, 0, width(), height()).contains(point)) {
return PointState::Outside;
}
for (const auto &part : _parts) {
if (part.geometry.contains(point)) {
return PointState::GroupPart;
}
}
return PointState::Inside;
}
HistoryView::TextState HistoryGroupedMedia::textState(
QPoint point, QPoint point,
HistoryStateRequest request) const { StateRequest request) const {
auto result = getPartState(point, request); auto result = getPartState(point, request);
if (!result.link && !_caption.isEmpty()) { if (!result.link && !_caption.isEmpty()) {
const auto captionw = width() - st::msgPadding.left() - st::msgPadding.right(); const auto captionw = width() - st::msgPadding.left() - st::msgPadding.right();
@ -212,7 +230,7 @@ HistoryTextState HistoryGroupedMedia::getState(
- (isBubbleBottom() ? st::msgPadding.bottom() : 0) - (isBubbleBottom() ? st::msgPadding.bottom() : 0)
- _caption.countHeight(captionw); - _caption.countHeight(captionw);
if (QRect(st::msgPadding.left(), captiony, captionw, height() - captiony).contains(point)) { if (QRect(st::msgPadding.left(), captiony, captionw, height() - captiony).contains(point)) {
return HistoryTextState(_parent->data(), _caption.getState( return TextState(_parent->data(), _caption.getState(
point - QPoint(st::msgPadding.left(), captiony), point - QPoint(st::msgPadding.left(), captiony),
captionw, captionw,
request.forText())); request.forText()));
@ -220,8 +238,8 @@ HistoryTextState HistoryGroupedMedia::getState(
} else if (_parent->media() == this) { } else if (_parent->media() == this) {
auto fullRight = width(); auto fullRight = width();
auto fullBottom = height(); auto fullBottom = height();
if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayOverImage)) { if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayType::Image)) {
result.cursor = HistoryInDateCursorState; result.cursor = CursorState::Date;
} }
if (!_parent->hasBubble() && _parent->displayRightAction()) { if (!_parent->hasBubble() && _parent->displayRightAction()) {
auto fastShareLeft = (fullRight + st::historyFastShareLeft); auto fastShareLeft = (fullRight + st::historyFastShareLeft);

View File

@ -28,9 +28,10 @@ public:
const QRect &clip, const QRect &clip,
TextSelection selection, TextSelection selection,
TimeMs ms) const override; TimeMs ms) const override;
HistoryTextState getState( PointState pointState(QPoint point) const override;
TextState textState(
QPoint point, QPoint point,
HistoryStateRequest request) const override; StateRequest request) const override;
bool toggleSelectionByHandlerClick( bool toggleSelectionByHandlerClick(
const ClickHandlerPtr &p) const override; const ClickHandlerPtr &p) const override;
@ -107,9 +108,9 @@ private:
not_null<HistoryMedia*> main() const; not_null<HistoryMedia*> main() const;
bool validateGroupParts( bool validateGroupParts(
const std::vector<not_null<HistoryItem*>> &items) const; const std::vector<not_null<HistoryItem*>> &items) const;
HistoryTextState getPartState( TextState getPartState(
QPoint point, QPoint point,
HistoryStateRequest request) const; StateRequest request) const;
Text _caption; Text _caption;
std::vector<Part> _parts; std::vector<Part> _parts;

View File

@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_location_manager.h" #include "history/history_location_manager.h"
#include "history/history_message.h" #include "history/history_message.h"
#include "history/view/history_view_element.h" #include "history/view/history_view_element.h"
#include "history/view/history_view_cursor_state.h"
#include "window/main_window.h" #include "window/main_window.h"
#include "window/window_controller.h" #include "window/window_controller.h"
#include "styles/style_history.h" #include "styles/style_history.h"
@ -41,6 +42,8 @@ namespace {
constexpr auto kMaxGifForwardedBarLines = 4; constexpr auto kMaxGifForwardedBarLines = 4;
constexpr auto kMaxOriginalEntryLines = 8192; constexpr auto kMaxOriginalEntryLines = 8192;
using TextState = HistoryView::TextState;
int documentMaxStatusWidth(DocumentData *document) { int documentMaxStatusWidth(DocumentData *document) {
auto result = st::normalFont->width(formatDownloadText(document->size, document->size)); auto result = st::normalFont->width(formatDownloadText(document->size, document->size));
if (const auto song = document->song()) { if (const auto song = document->song()) {
@ -419,7 +422,7 @@ void HistoryPhoto::draw(Painter &p, const QRect &r, TextSelection selection, Tim
auto fullRight = paintx + paintw; auto fullRight = paintx + paintw;
auto fullBottom = painty + painth; auto fullBottom = painty + painth;
if (needInfoDisplay()) { if (needInfoDisplay()) {
_parent->drawInfo(p, fullRight, fullBottom, 2 * paintx + paintw, selected, InfoDisplayOverImage); _parent->drawInfo(p, fullRight, fullBottom, 2 * paintx + paintw, selected, InfoDisplayType::Image);
} }
if (!bubble && _parent->displayRightAction()) { if (!bubble && _parent->displayRightAction()) {
auto fastShareLeft = (fullRight + st::historyFastShareLeft); auto fastShareLeft = (fullRight + st::historyFastShareLeft);
@ -429,8 +432,8 @@ void HistoryPhoto::draw(Painter &p, const QRect &r, TextSelection selection, Tim
} }
} }
HistoryTextState HistoryPhoto::getState(QPoint point, HistoryStateRequest request) const { TextState HistoryPhoto::textState(QPoint point, StateRequest request) const {
auto result = HistoryTextState(_parent); auto result = TextState(_parent);
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
return result; return result;
@ -447,7 +450,7 @@ HistoryTextState HistoryPhoto::getState(QPoint point, HistoryStateRequest reques
painth -= st::msgPadding.bottom(); painth -= st::msgPadding.bottom();
} }
if (QRect(st::msgPadding.left(), painth, captionw, height() - painth).contains(point)) { if (QRect(st::msgPadding.left(), painth, captionw, height() - painth).contains(point)) {
result = HistoryTextState(_parent, _caption.getState( result = TextState(_parent, _caption.getState(
point - QPoint(st::msgPadding.left(), painth), point - QPoint(st::msgPadding.left(), painth),
captionw, captionw,
request.forText())); request.forText()));
@ -472,8 +475,8 @@ HistoryTextState HistoryPhoto::getState(QPoint point, HistoryStateRequest reques
if (_caption.isEmpty() && _parent->media() == this) { if (_caption.isEmpty() && _parent->media() == this) {
auto fullRight = paintx + paintw; auto fullRight = paintx + paintw;
auto fullBottom = painty + painth; auto fullBottom = painty + painth;
if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayOverImage)) { if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayType::Image)) {
result.cursor = HistoryInDateCursorState; result.cursor = CursorState::Date;
} }
if (!bubble && _parent->displayRightAction()) { if (!bubble && _parent->displayRightAction()) {
auto fastShareLeft = (fullRight + st::historyFastShareLeft); auto fastShareLeft = (fullRight + st::historyFastShareLeft);
@ -586,15 +589,15 @@ void HistoryPhoto::drawGrouped(
} }
} }
HistoryTextState HistoryPhoto::getStateGrouped( TextState HistoryPhoto::getStateGrouped(
const QRect &geometry, const QRect &geometry,
QPoint point, QPoint point,
HistoryStateRequest request) const { StateRequest request) const {
if (!geometry.contains(point)) { if (!geometry.contains(point)) {
return {}; return {};
} }
const auto delayed = _data->full->toDelayedStorageImage(); const auto delayed = _data->full->toDelayedStorageImage();
return HistoryTextState(_parent, _data->uploading() return TextState(_parent, _data->uploading()
? _cancell ? _cancell
: _data->loaded() : _data->loaded()
? _openl ? _openl
@ -870,7 +873,7 @@ void HistoryVideo::draw(Painter &p, const QRect &r, TextSelection selection, Tim
_caption.draw(p, st::msgPadding.left(), painty + painth + st::mediaCaptionSkip, captionw, style::al_left, 0, -1, selection); _caption.draw(p, st::msgPadding.left(), painty + painth + st::mediaCaptionSkip, captionw, style::al_left, 0, -1, selection);
} else if (_parent->media() == this) { } else if (_parent->media() == this) {
auto fullRight = paintx + paintw, fullBottom = painty + painth; auto fullRight = paintx + paintw, fullBottom = painty + painth;
_parent->drawInfo(p, fullRight, fullBottom, 2 * paintx + paintw, selected, InfoDisplayOverImage); _parent->drawInfo(p, fullRight, fullBottom, 2 * paintx + paintw, selected, InfoDisplayType::Image);
if (!bubble && _parent->displayRightAction()) { if (!bubble && _parent->displayRightAction()) {
auto fastShareLeft = (fullRight + st::historyFastShareLeft); auto fastShareLeft = (fullRight + st::historyFastShareLeft);
auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize); auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize);
@ -879,12 +882,12 @@ void HistoryVideo::draw(Painter &p, const QRect &r, TextSelection selection, Tim
} }
} }
HistoryTextState HistoryVideo::getState(QPoint point, HistoryStateRequest request) const { TextState HistoryVideo::textState(QPoint point, StateRequest request) const {
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
return {}; return {};
} }
auto result = HistoryTextState(_parent); auto result = TextState(_parent);
bool loaded = _data->loaded(); bool loaded = _data->loaded();
auto paintx = 0, painty = 0, paintw = width(), painth = height(); auto paintx = 0, painty = 0, paintw = width(), painth = height();
@ -899,7 +902,7 @@ HistoryTextState HistoryVideo::getState(QPoint point, HistoryStateRequest reques
painth -= st::msgPadding.bottom(); painth -= st::msgPadding.bottom();
} }
if (QRect(st::msgPadding.left(), painth, captionw, height() - painth).contains(point)) { if (QRect(st::msgPadding.left(), painth, captionw, height() - painth).contains(point)) {
result = HistoryTextState(_parent, _caption.getState( result = TextState(_parent, _caption.getState(
point - QPoint(st::msgPadding.left(), painth), point - QPoint(st::msgPadding.left(), painth),
captionw, captionw,
request.forText())); request.forText()));
@ -916,8 +919,8 @@ HistoryTextState HistoryVideo::getState(QPoint point, HistoryStateRequest reques
if (_caption.isEmpty() && _parent->media() == this) { if (_caption.isEmpty() && _parent->media() == this) {
auto fullRight = paintx + paintw; auto fullRight = paintx + paintw;
auto fullBottom = painty + painth; auto fullBottom = painty + painth;
if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayOverImage)) { if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayType::Image)) {
result.cursor = HistoryInDateCursorState; result.cursor = CursorState::Date;
} }
if (!bubble && _parent->displayRightAction()) { if (!bubble && _parent->displayRightAction()) {
auto fastShareLeft = (fullRight + st::historyFastShareLeft); auto fastShareLeft = (fullRight + st::historyFastShareLeft);
@ -1026,14 +1029,14 @@ void HistoryVideo::drawGrouped(
} }
} }
HistoryTextState HistoryVideo::getStateGrouped( TextState HistoryVideo::getStateGrouped(
const QRect &geometry, const QRect &geometry,
QPoint point, QPoint point,
HistoryStateRequest request) const { StateRequest request) const {
if (!geometry.contains(point)) { if (!geometry.contains(point)) {
return {}; return {};
} }
return HistoryTextState(_parent, _data->uploading() return TextState(_parent, _data->uploading()
? _cancell ? _cancell
: _data->loaded() : _data->loaded()
? _openl ? _openl
@ -1564,8 +1567,8 @@ void HistoryDocument::draw(Painter &p, const QRect &r, TextSelection selection,
} }
} }
HistoryTextState HistoryDocument::getState(QPoint point, HistoryStateRequest request) const { TextState HistoryDocument::textState(QPoint point, StateRequest request) const {
auto result = HistoryTextState(_parent); auto result = TextState(_parent);
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
return result; return result;
@ -1631,7 +1634,7 @@ HistoryTextState HistoryDocument::getState(QPoint point, HistoryStateRequest req
auto painth = height(); auto painth = height();
if (auto captioned = Get<HistoryDocumentCaptioned>()) { if (auto captioned = Get<HistoryDocumentCaptioned>()) {
if (point.y() >= bottom) { if (point.y() >= bottom) {
result = HistoryTextState(_parent, captioned->_caption.getState( result = TextState(_parent, captioned->_caption.getState(
point - QPoint(st::msgPadding.left(), bottom), point - QPoint(st::msgPadding.left(), bottom),
width() - st::msgPadding.left() - st::msgPadding.right(), width() - st::msgPadding.left() - st::msgPadding.right(),
request.forText())); request.forText()));
@ -2306,7 +2309,7 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, TimeM
} }
} }
if (isRound || needInfoDisplay()) { if (isRound || needInfoDisplay()) {
_parent->drawInfo(p, fullRight, fullBottom, 2 * paintx + paintw, selected, isRound ? InfoDisplayOverBackground : InfoDisplayOverImage); _parent->drawInfo(p, fullRight, fullBottom, 2 * paintx + paintw, selected, isRound ? InfoDisplayType::Background : InfoDisplayType::Image);
} }
if (!bubble && _parent->displayRightAction()) { if (!bubble && _parent->displayRightAction()) {
auto fastShareLeft = (fullRight + st::historyFastShareLeft); auto fastShareLeft = (fullRight + st::historyFastShareLeft);
@ -2320,8 +2323,8 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, TimeM
} }
} }
HistoryTextState HistoryGif::getState(QPoint point, HistoryStateRequest request) const { TextState HistoryGif::textState(QPoint point, StateRequest request) const {
auto result = HistoryTextState(_parent); auto result = TextState(_parent);
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
return result; return result;
@ -2336,7 +2339,7 @@ HistoryTextState HistoryGif::getState(QPoint point, HistoryStateRequest request)
painth -= st::msgPadding.bottom(); painth -= st::msgPadding.bottom();
} }
if (QRect(st::msgPadding.left(), painth, captionw, height() - painth).contains(point)) { if (QRect(st::msgPadding.left(), painth, captionw, height() - painth).contains(point)) {
result = HistoryTextState(_parent, _caption.getState( result = TextState(_parent, _caption.getState(
point - QPoint(st::msgPadding.left(), painth), point - QPoint(st::msgPadding.left(), painth),
captionw, captionw,
request.forText())); request.forText()));
@ -2386,16 +2389,16 @@ HistoryTextState HistoryGif::getState(QPoint point, HistoryStateRequest request)
if (breakEverywhere) { if (breakEverywhere) {
textRequest.flags |= Text::StateRequest::Flag::BreakEverywhere; textRequest.flags |= Text::StateRequest::Flag::BreakEverywhere;
} }
result = HistoryTextState(_parent, forwarded->text.getState( result = TextState(_parent, forwarded->text.getState(
point - QPoint(rectx + st::msgReplyPadding.left(), recty + st::msgReplyPadding.top()), point - QPoint(rectx + st::msgReplyPadding.left(), recty + st::msgReplyPadding.top()),
innerw, innerw,
textRequest)); textRequest));
result.symbol = 0; result.symbol = 0;
result.afterSymbol = false; result.afterSymbol = false;
if (breakEverywhere) { if (breakEverywhere) {
result.cursor = HistoryInForwardedCursorState; result.cursor = CursorState::Forwarded;
} else { } else {
result.cursor = HistoryDefaultCursorState; result.cursor = CursorState::None;
} }
return result; return result;
} }
@ -2447,8 +2450,8 @@ HistoryTextState HistoryGif::getState(QPoint point, HistoryStateRequest request)
} }
} }
if (!inWebPage) { if (!inWebPage) {
if (_parent->pointInTime(fullRight, fullBottom, point, isRound ? InfoDisplayOverBackground : InfoDisplayOverImage)) { if (_parent->pointInTime(fullRight, fullBottom, point, isRound ? InfoDisplayType::Background : InfoDisplayType::Image)) {
result.cursor = HistoryInDateCursorState; result.cursor = CursorState::Date;
} }
} }
if (!bubble && _parent->displayRightAction()) { if (!bubble && _parent->displayRightAction()) {
@ -2810,7 +2813,7 @@ void HistorySticker::draw(Painter &p, const QRect &r, TextSelection selection, T
if (!inWebPage) { if (!inWebPage) {
auto fullRight = usex + usew; auto fullRight = usex + usew;
auto fullBottom = height(); auto fullBottom = height();
_parent->drawInfo(p, fullRight, fullBottom, usex * 2 + usew, selected, InfoDisplayOverBackground); _parent->drawInfo(p, fullRight, fullBottom, usex * 2 + usew, selected, InfoDisplayType::Background);
if (via || reply) { if (via || reply) {
int rectw = width() - usew - st::msgReplyPadding.left(); int rectw = width() - usew - st::msgReplyPadding.left();
int recth = st::msgReplyPadding.top() + st::msgReplyPadding.bottom(); int recth = st::msgReplyPadding.top() + st::msgReplyPadding.bottom();
@ -2850,8 +2853,8 @@ void HistorySticker::draw(Painter &p, const QRect &r, TextSelection selection, T
} }
} }
HistoryTextState HistorySticker::getState(QPoint point, HistoryStateRequest request) const { TextState HistorySticker::textState(QPoint point, StateRequest request) const {
auto result = HistoryTextState(_parent); auto result = TextState(_parent);
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
return result; return result;
} }
@ -2904,8 +2907,8 @@ HistoryTextState HistorySticker::getState(QPoint point, HistoryStateRequest requ
if (_parent->media() == this) { if (_parent->media() == this) {
auto fullRight = usex + usew; auto fullRight = usex + usew;
auto fullBottom = height(); auto fullBottom = height();
if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayOverImage)) { if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayType::Image)) {
result.cursor = HistoryInDateCursorState; result.cursor = CursorState::Date;
} }
if (_parent->displayRightAction()) { if (_parent->displayRightAction()) {
auto fastShareLeft = (fullRight + st::historyFastShareLeft); auto fastShareLeft = (fullRight + st::historyFastShareLeft);
@ -3112,8 +3115,8 @@ void HistoryContact::draw(Painter &p, const QRect &r, TextSelection selection, T
p.drawTextLeft(nameleft, statustop, paintw, _phone); p.drawTextLeft(nameleft, statustop, paintw, _phone);
} }
HistoryTextState HistoryContact::getState(QPoint point, HistoryStateRequest request) const { TextState HistoryContact::textState(QPoint point, StateRequest request) const {
auto result = HistoryTextState(_parent); auto result = TextState(_parent);
auto nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0; auto nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0;
auto topMinus = isBubbleTop() ? 0 : st::msgFileTopMinus; auto topMinus = isBubbleTop() ? 0 : st::msgFileTopMinus;
@ -3210,8 +3213,8 @@ void HistoryCall::draw(Painter &p, const QRect &r, TextSelection selection, Time
icon.paint(p, paintw - st::historyCallIconPosition.x() - icon.width(), st::historyCallIconPosition.y() - topMinus, paintw); icon.paint(p, paintw - st::historyCallIconPosition.x() - icon.width(), st::historyCallIconPosition.y() - topMinus, paintw);
} }
HistoryTextState HistoryCall::getState(QPoint point, HistoryStateRequest request) const { TextState HistoryCall::textState(QPoint point, StateRequest request) const {
auto result = HistoryTextState(_parent); auto result = TextState(_parent);
if (QRect(0, 0, width(), height()).contains(point)) { if (QRect(0, 0, width(), height()).contains(point)) {
result.link = _link; result.link = _link;
return result; return result;
@ -3626,8 +3629,8 @@ void HistoryWebPage::draw(Painter &p, const QRect &r, TextSelection selection, T
} }
} }
HistoryTextState HistoryWebPage::getState(QPoint point, HistoryStateRequest request) const { TextState HistoryWebPage::textState(QPoint point, StateRequest request) const {
auto result = HistoryTextState(_parent); auto result = TextState(_parent);
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
return result; return result;
@ -3660,7 +3663,7 @@ HistoryTextState HistoryWebPage::getState(QPoint point, HistoryStateRequest requ
if (point.y() >= tshift && point.y() < tshift + _titleLines * lineHeight) { if (point.y() >= tshift && point.y() < tshift + _titleLines * lineHeight) {
Text::StateRequestElided titleRequest = request.forText(); Text::StateRequestElided titleRequest = request.forText();
titleRequest.lines = _titleLines; titleRequest.lines = _titleLines;
result = HistoryTextState(_parent, _title.getStateElidedLeft( result = TextState(_parent, _title.getStateElidedLeft(
point - QPoint(padding.left(), tshift), point - QPoint(padding.left(), tshift),
paintw, paintw,
width(), width(),
@ -3676,13 +3679,13 @@ HistoryTextState HistoryWebPage::getState(QPoint point, HistoryStateRequest requ
if (_descriptionLines > 0) { if (_descriptionLines > 0) {
Text::StateRequestElided descriptionRequest = request.forText(); Text::StateRequestElided descriptionRequest = request.forText();
descriptionRequest.lines = _descriptionLines; descriptionRequest.lines = _descriptionLines;
result = HistoryTextState(_parent, _description.getStateElidedLeft( result = TextState(_parent, _description.getStateElidedLeft(
point - QPoint(padding.left(), tshift), point - QPoint(padding.left(), tshift),
paintw, paintw,
width(), width(),
descriptionRequest)); descriptionRequest));
} else { } else {
result = HistoryTextState(_parent, _description.getStateLeft( result = TextState(_parent, _description.getStateLeft(
point - QPoint(padding.left(), tshift), point - QPoint(padding.left(), tshift),
paintw, paintw,
width(), width(),
@ -3703,7 +3706,7 @@ HistoryTextState HistoryWebPage::getState(QPoint point, HistoryStateRequest requ
auto attachLeft = padding.left() - bubble.left(); auto attachLeft = padding.left() - bubble.left();
auto attachTop = tshift - bubble.top(); auto attachTop = tshift - bubble.top();
if (rtl()) attachLeft = width() - attachLeft - _attach->width(); if (rtl()) attachLeft = width() - attachLeft - _attach->width();
result = _attach->getState(point - QPoint(attachLeft, attachTop), request); result = _attach->textState(point - QPoint(attachLeft, attachTop), request);
if (result.link && !_data->document && _data->photo && _attach->isReadyForOpen()) { if (result.link && !_data->document && _data->photo && _attach->isReadyForOpen()) {
if (_data->type == WebPageProfile || _data->type == WebPageVideo) { if (_data->type == WebPageProfile || _data->type == WebPageVideo) {
@ -4059,8 +4062,8 @@ void HistoryGame::draw(Painter &p, const QRect &r, TextSelection selection, Time
} }
} }
HistoryTextState HistoryGame::getState(QPoint point, HistoryStateRequest request) const { TextState HistoryGame::textState(QPoint point, StateRequest request) const {
auto result = HistoryTextState(_parent); auto result = TextState(_parent);
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
return result; return result;
@ -4083,7 +4086,7 @@ HistoryTextState HistoryGame::getState(QPoint point, HistoryStateRequest request
if (point.y() >= tshift && point.y() < tshift + _titleLines * lineHeight) { if (point.y() >= tshift && point.y() < tshift + _titleLines * lineHeight) {
Text::StateRequestElided titleRequest = request.forText(); Text::StateRequestElided titleRequest = request.forText();
titleRequest.lines = _titleLines; titleRequest.lines = _titleLines;
result = HistoryTextState(_parent, _title.getStateElidedLeft( result = TextState(_parent, _title.getStateElidedLeft(
point - QPoint(padding.left(), tshift), point - QPoint(padding.left(), tshift),
paintw, paintw,
width(), width(),
@ -4097,7 +4100,7 @@ HistoryTextState HistoryGame::getState(QPoint point, HistoryStateRequest request
if (point.y() >= tshift && point.y() < tshift + _descriptionLines * lineHeight) { if (point.y() >= tshift && point.y() < tshift + _descriptionLines * lineHeight) {
Text::StateRequestElided descriptionRequest = request.forText(); Text::StateRequestElided descriptionRequest = request.forText();
descriptionRequest.lines = _descriptionLines; descriptionRequest.lines = _descriptionLines;
result = HistoryTextState(_parent, _description.getStateElidedLeft( result = TextState(_parent, _description.getStateElidedLeft(
point - QPoint(padding.left(), tshift), point - QPoint(padding.left(), tshift),
paintw, paintw,
width(), width(),
@ -4125,7 +4128,7 @@ HistoryTextState HistoryGame::getState(QPoint point, HistoryStateRequest request
result.link = _openl; result.link = _openl;
} }
} else { } else {
result = _attach->getState(point - QPoint(attachLeft, attachTop), request); result = _attach->textState(point - QPoint(attachLeft, attachTop), request);
} }
} }
} }
@ -4473,8 +4476,8 @@ void HistoryInvoice::draw(Painter &p, const QRect &r, TextSelection selection, T
} }
} }
HistoryTextState HistoryInvoice::getState(QPoint point, HistoryStateRequest request) const { TextState HistoryInvoice::textState(QPoint point, StateRequest request) const {
auto result = HistoryTextState(_parent); auto result = TextState(_parent);
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
return result; return result;
@ -4496,7 +4499,7 @@ HistoryTextState HistoryInvoice::getState(QPoint point, HistoryStateRequest requ
if (point.y() >= tshift && point.y() < tshift + _titleHeight) { if (point.y() >= tshift && point.y() < tshift + _titleHeight) {
Text::StateRequestElided titleRequest = request.forText(); Text::StateRequestElided titleRequest = request.forText();
titleRequest.lines = _titleHeight / lineHeight; titleRequest.lines = _titleHeight / lineHeight;
result = HistoryTextState(_parent, _title.getStateElidedLeft( result = TextState(_parent, _title.getStateElidedLeft(
point - QPoint(padding.left(), tshift), point - QPoint(padding.left(), tshift),
paintw, paintw,
width(), width(),
@ -4508,7 +4511,7 @@ HistoryTextState HistoryInvoice::getState(QPoint point, HistoryStateRequest requ
} }
if (_descriptionHeight) { if (_descriptionHeight) {
if (point.y() >= tshift && point.y() < tshift + _descriptionHeight) { if (point.y() >= tshift && point.y() < tshift + _descriptionHeight) {
result = HistoryTextState(_parent, _description.getStateLeft( result = TextState(_parent, _description.getStateLeft(
point - QPoint(padding.left(), tshift), point - QPoint(padding.left(), tshift),
paintw, paintw,
width(), width(),
@ -4527,7 +4530,7 @@ HistoryTextState HistoryInvoice::getState(QPoint point, HistoryStateRequest requ
if (rtl()) attachLeft = width() - attachLeft - _attach->width(); if (rtl()) attachLeft = width() - attachLeft - _attach->width();
if (QRect(attachLeft, tshift, _attach->width(), height() - tshift - bshift).contains(point)) { if (QRect(attachLeft, tshift, _attach->width(), height() - tshift - bshift).contains(point)) {
result = _attach->getState(point - QPoint(attachLeft, attachTop), request); result = _attach->textState(point - QPoint(attachLeft, attachTop), request);
} }
} }
@ -4753,7 +4756,7 @@ void HistoryLocation::draw(Painter &p, const QRect &r, TextSelection selection,
if (_parent->media() == this) { if (_parent->media() == this) {
auto fullRight = paintx + paintw; auto fullRight = paintx + paintw;
auto fullBottom = height(); auto fullBottom = height();
_parent->drawInfo(p, fullRight, fullBottom, paintx * 2 + paintw, selected, InfoDisplayOverImage); _parent->drawInfo(p, fullRight, fullBottom, paintx * 2 + paintw, selected, InfoDisplayType::Image);
if (!bubble && _parent->displayRightAction()) { if (!bubble && _parent->displayRightAction()) {
auto fastShareLeft = (fullRight + st::historyFastShareLeft); auto fastShareLeft = (fullRight + st::historyFastShareLeft);
auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize); auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize);
@ -4762,8 +4765,8 @@ void HistoryLocation::draw(Painter &p, const QRect &r, TextSelection selection,
} }
} }
HistoryTextState HistoryLocation::getState(QPoint point, HistoryStateRequest request) const { TextState HistoryLocation::textState(QPoint point, StateRequest request) const {
auto result = HistoryTextState(_parent); auto result = TextState(_parent);
auto symbolAdd = 0; auto symbolAdd = 0;
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) {
@ -4784,7 +4787,7 @@ HistoryTextState HistoryLocation::getState(QPoint point, HistoryStateRequest req
if (!_title.isEmpty()) { if (!_title.isEmpty()) {
auto titleh = qMin(_title.countHeight(textw), 2 * st::webPageTitleFont->height); auto titleh = qMin(_title.countHeight(textw), 2 * st::webPageTitleFont->height);
if (point.y() >= painty && point.y() < painty + titleh) { if (point.y() >= painty && point.y() < painty + titleh) {
result = HistoryTextState(_parent, _title.getStateLeft( result = TextState(_parent, _title.getStateLeft(
point - QPoint(paintx + st::msgPadding.left(), painty), point - QPoint(paintx + st::msgPadding.left(), painty),
textw, textw,
width(), width(),
@ -4798,7 +4801,7 @@ HistoryTextState HistoryLocation::getState(QPoint point, HistoryStateRequest req
if (!_description.isEmpty()) { if (!_description.isEmpty()) {
auto descriptionh = qMin(_description.countHeight(textw), 3 * st::webPageDescriptionFont->height); auto descriptionh = qMin(_description.countHeight(textw), 3 * st::webPageDescriptionFont->height);
if (point.y() >= painty && point.y() < painty + descriptionh) { if (point.y() >= painty && point.y() < painty + descriptionh) {
result = HistoryTextState(_parent, _description.getStateLeft( result = TextState(_parent, _description.getStateLeft(
point - QPoint(paintx + st::msgPadding.left(), painty), point - QPoint(paintx + st::msgPadding.left(), painty),
textw, textw,
width(), width(),
@ -4819,8 +4822,8 @@ HistoryTextState HistoryLocation::getState(QPoint point, HistoryStateRequest req
if (_parent->media() == this) { if (_parent->media() == this) {
auto fullRight = paintx + paintw; auto fullRight = paintx + paintw;
auto fullBottom = height(); auto fullBottom = height();
if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayOverImage)) { if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayType::Image)) {
result.cursor = HistoryInDateCursorState; result.cursor = CursorState::Date;
} }
if (!bubble && _parent->displayRightAction()) { if (!bubble && _parent->displayRightAction()) {
auto fastShareLeft = (fullRight + st::historyFastShareLeft); auto fastShareLeft = (fullRight + st::historyFastShareLeft);

View File

@ -141,7 +141,7 @@ public:
} }
void draw(Painter &p, const QRect &clip, TextSelection selection, TimeMs ms) const override; void draw(Painter &p, const QRect &clip, TextSelection selection, TimeMs ms) const override;
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; TextState textState(QPoint point, StateRequest request) const override;
[[nodiscard]] TextSelection adjustSelection( [[nodiscard]] TextSelection adjustSelection(
TextSelection selection, TextSelection selection,
@ -171,10 +171,10 @@ public:
RectParts corners, RectParts corners,
not_null<uint64*> cacheKey, not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const override; not_null<QPixmap*> cache) const override;
HistoryTextState getStateGrouped( TextState getStateGrouped(
const QRect &geometry, const QRect &geometry,
QPoint point, QPoint point,
HistoryStateRequest request) const override; StateRequest request) const override;
bool hasReplyPreview() const override { bool hasReplyPreview() const override {
return !_data->thumb->isNull(); return !_data->thumb->isNull();
@ -233,7 +233,7 @@ public:
} }
void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override;
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; TextState textState(QPoint point, StateRequest request) const override;
[[nodiscard]] TextSelection adjustSelection( [[nodiscard]] TextSelection adjustSelection(
TextSelection selection, TextSelection selection,
@ -263,10 +263,10 @@ public:
RectParts corners, RectParts corners,
not_null<uint64*> cacheKey, not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const override; not_null<QPixmap*> cache) const override;
HistoryTextState getStateGrouped( TextState getStateGrouped(
const QRect &geometry, const QRect &geometry,
QPoint point, QPoint point,
HistoryStateRequest request) const override; StateRequest request) const override;
bool uploading() const override { bool uploading() const override {
return _data->uploading(); return _data->uploading();
@ -328,7 +328,7 @@ public:
} }
void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override;
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; TextState textState(QPoint point, StateRequest request) const override;
void updatePressed(QPoint point) override; void updatePressed(QPoint point) override;
[[nodiscard]] TextSelection adjustSelection( [[nodiscard]] TextSelection adjustSelection(
@ -400,7 +400,7 @@ public:
} }
void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override;
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; TextState textState(QPoint point, StateRequest request) const override;
[[nodiscard]] TextSelection adjustSelection( [[nodiscard]] TextSelection adjustSelection(
TextSelection selection, TextSelection selection,
@ -501,7 +501,7 @@ public:
} }
void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override;
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; TextState textState(QPoint point, StateRequest request) const override;
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override { bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
return true; return true;
@ -562,7 +562,7 @@ public:
} }
void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override;
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; TextState textState(QPoint point, StateRequest request) const override;
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override { bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
return true; return true;
@ -619,7 +619,7 @@ public:
} }
void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override;
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; TextState textState(QPoint point, StateRequest request) const override;
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override { bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
return true; return true;
@ -665,7 +665,7 @@ public:
void refreshParentId(not_null<HistoryItem*> realParent) override; void refreshParentId(not_null<HistoryItem*> realParent) override;
void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override;
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; TextState textState(QPoint point, StateRequest request) const override;
bool hideMessageText() const override { bool hideMessageText() const override {
return false; return false;
@ -772,7 +772,7 @@ public:
void refreshParentId(not_null<HistoryItem*> realParent) override; void refreshParentId(not_null<HistoryItem*> realParent) override;
void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override;
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; TextState textState(QPoint point, StateRequest request) const override;
[[nodiscard]] TextSelection adjustSelection( [[nodiscard]] TextSelection adjustSelection(
TextSelection selection, TextSelection selection,
@ -780,9 +780,6 @@ public:
uint16 fullSelectionLength() const override { uint16 fullSelectionLength() const override {
return _title.length() + _description.length(); return _title.length() + _description.length();
} }
bool isAboveMessage() const override {
return true;
}
bool hasTextForCopy() const override { bool hasTextForCopy() const override {
return false; // we do not add _title and _description in FullSelection text copy. return false; // we do not add _title and _description in FullSelection text copy.
} }
@ -881,7 +878,7 @@ public:
} }
void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override;
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; TextState textState(QPoint point, StateRequest request) const override;
[[nodiscard]] TextSelection adjustSelection( [[nodiscard]] TextSelection adjustSelection(
TextSelection selection, TextSelection selection,
@ -962,7 +959,7 @@ public:
} }
void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override;
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; TextState textState(QPoint point, StateRequest request) const override;
[[nodiscard]] TextSelection adjustSelection( [[nodiscard]] TextSelection adjustSelection(
TextSelection selection, TextSelection selection,

View File

@ -666,14 +666,6 @@ HistoryWidget::HistoryWidget(
} }
} }
}); });
Auth().data().viewLayoutChanged(
) | rpl::start_with_next([this](auto view) {
if (view == view->data()->mainView()) {
if (view->isUnderCursor() && _list) {
_list->onUpdateSelected();
}
}
}, lifetime());
_topBar->membersShowAreaActive( _topBar->membersShowAreaActive(
) | rpl::start_with_next([=](bool active) { ) | rpl::start_with_next([=](bool active) {
setMembersShowAreaActive(active); setMembersShowAreaActive(active);

View File

@ -10,43 +10,61 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item.h" #include "history/history_item.h"
#include "history/view/history_view_element.h" #include "history/view/history_view_element.h"
HistoryTextState::HistoryTextState(not_null<const HistoryItem*> item) namespace HistoryView {
TextState::TextState(not_null<const HistoryItem*> item)
: itemId(item->fullId()) { : itemId(item->fullId()) {
} }
HistoryTextState::HistoryTextState( TextState::TextState(
not_null<const HistoryItem*> item, not_null<const HistoryItem*> item,
const Text::StateResult &state) const Text::StateResult &state)
: itemId(item->fullId()) : itemId(item->fullId())
, cursor(state.uponSymbol , cursor(state.uponSymbol
? HistoryInTextCursorState ? CursorState::Text
: HistoryDefaultCursorState) : CursorState::None)
, link(state.link) , link(state.link)
, afterSymbol(state.afterSymbol) , afterSymbol(state.afterSymbol)
, symbol(state.symbol) { , symbol(state.symbol) {
} }
HistoryTextState::HistoryTextState( TextState::TextState(
not_null<const HistoryItem*> item, not_null<const HistoryItem*> item,
ClickHandlerPtr link) ClickHandlerPtr link)
: itemId(item->fullId()) : itemId(item->fullId())
, link(link) { , link(link) {
} }
TextState::TextState(
HistoryTextState::HistoryTextState(
not_null<const HistoryView::Element*> view) not_null<const HistoryView::Element*> view)
: HistoryTextState(view->data()) { : TextState(view->data()) {
} }
HistoryTextState::HistoryTextState( TextState::TextState(
not_null<const HistoryView::Element*> view, not_null<const HistoryView::Element*> view,
const Text::StateResult &state) const Text::StateResult &state)
: HistoryTextState(view->data(), state) { : TextState(view->data(), state) {
} }
HistoryTextState::HistoryTextState( TextState::TextState(
not_null<const HistoryView::Element*> view, not_null<const HistoryView::Element*> view,
ClickHandlerPtr link) ClickHandlerPtr link)
: HistoryTextState(view->data(), link) { : TextState(view->data(), link) {
} }
TextState::TextState(
std::nullptr_t,
const Text::StateResult &state)
: cursor(state.uponSymbol
? CursorState::Text
: CursorState::None)
, link(state.link)
, afterSymbol(state.afterSymbol)
, symbol(state.symbol) {
}
TextState::TextState(std::nullptr_t, ClickHandlerPtr link)
: link(link) {
}
} // namespace HistoryView

View File

@ -7,58 +7,54 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
namespace HistoryView {
class Element;
} // namespace HistoryView
class HistoryItem; class HistoryItem;
enum HistoryCursorState { namespace HistoryView {
HistoryDefaultCursorState,
HistoryInTextCursorState, class Element;
HistoryInDateCursorState,
HistoryInForwardedCursorState, enum class PointState : char {
Outside,
Inside,
GroupPart,
};
enum class CursorState : char {
None,
Text,
Date,
Forwarded,
}; };
struct HistoryTextState { struct TextState {
HistoryTextState() = default; TextState() = default;
HistoryTextState(not_null<const HistoryItem*> item); TextState(not_null<const HistoryItem*> item);
HistoryTextState( TextState(
not_null<const HistoryItem*> item, not_null<const HistoryItem*> item,
const Text::StateResult &state); const Text::StateResult &state);
HistoryTextState( TextState(
not_null<const HistoryItem*> item, not_null<const HistoryItem*> item,
ClickHandlerPtr link); ClickHandlerPtr link);
HistoryTextState(not_null<const HistoryView::Element*> view); TextState(not_null<const HistoryView::Element*> view);
HistoryTextState( TextState(
not_null<const HistoryView::Element*> view, not_null<const HistoryView::Element*> view,
const Text::StateResult &state); const Text::StateResult &state);
HistoryTextState( TextState(
not_null<const HistoryView::Element*> view, not_null<const HistoryView::Element*> view,
ClickHandlerPtr link); ClickHandlerPtr link);
HistoryTextState( TextState(
std::nullptr_t, std::nullptr_t,
const Text::StateResult &state) const Text::StateResult &state);
: cursor(state.uponSymbol TextState(std::nullptr_t, ClickHandlerPtr link);
? HistoryInTextCursorState
: HistoryDefaultCursorState)
, link(state.link)
, afterSymbol(state.afterSymbol)
, symbol(state.symbol) {
}
HistoryTextState(std::nullptr_t, ClickHandlerPtr link)
: link(link) {
}
FullMsgId itemId; FullMsgId itemId;
HistoryCursorState cursor = HistoryDefaultCursorState; CursorState cursor = CursorState::None;
ClickHandlerPtr link; ClickHandlerPtr link;
bool afterSymbol = false; bool afterSymbol = false;
uint16 symbol = 0; uint16 symbol = 0;
}; };
struct HistoryStateRequest { struct StateRequest {
Text::StateRequest::Flags flags = Text::StateRequest::Flag::LookupLink; Text::StateRequest::Flags flags = Text::StateRequest::Flag::LookupLink;
Text::StateRequest forText() const { Text::StateRequest forText() const {
Text::StateRequest result; Text::StateRequest result;
@ -67,8 +63,10 @@ struct HistoryStateRequest {
} }
}; };
enum InfoDisplayType : char { enum class InfoDisplayType : char {
InfoDisplayDefault, Default,
InfoDisplayOverImage, Image,
InfoDisplayOverBackground, Background,
}; };
} // namespace HistoryView

View File

@ -17,12 +17,14 @@ class HistoryMessage;
class HistoryService; class HistoryService;
class HistoryMedia; class HistoryMedia;
class HistoryWebPage; class HistoryWebPage;
struct HistoryTextState;
struct HistoryStateRequest;
enum InfoDisplayType : char;
namespace HistoryView { namespace HistoryView {
enum class PointState : char;
enum class InfoDisplayType : char;
struct StateRequest;
struct TextState;
enum class Context : char { enum class Context : char {
History, History,
Feed, Feed,
@ -166,10 +168,10 @@ public:
QRect clip, QRect clip,
TextSelection selection, TextSelection selection,
TimeMs ms) const = 0; TimeMs ms) const = 0;
[[nodiscard]] virtual bool hasPoint(QPoint point) const = 0; [[nodiscard]] virtual PointState pointState(QPoint point) const = 0;
[[nodiscard]] virtual HistoryTextState getState( [[nodiscard]] virtual TextState textState(
QPoint point, QPoint point,
HistoryStateRequest request) const = 0; StateRequest request) const = 0;
virtual void updatePressed(QPoint point) = 0; virtual void updatePressed(QPoint point) = 0;
virtual void drawInfo( virtual void drawInfo(
Painter &p, Painter &p,

View File

@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_element.h" #include "history/view/history_view_element.h"
#include "history/view/history_view_message.h" #include "history/view/history_view_message.h"
#include "history/view/history_view_service_message.h" #include "history/view/history_view_service_message.h"
#include "history/view/history_view_cursor_state.h"
#include "chat_helpers/message_field.h" #include "chat_helpers/message_field.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "mainwidget.h" #include "mainwidget.h"
@ -44,6 +45,20 @@ constexpr auto kPreloadedScreensCountFull
} // namespace } // namespace
ListWidget::MouseState::MouseState() : pointState(PointState::Outside) {
}
ListWidget::MouseState::MouseState(
FullMsgId itemId,
int height,
QPoint point,
PointState pointState)
: itemId(itemId)
, height(height)
, point(point)
, pointState(pointState) {
}
template <ListWidget::EnumItemsDirection direction, typename Method> template <ListWidget::EnumItemsDirection direction, typename Method>
void ListWidget::enumerateItems(Method method) { void ListWidget::enumerateItems(Method method) {
constexpr auto TopToBottom = (direction == EnumItemsDirection::TopToBottom); constexpr auto TopToBottom = (direction == EnumItemsDirection::TopToBottom);
@ -501,40 +516,151 @@ bool ListWidget::hasSelectedItems() const {
return !_selected.empty(); return !_selected.empty();
} }
bool ListWidget::applyItemSelection( bool ListWidget::overSelectedItems() const {
SelectedMap &applyTo, if (_overState.pointState == PointState::GroupPart) {
FullMsgId itemId) const { return _overItemExact
if (applyTo.size() >= MaxSelectedItems) { && _selected.contains(_overItemExact->fullId());
return false; } else if (_overState.pointState == PointState::Inside) {
return _overElement
&& isSelectedAsGroup(_selected, _overElement->data());
} }
return false;
}
//bool ListWidget::applyItemSelection(
// SelectedMap &applyTo,
// FullMsgId itemId) const {
// if (applyTo.size() >= MaxSelectedItems) {
// return false;
// }
// auto [iterator, ok] = applyTo.try_emplace(
// itemId,
// SelectionData());
// if (!ok) {
// return false;
// }
// const auto item = App::histItemById(itemId);
// if (!item) {
// applyTo.erase(iterator);
// return false;
// }
// iterator->second.canDelete = item->canDelete();
// iterator->second.canForward = item->allowsForward();
// return true;
//}
//
//void ListWidget::toggleItemSelection(FullMsgId itemId) {
// auto it = _selected.find(itemId);
// if (it == _selected.cend()) {
// if (_selectedTextItem) {
// clearTextSelection();
// }
// if (applyItemSelection(_selected, itemId)) {
// repaintItem(itemId);
// pushSelectedItems();
// }
// } else {
// removeItemSelection(it);
// }
//}
bool ListWidget::isSelectedAsGroup(
const SelectedMap &applyTo,
not_null<HistoryItem*> item) const {
if (const auto group = Auth().data().groups().find(item)) {
for (const auto other : group->items) {
if (!applyTo.contains(other->fullId())) {
return false;
}
}
return true;
}
return applyTo.contains(item->fullId());
}
bool ListWidget::isGoodForSelection(
SelectedMap &applyTo,
not_null<HistoryItem*> item,
int &totalCount) const {
if (!IsServerMsgId(item->id) || item->serviceMsg()) {
return false;
} else if (!applyTo.contains(item->fullId())) {
++totalCount;
}
return (totalCount <= MaxSelectedItems);
}
bool ListWidget::addToSelection(
SelectedMap &applyTo,
not_null<HistoryItem*> item) const {
const auto itemId = item->fullId();
auto [iterator, ok] = applyTo.try_emplace( auto [iterator, ok] = applyTo.try_emplace(
itemId, itemId,
SelectionData()); SelectionData());
if (!ok) { if (!ok) {
return false; return false;
} }
const auto item = App::histItemById(itemId);
if (!item) {
applyTo.erase(iterator);
return false;
}
iterator->second.canDelete = item->canDelete(); iterator->second.canDelete = item->canDelete();
iterator->second.canForward = item->allowsForward(); iterator->second.canForward = item->allowsForward();
return true; return true;
} }
void ListWidget::toggleItemSelection(FullMsgId itemId) { bool ListWidget::removeFromSelection(
auto it = _selected.find(itemId); SelectedMap &applyTo,
if (it == _selected.cend()) { FullMsgId itemId) const {
if (_selectedTextItem) { return applyTo.remove(itemId);
clearTextSelection(); }
}
if (applyItemSelection(_selected, itemId)) { void ListWidget::changeSelection(
repaintItem(itemId); SelectedMap &applyTo,
pushSelectedItems(); not_null<HistoryItem*> item,
SelectAction action) const {
const auto itemId = item->fullId();
if (action == SelectAction::Invert) {
action = applyTo.contains(itemId)
? SelectAction::Deselect
: SelectAction::Select;
}
if (action == SelectAction::Select) {
auto already = int(applyTo.size());
if (isGoodForSelection(applyTo, item, already)) {
addToSelection(applyTo, item);
} }
} else { } else {
removeItemSelection(it); removeFromSelection(applyTo, itemId);
}
}
void ListWidget::changeSelectionAsGroup(
SelectedMap &applyTo,
not_null<HistoryItem*> item,
SelectAction action) const {
const auto group = Auth().data().groups().find(item);
if (!group) {
return changeSelection(applyTo, item, action);
}
if (action == SelectAction::Invert) {
action = isSelectedAsGroup(applyTo, item)
? SelectAction::Deselect
: SelectAction::Select;
}
auto already = int(applyTo.size());
const auto canSelect = [&] {
for (const auto other : group->items) {
if (!isGoodForSelection(applyTo, other, already)) {
return false;
}
}
return true;
}();
if (action == SelectAction::Select && canSelect) {
for (const auto other : group->items) {
addToSelection(applyTo, other);
}
} else {
for (const auto other : group->items) {
removeFromSelection(applyTo, other->fullId());
}
} }
} }
@ -543,21 +669,23 @@ bool ListWidget::isItemUnderPressSelected() const {
} }
auto ListWidget::itemUnderPressSelection() -> SelectedMap::iterator { auto ListWidget::itemUnderPressSelection() -> SelectedMap::iterator {
return (_pressState.itemId && _pressState.inside) return (_pressState.itemId
&& _pressState.pointState != PointState::Outside)
? _selected.find(_pressState.itemId) ? _selected.find(_pressState.itemId)
: _selected.end(); : _selected.end();
} }
auto ListWidget::itemUnderPressSelection() const auto ListWidget::itemUnderPressSelection() const
-> SelectedMap::const_iterator { -> SelectedMap::const_iterator {
return (_pressState.itemId && _pressState.inside) return (_pressState.itemId
&& _pressState.pointState != PointState::Outside)
? _selected.find(_pressState.itemId) ? _selected.find(_pressState.itemId)
: _selected.end(); : _selected.end();
} }
bool ListWidget::requiredToStartDragging( bool ListWidget::requiredToStartDragging(
not_null<Element*> view) const { not_null<Element*> view) const {
if (_mouseCursorState == HistoryInDateCursorState) { if (_mouseCursorState == CursorState::Date) {
return true; return true;
} else if (const auto media = view->media()) { } else if (const auto media = view->media()) {
return media->type() == MediaTypeSticker; return media->type() == MediaTypeSticker;
@ -565,8 +693,8 @@ bool ListWidget::requiredToStartDragging(
return false; return false;
} }
bool ListWidget::isPressInSelectedText(HistoryTextState state) const { bool ListWidget::isPressInSelectedText(TextState state) const {
if (state.cursor != HistoryInTextCursorState) { if (state.cursor != CursorState::Text) {
return false; return false;
} }
if (!hasSelectedText() if (!hasSelectedText()
@ -692,13 +820,13 @@ void ListWidget::checkMoveToOtherViewer() {
} }
QString ListWidget::tooltipText() const { QString ListWidget::tooltipText() const {
const auto item = (_overItem && _mouseAction == MouseAction::None) const auto item = (_overElement && _mouseAction == MouseAction::None)
? _overItem->data().get() ? _overElement->data().get()
: nullptr; : nullptr;
if (_mouseCursorState == HistoryInDateCursorState && item) { if (_mouseCursorState == CursorState::Date && item) {
return item->date.toString( return item->date.toString(
QLocale::system().dateTimeFormat(QLocale::LongFormat)); QLocale::system().dateTimeFormat(QLocale::LongFormat));
} else if (_mouseCursorState == HistoryInForwardedCursorState && item) { } else if (_mouseCursorState == CursorState::Forwarded && item) {
if (const auto forwarded = item->Get<HistoryMessageForwarded>()) { if (const auto forwarded = item->Get<HistoryMessageForwarded>()) {
return forwarded->text.originalText( return forwarded->text.originalText(
AllTextSelection, AllTextSelection,
@ -730,7 +858,7 @@ std::unique_ptr<Element> ListWidget::elementCreate(
bool ListWidget::elementUnderCursor( bool ListWidget::elementUnderCursor(
not_null<const HistoryView::Element*> view) { not_null<const HistoryView::Element*> view) {
return (_overItem == view); return (_overElement == view);
} }
void ListWidget::elementAnimationAutoplayAsync( void ListWidget::elementAnimationAutoplayAsync(
@ -974,11 +1102,17 @@ void ListWidget::applyDragSelection() {
void ListWidget::applyDragSelection(SelectedMap &applyTo) const { void ListWidget::applyDragSelection(SelectedMap &applyTo) const {
if (_dragSelectAction == DragSelectAction::Selecting) { if (_dragSelectAction == DragSelectAction::Selecting) {
for (const auto itemId : _dragSelected) { for (const auto itemId : _dragSelected) {
applyItemSelection(applyTo, itemId); if (applyTo.size() >= MaxSelectedItems) {
break;
} else if (!applyTo.contains(itemId)) {
if (const auto item = App::histItemById(itemId)) {
addToSelection(applyTo, item);
}
}
} }
} else if (_dragSelectAction == DragSelectAction::Deselecting) { } else if (_dragSelectAction == DragSelectAction::Deselecting) {
for (const auto itemId : _dragSelected) { for (const auto itemId : _dragSelected) {
applyTo.remove(itemId); removeFromSelection(applyTo, itemId);
} }
} }
} }
@ -1132,7 +1266,7 @@ void ListWidget::trySwitchToWordSelection() {
&& hasSelectedText(); && hasSelectedText();
auto willSelectSome = (_mouseAction == MouseAction::None) auto willSelectSome = (_mouseAction == MouseAction::None)
&& !hasSelectedItems(); && !hasSelectedItems();
auto checkSwitchToWordSelection = _overItem auto checkSwitchToWordSelection = _overElement
&& (_mouseSelectType == TextSelectType::Letters) && (_mouseSelectType == TextSelectType::Letters)
&& (selectingSome || willSelectSome); && (selectingSome || willSelectSome);
if (checkSwitchToWordSelection) { if (checkSwitchToWordSelection) {
@ -1141,19 +1275,19 @@ void ListWidget::trySwitchToWordSelection() {
} }
void ListWidget::switchToWordSelection() { void ListWidget::switchToWordSelection() {
Expects(_overItem != nullptr); Expects(_overElement != nullptr);
HistoryStateRequest request; StateRequest request;
request.flags |= Text::StateRequest::Flag::LookupSymbol; request.flags |= Text::StateRequest::Flag::LookupSymbol;
auto dragState = _overItem->getState(_pressState.cursor, request); auto dragState = _overElement->textState(_pressState.point, request);
if (dragState.cursor != HistoryInTextCursorState) { if (dragState.cursor != CursorState::Text) {
return; return;
} }
_mouseTextSymbol = dragState.symbol; _mouseTextSymbol = dragState.symbol;
_mouseSelectType = TextSelectType::Words; _mouseSelectType = TextSelectType::Words;
if (_mouseAction == MouseAction::None) { if (_mouseAction == MouseAction::None) {
_mouseAction = MouseAction::Selecting; _mouseAction = MouseAction::Selecting;
setTextSelection(_overItem, TextSelection( setTextSelection(_overElement, TextSelection(
dragState.symbol, dragState.symbol,
dragState.symbol dragState.symbol
)); ));
@ -1184,8 +1318,10 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
ContextMenuRequest request; ContextMenuRequest request;
request.link = ClickHandler::getActive(); request.link = ClickHandler::getActive();
request.view = _overItem; request.view = _overElement;
request.overView = _overItem && _overState.inside; // #TODO group part context menu using _overItemExact
request.overView = _overElement
&& (_overState.pointState != PointState::Outside);
request.selectedText = _selectedText; request.selectedText = _selectedText;
const auto itemId = request.view const auto itemId = request.view
? request.view->data()->fullId() ? request.view->data()->fullId()
@ -1202,12 +1338,12 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
const auto pointInItem = mapPointToItem( const auto pointInItem = mapPointToItem(
mapFromGlobal(_mousePosition), mapFromGlobal(_mousePosition),
request.view); request.view);
HistoryStateRequest stateRequest; StateRequest stateRequest;
stateRequest.flags |= Text::StateRequest::Flag::LookupSymbol; stateRequest.flags |= Text::StateRequest::Flag::LookupSymbol;
const auto dragState = request.view->getState( const auto dragState = request.view->textState(
pointInItem, pointInItem,
stateRequest); stateRequest);
if (dragState.cursor == HistoryInTextCursorState if (dragState.cursor == CursorState::Text
&& base::in_range( && base::in_range(
dragState.symbol, dragState.symbol,
_selectedTextRange.from, _selectedTextRange.from,
@ -1257,10 +1393,10 @@ void ListWidget::enterEventHook(QEvent *e) {
} }
void ListWidget::leaveEventHook(QEvent *e) { void ListWidget::leaveEventHook(QEvent *e) {
if (const auto view = _overItem) { if (const auto view = _overElement) {
if (_overState.inside) { if (_overState.pointState != PointState::Outside) {
repaintItem(view); repaintItem(view);
_overState.inside = false; _overState.pointState = PointState::Outside;
} }
} }
ClickHandler::clearActive(); ClickHandler::clearActive();
@ -1276,7 +1412,7 @@ void ListWidget::updateDragSelection() {
if (!_overState.itemId || !_pressState.itemId) { if (!_overState.itemId || !_pressState.itemId) {
clearDragSelection(); clearDragSelection();
return; return;
} else if (_items.empty() || !_overItem || !_selectEnabled) { } else if (_items.empty() || !_overElement || !_selectEnabled) {
return; return;
} }
const auto pressItem = App::histItemById(_pressState.itemId); const auto pressItem = App::histItemById(_pressState.itemId);
@ -1284,7 +1420,7 @@ void ListWidget::updateDragSelection() {
return; return;
} }
const auto overView = _overItem; const auto overView = _overElement;
const auto pressView = viewForItem(pressItem); const auto pressView = viewForItem(pressItem);
const auto selectingUp = _delegate->listIsLessInOrder( const auto selectingUp = _delegate->listIsLessInOrder(
overView->data(), overView->data(),
@ -1309,14 +1445,37 @@ void ListWidget::updateDragSelection() {
[](auto view) { return view.get(); }) [](auto view) { return view.get(); })
: end(_items); : end(_items);
Assert(from <= till); Assert(from <= till);
const auto &groups = Auth().data().groups();
const auto changeItem = [&](not_null<HistoryItem*> item, bool add) {
const auto itemId = item->fullId();
if (add) {
_dragSelected.emplace(itemId);
} else {
_dragSelected.remove(itemId);
}
};
const auto changeGroup = [&](not_null<HistoryItem*> item, bool add) {
if (const auto group = groups.find(item)) {
for (const auto item : group->items) {
changeItem(item, add);
}
} else {
changeItem(item, add);
}
};
const auto changeView = [&](not_null<Element*> view, bool add) {
if (!view->isHiddenByGroup()) {
changeGroup(view->data(), add);
}
};
for (auto i = begin(_items); i != from; ++i) { for (auto i = begin(_items); i != from; ++i) {
_dragSelected.remove((*i)->data()->fullId()); changeView(*i, false);
} }
for (auto i = from; i != till; ++i) { for (auto i = from; i != till; ++i) {
_dragSelected.emplace((*i)->data()->fullId()); changeView(*i, true);
} }
for (auto i = till; i != end(_items); ++i) { for (auto i = till; i != end(_items); ++i) {
_dragSelected.remove((*i)->data()->fullId()); changeView(*i, false);
} }
_dragSelectAction = [&] { _dragSelectAction = [&] {
if (_dragSelected.empty()) { if (_dragSelected.empty()) {
@ -1363,7 +1522,7 @@ void ListWidget::mouseActionStart(
_pressState = _overState; _pressState = _overState;
repaintItem(_overState.itemId); repaintItem(_overState.itemId);
} }
const auto pressedItem = _overItem; const auto pressedView = _overElement;
_mouseAction = MouseAction::None; _mouseAction = MouseAction::None;
_pressWasInactive = _controller->window()->wasInactivePress(); _pressWasInactive = _controller->window()->wasInactivePress();
@ -1371,18 +1530,24 @@ void ListWidget::mouseActionStart(
if (ClickHandler::getPressed()) { if (ClickHandler::getPressed()) {
_mouseAction = MouseAction::PrepareDrag; _mouseAction = MouseAction::PrepareDrag;
} else if (hasSelectedItems()) {
if (overSelectedItems()) {
_mouseAction = MouseAction::PrepareDrag;
} else if (!_pressWasInactive) {
_mouseAction = MouseAction::PrepareSelect;
}
} }
if (_mouseAction == MouseAction::None && pressedItem) { if (_mouseAction == MouseAction::None && pressedView) {
validateTrippleClickStartTime(); validateTrippleClickStartTime();
HistoryTextState dragState; TextState dragState;
auto startDistance = (globalPosition - _trippleClickPoint).manhattanLength(); auto startDistance = (globalPosition - _trippleClickPoint).manhattanLength();
auto validStartPoint = startDistance < QApplication::startDragDistance(); auto validStartPoint = startDistance < QApplication::startDragDistance();
if (_trippleClickStartTime != 0 && validStartPoint) { if (_trippleClickStartTime != 0 && validStartPoint) {
HistoryStateRequest request; StateRequest request;
request.flags = Text::StateRequest::Flag::LookupSymbol; request.flags = Text::StateRequest::Flag::LookupSymbol;
dragState = pressedItem->getState(_pressState.cursor, request); dragState = pressedView->textState(_pressState.point, request);
if (dragState.cursor == HistoryInTextCursorState) { if (dragState.cursor == CursorState::Text) {
setTextSelection(pressedItem, TextSelection( setTextSelection(pressedView, TextSelection(
dragState.symbol, dragState.symbol,
dragState.symbol dragState.symbol
)); ));
@ -1392,23 +1557,22 @@ void ListWidget::mouseActionStart(
mouseActionUpdate(); mouseActionUpdate();
_trippleClickStartTime = getms(); _trippleClickStartTime = getms();
} }
} else if (pressedItem) { } else if (pressedView) {
HistoryStateRequest request; StateRequest request;
request.flags = Text::StateRequest::Flag::LookupSymbol; request.flags = Text::StateRequest::Flag::LookupSymbol;
dragState = pressedItem->getState(_pressState.cursor, request); dragState = pressedView->textState(_pressState.point, request);
} }
if (_mouseSelectType != TextSelectType::Paragraphs) { if (_mouseSelectType != TextSelectType::Paragraphs) {
_mouseTextSymbol = dragState.symbol; _mouseTextSymbol = dragState.symbol;
if (isPressInSelectedText(dragState)) { if (isPressInSelectedText(dragState)) {
_mouseAction = MouseAction::PrepareDrag; // start text drag _mouseAction = MouseAction::PrepareDrag; // start text drag
} else if (!_pressWasInactive) { } else if (!_pressWasInactive) {
if (requiredToStartDragging(pressedItem)) { if (requiredToStartDragging(pressedView)) {
_mouseAction = MouseAction::PrepareDrag; _mouseAction = MouseAction::PrepareDrag;
} else { } else {
if (dragState.afterSymbol) ++_mouseTextSymbol; if (dragState.afterSymbol) ++_mouseTextSymbol;
;
if (!hasSelectedItems()) { if (!hasSelectedItems()) {
setTextSelection(pressedItem, TextSelection( setTextSelection(pressedView, TextSelection(
_mouseTextSymbol, _mouseTextSymbol,
_mouseTextSymbol)); _mouseTextSymbol));
_mouseAction = MouseAction::Selecting; _mouseAction = MouseAction::Selecting;
@ -1419,7 +1583,7 @@ void ListWidget::mouseActionStart(
} }
} }
} }
if (!pressedItem) { if (!pressedView) {
_mouseAction = MouseAction::None; _mouseAction = MouseAction::None;
} else if (_mouseAction == MouseAction::None) { } else if (_mouseAction == MouseAction::None) {
mouseActionCancel(); mouseActionCancel();
@ -1432,7 +1596,7 @@ void ListWidget::mouseActionUpdate(const QPoint &globalPosition) {
} }
void ListWidget::mouseActionCancel() { void ListWidget::mouseActionCancel() {
_pressState = CursorState(); _pressState = MouseState();
_mouseAction = MouseAction::None; _mouseAction = MouseAction::None;
clearDragSelection(); clearDragSelection();
_wasSelectedText = false; _wasSelectedText = false;
@ -1444,33 +1608,63 @@ void ListWidget::mouseActionFinish(
Qt::MouseButton button) { Qt::MouseButton button) {
mouseActionUpdate(globalPosition); mouseActionUpdate(globalPosition);
auto activated = ClickHandler::unpressed();
if (_mouseAction == MouseAction::Dragging) {
activated = nullptr;
}
auto pressState = base::take(_pressState); auto pressState = base::take(_pressState);
repaintItem(pressState.itemId); repaintItem(pressState.itemId);
const auto toggleByHandler = [&](const ClickHandlerPtr &handler) {
if (_overElement) {
// If we are in selecting items mode perhaps we want to
// toggle selection instead of activating the pressed link.
if (const auto media = _overElement->media()) {
if (media->toggleSelectionByHandlerClick(handler)) {
return true;
}
}
}
return false;
};
auto activated = ClickHandler::unpressed();
auto simpleSelectionChange = pressState.itemId auto simpleSelectionChange = pressState.itemId
&& pressState.inside && (pressState.pointState != PointState::Outside)
&& !_pressWasInactive && !_pressWasInactive
&& (button != Qt::RightButton) && (button != Qt::RightButton)
&& (_mouseAction == MouseAction::PrepareDrag && (_mouseAction == MouseAction::PrepareSelect
|| _mouseAction == MouseAction::PrepareSelect); || _mouseAction == MouseAction::PrepareDrag);
auto needItemSelectionToggle = simpleSelectionChange auto needItemSelectionToggle = simpleSelectionChange
&& (!activated || toggleByHandler(activated))
&& hasSelectedItems(); && hasSelectedItems();
auto needTextSelectionClear = simpleSelectionChange auto needTextSelectionClear = simpleSelectionChange
&& hasSelectedText(); && hasSelectedText();
_wasSelectedText = false; _wasSelectedText = false;
if (activated) { if (_mouseAction == MouseAction::Dragging
|| _mouseAction == MouseAction::Selecting
|| needItemSelectionToggle) {
activated = nullptr;
} else if (activated) {
mouseActionCancel(); mouseActionCancel();
App::activateClickHandler(activated, button); App::activateClickHandler(activated, button);
return; return;
} }
if (needItemSelectionToggle) { if (needItemSelectionToggle) {
toggleItemSelection(pressState.itemId); if (const auto item = App::histItemById(pressState.itemId)) {
clearTextSelection();
if (pressState.pointState == PointState::GroupPart) {
changeSelection(
_selected,
_overItemExact ? _overItemExact : item,
SelectAction::Invert);
} else {
changeSelectionAsGroup(
_selected,
item,
SelectAction::Invert);
}
pushSelectedItems();
}
} else if (needTextSelectionClear) { } else if (needTextSelectionClear) {
clearTextSelection(); clearTextSelection();
} else if (_mouseAction == MouseAction::Selecting) { } else if (_mouseAction == MouseAction::Selecting) {
@ -1506,26 +1700,26 @@ void ListWidget::mouseActionUpdate() {
const auto view = strictFindItemByY(point.y()); const auto view = strictFindItemByY(point.y());
const auto item = view ? view->data().get() : nullptr; const auto item = view ? view->data().get() : nullptr;
const auto itemPoint = mapPointToItem(point, view); const auto itemPoint = mapPointToItem(point, view);
_overState = CursorState{ _overState = MouseState{
item ? item->fullId() : FullMsgId(), item ? item->fullId() : FullMsgId(),
view ? view->height() : 0, view ? view->height() : 0,
itemPoint, itemPoint,
view ? view->hasPoint(itemPoint) : false view ? view->pointState(itemPoint) : PointState::Outside
}; };
if (_overItem != view) { if (_overElement != view) {
repaintItem(_overItem); repaintItem(_overElement);
_overItem = view; _overElement = view;
repaintItem(_overItem); repaintItem(_overElement);
} }
HistoryTextState dragState; TextState dragState;
ClickHandlerHost *lnkhost = nullptr; ClickHandlerHost *lnkhost = nullptr;
auto inTextSelection = _overState.inside auto inTextSelection = (_overState.pointState != PointState::Outside)
&& (_overState.itemId == _pressState.itemId) && (_overState.itemId == _pressState.itemId)
&& hasSelectedText(); && hasSelectedText();
if (view) { if (view) {
auto cursorDeltaLength = [&] { auto cursorDeltaLength = [&] {
auto cursorDelta = (_overState.cursor - _pressState.cursor); auto cursorDelta = (_overState.point - _pressState.point);
return cursorDelta.manhattanLength(); return cursorDelta.manhattanLength();
}; };
auto dragStartLength = [] { auto dragStartLength = [] {
@ -1540,14 +1734,15 @@ void ListWidget::mouseActionUpdate() {
_mouseAction = MouseAction::Selecting; _mouseAction = MouseAction::Selecting;
} }
} }
HistoryStateRequest request; StateRequest request;
if (_mouseAction == MouseAction::Selecting) { if (_mouseAction == MouseAction::Selecting) {
request.flags |= Text::StateRequest::Flag::LookupSymbol; request.flags |= Text::StateRequest::Flag::LookupSymbol;
} else { } else {
inTextSelection = false; inTextSelection = false;
} }
// #TODO enumerate dates like HistoryInner // #TODO enumerate dates like HistoryInner
dragState = view->getState(itemPoint, request); dragState = view->textState(itemPoint, request);
_overItemExact = App::histItemById(dragState.itemId);
lnkhost = view; lnkhost = view;
if (!dragState.link if (!dragState.link
&& itemPoint.x() >= st::historyPhotoLeft && itemPoint.x() >= st::historyPhotoLeft
@ -1564,7 +1759,10 @@ void ListWidget::mouseActionUpdate() {
const auto message = view->data()->toHistoryMessage(); const auto message = view->data()->toHistoryMessage();
Assert(message != nullptr); Assert(message != nullptr);
dragState.link = message->from()->openLink(); dragState = TextState(
nullptr,
message->displayFrom()->openLink());
_overItemExact = App::histItemById(dragState.itemId);
lnkhost = view; lnkhost = view;
return false; return false;
} }
@ -1578,8 +1776,8 @@ void ListWidget::mouseActionUpdate() {
Ui::Tooltip::Hide(); Ui::Tooltip::Hide();
} }
if (dragState.link if (dragState.link
|| dragState.cursor == HistoryInDateCursorState || dragState.cursor == CursorState::Date
|| dragState.cursor == HistoryInForwardedCursorState) { || dragState.cursor == CursorState::Forwarded) {
Ui::Tooltip::Show(1000, this); Ui::Tooltip::Show(1000, this);
} }
@ -1617,7 +1815,8 @@ void ListWidget::mouseActionUpdate() {
} }
// Voice message seek support. // Voice message seek support.
if (_pressState.inside && ClickHandler::getPressed()) { if (_pressState.pointState != PointState::Outside
&& ClickHandler::getPressed()) {
if (const auto item = App::histItemById(_pressState.itemId)) { if (const auto item = App::histItemById(_pressState.itemId)) {
if (const auto view = viewForItem(item)) { if (const auto view = viewForItem(item)) {
auto adjustedPoint = mapPointToItem(point, view); auto adjustedPoint = mapPointToItem(point, view);
@ -1637,7 +1836,7 @@ style::cursor ListWidget::computeMouseCursor() const {
if (ClickHandler::getPressed() || ClickHandler::getActive()) { if (ClickHandler::getPressed() || ClickHandler::getActive()) {
return style::cur_pointer; return style::cur_pointer;
} else if (!hasSelectedItems() } else if (!hasSelectedItems()
&& (_mouseCursorState == HistoryInTextCursorState)) { && (_mouseCursorState == CursorState::Text)) {
return style::cur_text; return style::cur_text;
} }
return style::cur_default; return style::cur_default;
@ -1651,10 +1850,10 @@ void ListWidget::performDrag() {
// if (!_selected.isEmpty() && _selected.cbegin().value() == FullSelection) { // if (!_selected.isEmpty() && _selected.cbegin().value() == FullSelection) {
// uponSelected = _selected.contains(_mouseActionItem); // uponSelected = _selected.contains(_mouseActionItem);
// } else { // } else {
// HistoryStateRequest request; // StateRequest request;
// request.flags |= Text::StateRequest::Flag::LookupSymbol; // request.flags |= Text::StateRequest::Flag::LookupSymbol;
// auto dragState = _mouseActionItem->getState(_dragStartPosition.x(), _dragStartPosition.y(), request); // auto dragState = _mouseActionItem->textState(_dragStartPosition.x(), _dragStartPosition.y(), request);
// uponSelected = (dragState.cursor == HistoryInTextCursorState); // uponSelected = (dragState.cursor == CursorState::Text);
// if (uponSelected) { // if (uponSelected) {
// if (_selected.isEmpty() || // if (_selected.isEmpty() ||
// _selected.cbegin().value() == FullSelection || // _selected.cbegin().value() == FullSelection ||
@ -1705,7 +1904,7 @@ void ListWidget::performDrag() {
// auto pressedMedia = static_cast<HistoryMedia*>(nullptr); // auto pressedMedia = static_cast<HistoryMedia*>(nullptr);
// if (auto pressedItem = App::pressedItem()) { // #TODO no App:: // if (auto pressedItem = App::pressedItem()) { // #TODO no App::
// pressedMedia = pressedItem->media(); // pressedMedia = pressedItem->media();
// if (_mouseCursorState == HistoryInDateCursorState // if (_mouseCursorState == CursorState::Date
// || (pressedMedia && pressedMedia->dragItem())) { // || (pressedMedia && pressedMedia->dragItem())) {
// Auth().data().setMimeForwardIds( // Auth().data().setMimeForwardIds(
// Auth().data().itemOrItsGroup(pressedItem->data())); // Auth().data().itemOrItsGroup(pressedItem->data()));
@ -1779,7 +1978,8 @@ void ListWidget::refreshAttachmentsAtIndex(int index) {
return index; return index;
}(); }();
const auto till = [&] { const auto till = [&] {
for (auto i = index + 1, count = int(_items.size()); i != count; ) { const auto count = int(_items.size());
for (auto i = index + 1; i != count; ++i) {
if (!_items[i]->isHiddenByGroup()) { if (!_items[i]->isHiddenByGroup()) {
return i + 1; return i + 1;
} }
@ -1835,13 +2035,16 @@ void ListWidget::refreshItem(not_null<const Element*> view) {
void ListWidget::viewReplaced(not_null<const Element*> was, Element *now) { void ListWidget::viewReplaced(not_null<const Element*> was, Element *now) {
if (_visibleTopItem == was) _visibleTopItem = now; if (_visibleTopItem == was) _visibleTopItem = now;
if (_scrollDateLastItem == was) _scrollDateLastItem = now; if (_scrollDateLastItem == was) _scrollDateLastItem = now;
if (_overItem == was) _overItem = now; if (_overElement == was) _overElement = now;
} }
void ListWidget::itemRemoved(not_null<const HistoryItem*> item) { void ListWidget::itemRemoved(not_null<const HistoryItem*> item) {
if (_selectedTextItem == item) { if (_selectedTextItem == item) {
clearTextSelection(); clearTextSelection();
} }
if (_overItemExact == item) {
_overItemExact = nullptr;
}
const auto i = _views.find(item); const auto i = _views.find(item);
if (i == end(_views)) { if (i == end(_views)) {
return; return;

View File

@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/sender.h" #include "mtproto/sender.h"
#include "base/timer.h" #include "base/timer.h"
#include "data/data_messages.h" #include "data/data_messages.h"
#include "history/view/history_view_cursor_state.h"
#include "history/view/history_view_element.h" #include "history/view/history_view_element.h"
namespace Ui { namespace Ui {
@ -25,6 +24,10 @@ class Controller;
namespace HistoryView { namespace HistoryView {
struct TextState;
struct StateRequest;
enum class CursorState : char;
enum class PointState : char;
enum class Context : char; enum class Context : char;
struct SelectedItem { struct SelectedItem {
@ -166,17 +169,24 @@ protected:
int resizeGetHeight(int newWidth) override; int resizeGetHeight(int newWidth) override;
private: private:
struct CursorState { struct MouseState {
MouseState();
MouseState(
FullMsgId itemId,
int height,
QPoint point,
PointState pointState);
FullMsgId itemId; FullMsgId itemId;
int height = 0; int height = 0;
QPoint cursor; QPoint point;
bool inside = false; PointState pointState;
inline bool operator==(const CursorState &other) const { inline bool operator==(const MouseState &other) const {
return (itemId == other.itemId) return (itemId == other.itemId)
&& (cursor == other.cursor); && (point == other.point);
} }
inline bool operator!=(const CursorState &other) const { inline bool operator!=(const MouseState &other) const {
return !(*this == other); return !(*this == other);
} }
@ -192,6 +202,11 @@ private:
PrepareSelect, PrepareSelect,
Selecting, Selecting,
}; };
enum class SelectAction {
Select,
Deselect,
Invert,
};
enum class EnumItemsDirection { enum class EnumItemsDirection {
TopToBottom, TopToBottom,
BottomToTop, BottomToTop,
@ -202,6 +217,8 @@ private:
Deselecting, Deselecting,
}; };
using ScrollTopState = ListMemento::ScrollTopState; using ScrollTopState = ListMemento::ScrollTopState;
using PointState = HistoryView::PointState;
using CursorState = HistoryView::CursorState;
void refreshViewer(); void refreshViewer();
void updateAroundPositionFromRows(); void updateAroundPositionFromRows();
@ -264,18 +281,42 @@ private:
const SelectedMap::const_iterator &i); const SelectedMap::const_iterator &i);
bool hasSelectedText() const; bool hasSelectedText() const;
bool hasSelectedItems() const; bool hasSelectedItems() const;
bool overSelectedItems() const;
void clearTextSelection(); void clearTextSelection();
void clearSelected(); void clearSelected();
void setTextSelection( void setTextSelection(
not_null<Element*> view, not_null<Element*> view,
TextSelection selection); TextSelection selection);
bool applyItemSelection(SelectedMap &applyTo, FullMsgId itemId) const; //bool applyItemSelection(SelectedMap &applyTo, FullMsgId itemId) const;
void toggleItemSelection(FullMsgId itemId); //void toggleItemSelection(FullMsgId itemId);
bool isGoodForSelection(
SelectedMap &applyTo,
not_null<HistoryItem*> item,
int &totalCount) const;
bool addToSelection(
SelectedMap &applyTo,
not_null<HistoryItem*> item) const;
bool removeFromSelection(
SelectedMap &applyTo,
FullMsgId itemId) const;
void changeSelection(
SelectedMap &applyTo,
not_null<HistoryItem*> item,
SelectAction action) const;
bool isSelectedAsGroup(
const SelectedMap &applyTo,
not_null<HistoryItem*> item) const;
void changeSelectionAsGroup(
SelectedMap &applyTo,
not_null<HistoryItem*> item,
SelectAction action) const;
SelectedMap::iterator itemUnderPressSelection(); SelectedMap::iterator itemUnderPressSelection();
SelectedMap::const_iterator itemUnderPressSelection() const; SelectedMap::const_iterator itemUnderPressSelection() const;
bool isItemUnderPressSelected() const; bool isItemUnderPressSelected() const;
bool requiredToStartDragging(not_null<Element*> view) const; bool requiredToStartDragging(not_null<Element*> view) const;
bool isPressInSelectedText(HistoryTextState state) const; bool isPressInSelectedText(TextState state) const;
void updateDragSelection(); void updateDragSelection();
void clearDragSelection(); void clearDragSelection();
void applyDragSelection(); void applyDragSelection();
@ -345,10 +386,11 @@ private:
MouseAction _mouseAction = MouseAction::None; MouseAction _mouseAction = MouseAction::None;
TextSelectType _mouseSelectType = TextSelectType::Letters; TextSelectType _mouseSelectType = TextSelectType::Letters;
QPoint _mousePosition; QPoint _mousePosition;
CursorState _overState; MouseState _overState;
CursorState _pressState; MouseState _pressState;
Element *_overItem = nullptr; Element *_overElement = nullptr;
HistoryCursorState _mouseCursorState = HistoryDefaultCursorState; HistoryItem *_overItemExact = nullptr;
CursorState _mouseCursorState = CursorState();
uint16 _mouseTextSymbol = 0; uint16 _mouseTextSymbol = 0;
bool _pressWasInactive = false; bool _pressWasInactive = false;

View File

@ -435,31 +435,15 @@ void Message::draw(
if (entry) { if (entry) {
trect.setHeight(trect.height() - entry->height()); trect.setHeight(trect.height() - entry->height());
} }
auto needDrawInfo = mediaOnBottom paintText(p, trect, selection);
? !(entry
? entry->customInfoLayout()
: media->customInfoLayout())
: true;
if (mediaDisplayed) { if (mediaDisplayed) {
auto mediaAboveText = media->isAboveMessage();
auto mediaHeight = media->height(); auto mediaHeight = media->height();
auto mediaLeft = g.left(); auto mediaLeft = g.left();
auto mediaTop = mediaAboveText ? trect.y() : (trect.y() + trect.height() - mediaHeight); auto mediaTop = (trect.y() + trect.height() - mediaHeight);
if (!mediaAboveText) {
paintText(p, trect, selection);
}
p.translate(mediaLeft, mediaTop); p.translate(mediaLeft, mediaTop);
media->draw(p, clip.translated(-mediaLeft, -mediaTop), skipTextSelection(selection), ms); media->draw(p, clip.translated(-mediaLeft, -mediaTop), skipTextSelection(selection), ms);
p.translate(-mediaLeft, -mediaTop); p.translate(-mediaLeft, -mediaTop);
if (mediaAboveText) {
trect.setY(trect.y() + mediaHeight);
paintText(p, trect, selection);
} else {
needDrawInfo = !media->customInfoLayout();
}
} else {
paintText(p, trect, selection);
} }
if (entry) { if (entry) {
auto entryLeft = g.left(); auto entryLeft = g.left();
@ -472,8 +456,13 @@ void Message::draw(
entry->draw(p, clip.translated(-entryLeft, -entryTop), entrySelection, ms); entry->draw(p, clip.translated(-entryLeft, -entryTop), entrySelection, ms);
p.translate(-entryLeft, -entryTop); p.translate(-entryLeft, -entryTop);
} }
const auto needDrawInfo = entry
? !entry->customInfoLayout()
: (mediaDisplayed
? !media->customInfoLayout()
: true);
if (needDrawInfo) { if (needDrawInfo) {
drawInfo(p, g.left() + g.width(), g.top() + g.height(), 2 * g.left() + g.width(), selected, InfoDisplayDefault); drawInfo(p, g.left() + g.width(), g.top() + g.height(), 2 * g.left() + g.width(), selected, InfoDisplayType::Default);
} }
if (displayRightAction()) { if (displayRightAction()) {
const auto fastShareSkip = snap( const auto fastShareSkip = snap(
@ -618,20 +607,56 @@ void Message::paintText(Painter &p, QRect &trect, TextSelection selection) const
item->_text.draw(p, trect.x(), trect.y(), trect.width(), style::al_left, 0, -1, selection); item->_text.draw(p, trect.x(), trect.y(), trect.width(), style::al_left, 0, -1, selection);
} }
bool Message::hasPoint(QPoint point) const { PointState Message::pointState(QPoint point) const {
const auto g = countGeometry(); const auto g = countGeometry();
if (g.width() < 1) { if (g.width() < 1) {
return false; return PointState::Outside;
} }
const auto media = this->media();
const auto item = message(); const auto item = message();
if (drawBubble()) { if (drawBubble()) {
return g.contains(point); if (!g.contains(point)) {
} else if (const auto media = this->media()) { return PointState::Outside;
return media->hasPoint(point - g.topLeft()); }
} else { if (const auto mediaDisplayed = media && media->isDisplayed()) {
return false; // Hack for grouped media point state.
auto entry = logEntryOriginal();
// Entry page is always a bubble bottom.
auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/);
auto mediaOnTop = (mediaDisplayed && media->isBubbleTop()) || (entry && entry->isBubbleTop());
auto trect = g.marginsRemoved(st::msgPadding);
if (mediaOnBottom) {
trect.setHeight(trect.height() + st::msgPadding.bottom());
}
//if (mediaOnTop) {
// trect.setY(trect.y() - st::msgPadding.top());
//} else {
// if (getStateFromName(point, trect, &result)) return result;
// if (getStateForwardedInfo(point, trect, &result, request)) return result;
// if (getStateReplyInfo(point, trect, &result)) return result;
// if (getStateViaBotIdInfo(point, trect, &result)) return result;
//}
if (entry) {
auto entryHeight = entry->height();
trect.setHeight(trect.height() - entryHeight);
}
auto mediaHeight = media->height();
auto mediaLeft = trect.x() - st::msgPadding.left();
auto mediaTop = (trect.y() + trect.height() - mediaHeight);
if (point.y() >= mediaTop && point.y() < mediaTop + mediaHeight) {
return media->pointState(point - QPoint(mediaLeft, mediaTop));
}
}
return PointState::Inside;
} else if (media) {
return media->pointState(point - g.topLeft());
} }
return PointState::Outside;
} }
bool Message::displayFromPhoto() const { bool Message::displayFromPhoto() const {
@ -661,13 +686,13 @@ bool Message::hasFromPhoto() const {
Unexpected("Context in Message::hasFromPhoto."); Unexpected("Context in Message::hasFromPhoto.");
} }
HistoryTextState Message::getState( TextState Message::textState(
QPoint point, QPoint point,
HistoryStateRequest request) const { StateRequest request) const {
const auto item = message(); const auto item = message();
const auto media = this->media(); const auto media = this->media();
auto result = HistoryTextState(item); auto result = TextState(item);
auto g = countGeometry(); auto g = countGeometry();
if (g.width() < 1) { if (g.width() < 1) {
@ -707,7 +732,7 @@ HistoryTextState Message::getState(
auto entryLeft = g.left(); auto entryLeft = g.left();
auto entryTop = trect.y() + trect.height(); auto entryTop = trect.y() + trect.height();
if (point.y() >= entryTop && point.y() < entryTop + entryHeight) { if (point.y() >= entryTop && point.y() < entryTop + entryHeight) {
result = entry->getState( result = entry->textState(
point - QPoint(entryLeft, entryTop), point - QPoint(entryLeft, entryTop),
request); request);
result.symbol += item->_text.length() + (mediaDisplayed ? media->fullSelectionLength() : 0); result.symbol += item->_text.length() + (mediaDisplayed ? media->fullSelectionLength() : 0);
@ -720,28 +745,22 @@ HistoryTextState Message::getState(
: media->customInfoLayout()) : media->customInfoLayout())
: true; : true;
if (mediaDisplayed) { if (mediaDisplayed) {
auto mediaAboveText = media->isAboveMessage();
auto mediaHeight = media->height(); auto mediaHeight = media->height();
auto mediaLeft = trect.x() - st::msgPadding.left(); auto mediaLeft = trect.x() - st::msgPadding.left();
auto mediaTop = mediaAboveText ? trect.y() : (trect.y() + trect.height() - mediaHeight); auto mediaTop = (trect.y() + trect.height() - mediaHeight);
if (point.y() >= mediaTop && point.y() < mediaTop + mediaHeight) { if (point.y() >= mediaTop && point.y() < mediaTop + mediaHeight) {
result = media->getState(point - QPoint(mediaLeft, mediaTop), request); result = media->textState(point - QPoint(mediaLeft, mediaTop), request);
result.symbol += item->_text.length(); result.symbol += item->_text.length();
} else { } else if (trect.contains(point)) {
if (mediaAboveText) { getStateText(point, trect, &result, request);
trect.setY(trect.y() + mediaHeight);
}
if (trect.contains(point)) {
getStateText(point, trect, &result, request);
}
} }
} else if (trect.contains(point)) { } else if (trect.contains(point)) {
getStateText(point, trect, &result, request); getStateText(point, trect, &result, request);
} }
if (needDateCheck) { if (needDateCheck) {
if (pointInTime(g.left() + g.width(), g.top() + g.height(), point, InfoDisplayDefault)) { if (pointInTime(g.left() + g.width(), g.top() + g.height(), point, InfoDisplayType::Default)) {
result.cursor = HistoryInDateCursorState; result.cursor = CursorState::Date;
} }
} }
if (displayRightAction()) { if (displayRightAction()) {
@ -761,14 +780,14 @@ HistoryTextState Message::getState(
} }
} }
} else if (media && media->isDisplayed()) { } else if (media && media->isDisplayed()) {
result = media->getState(point - g.topLeft(), request); result = media->textState(point - g.topLeft(), request);
result.symbol += item->_text.length(); result.symbol += item->_text.length();
} }
if (keyboard && !item->isLogEntry()) { if (keyboard && !item->isLogEntry()) {
auto keyboardTop = g.top() + g.height() + st::msgBotKbButton.margin; auto keyboardTop = g.top() + g.height() + st::msgBotKbButton.margin;
if (QRect(g.left(), keyboardTop, g.width(), keyboardHeight).contains(point)) { if (QRect(g.left(), keyboardTop, g.width(), keyboardHeight).contains(point)) {
result.link = keyboard->getState(point - QPoint(g.left(), keyboardTop)); result.link = keyboard->getLink(point - QPoint(g.left(), keyboardTop));
return result; return result;
} }
} }
@ -779,7 +798,7 @@ HistoryTextState Message::getState(
bool Message::getStateFromName( bool Message::getStateFromName(
QPoint point, QPoint point,
QRect &trect, QRect &trect,
not_null<HistoryTextState*> outResult) const { not_null<TextState*> outResult) const {
const auto item = message(); const auto item = message();
if (displayFromName()) { if (displayFromName()) {
const auto replyWidth = [&] { const auto replyWidth = [&] {
@ -828,8 +847,8 @@ bool Message::getStateFromName(
bool Message::getStateForwardedInfo( bool Message::getStateForwardedInfo(
QPoint point, QPoint point,
QRect &trect, QRect &trect,
not_null<HistoryTextState*> outResult, not_null<TextState*> outResult,
HistoryStateRequest request) const { StateRequest request) const {
if (displayForwardedFrom()) { if (displayForwardedFrom()) {
const auto item = message(); const auto item = message();
auto forwarded = item->Get<HistoryMessageForwarded>(); auto forwarded = item->Get<HistoryMessageForwarded>();
@ -840,16 +859,16 @@ bool Message::getStateForwardedInfo(
if (breakEverywhere) { if (breakEverywhere) {
textRequest.flags |= Text::StateRequest::Flag::BreakEverywhere; textRequest.flags |= Text::StateRequest::Flag::BreakEverywhere;
} }
*outResult = HistoryTextState(item, forwarded->text.getState( *outResult = TextState(item, forwarded->text.getState(
point - trect.topLeft(), point - trect.topLeft(),
trect.width(), trect.width(),
textRequest)); textRequest));
outResult->symbol = 0; outResult->symbol = 0;
outResult->afterSymbol = false; outResult->afterSymbol = false;
if (breakEverywhere) { if (breakEverywhere) {
outResult->cursor = HistoryInForwardedCursorState; outResult->cursor = CursorState::Forwarded;
} else { } else {
outResult->cursor = HistoryDefaultCursorState; outResult->cursor = CursorState::None;
} }
return true; return true;
} }
@ -861,7 +880,7 @@ bool Message::getStateForwardedInfo(
bool Message::getStateReplyInfo( bool Message::getStateReplyInfo(
QPoint point, QPoint point,
QRect &trect, QRect &trect,
not_null<HistoryTextState*> outResult) const { not_null<TextState*> outResult) const {
const auto item = message(); const auto item = message();
if (auto reply = item->Get<HistoryMessageReply>()) { if (auto reply = item->Get<HistoryMessageReply>()) {
int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
@ -879,7 +898,7 @@ bool Message::getStateReplyInfo(
bool Message::getStateViaBotIdInfo( bool Message::getStateViaBotIdInfo(
QPoint point, QPoint point,
QRect &trect, QRect &trect,
not_null<HistoryTextState*> outResult) const { not_null<TextState*> outResult) const {
const auto item = message(); const auto item = message();
if (!displayFromName() && !item->Has<HistoryMessageForwarded>()) { if (!displayFromName() && !item->Has<HistoryMessageForwarded>()) {
if (auto via = item->Get<HistoryMessageVia>()) { if (auto via = item->Get<HistoryMessageVia>()) {
@ -896,14 +915,14 @@ bool Message::getStateViaBotIdInfo(
bool Message::getStateText( bool Message::getStateText(
QPoint point, QPoint point,
QRect &trect, QRect &trect,
not_null<HistoryTextState*> outResult, not_null<TextState*> outResult,
HistoryStateRequest request) const { StateRequest request) const {
if (!hasVisibleText()) { if (!hasVisibleText()) {
return false; return false;
} }
const auto item = message(); const auto item = message();
if (trect.contains(point)) { if (trect.contains(point)) {
*outResult = HistoryTextState(item, item->_text.getState( *outResult = TextState(item, item->_text.getState(
point - trect.topLeft(), point - trect.topLeft(),
trect.width(), trect.width(),
request.forText())); request.forText()));
@ -954,10 +973,9 @@ void Message::updatePressed(QPoint point) {
auto needDateCheck = true; auto needDateCheck = true;
if (mediaDisplayed) { if (mediaDisplayed) {
auto mediaAboveText = media->isAboveMessage();
auto mediaHeight = media->height(); auto mediaHeight = media->height();
auto mediaLeft = trect.x() - st::msgPadding.left(); auto mediaLeft = trect.x() - st::msgPadding.left();
auto mediaTop = mediaAboveText ? trect.y() : (trect.y() + trect.height() - mediaHeight); auto mediaTop = (trect.y() + trect.height() - mediaHeight);
media->updatePressed(point - QPoint(mediaLeft, mediaTop)); media->updatePressed(point - QPoint(mediaLeft, mediaTop));
} }
} else { } else {
@ -1054,23 +1072,23 @@ void Message::drawInfo(
p.setFont(st::msgDateFont); p.setFont(st::msgDateFont);
bool outbg = hasOutLayout(); bool outbg = hasOutLayout();
bool invertedsprites = (type == InfoDisplayOverImage) bool invertedsprites = (type == InfoDisplayType::Image)
|| (type == InfoDisplayOverBackground); || (type == InfoDisplayType::Background);
int32 infoRight = right, infoBottom = bottom; int32 infoRight = right, infoBottom = bottom;
switch (type) { switch (type) {
case InfoDisplayDefault: case InfoDisplayType::Default:
infoRight -= st::msgPadding.right() - st::msgDateDelta.x(); infoRight -= st::msgPadding.right() - st::msgDateDelta.x();
infoBottom -= st::msgPadding.bottom() - st::msgDateDelta.y(); infoBottom -= st::msgPadding.bottom() - st::msgDateDelta.y();
p.setPen(selected p.setPen(selected
? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected) ? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected)
: (outbg ? st::msgOutDateFg : st::msgInDateFg)); : (outbg ? st::msgOutDateFg : st::msgInDateFg));
break; break;
case InfoDisplayOverImage: case InfoDisplayType::Image:
infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x(); infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x();
infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y(); infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y();
p.setPen(st::msgDateImgFg); p.setPen(st::msgDateImgFg);
break; break;
case InfoDisplayOverBackground: case InfoDisplayType::Background:
infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x(); infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x();
infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y(); infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y();
p.setPen(st::msgServiceFg); p.setPen(st::msgServiceFg);
@ -1083,10 +1101,10 @@ void Message::drawInfo(
auto dateX = infoRight - infoW; auto dateX = infoRight - infoW;
auto dateY = infoBottom - st::msgDateFont->height; auto dateY = infoBottom - st::msgDateFont->height;
if (type == InfoDisplayOverImage) { if (type == InfoDisplayType::Image) {
auto dateW = infoW + 2 * st::msgDateImgPadding.x(), dateH = st::msgDateFont->height + 2 * st::msgDateImgPadding.y(); auto dateW = infoW + 2 * st::msgDateImgPadding.x(), dateH = st::msgDateFont->height + 2 * st::msgDateImgPadding.y();
App::roundRect(p, dateX - st::msgDateImgPadding.x(), dateY - st::msgDateImgPadding.y(), dateW, dateH, selected ? st::msgDateImgBgSelected : st::msgDateImgBg, selected ? DateSelectedCorners : DateCorners); App::roundRect(p, dateX - st::msgDateImgPadding.x(), dateY - st::msgDateImgPadding.y(), dateW, dateH, selected ? st::msgDateImgBgSelected : st::msgDateImgBg, selected ? DateSelectedCorners : DateCorners);
} else if (type == InfoDisplayOverBackground) { } else if (type == InfoDisplayType::Background) {
auto dateW = infoW + 2 * st::msgDateImgPadding.x(), dateH = st::msgDateFont->height + 2 * st::msgDateImgPadding.y(); auto dateW = infoW + 2 * st::msgDateImgPadding.x(), dateH = st::msgDateFont->height + 2 * st::msgDateImgPadding.y();
App::roundRect(p, dateX - st::msgDateImgPadding.x(), dateY - st::msgDateImgPadding.y(), dateW, dateH, selected ? st::msgServiceBgSelected : st::msgServiceBg, selected ? StickerSelectedCorners : StickerCorners); App::roundRect(p, dateX - st::msgDateImgPadding.x(), dateY - st::msgDateImgPadding.y(), dateW, dateH, selected ? st::msgServiceBgSelected : st::msgServiceBg, selected ? StickerSelectedCorners : StickerCorners);
} }
@ -1143,11 +1161,11 @@ bool Message::pointInTime(
auto infoRight = right; auto infoRight = right;
auto infoBottom = bottom; auto infoBottom = bottom;
switch (type) { switch (type) {
case InfoDisplayDefault: case InfoDisplayType::Default:
infoRight -= st::msgPadding.right() - st::msgDateDelta.x(); infoRight -= st::msgPadding.right() - st::msgDateDelta.x();
infoBottom -= st::msgPadding.bottom() - st::msgDateDelta.y(); infoBottom -= st::msgPadding.bottom() - st::msgDateDelta.y();
break; break;
case InfoDisplayOverImage: case InfoDisplayType::Image:
infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x(); infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x();
infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y(); infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y();
break; break;
@ -1414,11 +1432,7 @@ void Message::updateMediaInBubbleState() {
mediaHasSomethingAbove = getMediaHasSomethingAbove(); mediaHasSomethingAbove = getMediaHasSomethingAbove();
} }
if (hasVisibleText()) { if (hasVisibleText()) {
if (media->isAboveMessage()) { mediaHasSomethingAbove = true;
mediaHasSomethingBelow = true;
} else {
mediaHasSomethingAbove = true;
}
} }
const auto state = [&] { const auto state = [&] {
if (mediaHasSomethingAbove) { if (mediaHasSomethingAbove) {

View File

@ -37,10 +37,10 @@ public:
QRect clip, QRect clip,
TextSelection selection, TextSelection selection,
TimeMs ms) const override; TimeMs ms) const override;
bool hasPoint(QPoint point) const override; PointState pointState(QPoint point) const override;
HistoryTextState getState( TextState textState(
QPoint point, QPoint point,
HistoryStateRequest request) const override; StateRequest request) const override;
void updatePressed(QPoint point) override; void updatePressed(QPoint point) override;
void drawInfo( void drawInfo(
Painter &p, Painter &p,
@ -104,25 +104,25 @@ private:
bool getStateFromName( bool getStateFromName(
QPoint point, QPoint point,
QRect &trect, QRect &trect,
not_null<HistoryTextState*> outResult) const; not_null<TextState*> outResult) const;
bool getStateForwardedInfo( bool getStateForwardedInfo(
QPoint point, QPoint point,
QRect &trect, QRect &trect,
not_null<HistoryTextState*> outResult, not_null<TextState*> outResult,
HistoryStateRequest request) const; StateRequest request) const;
bool getStateReplyInfo( bool getStateReplyInfo(
QPoint point, QPoint point,
QRect &trect, QRect &trect,
not_null<HistoryTextState*> outResult) const; not_null<TextState*> outResult) const;
bool getStateViaBotIdInfo( bool getStateViaBotIdInfo(
QPoint point, QPoint point,
QRect &trect, QRect &trect,
not_null<HistoryTextState*> outResult) const; not_null<TextState*> outResult) const;
bool getStateText( bool getStateText(
QPoint point, QPoint point,
QRect &trect, QRect &trect,
not_null<HistoryTextState*> outResult, not_null<TextState*> outResult,
HistoryStateRequest request) const; StateRequest request) const;
void updateMediaInBubbleState(); void updateMediaInBubbleState();
QRect countGeometry() const; QRect countGeometry() const;

View File

@ -436,13 +436,13 @@ void Service::draw(
} }
} }
bool Service::hasPoint(QPoint point) const { PointState Service::pointState(QPoint point) const {
const auto item = message(); const auto item = message();
const auto media = this->media(); const auto media = this->media();
auto g = countGeometry(); auto g = countGeometry();
if (g.width() < 1) { if (g.width() < 1) {
return false; return PointState::Outside;
} }
if (const auto dateh = displayedDateHeight()) { if (const auto dateh = displayedDateHeight()) {
@ -454,14 +454,14 @@ bool Service::hasPoint(QPoint point) const {
if (media) { if (media) {
g.setHeight(g.height() - (st::msgServiceMargin.top() + media->height())); g.setHeight(g.height() - (st::msgServiceMargin.top() + media->height()));
} }
return g.contains(point); return g.contains(point) ? PointState::Inside : PointState::Outside;
} }
HistoryTextState Service::getState(QPoint point, HistoryStateRequest request) const { TextState Service::textState(QPoint point, StateRequest request) const {
const auto item = message(); const auto item = message();
const auto media = this->media(); const auto media = this->media();
auto result = HistoryTextState(item); auto result = TextState(item);
auto g = countGeometry(); auto g = countGeometry();
if (g.width() < 1) { if (g.width() < 1) {
@ -485,21 +485,25 @@ HistoryTextState Service::getState(QPoint point, HistoryStateRequest request) co
if (trect.contains(point)) { if (trect.contains(point)) {
auto textRequest = request.forText(); auto textRequest = request.forText();
textRequest.align = style::al_center; textRequest.align = style::al_center;
result = HistoryTextState(item, item->_text.getState( result = TextState(item, item->_text.getState(
point - trect.topLeft(), point - trect.topLeft(),
trect.width(), trect.width(),
textRequest)); textRequest));
if (auto gamescore = item->Get<HistoryServiceGameScore>()) { if (auto gamescore = item->Get<HistoryServiceGameScore>()) {
if (!result.link && result.cursor == HistoryInTextCursorState && g.contains(point)) { if (!result.link
&& result.cursor == CursorState::Text
&& g.contains(point)) {
result.link = gamescore->lnk; result.link = gamescore->lnk;
} }
} else if (auto payment = item->Get<HistoryServicePayment>()) { } else if (auto payment = item->Get<HistoryServicePayment>()) {
if (!result.link && result.cursor == HistoryInTextCursorState && g.contains(point)) { if (!result.link
&& result.cursor == CursorState::Text
&& g.contains(point)) {
result.link = payment->lnk; result.link = payment->lnk;
} }
} }
} else if (media) { } else if (media) {
result = media->getState(point - QPoint(st::msgServiceMargin.left() + (g.width() - media->maxWidth()) / 2, st::msgServiceMargin.top() + g.height() + st::msgServiceMargin.top()), request); result = media->textState(point - QPoint(st::msgServiceMargin.left() + (g.width() - media->maxWidth()) / 2, st::msgServiceMargin.top() + g.height() + st::msgServiceMargin.top()), request);
} }
return result; return result;
} }

View File

@ -24,10 +24,10 @@ public:
QRect clip, QRect clip,
TextSelection selection, TextSelection selection,
TimeMs ms) const override; TimeMs ms) const override;
bool hasPoint(QPoint point) const override; PointState pointState(QPoint point) const override;
HistoryTextState getState( TextState textState(
QPoint point, QPoint point,
HistoryStateRequest request) const override; StateRequest request) const override;
void updatePressed(QPoint point) override; void updatePressed(QPoint point) override;
TextWithEntities selectedText(TextSelection selection) const override; TextWithEntities selectedText(TextSelection selection) const override;
TextSelection adjustSelection( TextSelection adjustSelection(

View File

@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h" #include "data/data_session.h"
#include "history/history_item.h" #include "history/history_item.h"
#include "history/history.h" #include "history/history.h"
#include "history/view/history_view_cursor_state.h"
#include "window/themes/window_theme.h" #include "window/themes/window_theme.h"
#include "window/window_controller.h" #include "window/window_controller.h"
#include "window/window_peer_menu.h" #include "window/window_peer_menu.h"
@ -151,8 +152,8 @@ private:
}; };
bool ListWidget::IsAfter( bool ListWidget::IsAfter(
const CursorState &a, const MouseState &a,
const CursorState &b) { const MouseState &b) {
if (a.itemId != b.itemId) { if (a.itemId != b.itemId) {
return (a.itemId < b.itemId); return (a.itemId < b.itemId);
} }
@ -161,7 +162,7 @@ bool ListWidget::IsAfter(
return (xAfter + yAfter >= 0); return (xAfter + yAfter >= 0);
} }
bool ListWidget::SkipSelectFromItem(const CursorState &state) { bool ListWidget::SkipSelectFromItem(const MouseState &state) {
if (state.cursor.y() >= state.size.height() if (state.cursor.y() >= state.size.height()
|| state.cursor.x() >= state.size.width()) { || state.cursor.x() >= state.size.width()) {
return true; return true;
@ -169,7 +170,7 @@ bool ListWidget::SkipSelectFromItem(const CursorState &state) {
return false; return false;
} }
bool ListWidget::SkipSelectTillItem(const CursorState &state) { bool ListWidget::SkipSelectTillItem(const MouseState &state) {
if (state.cursor.x() < 0 || state.cursor.y() < 0) { if (state.cursor.x() < 0 || state.cursor.y() < 0) {
return true; return true;
} }
@ -1440,10 +1441,10 @@ void ListWidget::trySwitchToWordSelection() {
void ListWidget::switchToWordSelection() { void ListWidget::switchToWordSelection() {
Expects(_overLayout != nullptr); Expects(_overLayout != nullptr);
HistoryStateRequest request; StateRequest request;
request.flags |= Text::StateRequest::Flag::LookupSymbol; request.flags |= Text::StateRequest::Flag::LookupSymbol;
auto dragState = _overLayout->getState(_pressState.cursor, request); auto dragState = _overLayout->getState(_pressState.cursor, request);
if (dragState.cursor != HistoryInTextCursorState) { if (dragState.cursor != CursorState::Text) {
return; return;
} }
_mouseTextSymbol = dragState.symbol; _mouseTextSymbol = dragState.symbol;
@ -1535,15 +1536,15 @@ auto ListWidget::itemUnderPressSelection() const
bool ListWidget::requiredToStartDragging( bool ListWidget::requiredToStartDragging(
not_null<BaseLayout*> layout) const { not_null<BaseLayout*> layout) const {
if (_mouseCursorState == HistoryInDateCursorState) { if (_mouseCursorState == CursorState::Date) {
return true; return true;
} }
// return dynamic_cast<HistorySticker*>(layout->getMedia()); // return dynamic_cast<HistorySticker*>(layout->getMedia());
return false; return false;
} }
bool ListWidget::isPressInSelectedText(HistoryTextState state) const { bool ListWidget::isPressInSelectedText(TextState state) const {
if (state.cursor != HistoryInTextCursorState) { if (state.cursor != CursorState::Text) {
return false; return false;
} }
if (!hasSelectedText() if (!hasSelectedText()
@ -1616,7 +1617,7 @@ void ListWidget::mouseActionUpdate(const QPoint &globalPosition) {
auto local = mapFromGlobal(_mousePosition); auto local = mapFromGlobal(_mousePosition);
auto point = clampMousePosition(local); auto point = clampMousePosition(local);
auto [layout, geometry, inside] = findItemByPoint(point); auto [layout, geometry, inside] = findItemByPoint(point);
auto state = CursorState { auto state = MouseState{
GetUniversalId(layout), GetUniversalId(layout),
geometry.size(), geometry.size(),
point - geometry.topLeft(), point - geometry.topLeft(),
@ -1630,7 +1631,7 @@ void ListWidget::mouseActionUpdate(const QPoint &globalPosition) {
} }
_overState = state; _overState = state;
HistoryTextState dragState; TextState dragState;
ClickHandlerHost *lnkhost = nullptr; ClickHandlerHost *lnkhost = nullptr;
auto inTextSelection = _overState.inside auto inTextSelection = _overState.inside
&& (_overState.itemId == _pressState.itemId) && (_overState.itemId == _pressState.itemId)
@ -1652,7 +1653,7 @@ void ListWidget::mouseActionUpdate(const QPoint &globalPosition) {
_mouseAction = MouseAction::Selecting; _mouseAction = MouseAction::Selecting;
} }
} }
HistoryStateRequest request; StateRequest request;
if (_mouseAction == MouseAction::Selecting) { if (_mouseAction == MouseAction::Selecting) {
request.flags |= Text::StateRequest::Flag::LookupSymbol; request.flags |= Text::StateRequest::Flag::LookupSymbol;
} else { } else {
@ -1709,7 +1710,7 @@ style::cursor ListWidget::computeMouseCursor() const {
if (ClickHandler::getPressed() || ClickHandler::getActive()) { if (ClickHandler::getPressed() || ClickHandler::getActive()) {
return style::cur_pointer; return style::cur_pointer;
} else if (!hasSelectedItems() } else if (!hasSelectedItems()
&& (_mouseCursorState == HistoryInTextCursorState)) { && (_mouseCursorState == CursorState::Text)) {
return style::cur_text; return style::cur_text;
} }
return style::cur_default; return style::cur_default;
@ -1814,14 +1815,14 @@ void ListWidget::mouseActionStart(
} }
if (_mouseAction == MouseAction::None && pressLayout) { if (_mouseAction == MouseAction::None && pressLayout) {
validateTrippleClickStartTime(); validateTrippleClickStartTime();
HistoryTextState dragState; TextState dragState;
auto startDistance = (globalPosition - _trippleClickPoint).manhattanLength(); auto startDistance = (globalPosition - _trippleClickPoint).manhattanLength();
auto validStartPoint = startDistance < QApplication::startDragDistance(); auto validStartPoint = startDistance < QApplication::startDragDistance();
if (_trippleClickStartTime != 0 && validStartPoint) { if (_trippleClickStartTime != 0 && validStartPoint) {
HistoryStateRequest request; StateRequest request;
request.flags = Text::StateRequest::Flag::LookupSymbol; request.flags = Text::StateRequest::Flag::LookupSymbol;
dragState = pressLayout->getState(_pressState.cursor, request); dragState = pressLayout->getState(_pressState.cursor, request);
if (dragState.cursor == HistoryInTextCursorState) { if (dragState.cursor == CursorState::Text) {
TextSelection selStatus = { dragState.symbol, dragState.symbol }; TextSelection selStatus = { dragState.symbol, dragState.symbol };
if (selStatus != FullSelection && !hasSelectedItems()) { if (selStatus != FullSelection && !hasSelectedItems()) {
clearSelected(); clearSelected();
@ -1834,7 +1835,7 @@ void ListWidget::mouseActionStart(
} }
} }
} else { } else {
HistoryStateRequest request; StateRequest request;
request.flags = Text::StateRequest::Flag::LookupSymbol; request.flags = Text::StateRequest::Flag::LookupSymbol;
dragState = pressLayout->getState(_pressState.cursor, request); dragState = pressLayout->getState(_pressState.cursor, request);
} }
@ -1873,7 +1874,7 @@ void ListWidget::mouseActionStart(
} }
void ListWidget::mouseActionCancel() { void ListWidget::mouseActionCancel() {
_pressState = CursorState(); _pressState = MouseState();
_mouseAction = MouseAction::None; _mouseAction = MouseAction::None;
clearDragSelection(); clearDragSelection();
_wasSelectedText = false; _wasSelectedText = false;
@ -1889,7 +1890,7 @@ void ListWidget::performDrag() {
uponSelected = isItemUnderPressSelected(); uponSelected = isItemUnderPressSelected();
} else if (auto pressLayout = getExistingLayout( } else if (auto pressLayout = getExistingLayout(
_pressState.itemId)) { _pressState.itemId)) {
HistoryStateRequest request; StateRequest request;
request.flags |= Text::StateRequest::Flag::LookupSymbol; request.flags |= Text::StateRequest::Flag::LookupSymbol;
auto dragState = pressLayout->getState( auto dragState = pressLayout->getState(
_pressState.cursor, _pressState.cursor,
@ -1932,7 +1933,7 @@ void ListWidget::performDrag() {
// auto pressedMedia = static_cast<HistoryMedia*>(nullptr); // auto pressedMedia = static_cast<HistoryMedia*>(nullptr);
// if (auto pressedItem = _pressState.layout) { // if (auto pressedItem = _pressState.layout) {
// pressedMedia = pressedItem->getMedia(); // pressedMedia = pressedItem->getMedia();
// if (_mouseCursorState == HistoryInDateCursorState || (pressedMedia && pressedMedia->dragItem())) { // if (_mouseCursorState == CursorState::Date || (pressedMedia && pressedMedia->dragItem())) {
// Auth().data().setMimeForwardIds(Auth().data().itemOrItsGroup(pressedItem)); // Auth().data().setMimeForwardIds(Auth().data().itemOrItsGroup(pressedItem));
// forwardMimeType = qsl("application/x-td-forward"); // forwardMimeType = qsl("application/x-td-forward");
// } // }

View File

@ -10,10 +10,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/rp_widget.h" #include "ui/rp_widget.h"
#include "info/media/info_media_widget.h" #include "info/media/info_media_widget.h"
#include "data/data_shared_media.h" #include "data/data_shared_media.h"
#include "history/view/history_view_cursor_state.h"
class DeleteMessagesBox; class DeleteMessagesBox;
namespace HistoryView {
struct TextState;
struct StateRequest;
enum class CursorState : char;
enum class PointState : char;
} // namespace HistoryView
namespace Ui { namespace Ui {
class PopupMenu; class PopupMenu;
} // namespace Ui } // namespace Ui
@ -80,6 +86,11 @@ protected:
void leaveEventHook(QEvent *e) override; void leaveEventHook(QEvent *e) override;
private: private:
struct Context;
class Section;
using CursorState = HistoryView::CursorState;
using TextState = HistoryView::TextState;
using StateRequest = HistoryView::StateRequest;
enum class MouseAction { enum class MouseAction {
None, None,
PrepareDrag, PrepareDrag,
@ -94,8 +105,6 @@ private:
std::unique_ptr<BaseLayout> item; std::unique_ptr<BaseLayout> item;
bool stale = false; bool stale = false;
}; };
struct Context;
class Section;
struct FoundItem { struct FoundItem {
not_null<BaseLayout*> layout; not_null<BaseLayout*> layout;
QRect geometry; QRect geometry;
@ -118,17 +127,17 @@ private:
Selecting, Selecting,
Deselecting, Deselecting,
}; };
struct CursorState { struct MouseState {
UniversalMsgId itemId = 0; UniversalMsgId itemId = 0;
QSize size; QSize size;
QPoint cursor; QPoint cursor;
bool inside = false; bool inside = false;
inline bool operator==(const CursorState &other) const { inline bool operator==(const MouseState &other) const {
return (itemId == other.itemId) return (itemId == other.itemId)
&& (cursor == other.cursor); && (cursor == other.cursor);
} }
inline bool operator!=(const CursorState &other) const { inline bool operator!=(const MouseState &other) const {
return !(*this == other); return !(*this == other);
} }
@ -198,7 +207,7 @@ private:
SelectedMap::const_iterator itemUnderPressSelection() const; SelectedMap::const_iterator itemUnderPressSelection() const;
bool isItemUnderPressSelected() const; bool isItemUnderPressSelected() const;
bool requiredToStartDragging(not_null<BaseLayout*> layout) const; bool requiredToStartDragging(not_null<BaseLayout*> layout) const;
bool isPressInSelectedText(HistoryTextState state) const; bool isPressInSelectedText(TextState state) const;
void applyDragSelection(); void applyDragSelection();
void applyDragSelection(SelectedMap &applyTo) const; void applyDragSelection(SelectedMap &applyTo) const;
bool changeItemSelection( bool changeItemSelection(
@ -207,10 +216,10 @@ private:
TextSelection selection) const; TextSelection selection) const;
static bool IsAfter( static bool IsAfter(
const CursorState &a, const MouseState &a,
const CursorState &b); const MouseState &b);
static bool SkipSelectFromItem(const CursorState &state); static bool SkipSelectFromItem(const MouseState &state);
static bool SkipSelectTillItem(const CursorState &state); static bool SkipSelectTillItem(const MouseState &state);
void markLayoutsStale(); void markLayoutsStale();
void clearStaleLayouts(); void clearStaleLayouts();
@ -281,11 +290,11 @@ private:
MouseAction _mouseAction = MouseAction::None; MouseAction _mouseAction = MouseAction::None;
TextSelectType _mouseSelectType = TextSelectType::Letters; TextSelectType _mouseSelectType = TextSelectType::Letters;
QPoint _mousePosition; QPoint _mousePosition;
CursorState _overState; MouseState _overState;
CursorState _pressState; MouseState _pressState;
BaseLayout *_overLayout = nullptr; BaseLayout *_overLayout = nullptr;
UniversalMsgId _contextUniversalId = 0; UniversalMsgId _contextUniversalId = 0;
HistoryCursorState _mouseCursorState = HistoryDefaultCursorState; CursorState _mouseCursorState = CursorState();
uint16 _mouseTextSymbol = 0; uint16 _mouseTextSymbol = 0;
bool _pressWasInactive = false; bool _pressWasInactive = false;
SelectedMap _selected; SelectedMap _selected;

View File

@ -28,6 +28,8 @@ namespace InlineBots {
namespace Layout { namespace Layout {
namespace internal { namespace internal {
using TextState = HistoryView::TextState;
FileBase::FileBase(not_null<Context*> context, Result *result) : ItemBase(context, result) { FileBase::FileBase(not_null<Context*> context, Result *result) : ItemBase(context, result) {
} }
@ -208,9 +210,9 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons
} }
} }
HistoryTextState Gif::getState( TextState Gif::getState(
QPoint point, QPoint point,
HistoryStateRequest request) const { StateRequest request) const {
if (QRect(0, 0, _width, st::inlineMediaHeight).contains(point)) { if (QRect(0, 0, _width, st::inlineMediaHeight).contains(point)) {
if (_delete && rtlpoint(point, _width).x() >= _width - st::stickerPanDeleteIconBg.width() && point.y() < st::stickerPanDeleteIconBg.height()) { if (_delete && rtlpoint(point, _width).x() >= _width - st::stickerPanDeleteIconBg.width() && point.y() < st::stickerPanDeleteIconBg.height()) {
return { nullptr, _delete }; return { nullptr, _delete };
@ -402,9 +404,9 @@ void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context)
} }
} }
HistoryTextState Sticker::getState( TextState Sticker::getState(
QPoint point, QPoint point,
HistoryStateRequest request) const { StateRequest request) const {
if (QRect(0, 0, _width, st::inlineMediaHeight).contains(point)) { if (QRect(0, 0, _width, st::inlineMediaHeight).contains(point)) {
return { nullptr, _send }; return { nullptr, _send };
} }
@ -492,9 +494,9 @@ void Photo::paint(Painter &p, const QRect &clip, const PaintContext *context) co
} }
} }
HistoryTextState Photo::getState( TextState Photo::getState(
QPoint point, QPoint point,
HistoryStateRequest request) const { StateRequest request) const {
if (QRect(0, 0, _width, st::inlineMediaHeight).contains(point)) { if (QRect(0, 0, _width, st::inlineMediaHeight).contains(point)) {
return { nullptr, _send }; return { nullptr, _send };
} }
@ -637,9 +639,9 @@ void Video::paint(Painter &p, const QRect &clip, const PaintContext *context) co
} }
} }
HistoryTextState Video::getState( TextState Video::getState(
QPoint point, QPoint point,
HistoryStateRequest request) const { StateRequest request) const {
if (QRect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize).contains(point)) { if (QRect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize).contains(point)) {
return { nullptr, _link }; return { nullptr, _link };
} }
@ -778,9 +780,9 @@ void File::paint(Painter &p, const QRect &clip, const PaintContext *context) con
} }
} }
HistoryTextState File::getState( TextState File::getState(
QPoint point, QPoint point,
HistoryStateRequest request) const { StateRequest request) const {
if (QRect(0, st::inlineRowMargin, st::msgFileSize, st::msgFileSize).contains(point)) { if (QRect(0, st::inlineRowMargin, st::msgFileSize, st::msgFileSize).contains(point)) {
return { nullptr, getShownDocument()->loading() ? _cancel : _open }; return { nullptr, getShownDocument()->loading() ? _cancel : _open };
} else { } else {
@ -938,9 +940,9 @@ void Contact::paint(Painter &p, const QRect &clip, const PaintContext *context)
} }
} }
HistoryTextState Contact::getState( TextState Contact::getState(
QPoint point, QPoint point,
HistoryStateRequest request) const { StateRequest request) const {
if (!QRect(0, st::inlineRowMargin, st::msgFileSize, st::inlineThumbSize).contains(point)) { if (!QRect(0, st::inlineRowMargin, st::msgFileSize, st::inlineThumbSize).contains(point)) {
auto left = (st::msgFileSize + st::inlineThumbSkip); auto left = (st::msgFileSize + st::inlineThumbSkip);
if (QRect(left, 0, _width - left, _height).contains(point)) { if (QRect(left, 0, _width - left, _height).contains(point)) {
@ -1075,9 +1077,9 @@ void Article::paint(Painter &p, const QRect &clip, const PaintContext *context)
} }
} }
HistoryTextState Article::getState( TextState Article::getState(
QPoint point, QPoint point,
HistoryStateRequest request) const { StateRequest request) const {
if (_withThumb && QRect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize).contains(point)) { if (_withThumb && QRect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize).contains(point)) {
return { nullptr, _link }; return { nullptr, _link };
} }
@ -1259,9 +1261,9 @@ void Game::paint(Painter &p, const QRect &clip, const PaintContext *context) con
} }
} }
HistoryTextState Game::getState( TextState Game::getState(
QPoint point, QPoint point,
HistoryStateRequest request) const { StateRequest request) const {
int left = st::inlineThumbSize + st::inlineThumbSkip; int left = st::inlineThumbSize + st::inlineThumbSkip;
if (QRect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize).contains(point)) { if (QRect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize).contains(point)) {
return { nullptr, _send }; return { nullptr, _send };

View File

@ -60,9 +60,9 @@ public:
} }
void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
HistoryTextState getState( TextState getState(
QPoint point, QPoint point,
HistoryStateRequest request) const override; StateRequest request) const override;
// ClickHandlerHost interface // ClickHandlerHost interface
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override; void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
@ -121,9 +121,9 @@ public:
} }
void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
HistoryTextState getState( TextState getState(
QPoint point, QPoint point,
HistoryStateRequest request) const override; StateRequest request) const override;
private: private:
PhotoData *getShownPhoto() const; PhotoData *getShownPhoto() const;
@ -153,9 +153,9 @@ public:
void preload() const override; void preload() const override;
void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
HistoryTextState getState( TextState getState(
QPoint point, QPoint point,
HistoryStateRequest request) const override; StateRequest request) const override;
// ClickHandlerHost interface // ClickHandlerHost interface
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override; void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
@ -179,9 +179,9 @@ public:
void initDimensions() override; void initDimensions() override;
void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
HistoryTextState getState( TextState getState(
QPoint point, QPoint point,
HistoryStateRequest request) const override; StateRequest request) const override;
private: private:
ClickHandlerPtr _link; ClickHandlerPtr _link;
@ -228,9 +228,9 @@ public:
void initDimensions() override; void initDimensions() override;
void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
HistoryTextState getState( TextState getState(
QPoint point, QPoint point,
HistoryStateRequest request) const override; StateRequest request) const override;
// ClickHandlerHost interface // ClickHandlerHost interface
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override; void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
@ -292,9 +292,9 @@ public:
void initDimensions() override; void initDimensions() override;
void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
HistoryTextState getState( TextState getState(
QPoint point, QPoint point,
HistoryStateRequest request) const override; StateRequest request) const override;
private: private:
mutable QPixmap _thumb; mutable QPixmap _thumb;
@ -312,9 +312,9 @@ public:
int resizeGetHeight(int width) override; int resizeGetHeight(int width) override;
void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
HistoryTextState getState( TextState getState(
QPoint point, QPoint point,
HistoryStateRequest request) const override; StateRequest request) const override;
private: private:
ClickHandlerPtr _url, _link; ClickHandlerPtr _url, _link;
@ -337,9 +337,9 @@ public:
void initDimensions() override; void initDimensions() override;
void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
HistoryTextState getState( TextState getState(
QPoint point, QPoint point,
HistoryStateRequest request) const override; StateRequest request) const override;
private: private:
void countFrameSize(); void countFrameSize();

View File

@ -607,14 +607,14 @@ void Inner::updateSelected() {
int row = -1, col = -1, sel = -1; int row = -1, col = -1, sel = -1;
ClickHandlerPtr lnk; ClickHandlerPtr lnk;
ClickHandlerHost *lnkhost = nullptr; ClickHandlerHost *lnkhost = nullptr;
HistoryCursorState cursor = HistoryDefaultCursorState; HistoryView::CursorState cursor = HistoryView::CursorState::None;
if (sy >= 0) { if (sy >= 0) {
row = 0; row = 0;
for (int rows = _rows.size(); row < rows; ++row) { for (int rows = _rows.size(); row < rows; ++row) {
if (sy < _rows.at(row).height) { if (sy < _rows[row].height) {
break; break;
} }
sy -= _rows.at(row).height; sy -= _rows[row].height;
} }
} }
if (sx >= 0 && row >= 0 && row < _rows.size()) { if (sx >= 0 && row >= 0 && row < _rows.size()) {
@ -632,7 +632,9 @@ void Inner::updateSelected() {
} }
if (col < inlineItems.size()) { if (col < inlineItems.size()) {
sel = row * MatrixRowShift + col; sel = row * MatrixRowShift + col;
auto result = inlineItems[col]->getState(QPoint(sx, sy), HistoryStateRequest()); auto result = inlineItems[col]->getState(
QPoint(sx, sy),
HistoryView::StateRequest());
lnk = result.link; lnk = result.link;
cursor = result.cursor; cursor = result.cursor;
lnkhost = inlineItems[col]; lnkhost = inlineItems[col];

View File

@ -223,9 +223,9 @@ msp mst paf pif ps1 reg rgs sct shb shs u3p vb vbe vbs vbscript ws wsf\
return (lastDotIndex >= 0) && (executableTypes->indexOf(filename.mid(lastDotIndex + 1).toLower()) >= 0); return (lastDotIndex >= 0) && (executableTypes->indexOf(filename.mid(lastDotIndex + 1).toLower()) >= 0);
} }
[[nodiscard]] HistoryTextState LayoutItemBase::getState( [[nodiscard]] HistoryView::TextState LayoutItemBase::getState(
QPoint point, QPoint point,
HistoryStateRequest request) const { StateRequest request) const {
return {}; return {};
} }

View File

@ -9,8 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/runtime_composer.h" #include "base/runtime_composer.h"
struct HistoryTextState; namespace HistoryView {
struct HistoryStateRequest; struct TextState;
struct StateRequest;
} // namespace HistoryView
constexpr auto FullSelection = TextSelection { 0xFFFF, 0xFFFF }; constexpr auto FullSelection = TextSelection { 0xFFFF, 0xFFFF };
@ -82,6 +84,9 @@ class LayoutItemBase
: public RuntimeComposer<LayoutItemBase> : public RuntimeComposer<LayoutItemBase>
, public ClickHandlerHost { , public ClickHandlerHost {
public: public:
using TextState = HistoryView::TextState;
using StateRequest = HistoryView::StateRequest;
LayoutItemBase() { LayoutItemBase() {
} }
@ -101,9 +106,9 @@ public:
return _height; return _height;
} }
[[nodiscard]] virtual HistoryTextState getState( [[nodiscard]] virtual TextState getState(
QPoint point, QPoint point,
HistoryStateRequest request) const; StateRequest request) const;
[[nodiscard]] virtual TextSelection adjustSelection( [[nodiscard]] virtual TextSelection adjustSelection(
TextSelection selection, TextSelection selection,
TextSelectType type) const; TextSelectType type) const;

View File

@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "storage/localstorage.h" #include "storage/localstorage.h"
#include "history/history_item.h" #include "history/history_item.h"
#include "history/history_item_components.h" #include "history/history_item_components.h"
#include "history/view/history_view_cursor_state.h"
#include "ui/effects/round_checkbox.h" #include "ui/effects/round_checkbox.h"
#include "ui/text_options.h" #include "ui/text_options.h"
@ -33,6 +34,8 @@ namespace Overview {
namespace Layout { namespace Layout {
namespace { namespace {
using TextState = HistoryView::TextState;
TextParseOptions _documentNameOptions = { TextParseOptions _documentNameOptions = {
TextParseMultiline | TextParseRichText | TextParseLinks | TextParseMarkdown, // flags TextParseMultiline | TextParseRichText | TextParseLinks | TextParseMarkdown, // flags
0, // maxw 0, // maxw
@ -350,9 +353,9 @@ void Photo::paint(Painter &p, const QRect &clip, TextSelection selection, const
paintCheckbox(p, { checkLeft, checkTop }, selected, context); paintCheckbox(p, { checkLeft, checkTop }, selected, context);
} }
HistoryTextState Photo::getState( TextState Photo::getState(
QPoint point, QPoint point,
HistoryStateRequest request) const { StateRequest request) const {
if (hasPoint(point)) { if (hasPoint(point)) {
return { parent(), _link }; return { parent(), _link };
} }
@ -505,9 +508,9 @@ bool Video::iconAnimated() const {
return true; return true;
} }
HistoryTextState Video::getState( TextState Video::getState(
QPoint point, QPoint point,
HistoryStateRequest request) const { StateRequest request) const {
bool loaded = _data->loaded(); bool loaded = _data->loaded();
if (hasPoint(point)) { if (hasPoint(point)) {
@ -676,9 +679,9 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const
paintCheckbox(p, { checkLeft, checkTop }, selected, context); paintCheckbox(p, { checkLeft, checkTop }, selected, context);
} }
HistoryTextState Voice::getState( TextState Voice::getState(
QPoint point, QPoint point,
HistoryStateRequest request) const { StateRequest request) const {
const auto loaded = _data->loaded(); const auto loaded = _data->loaded();
const auto nameleft = _st.songPadding.left() const auto nameleft = _st.songPadding.left()
@ -702,7 +705,7 @@ HistoryTextState Voice::getState(
: _openl; : _openl;
return { parent(), link }; return { parent(), link };
} }
auto result = HistoryTextState(parent()); auto result = TextState(parent());
const auto statusmaxwidth = _width - nameleft - nameright; const auto statusmaxwidth = _width - nameleft - nameright;
const auto statusrect = rtlrect( const auto statusrect = rtlrect(
nameleft, nameleft,
@ -714,7 +717,9 @@ HistoryTextState Voice::getState(
if (_status.size() == FileStatusSizeLoaded || _status.size() == FileStatusSizeReady) { if (_status.size() == FileStatusSizeLoaded || _status.size() == FileStatusSizeReady) {
auto textState = _details.getStateLeft(point - QPoint(nameleft, statustop), _width, _width); auto textState = _details.getStateLeft(point - QPoint(nameleft, statustop), _width, _width);
result.link = textState.link; result.link = textState.link;
result.cursor = textState.uponSymbol ? HistoryInTextCursorState : HistoryDefaultCursorState; result.cursor = textState.uponSymbol
? HistoryView::CursorState::Text
: HistoryView::CursorState::None;
} }
} }
const auto namewidth = std::min( const auto namewidth = std::min(
@ -1000,9 +1005,9 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con
paintCheckbox(p, { checkLeft, checkTop }, selected, context); paintCheckbox(p, { checkLeft, checkTop }, selected, context);
} }
HistoryTextState Document::getState( TextState Document::getState(
QPoint point, QPoint point,
HistoryStateRequest request) const { StateRequest request) const {
const auto loaded = _data->loaded() const auto loaded = _data->loaded()
|| Local::willStickerImageLoad(_data->mediaKey()); || Local::willStickerImageLoad(_data->mediaKey());
const auto wthumb = withThumb(); const auto wthumb = withThumb();
@ -1426,9 +1431,9 @@ void Link::paint(Painter &p, const QRect &clip, TextSelection selection, const P
paintCheckbox(p, { checkLeft, checkTop }, selected, context); paintCheckbox(p, { checkLeft, checkTop }, selected, context);
} }
HistoryTextState Link::getState( TextState Link::getState(
QPoint point, QPoint point,
HistoryStateRequest request) const { StateRequest request) const {
int32 left = st::linksPhotoSize + st::linksPhotoPadding, top = st::linksMargin.top() + st::linksBorder, w = _width - left; int32 left = st::linksPhotoSize + st::linksPhotoPadding, top = st::linksMargin.top() + st::linksBorder, w = _width - left;
if (rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width).contains(point)) { if (rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width).contains(point)) {
return { parent(), _photol }; return { parent(), _photol };

View File

@ -12,8 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/radial_animation.h" #include "ui/effects/radial_animation.h"
#include "styles/style_overview.h" #include "styles/style_overview.h"
struct HistoryTextState;
struct HistoryStateRequest;
class HistoryMedia; class HistoryMedia;
namespace style { namespace style {
@ -202,9 +200,9 @@ public:
void initDimensions() override; void initDimensions() override;
int32 resizeGetHeight(int32 width) override; int32 resizeGetHeight(int32 width) override;
void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override; void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override;
HistoryTextState getState( TextState getState(
QPoint point, QPoint point,
HistoryStateRequest request) const override; StateRequest request) const override;
private: private:
not_null<PhotoData*> _data; not_null<PhotoData*> _data;
@ -224,9 +222,9 @@ public:
void initDimensions() override; void initDimensions() override;
int32 resizeGetHeight(int32 width) override; int32 resizeGetHeight(int32 width) override;
void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override; void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override;
HistoryTextState getState( TextState getState(
QPoint point, QPoint point,
HistoryStateRequest request) const override; StateRequest request) const override;
protected: protected:
float64 dataProgress() const override; float64 dataProgress() const override;
@ -255,9 +253,9 @@ public:
void initDimensions() override; void initDimensions() override;
void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override; void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override;
HistoryTextState getState( TextState getState(
QPoint point, QPoint point,
HistoryStateRequest request) const override; StateRequest request) const override;
protected: protected:
float64 dataProgress() const override; float64 dataProgress() const override;
@ -290,9 +288,9 @@ public:
void initDimensions() override; void initDimensions() override;
void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override; void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override;
HistoryTextState getState( TextState getState(
QPoint point, QPoint point,
HistoryStateRequest request) const override; StateRequest request) const override;
virtual DocumentData *getDocument() const override { virtual DocumentData *getDocument() const override {
return _data; return _data;
@ -334,9 +332,9 @@ public:
void initDimensions() override; void initDimensions() override;
int32 resizeGetHeight(int32 width) override; int32 resizeGetHeight(int32 width) override;
void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override; void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override;
HistoryTextState getState( TextState getState(
QPoint point, QPoint point,
HistoryStateRequest request) const override; StateRequest request) const override;
protected: protected:
const style::RoundCheckbox &checkboxStyle() const override; const style::RoundCheckbox &checkboxStyle() const override;