From 2fdc3169ce3d50aaebd78768db9789e5c160da1d Mon Sep 17 00:00:00 2001 From: John Preston Date: Sat, 27 Jan 2018 16:59:24 +0300 Subject: [PATCH] Fix / improve support for album items selection. --- .../SourceFiles/chat_helpers/bot_keyboard.cpp | 2 +- .../chat_helpers/gifs_list_widget.cpp | 8 +- .../admin_log/history_admin_log_inner.cpp | 57 +-- .../admin_log/history_admin_log_inner.h | 15 +- .../history/history_inner_widget.cpp | 184 ++++---- .../history/history_inner_widget.h | 26 +- Telegram/SourceFiles/history/history_item.h | 5 +- .../history/history_item_components.cpp | 2 +- .../history/history_item_components.h | 2 +- .../SourceFiles/history/history_media.cpp | 18 +- Telegram/SourceFiles/history/history_media.h | 30 +- .../history/history_media_grouped.cpp | 36 +- .../history/history_media_grouped.h | 9 +- .../history/history_media_types.cpp | 127 +++--- .../SourceFiles/history/history_media_types.h | 33 +- .../SourceFiles/history/history_widget.cpp | 8 - .../view/history_view_cursor_state.cpp | 42 +- .../history/view/history_view_cursor_state.h | 68 ++- .../history/view/history_view_element.h | 14 +- .../history/view/history_view_list_widget.cpp | 397 +++++++++++++----- .../history/view/history_view_list_widget.h | 70 ++- .../history/view/history_view_message.cpp | 158 +++---- .../history/view/history_view_message.h | 20 +- .../view/history_view_service_message.cpp | 22 +- .../view/history_view_service_message.h | 6 +- .../info/media/info_media_list_widget.cpp | 41 +- .../info/media/info_media_list_widget.h | 37 +- .../inline_bot_layout_internal.cpp | 34 +- .../inline_bots/inline_bot_layout_internal.h | 32 +- .../inline_bots/inline_results_widget.cpp | 10 +- Telegram/SourceFiles/layout.cpp | 4 +- Telegram/SourceFiles/layout.h | 13 +- .../SourceFiles/overview/overview_layout.cpp | 29 +- .../SourceFiles/overview/overview_layout.h | 22 +- 34 files changed, 983 insertions(+), 598 deletions(-) diff --git a/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp b/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp index 5978a6411..207ee94b7 100644 --- a/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp +++ b/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp @@ -280,7 +280,7 @@ void BotKeyboard::updateSelected() { auto p = mapFromGlobal(_lastMousePos); 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)) { Ui::Tooltip::Hide(); setCursor(link ? style::cur_pointer : style::cur_default); diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp index 8b1fac79c..8d3a9dc9e 100644 --- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp @@ -888,7 +888,7 @@ void GifsListWidget::updateSelected() { int row = -1, col = -1, sel = -1; ClickHandlerPtr lnk; ClickHandlerHost *lnkhost = nullptr; - HistoryCursorState cursor = HistoryDefaultCursorState; + HistoryView::CursorState cursor = HistoryView::CursorState::None; if (sy >= 0) { row = 0; for (int rows = _rows.size(); row < rows; ++row) { @@ -913,10 +913,12 @@ void GifsListWidget::updateSelected() { } if (col < inlineItems.size()) { 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; cursor = result.cursor; - lnkhost = inlineItems.at(col); + lnkhost = inlineItems[col]; } else { row = col = -1; } diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp index 260daa361..52fb6c7f4 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp @@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/admin_log/history_admin_log_filter.h" #include "history/view/history_view_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 "mainwindow.h" #include "mainwidget.h" @@ -451,13 +452,15 @@ void InnerWidget::updateEmptyText() { } QString InnerWidget::tooltipText() const { - if (_mouseCursorState == HistoryInDateCursorState && _mouseAction == MouseAction::None) { + if (_mouseCursorState == CursorState::Date + && _mouseAction == MouseAction::None) { if (const auto view = App::hoveredItem()) { auto dateText = view->data()->date.toString( QLocale::system().dateTimeFormat(QLocale::LongFormat)); 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 forwarded = view->data()->Get()) { return forwarded->text.originalText(AllTextSelection, ExpandLinksNone); @@ -872,10 +875,10 @@ void InnerWidget::keyPressEvent(QKeyEvent *e) { void InnerWidget::mouseDoubleClickEvent(QMouseEvent *e) { mouseActionStart(e->globalPos(), e->button()); if (((_mouseAction == MouseAction::Selecting && _selectedItem != nullptr) || (_mouseAction == MouseAction::None)) && _mouseSelectType == TextSelectType::Letters && _mouseActionItem) { - HistoryStateRequest request; + StateRequest request; request.flags |= Text::StateRequest::Flag::LookupSymbol; - auto dragState = _mouseActionItem->getState(_dragStartPosition, request); - if (dragState.cursor == HistoryInTextCursorState) { + auto dragState = _mouseActionItem->textState(_dragStartPosition, request); + if (dragState.cursor == CursorState::Text) { _mouseTextSymbol = dragState.symbol; _mouseSelectType = TextSelectType::Words; if (_mouseAction == MouseAction::None) { @@ -914,10 +917,10 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { auto mousePos = mapPointToItem( mapFromGlobal(_mousePosition), App::mousedItem()); - HistoryStateRequest request; + StateRequest request; request.flags |= Text::StateRequest::Flag::LookupSymbol; - auto dragState = App::mousedItem()->getState(mousePos, request); - if (dragState.cursor == HistoryInTextCursorState + auto dragState = App::mousedItem()->textState(mousePos, request); + if (dragState.cursor == CursorState::Text && base::in_range(dragState.symbol, selFrom, selTo)) { isUponSelected = 1; } @@ -1275,12 +1278,12 @@ void InnerWidget::mouseActionStart(const QPoint &screenPos, Qt::MouseButton butt _mouseAction = MouseAction::PrepareDrag; } if (_mouseAction == MouseAction::None && _mouseActionItem) { - HistoryTextState dragState; + TextState dragState; if (_trippleClickTimer.isActive() && (screenPos - _trippleClickPoint).manhattanLength() < QApplication::startDragDistance()) { - HistoryStateRequest request; + StateRequest request; request.flags = Text::StateRequest::Flag::LookupSymbol; - dragState = _mouseActionItem->getState(_dragStartPosition, request); - if (dragState.cursor == HistoryInTextCursorState) { + dragState = _mouseActionItem->textState(_dragStartPosition, request); + if (dragState.cursor == CursorState::Text) { auto selection = TextSelection { dragState.symbol, dragState.symbol }; repaintItem(std::exchange(_selectedItem, _mouseActionItem)); _selectedText = selection; @@ -1291,14 +1294,14 @@ void InnerWidget::mouseActionStart(const QPoint &screenPos, Qt::MouseButton butt _trippleClickTimer.callOnce(QApplication::doubleClickInterval()); } } else if (App::pressedItem()) { - HistoryStateRequest request; + StateRequest request; request.flags = Text::StateRequest::Flag::LookupSymbol; - dragState = _mouseActionItem->getState(_dragStartPosition, request); + dragState = _mouseActionItem->textState(_dragStartPosition, request); } if (_mouseSelectType != TextSelectType::Paragraphs) { if (App::pressedItem()) { _mouseTextSymbol = dragState.symbol; - auto uponSelected = (dragState.cursor == HistoryInTextCursorState); + auto uponSelected = (dragState.cursor == CursorState::Text); if (uponSelected) { if (!_selectedItem || _selectedItem != _mouseActionItem) { uponSelected = false; @@ -1399,7 +1402,7 @@ void InnerWidget::updateSelected() { if (item) { App::mousedItem(view); itemPoint = mapPointToItem(point, view); - if (view->hasPoint(itemPoint)) { + if (view->pointState(itemPoint) != PointState::Outside) { if (App::hoveredItem() != view) { repaintItem(App::hoveredItem()); App::hoveredItem(view); @@ -1411,7 +1414,7 @@ void InnerWidget::updateSelected() { } } - HistoryTextState dragState; + TextState dragState; ClickHandlerHost *lnkhost = nullptr; auto selectingText = _selectedItem && (view == _mouseActionItem) @@ -1423,13 +1426,13 @@ void InnerWidget::updateSelected() { InvokeQueued(this, [this] { performDrag(); }); } } - HistoryStateRequest request; + StateRequest request; if (_mouseAction == MouseAction::Selecting) { request.flags |= Text::StateRequest::Flag::LookupSymbol; } else { selectingText = false; } - dragState = view->getState(itemPoint, request); + dragState = view->textState(itemPoint, request); lnkhost = view; if (!dragState.link && itemPoint.x() >= st::historyPhotoLeft && itemPoint.x() < st::historyPhotoLeft + st::msgPhotoSize) { if (auto message = item->toHistoryMessage()) { @@ -1459,7 +1462,9 @@ void InnerWidget::updateSelected() { if (lnkChanged || dragState.cursor != _mouseCursorState) { 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); } @@ -1468,9 +1473,9 @@ void InnerWidget::updateSelected() { _mouseCursorState = dragState.cursor; if (dragState.link) { cursor = style::cur_pointer; - } else if (_mouseCursorState == HistoryInTextCursorState) { + } else if (_mouseCursorState == CursorState::Text) { cursor = style::cur_text; - } else if (_mouseCursorState == HistoryInDateCursorState) { + } else if (_mouseCursorState == CursorState::Date) { // cursor = style::cur_cross; } } else if (item) { @@ -1530,10 +1535,10 @@ void InnerWidget::performDrag() { // if (!_selected.isEmpty() && _selected.cbegin().value() == FullSelection) { // uponSelected = _selected.contains(_mouseActionItem); // } else { - // HistoryStateRequest request; + // StateRequest request; // request.flags |= Text::StateRequest::Flag::LookupSymbol; - // auto dragState = _mouseActionItem->getState(_dragStartPosition.x(), _dragStartPosition.y(), request); - // uponSelected = (dragState.cursor == HistoryInTextCursorState); + // auto dragState = _mouseActionItem->textState(_dragStartPosition.x(), _dragStartPosition.y(), request); + // uponSelected = (dragState.cursor == CursorState::Text); // if (uponSelected) { // if (_selected.isEmpty() || // _selected.cbegin().value() == FullSelection || @@ -1584,7 +1589,7 @@ void InnerWidget::performDrag() { // auto pressedMedia = static_cast(nullptr); // if (auto pressedItem = App::pressedItem()) { // pressedMedia = pressedItem->media(); - // if (_mouseCursorState == HistoryInDateCursorState + // if (_mouseCursorState == CursorState::Date // || (pressedMedia && pressedMedia->dragItem())) { // forwardMimeType = qsl("application/x-td-forward"); // Auth().data().setMimeForwardIds( diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h index a2e073a56..2537f8ff5 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.h @@ -7,7 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -#include "history/view/history_view_cursor_state.h" #include "history/view/history_view_element.h" #include "history/admin_log/history_admin_log_item.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 "base/timer.h" +namespace HistoryView { +class Element; +struct TextState; +struct StateRequest; +enum class CursorState : char; +enum class PointState : char; +} // namespace HistoryView + namespace Ui { class PopupMenu; } // namespace Ui @@ -115,6 +122,10 @@ private: TopToBottom, 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 mouseActionUpdate(const QPoint &screenPos); @@ -228,7 +239,7 @@ private: QPoint _dragStartPosition; QPoint _mousePosition; Element *_mouseActionItem = nullptr; - HistoryCursorState _mouseCursorState = HistoryDefaultCursorState; + CursorState _mouseCursorState = CursorState(); uint16 _mouseTextSymbol = 0; bool _pressWasInactive = false; diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 99938c4cf..8c738c525 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_item_text.h" #include "history/view/history_view_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/widgets/popup_menu.h" #include "window/window_controller.h" @@ -131,7 +132,8 @@ HistoryInner::HistoryInner( , _migrated(history->migrateFrom()) , _widget(historyWidget) , _scroll(scroll) -, _scrollDateCheck([this] { onScrollDateCheck(); }) { +, _scrollDateCheck([this] { scrollDateCheck(); }) +, _scrollDateHideTimer([this] { scrollDateHideByTimer(); }) { _touchSelectTimer.setSingleShot(true); connect(&_touchSelectTimer, SIGNAL(timeout()), this, SLOT(onTouchSelect())); @@ -140,8 +142,6 @@ HistoryInner::HistoryInner( _trippleClickTimer.setSingleShot(true); - connect(&_scrollDateHideTimer, SIGNAL(timeout()), this, SLOT(onScrollDateHideByTimer())); - notifyIsBotChanged(); setMouseTracking(true); @@ -166,9 +166,15 @@ HistoryInner::HistoryInner( mouseActionCancel(); }, lifetime()); Auth().data().viewRepaintRequest( - ) | rpl::start_with_next( - [this](auto view) { repaintItem(view); }, - lifetime()); + ) | rpl::start_with_next([this](not_null view) { + repaintItem(view); + }, lifetime()); + Auth().data().viewLayoutChanged( + ) | rpl::filter([](not_null view) { + return (view == view->data()->mainView()) && view->isUnderCursor(); + }) | rpl::start_with_next([this](not_null view) { + mouseActionUpdate(); + }, lifetime()); } void HistoryInner::messagesReceived(PeerData *peer, const QVector &messages) { @@ -423,6 +429,10 @@ void HistoryInner::enumerateDates(Method method) { TextSelection HistoryInner::computeRenderSelection( not_null selected, not_null view) const { + if (view->isHiddenByGroup()) { + return TextSelection(); + } + const auto item = view->data(); const auto itemSelection = [&](not_null item) { auto i = selected->find(item); if (i != selected->end()) { @@ -430,32 +440,30 @@ TextSelection HistoryInner::computeRenderSelection( } return TextSelection(); }; - // #TODO group selection - //if (const auto group = view->Get()) { - // if (group->leader != view) { - // return TextSelection(); - // } - // auto result = TextSelection(); - // auto allFullSelected = true; - // const auto count = int(group->others.size()); - // for (auto i = 0; i != count; ++i) { - // if (itemSelection(group->others[i]->data()) == FullSelection) { - // result = AddGroupItemSelection(result, i); - // } else { - // allFullSelected = false; - // } - // } - // const auto leaderSelection = itemSelection(view->data()); - // if (leaderSelection == FullSelection) { - // return allFullSelected - // ? FullSelection - // : AddGroupItemSelection(result, count); - // } else if (leaderSelection != TextSelection()) { - // return leaderSelection; - // } - // return result; - //} - return itemSelection(view->data()); + const auto result = itemSelection(item); + if (result != TextSelection() && result != FullSelection) { + return result; + } + if (const auto group = Auth().data().groups().find(item)) { + auto parts = TextSelection(); + auto allFullSelected = true; + const auto count = int(group->items.size()); + for (auto i = 0; i != count; ++i) { + const auto part = group->items[i]; + const auto selection = itemSelection(part); + if (part == item + && selection != FullSelection + && selection != TextSelection()) { + return selection; + } else if (selection == FullSelection) { + parts = AddGroupItemSelection(parts, i); + } else { + allFullSelected = false; + } + } + return allFullSelected ? FullSelection : parts; + } + return itemSelection(item); } TextSelection HistoryInner::itemRenderSelection( @@ -894,7 +902,7 @@ void HistoryInner::mouseMoveEvent(QMouseEvent *e) { void HistoryInner::mouseActionUpdate(const QPoint &screenPos) { _mousePosition = screenPos; - onUpdateSelected(); + mouseActionUpdate(); } void HistoryInner::touchScrollUpdated(const QPoint &screenPos) { @@ -958,12 +966,12 @@ void HistoryInner::mouseActionStart(const QPoint &screenPos, Qt::MouseButton but } } if (_mouseAction == MouseAction::None && mouseActionView) { - HistoryTextState dragState; + TextState dragState; if (_trippleClickTimer.isActive() && (screenPos - _trippleClickPoint).manhattanLength() < QApplication::startDragDistance()) { - HistoryStateRequest request; + StateRequest request; request.flags = Text::StateRequest::Flag::LookupSymbol; - dragState = mouseActionView->getState(_dragStartPosition, request); - if (dragState.cursor == HistoryInTextCursorState) { + dragState = mouseActionView->textState(_dragStartPosition, request); + if (dragState.cursor == CursorState::Text) { TextSelection selStatus = { dragState.symbol, dragState.symbol }; if (selStatus != FullSelection && (_selected.empty() || _selected.cbegin()->second != FullSelection)) { if (!_selected.empty()) { @@ -979,14 +987,14 @@ void HistoryInner::mouseActionStart(const QPoint &screenPos, Qt::MouseButton but } } } else if (App::pressedItem()) { - HistoryStateRequest request; + StateRequest request; request.flags = Text::StateRequest::Flag::LookupSymbol; - dragState = mouseActionView->getState(_dragStartPosition, request); + dragState = mouseActionView->textState(_dragStartPosition, request); } if (_mouseSelectType != TextSelectType::Paragraphs) { if (App::pressedItem()) { _mouseTextSymbol = dragState.symbol; - bool uponSelected = (dragState.cursor == HistoryInTextCursorState); + bool uponSelected = (dragState.cursor == CursorState::Text); if (uponSelected) { if (_selected.empty() || _selected.cbegin()->second == FullSelection @@ -1002,7 +1010,8 @@ void HistoryInner::mouseActionStart(const QPoint &screenPos, Qt::MouseButton but if (uponSelected) { _mouseAction = MouseAction::PrepareDrag; // start text drag } else if (!_pressWasInactive) { - if (dynamic_cast(App::pressedItem()->media()) || _mouseCursorState == HistoryInDateCursorState) { + if (dynamic_cast(App::pressedItem()->media()) + || _mouseCursorState == CursorState::Date) { _mouseAction = MouseAction::PrepareDrag; // start sticker drag or by-date drag } else { if (dragState.afterSymbol) ++_mouseTextSymbol; @@ -1055,10 +1064,10 @@ void HistoryInner::performDrag() { uponSelected = _dragStateItem && (_selected.find(_dragStateItem) != _selected.cend()); } else { - HistoryStateRequest request; + StateRequest request; request.flags |= Text::StateRequest::Flag::LookupSymbol; - auto dragState = mouseActionView->getState(_dragStartPosition, request); - uponSelected = (dragState.cursor == HistoryInTextCursorState); + auto dragState = mouseActionView->textState(_dragStartPosition, request); + uponSelected = (dragState.cursor == CursorState::Text); if (uponSelected) { if (_selected.empty() || _selected.cbegin()->second == FullSelection @@ -1108,7 +1117,7 @@ void HistoryInner::performDrag() { auto pressedMedia = static_cast(nullptr); if (auto pressedItem = App::pressedItem()) { pressedMedia = pressedItem->media(); - if (_mouseCursorState == HistoryInDateCursorState + if (_mouseCursorState == CursorState::Date || (pressedMedia && pressedMedia->dragItem())) { Auth().data().setMimeForwardIds( Auth().data().itemOrItsGroup(pressedItem->data())); @@ -1173,10 +1182,12 @@ void HistoryInner::itemRemoved(not_null item) { _dragSelTo = nullptr; update(); } - onUpdateSelected(); + mouseActionUpdate(); } -void HistoryInner::mouseActionFinish(const QPoint &screenPos, Qt::MouseButton button) { +void HistoryInner::mouseActionFinish( + const QPoint &screenPos, + Qt::MouseButton button) { mouseActionUpdate(screenPos); auto activated = ClickHandler::unpressed(); @@ -1290,10 +1301,10 @@ void HistoryInner::mouseDoubleClickEvent(QMouseEvent *e) { || (_mouseAction == MouseAction::None && (_selected.empty() || _selected.cbegin()->second != FullSelection)))) { - HistoryStateRequest request; + StateRequest request; request.flags |= Text::StateRequest::Flag::LookupSymbol; - auto dragState = mouseActionView->getState(_dragStartPosition, request); - if (dragState.cursor == HistoryInTextCursorState) { + auto dragState = mouseActionView->textState(_dragStartPosition, request); + if (dragState.cursor == CursorState::Text) { _mouseTextSymbol = dragState.symbol; _mouseSelectType = TextSelectType::Words; if (_mouseAction == MouseAction::None) { @@ -1342,10 +1353,12 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { hasSelected = (selTo > selFrom) ? 1 : 0; if (App::mousedItem() && App::mousedItem() == App::hoveredItem()) { auto mousePos = mapPointToItem(mapFromGlobal(_mousePosition), App::mousedItem()); - HistoryStateRequest request; + StateRequest request; request.flags |= Text::StateRequest::Flag::LookupSymbol; - auto dragState = App::mousedItem()->getState(mousePos, request); - if (dragState.cursor == HistoryInTextCursorState && dragState.symbol >= selFrom && dragState.symbol < selTo) { + auto dragState = App::mousedItem()->textState(mousePos, request); + if (dragState.cursor == CursorState::Text + && dragState.symbol >= selFrom + && dragState.symbol < selTo) { isUponSelected = 1; } } @@ -1397,7 +1410,11 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { const auto item = _dragStateItem; const auto itemId = item ? item->fullId() : FullMsgId(); 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); if (lnkPhoto) { @@ -1503,7 +1520,11 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { const auto msg = dynamic_cast(item); 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); } else { addItemActions(item); @@ -1724,7 +1745,7 @@ void HistoryInner::copyContextText(FullMsgId itemId) { } void HistoryInner::resizeEvent(QResizeEvent *e) { - onUpdateSelected(); + mouseActionUpdate(); } TextWithEntities HistoryInner::getSelectedText() const { @@ -1986,7 +2007,7 @@ void HistoryInner::visibleAreaUpdated(int top, int bottom) { if (scrolledUp) { _scrollDateCheck.call(); } else { - onScrollDateHideByTimer(); + scrollDateHideByTimer(); } } @@ -1994,7 +2015,7 @@ bool HistoryInner::displayScrollDate() const { return (_visibleAreaTop <= height() - 2 * (_visibleAreaBottom - _visibleAreaTop)); } -void HistoryInner::onScrollDateCheck() { +void HistoryInner::scrollDateCheck() { if (!_history) return; auto newScrollDateItem = _history->scrollTopItem ? _history->scrollTopItem : (_migrated ? _migrated->scrollTopItem : nullptr); @@ -2015,12 +2036,12 @@ void HistoryInner::onScrollDateCheck() { } _scrollDateLastItem = newScrollDateItem; _scrollDateLastItemTop = newScrollDateItemTop; - _scrollDateHideTimer.start(kScrollDateHideTimeout); + _scrollDateHideTimer.callOnce(kScrollDateHideTimeout); } } -void HistoryInner::onScrollDateHideByTimer() { - _scrollDateHideTimer.stop(); +void HistoryInner::scrollDateHideByTimer() { + _scrollDateHideTimer.cancel(); if (!_scrollDateLink || ClickHandler::getPressed() != _scrollDateLink) { scrollDateHide(); } @@ -2036,7 +2057,7 @@ void HistoryInner::keepScrollDateForNow() { if (!_scrollDateShown && _scrollDateLastItem && _scrollDateOpacity.animating()) { toggleScrollDateShown(); } - _scrollDateHideTimer.start(kScrollDateHideTimeout); + _scrollDateHideTimer.callOnce(kScrollDateHideTimeout); } void HistoryInner::toggleScrollDateShown() { @@ -2261,7 +2282,7 @@ void HistoryInner::onTouchSelect() { mouseActionStart(_touchPos, Qt::LeftButton); } -void HistoryInner::onUpdateSelected() { +void HistoryInner::mouseActionUpdate() { if (!_history || hasPendingResizedItems()) { return; } @@ -2282,7 +2303,7 @@ void HistoryInner::onUpdateSelected() { App::mousedItem(view); m = mapPointToItem(point, view); - if (view->hasPoint(m)) { + if (view->pointState(m) != PointState::Outside) { if (App::hoveredItem() != view) { repaintItem(App::hoveredItem()); App::hoveredItem(view); @@ -2297,7 +2318,7 @@ void HistoryInner::onUpdateSelected() { mouseActionCancel(); } - HistoryTextState dragState; + TextState dragState; ClickHandlerHost *lnkhost = nullptr; auto selectingText = (item == _mouseActionItem) && (view == App::hoveredItem()) @@ -2305,7 +2326,7 @@ void HistoryInner::onUpdateSelected() { && (_selected.cbegin()->second != FullSelection); if (point.y() < _historyPaddingTop) { 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), _botAbout->width)); _dragStateItem = App::histItemById(dragState.itemId); @@ -2363,7 +2384,7 @@ void HistoryInner::onUpdateSelected() { } else { static_cast(_scrollDateLink.get())->setDate(item->date.date()); } - dragState = HistoryTextState( + dragState = TextState( nullptr, _scrollDateLink); _dragStateItem = App::histItemById(dragState.itemId); @@ -2375,13 +2396,13 @@ void HistoryInner::onUpdateSelected() { return true; }); if (!dragState.link) { - HistoryStateRequest request; + StateRequest request; if (_mouseAction == MouseAction::Selecting) { request.flags |= Text::StateRequest::Flag::LookupSymbol; } else { selectingText = false; } - dragState = view->getState(m, request); + dragState = view->textState(m, request); _dragStateItem = App::histItemById(dragState.itemId); lnkhost = view; 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(); Assert(message != nullptr); - dragState = HistoryTextState( + dragState = TextState( nullptr, message->displayFrom()->openLink()); _dragStateItem = App::histItemById(dragState.itemId); @@ -2416,7 +2437,9 @@ void HistoryInner::onUpdateSelected() { if (lnkChanged || dragState.cursor != _mouseCursorState) { 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); } @@ -2425,9 +2448,9 @@ void HistoryInner::onUpdateSelected() { _mouseCursorState = dragState.cursor; if (dragState.link) { 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; - } else if (_mouseCursorState == HistoryInDateCursorState) { + } else if (_mouseCursorState == CursorState::Date) { //cur = style::cur_cross; } } else if (item) { @@ -2457,7 +2480,8 @@ void HistoryInner::onUpdateSelected() { auto selectingDown = (itemTop(_mouseActionItem) < itemTop(item)) || (_mouseActionItem == item && _dragStartPosition.y() < m.y()); auto dragSelFrom = _mouseActionItem->mainView(); auto dragSelTo = view; - if (!dragSelFrom->hasPoint(_dragStartPosition)) { // maybe exclude dragSelFrom + // Maybe exclude dragSelFrom. + if (dragSelFrom->pointState(_dragStartPosition) == PointState::Outside) { if (selectingDown) { if (_dragStartPosition.y() >= dragSelFrom->height() - dragSelFrom->marginBottom() || ((view == dragSelFrom) && (m.y() < _dragStartPosition.y() + QApplication::startDragDistance() || m.y() < dragSelFrom->marginTop()))) { dragSelFrom = (dragSelFrom != dragSelTo) @@ -2743,9 +2767,7 @@ void HistoryInner::changeSelectionAsGroup( : SelectAction::Select; } auto total = int(toItems->size()); - const auto add = (action == SelectAction::Select); - - const auto adding = [&] { + const auto canSelect = [&] { for (const auto other : group->items) { if (!goodForSelection(toItems, other, total)) { return false; @@ -2753,7 +2775,7 @@ void HistoryInner::changeSelectionAsGroup( } return (total <= MaxSelectedItems); }(); - if (adding) { + if (action == SelectAction::Select && canSelect) { for (const auto other : group->items) { addToSelection(toItems, other); } @@ -2880,7 +2902,8 @@ void HistoryInner::applyDragSelection( } QString HistoryInner::tooltipText() const { - if (_mouseCursorState == HistoryInDateCursorState && _mouseAction == MouseAction::None) { + if (_mouseCursorState == CursorState::Date + && _mouseAction == MouseAction::None) { if (const auto view = App::hoveredItem()) { auto dateText = view->data()->date.toString( QLocale::system().dateTimeFormat(QLocale::LongFormat)); @@ -2893,7 +2916,8 @@ QString HistoryInner::tooltipText() const { } 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 forwarded = view->data()->Get()) { return forwarded->text.originalText(AllTextSelection, ExpandLinksNone); diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index c8037975f..77d97a9a0 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -7,14 +7,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "base/timer.h" #include "ui/rp_widget.h" #include "ui/widgets/tooltip.h" #include "ui/widgets/scroll_area.h" -#include "history/view/history_view_cursor_state.h" #include "history/view/history_view_top_bar_widget.h" namespace HistoryView { class ElementDelegate; +struct TextState; +struct StateRequest; +enum class CursorState : char; +enum class PointState : char; } // namespace HistoryView namespace Window { @@ -113,18 +117,11 @@ protected: void contextMenuEvent(QContextMenuEvent *e) override; public slots: - void onUpdateSelected(); void onParentGeometryChanged(); - void copySelectedText(); - void onTouchSelect(); void onTouchScrollTimer(); -private slots: - void onScrollDateCheck(); - void onScrollDateHideByTimer(); - private: class BotAbout; using SelectedItems = std::map>; @@ -144,6 +141,11 @@ private: TopToBottom, 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 // for each found message (in given direction) in the passed history with passed top offset. // @@ -180,8 +182,11 @@ private: template void enumerateDates(Method method); + void scrollDateCheck(); + void scrollDateHideByTimer(); bool canHaveFromUserpics() const; void mouseActionStart(const QPoint &screenPos, Qt::MouseButton button); + void mouseActionUpdate(); void mouseActionUpdate(const QPoint &screenPos); void mouseActionFinish(const QPoint &screenPos, Qt::MouseButton button); void mouseActionCancel(); @@ -265,6 +270,7 @@ private: void deleteItem(not_null item); void deleteItem(FullMsgId itemId); void deleteAsGroup(FullMsgId itemId); + void copySelectedText(); // Does any of the shown histories has this flag set. bool hasPendingResizedItems() const; @@ -301,7 +307,7 @@ private: QPoint _mousePosition; HistoryItem *_mouseActionItem = nullptr; HistoryItem *_dragStateItem = nullptr; - HistoryCursorState _mouseCursorState = HistoryDefaultCursorState; + CursorState _mouseCursorState = CursorState(); uint16 _mouseTextSymbol = 0; bool _pressWasInactive = false; @@ -338,7 +344,7 @@ private: bool _scrollDateShown = false; Animation _scrollDateOpacity; SingleQueuedInvokation _scrollDateCheck; - SingleTimer _scrollDateHideTimer; + base::Timer _scrollDateHideTimer; Element *_scrollDateLastItem = nullptr; int _scrollDateLastItemTop = 0; ClickHandlerPtr _scrollDateLink; diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index bf1ad42c8..3b3cc0e2e 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -10,7 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/runtime_composer.h" #include "base/flags.h" #include "base/value_ordering.h" -#include "history/view/history_view_cursor_state.h" enum class UnreadMentionType; struct HistoryMessageReplyMarkup; @@ -47,6 +46,10 @@ class Controller; } // namespace Window namespace HistoryView { +struct TextState; +struct StateRequest; +enum class CursorState : char; +enum class PointState : char; enum class Context : char; class ElementDelegate; } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/history_item_components.cpp b/Telegram/SourceFiles/history/history_item_components.cpp index db32b4721..1284041f1 100644 --- a/Telegram/SourceFiles/history/history_item_components.cpp +++ b/Telegram/SourceFiles/history/history_item_components.cpp @@ -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); for_const (auto &row, _rows) { diff --git a/Telegram/SourceFiles/history/history_item_components.h b/Telegram/SourceFiles/history/history_item_components.h index 76c8c3ba9..ca2cda783 100644 --- a/Telegram/SourceFiles/history/history_item_components.h +++ b/Telegram/SourceFiles/history/history_item_components.h @@ -274,7 +274,7 @@ public: int naturalHeight() 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 clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed); diff --git a/Telegram/SourceFiles/history/history_media.cpp b/Telegram/SourceFiles/history/history_media.cpp index 4eb204a65..fa8bbcdf4 100644 --- a/Telegram/SourceFiles/history/history_media.cpp +++ b/Telegram/SourceFiles/history/history_media.cpp @@ -9,9 +9,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_item.h" #include "history/view/history_view_element.h" +#include "history/view/history_view_cursor_state.h" #include "storage/storage_shared_media.h" #include "ui/text_options.h" +namespace { + +using PointState = HistoryView::PointState; +using TextState = HistoryView::TextState; + +} // namespace + Storage::SharedMediaTypesMask HistoryMedia::sharedMediaTypes() const { return {}; } @@ -54,9 +62,15 @@ TextSelection HistoryMedia::unskipSelection(TextSelection selection) const { 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, QPoint point, - HistoryStateRequest request) const { + StateRequest request) const { Unexpected("Grouping method call."); } diff --git a/Telegram/SourceFiles/history/history_media.h b/Telegram/SourceFiles/history/history_media.h index 253c06741..e079e6f73 100644 --- a/Telegram/SourceFiles/history/history_media.h +++ b/Telegram/SourceFiles/history/history_media.h @@ -10,8 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_object.h" struct HistoryMessageEdited; -struct HistoryTextState; -struct HistoryStateRequest; struct TextSelection; namespace base { @@ -24,6 +22,14 @@ enum class SharedMediaType : char; using SharedMediaTypesMask = base::enum_mask; } // 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 { None, Top, @@ -53,6 +59,9 @@ enum HistoryMediaType : char { class HistoryMedia : public HistoryView::Object { public: using Element = HistoryView::Element; + using PointState = HistoryView::PointState; + using TextState = HistoryView::TextState; + using StateRequest = HistoryView::StateRequest; HistoryMedia(not_null parent) : _parent(parent) { } @@ -63,16 +72,9 @@ public: return TextWithEntities(); } - bool hasPoint(QPoint point) const { - return QRect(0, 0, width(), height()).contains(point); - } - virtual bool isDisplayed() const; virtual void updateNeedBubbleState() { } - virtual bool isAboveMessage() const { - return false; - } virtual bool hasTextForCopy() const { return false; } @@ -85,7 +87,8 @@ public: virtual void refreshParentId(not_null realParent) { } 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) { } @@ -156,10 +159,10 @@ public: not_null cache) const { Unexpected("Grouping method call."); } - virtual HistoryTextState getStateGrouped( + virtual TextState getStateGrouped( const QRect &geometry, QPoint point, - HistoryStateRequest request) const; + StateRequest request) const; virtual std::unique_ptr takeLastFromGroup() { return nullptr; } @@ -236,6 +239,9 @@ public: virtual ~HistoryMedia() = default; protected: + using CursorState = HistoryView::CursorState; + using InfoDisplayType = HistoryView::InfoDisplayType; + QSize countCurrentSize(int newWidth) override; Text createCaption(not_null item) const; diff --git a/Telegram/SourceFiles/history/history_media_grouped.cpp b/Telegram/SourceFiles/history/history_media_grouped.cpp index 3cc4a3aef..1b0dbb800 100644 --- a/Telegram/SourceFiles/history/history_media_grouped.cpp +++ b/Telegram/SourceFiles/history/history_media_grouped.cpp @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_media_types.h" #include "history/history_message.h" #include "history/view/history_view_element.h" +#include "history/view/history_view_cursor_state.h" #include "data/data_media_types.h" #include "storage/storage_shared_media.h" #include "lang/lang_keys.h" @@ -19,6 +20,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_history.h" #include "layout.h" +namespace { +using TextState = HistoryView::TextState; +using PointState = HistoryView::PointState; +} // namespace + HistoryGroupedMedia::Part::Part(not_null item) : item(item) { } @@ -176,7 +182,7 @@ void HistoryGroupedMedia::draw( auto fullRight = width(); auto fullBottom = height(); if (needInfoDisplay()) { - _parent->drawInfo(p, fullRight, fullBottom, width(), selected, InfoDisplayOverImage); + _parent->drawInfo(p, fullRight, fullBottom, width(), selected, InfoDisplayType::Image); } if (!_parent->hasBubble() && _parent->displayRightAction()) { auto fastShareLeft = (fullRight + st::historyFastShareLeft); @@ -186,9 +192,9 @@ void HistoryGroupedMedia::draw( } } -HistoryTextState HistoryGroupedMedia::getPartState( +TextState HistoryGroupedMedia::getPartState( QPoint point, - HistoryStateRequest request) const { + StateRequest request) const { for (const auto &part : _parts) { if (part.geometry.contains(point)) { auto result = part.content->getStateGrouped( @@ -199,12 +205,24 @@ HistoryTextState HistoryGroupedMedia::getPartState( 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, - HistoryStateRequest request) const { + StateRequest request) const { auto result = getPartState(point, request); if (!result.link && !_caption.isEmpty()) { const auto captionw = width() - st::msgPadding.left() - st::msgPadding.right(); @@ -212,7 +230,7 @@ HistoryTextState HistoryGroupedMedia::getState( - (isBubbleBottom() ? st::msgPadding.bottom() : 0) - _caption.countHeight(captionw); 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), captionw, request.forText())); @@ -220,8 +238,8 @@ HistoryTextState HistoryGroupedMedia::getState( } else if (_parent->media() == this) { auto fullRight = width(); auto fullBottom = height(); - if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayOverImage)) { - result.cursor = HistoryInDateCursorState; + if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayType::Image)) { + result.cursor = CursorState::Date; } if (!_parent->hasBubble() && _parent->displayRightAction()) { auto fastShareLeft = (fullRight + st::historyFastShareLeft); diff --git a/Telegram/SourceFiles/history/history_media_grouped.h b/Telegram/SourceFiles/history/history_media_grouped.h index 8abd0ecc0..4be0d6ecd 100644 --- a/Telegram/SourceFiles/history/history_media_grouped.h +++ b/Telegram/SourceFiles/history/history_media_grouped.h @@ -28,9 +28,10 @@ public: const QRect &clip, TextSelection selection, TimeMs ms) const override; - HistoryTextState getState( + PointState pointState(QPoint point) const override; + TextState textState( QPoint point, - HistoryStateRequest request) const override; + StateRequest request) const override; bool toggleSelectionByHandlerClick( const ClickHandlerPtr &p) const override; @@ -107,9 +108,9 @@ private: not_null main() const; bool validateGroupParts( const std::vector> &items) const; - HistoryTextState getPartState( + TextState getPartState( QPoint point, - HistoryStateRequest request) const; + StateRequest request) const; Text _caption; std::vector _parts; diff --git a/Telegram/SourceFiles/history/history_media_types.cpp b/Telegram/SourceFiles/history/history_media_types.cpp index 61046e43a..86175680b 100644 --- a/Telegram/SourceFiles/history/history_media_types.cpp +++ b/Telegram/SourceFiles/history/history_media_types.cpp @@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_location_manager.h" #include "history/history_message.h" #include "history/view/history_view_element.h" +#include "history/view/history_view_cursor_state.h" #include "window/main_window.h" #include "window/window_controller.h" #include "styles/style_history.h" @@ -41,6 +42,8 @@ namespace { constexpr auto kMaxGifForwardedBarLines = 4; constexpr auto kMaxOriginalEntryLines = 8192; +using TextState = HistoryView::TextState; + int documentMaxStatusWidth(DocumentData *document) { auto result = st::normalFont->width(formatDownloadText(document->size, document->size)); 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 fullBottom = painty + painth; 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()) { 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 { - auto result = HistoryTextState(_parent); +TextState HistoryPhoto::textState(QPoint point, StateRequest request) const { + auto result = TextState(_parent); if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { return result; @@ -447,7 +450,7 @@ HistoryTextState HistoryPhoto::getState(QPoint point, HistoryStateRequest reques painth -= st::msgPadding.bottom(); } 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), captionw, request.forText())); @@ -472,8 +475,8 @@ HistoryTextState HistoryPhoto::getState(QPoint point, HistoryStateRequest reques if (_caption.isEmpty() && _parent->media() == this) { auto fullRight = paintx + paintw; auto fullBottom = painty + painth; - if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayOverImage)) { - result.cursor = HistoryInDateCursorState; + if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayType::Image)) { + result.cursor = CursorState::Date; } if (!bubble && _parent->displayRightAction()) { auto fastShareLeft = (fullRight + st::historyFastShareLeft); @@ -586,15 +589,15 @@ void HistoryPhoto::drawGrouped( } } -HistoryTextState HistoryPhoto::getStateGrouped( +TextState HistoryPhoto::getStateGrouped( const QRect &geometry, QPoint point, - HistoryStateRequest request) const { + StateRequest request) const { if (!geometry.contains(point)) { return {}; } const auto delayed = _data->full->toDelayedStorageImage(); - return HistoryTextState(_parent, _data->uploading() + return TextState(_parent, _data->uploading() ? _cancell : _data->loaded() ? _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); } else if (_parent->media() == this) { 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()) { auto fastShareLeft = (fullRight + st::historyFastShareLeft); 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) { return {}; } - auto result = HistoryTextState(_parent); + auto result = TextState(_parent); bool loaded = _data->loaded(); auto paintx = 0, painty = 0, paintw = width(), painth = height(); @@ -899,7 +902,7 @@ HistoryTextState HistoryVideo::getState(QPoint point, HistoryStateRequest reques painth -= st::msgPadding.bottom(); } 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), captionw, request.forText())); @@ -916,8 +919,8 @@ HistoryTextState HistoryVideo::getState(QPoint point, HistoryStateRequest reques if (_caption.isEmpty() && _parent->media() == this) { auto fullRight = paintx + paintw; auto fullBottom = painty + painth; - if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayOverImage)) { - result.cursor = HistoryInDateCursorState; + if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayType::Image)) { + result.cursor = CursorState::Date; } if (!bubble && _parent->displayRightAction()) { auto fastShareLeft = (fullRight + st::historyFastShareLeft); @@ -1026,14 +1029,14 @@ void HistoryVideo::drawGrouped( } } -HistoryTextState HistoryVideo::getStateGrouped( +TextState HistoryVideo::getStateGrouped( const QRect &geometry, QPoint point, - HistoryStateRequest request) const { + StateRequest request) const { if (!geometry.contains(point)) { return {}; } - return HistoryTextState(_parent, _data->uploading() + return TextState(_parent, _data->uploading() ? _cancell : _data->loaded() ? _openl @@ -1564,8 +1567,8 @@ void HistoryDocument::draw(Painter &p, const QRect &r, TextSelection selection, } } -HistoryTextState HistoryDocument::getState(QPoint point, HistoryStateRequest request) const { - auto result = HistoryTextState(_parent); +TextState HistoryDocument::textState(QPoint point, StateRequest request) const { + auto result = TextState(_parent); if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { return result; @@ -1631,7 +1634,7 @@ HistoryTextState HistoryDocument::getState(QPoint point, HistoryStateRequest req auto painth = height(); if (auto captioned = Get()) { if (point.y() >= bottom) { - result = HistoryTextState(_parent, captioned->_caption.getState( + result = TextState(_parent, captioned->_caption.getState( point - QPoint(st::msgPadding.left(), bottom), width() - st::msgPadding.left() - st::msgPadding.right(), request.forText())); @@ -2306,7 +2309,7 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, TimeM } } 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()) { 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 { - auto result = HistoryTextState(_parent); +TextState HistoryGif::textState(QPoint point, StateRequest request) const { + auto result = TextState(_parent); if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { return result; @@ -2336,7 +2339,7 @@ HistoryTextState HistoryGif::getState(QPoint point, HistoryStateRequest request) painth -= st::msgPadding.bottom(); } 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), captionw, request.forText())); @@ -2386,16 +2389,16 @@ HistoryTextState HistoryGif::getState(QPoint point, HistoryStateRequest request) if (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()), innerw, textRequest)); result.symbol = 0; result.afterSymbol = false; if (breakEverywhere) { - result.cursor = HistoryInForwardedCursorState; + result.cursor = CursorState::Forwarded; } else { - result.cursor = HistoryDefaultCursorState; + result.cursor = CursorState::None; } return result; } @@ -2447,8 +2450,8 @@ HistoryTextState HistoryGif::getState(QPoint point, HistoryStateRequest request) } } if (!inWebPage) { - if (_parent->pointInTime(fullRight, fullBottom, point, isRound ? InfoDisplayOverBackground : InfoDisplayOverImage)) { - result.cursor = HistoryInDateCursorState; + if (_parent->pointInTime(fullRight, fullBottom, point, isRound ? InfoDisplayType::Background : InfoDisplayType::Image)) { + result.cursor = CursorState::Date; } } if (!bubble && _parent->displayRightAction()) { @@ -2810,7 +2813,7 @@ void HistorySticker::draw(Painter &p, const QRect &r, TextSelection selection, T if (!inWebPage) { auto fullRight = usex + usew; 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) { int rectw = width() - usew - st::msgReplyPadding.left(); 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 { - auto result = HistoryTextState(_parent); +TextState HistorySticker::textState(QPoint point, StateRequest request) const { + auto result = TextState(_parent); if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { return result; } @@ -2904,8 +2907,8 @@ HistoryTextState HistorySticker::getState(QPoint point, HistoryStateRequest requ if (_parent->media() == this) { auto fullRight = usex + usew; auto fullBottom = height(); - if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayOverImage)) { - result.cursor = HistoryInDateCursorState; + if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayType::Image)) { + result.cursor = CursorState::Date; } if (_parent->displayRightAction()) { 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); } -HistoryTextState HistoryContact::getState(QPoint point, HistoryStateRequest request) const { - auto result = HistoryTextState(_parent); +TextState HistoryContact::textState(QPoint point, StateRequest request) const { + auto result = TextState(_parent); auto nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0; 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); } -HistoryTextState HistoryCall::getState(QPoint point, HistoryStateRequest request) const { - auto result = HistoryTextState(_parent); +TextState HistoryCall::textState(QPoint point, StateRequest request) const { + auto result = TextState(_parent); if (QRect(0, 0, width(), height()).contains(point)) { result.link = _link; 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 { - auto result = HistoryTextState(_parent); +TextState HistoryWebPage::textState(QPoint point, StateRequest request) const { + auto result = TextState(_parent); if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { return result; @@ -3660,7 +3663,7 @@ HistoryTextState HistoryWebPage::getState(QPoint point, HistoryStateRequest requ if (point.y() >= tshift && point.y() < tshift + _titleLines * lineHeight) { Text::StateRequestElided titleRequest = request.forText(); titleRequest.lines = _titleLines; - result = HistoryTextState(_parent, _title.getStateElidedLeft( + result = TextState(_parent, _title.getStateElidedLeft( point - QPoint(padding.left(), tshift), paintw, width(), @@ -3676,13 +3679,13 @@ HistoryTextState HistoryWebPage::getState(QPoint point, HistoryStateRequest requ if (_descriptionLines > 0) { Text::StateRequestElided descriptionRequest = request.forText(); descriptionRequest.lines = _descriptionLines; - result = HistoryTextState(_parent, _description.getStateElidedLeft( + result = TextState(_parent, _description.getStateElidedLeft( point - QPoint(padding.left(), tshift), paintw, width(), descriptionRequest)); } else { - result = HistoryTextState(_parent, _description.getStateLeft( + result = TextState(_parent, _description.getStateLeft( point - QPoint(padding.left(), tshift), paintw, width(), @@ -3703,7 +3706,7 @@ HistoryTextState HistoryWebPage::getState(QPoint point, HistoryStateRequest requ auto attachLeft = padding.left() - bubble.left(); auto attachTop = tshift - bubble.top(); 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 (_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 { - auto result = HistoryTextState(_parent); +TextState HistoryGame::textState(QPoint point, StateRequest request) const { + auto result = TextState(_parent); if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { return result; @@ -4083,7 +4086,7 @@ HistoryTextState HistoryGame::getState(QPoint point, HistoryStateRequest request if (point.y() >= tshift && point.y() < tshift + _titleLines * lineHeight) { Text::StateRequestElided titleRequest = request.forText(); titleRequest.lines = _titleLines; - result = HistoryTextState(_parent, _title.getStateElidedLeft( + result = TextState(_parent, _title.getStateElidedLeft( point - QPoint(padding.left(), tshift), paintw, width(), @@ -4097,7 +4100,7 @@ HistoryTextState HistoryGame::getState(QPoint point, HistoryStateRequest request if (point.y() >= tshift && point.y() < tshift + _descriptionLines * lineHeight) { Text::StateRequestElided descriptionRequest = request.forText(); descriptionRequest.lines = _descriptionLines; - result = HistoryTextState(_parent, _description.getStateElidedLeft( + result = TextState(_parent, _description.getStateElidedLeft( point - QPoint(padding.left(), tshift), paintw, width(), @@ -4125,7 +4128,7 @@ HistoryTextState HistoryGame::getState(QPoint point, HistoryStateRequest request result.link = _openl; } } 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 { - auto result = HistoryTextState(_parent); +TextState HistoryInvoice::textState(QPoint point, StateRequest request) const { + auto result = TextState(_parent); if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { return result; @@ -4496,7 +4499,7 @@ HistoryTextState HistoryInvoice::getState(QPoint point, HistoryStateRequest requ if (point.y() >= tshift && point.y() < tshift + _titleHeight) { Text::StateRequestElided titleRequest = request.forText(); titleRequest.lines = _titleHeight / lineHeight; - result = HistoryTextState(_parent, _title.getStateElidedLeft( + result = TextState(_parent, _title.getStateElidedLeft( point - QPoint(padding.left(), tshift), paintw, width(), @@ -4508,7 +4511,7 @@ HistoryTextState HistoryInvoice::getState(QPoint point, HistoryStateRequest requ } if (_descriptionHeight) { if (point.y() >= tshift && point.y() < tshift + _descriptionHeight) { - result = HistoryTextState(_parent, _description.getStateLeft( + result = TextState(_parent, _description.getStateLeft( point - QPoint(padding.left(), tshift), paintw, width(), @@ -4527,7 +4530,7 @@ HistoryTextState HistoryInvoice::getState(QPoint point, HistoryStateRequest requ if (rtl()) attachLeft = width() - attachLeft - _attach->width(); 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) { auto fullRight = paintx + paintw; 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()) { auto fastShareLeft = (fullRight + st::historyFastShareLeft); 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 { - auto result = HistoryTextState(_parent); +TextState HistoryLocation::textState(QPoint point, StateRequest request) const { + auto result = TextState(_parent); auto symbolAdd = 0; if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { @@ -4784,7 +4787,7 @@ HistoryTextState HistoryLocation::getState(QPoint point, HistoryStateRequest req if (!_title.isEmpty()) { auto titleh = qMin(_title.countHeight(textw), 2 * st::webPageTitleFont->height); 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), textw, width(), @@ -4798,7 +4801,7 @@ HistoryTextState HistoryLocation::getState(QPoint point, HistoryStateRequest req if (!_description.isEmpty()) { auto descriptionh = qMin(_description.countHeight(textw), 3 * st::webPageDescriptionFont->height); 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), textw, width(), @@ -4819,8 +4822,8 @@ HistoryTextState HistoryLocation::getState(QPoint point, HistoryStateRequest req if (_parent->media() == this) { auto fullRight = paintx + paintw; auto fullBottom = height(); - if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayOverImage)) { - result.cursor = HistoryInDateCursorState; + if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayType::Image)) { + result.cursor = CursorState::Date; } if (!bubble && _parent->displayRightAction()) { auto fastShareLeft = (fullRight + st::historyFastShareLeft); diff --git a/Telegram/SourceFiles/history/history_media_types.h b/Telegram/SourceFiles/history/history_media_types.h index e094ed918..63d1916e7 100644 --- a/Telegram/SourceFiles/history/history_media_types.h +++ b/Telegram/SourceFiles/history/history_media_types.h @@ -141,7 +141,7 @@ public: } 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( TextSelection selection, @@ -171,10 +171,10 @@ public: RectParts corners, not_null cacheKey, not_null cache) const override; - HistoryTextState getStateGrouped( + TextState getStateGrouped( const QRect &geometry, QPoint point, - HistoryStateRequest request) const override; + StateRequest request) const override; bool hasReplyPreview() const override { return !_data->thumb->isNull(); @@ -233,7 +233,7 @@ public: } 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( TextSelection selection, @@ -263,10 +263,10 @@ public: RectParts corners, not_null cacheKey, not_null cache) const override; - HistoryTextState getStateGrouped( + TextState getStateGrouped( const QRect &geometry, QPoint point, - HistoryStateRequest request) const override; + StateRequest request) const override; bool uploading() const override { return _data->uploading(); @@ -328,7 +328,7 @@ public: } 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; [[nodiscard]] TextSelection adjustSelection( @@ -400,7 +400,7 @@ public: } 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( TextSelection selection, @@ -501,7 +501,7 @@ public: } 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 { return true; @@ -562,7 +562,7 @@ public: } 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 { return true; @@ -619,7 +619,7 @@ public: } 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 { return true; @@ -665,7 +665,7 @@ public: void refreshParentId(not_null realParent) 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 { return false; @@ -772,7 +772,7 @@ public: void refreshParentId(not_null realParent) 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( TextSelection selection, @@ -780,9 +780,6 @@ public: uint16 fullSelectionLength() const override { return _title.length() + _description.length(); } - bool isAboveMessage() const override { - return true; - } bool hasTextForCopy() const override { 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; - HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; + TextState textState(QPoint point, StateRequest request) const override; [[nodiscard]] TextSelection adjustSelection( TextSelection selection, @@ -962,7 +959,7 @@ public: } 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( TextSelection selection, diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 80e966906..b02b39ff4 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -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( ) | rpl::start_with_next([=](bool active) { setMembersShowAreaActive(active); diff --git a/Telegram/SourceFiles/history/view/history_view_cursor_state.cpp b/Telegram/SourceFiles/history/view/history_view_cursor_state.cpp index 86c871070..4579aae06 100644 --- a/Telegram/SourceFiles/history/view/history_view_cursor_state.cpp +++ b/Telegram/SourceFiles/history/view/history_view_cursor_state.cpp @@ -10,43 +10,61 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_item.h" #include "history/view/history_view_element.h" -HistoryTextState::HistoryTextState(not_null item) +namespace HistoryView { + +TextState::TextState(not_null item) : itemId(item->fullId()) { } -HistoryTextState::HistoryTextState( +TextState::TextState( not_null item, const Text::StateResult &state) : itemId(item->fullId()) , cursor(state.uponSymbol - ? HistoryInTextCursorState - : HistoryDefaultCursorState) + ? CursorState::Text + : CursorState::None) , link(state.link) , afterSymbol(state.afterSymbol) , symbol(state.symbol) { } -HistoryTextState::HistoryTextState( +TextState::TextState( not_null item, ClickHandlerPtr link) : itemId(item->fullId()) , link(link) { } - -HistoryTextState::HistoryTextState( +TextState::TextState( not_null view) -: HistoryTextState(view->data()) { +: TextState(view->data()) { } -HistoryTextState::HistoryTextState( +TextState::TextState( not_null view, const Text::StateResult &state) -: HistoryTextState(view->data(), state) { +: TextState(view->data(), state) { } -HistoryTextState::HistoryTextState( +TextState::TextState( not_null view, 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 diff --git a/Telegram/SourceFiles/history/view/history_view_cursor_state.h b/Telegram/SourceFiles/history/view/history_view_cursor_state.h index 506e47a1f..b938f8f04 100644 --- a/Telegram/SourceFiles/history/view/history_view_cursor_state.h +++ b/Telegram/SourceFiles/history/view/history_view_cursor_state.h @@ -7,58 +7,54 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -namespace HistoryView { -class Element; -} // namespace HistoryView - class HistoryItem; -enum HistoryCursorState { - HistoryDefaultCursorState, - HistoryInTextCursorState, - HistoryInDateCursorState, - HistoryInForwardedCursorState, +namespace HistoryView { + +class Element; + +enum class PointState : char { + Outside, + Inside, + GroupPart, +}; +enum class CursorState : char { + None, + Text, + Date, + Forwarded, }; -struct HistoryTextState { - HistoryTextState() = default; - HistoryTextState(not_null item); - HistoryTextState( +struct TextState { + TextState() = default; + TextState(not_null item); + TextState( not_null item, const Text::StateResult &state); - HistoryTextState( + TextState( not_null item, ClickHandlerPtr link); - HistoryTextState(not_null view); - HistoryTextState( + TextState(not_null view); + TextState( not_null view, const Text::StateResult &state); - HistoryTextState( + TextState( not_null view, ClickHandlerPtr link); - HistoryTextState( + TextState( std::nullptr_t, - const Text::StateResult &state) - : cursor(state.uponSymbol - ? HistoryInTextCursorState - : HistoryDefaultCursorState) - , link(state.link) - , afterSymbol(state.afterSymbol) - , symbol(state.symbol) { - } - HistoryTextState(std::nullptr_t, ClickHandlerPtr link) - : link(link) { - } + const Text::StateResult &state); + TextState(std::nullptr_t, ClickHandlerPtr link); FullMsgId itemId; - HistoryCursorState cursor = HistoryDefaultCursorState; + CursorState cursor = CursorState::None; ClickHandlerPtr link; bool afterSymbol = false; uint16 symbol = 0; }; -struct HistoryStateRequest { +struct StateRequest { Text::StateRequest::Flags flags = Text::StateRequest::Flag::LookupLink; Text::StateRequest forText() const { Text::StateRequest result; @@ -67,8 +63,10 @@ struct HistoryStateRequest { } }; -enum InfoDisplayType : char { - InfoDisplayDefault, - InfoDisplayOverImage, - InfoDisplayOverBackground, +enum class InfoDisplayType : char { + Default, + Image, + Background, }; + +} // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h index 92d53b913..947cbb9de 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.h +++ b/Telegram/SourceFiles/history/view/history_view_element.h @@ -17,12 +17,14 @@ class HistoryMessage; class HistoryService; class HistoryMedia; class HistoryWebPage; -struct HistoryTextState; -struct HistoryStateRequest; -enum InfoDisplayType : char; namespace HistoryView { +enum class PointState : char; +enum class InfoDisplayType : char; +struct StateRequest; +struct TextState; + enum class Context : char { History, Feed, @@ -166,10 +168,10 @@ public: QRect clip, TextSelection selection, TimeMs ms) const = 0; - [[nodiscard]] virtual bool hasPoint(QPoint point) const = 0; - [[nodiscard]] virtual HistoryTextState getState( + [[nodiscard]] virtual PointState pointState(QPoint point) const = 0; + [[nodiscard]] virtual TextState textState( QPoint point, - HistoryStateRequest request) const = 0; + StateRequest request) const = 0; virtual void updatePressed(QPoint point) = 0; virtual void drawInfo( Painter &p, diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 02873133b..40c3d6d6b 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_element.h" #include "history/view/history_view_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 "mainwindow.h" #include "mainwidget.h" @@ -44,6 +45,20 @@ constexpr auto kPreloadedScreensCountFull } // 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 void ListWidget::enumerateItems(Method method) { constexpr auto TopToBottom = (direction == EnumItemsDirection::TopToBottom); @@ -501,40 +516,151 @@ bool ListWidget::hasSelectedItems() const { return !_selected.empty(); } -bool ListWidget::applyItemSelection( - SelectedMap &applyTo, - FullMsgId itemId) const { - if (applyTo.size() >= MaxSelectedItems) { - return false; +bool ListWidget::overSelectedItems() const { + if (_overState.pointState == PointState::GroupPart) { + return _overItemExact + && _selected.contains(_overItemExact->fullId()); + } 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 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 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 item) const { + const auto itemId = item->fullId(); 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(); +bool ListWidget::removeFromSelection( + SelectedMap &applyTo, + FullMsgId itemId) const { + return applyTo.remove(itemId); +} + +void ListWidget::changeSelection( + SelectedMap &applyTo, + not_null 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 { - removeItemSelection(it); + removeFromSelection(applyTo, itemId); + } +} + +void ListWidget::changeSelectionAsGroup( + SelectedMap &applyTo, + not_null 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 { - return (_pressState.itemId && _pressState.inside) + return (_pressState.itemId + && _pressState.pointState != PointState::Outside) ? _selected.find(_pressState.itemId) : _selected.end(); } auto ListWidget::itemUnderPressSelection() const -> SelectedMap::const_iterator { - return (_pressState.itemId && _pressState.inside) + return (_pressState.itemId + && _pressState.pointState != PointState::Outside) ? _selected.find(_pressState.itemId) : _selected.end(); } bool ListWidget::requiredToStartDragging( not_null view) const { - if (_mouseCursorState == HistoryInDateCursorState) { + if (_mouseCursorState == CursorState::Date) { return true; } else if (const auto media = view->media()) { return media->type() == MediaTypeSticker; @@ -565,8 +693,8 @@ bool ListWidget::requiredToStartDragging( return false; } -bool ListWidget::isPressInSelectedText(HistoryTextState state) const { - if (state.cursor != HistoryInTextCursorState) { +bool ListWidget::isPressInSelectedText(TextState state) const { + if (state.cursor != CursorState::Text) { return false; } if (!hasSelectedText() @@ -692,13 +820,13 @@ void ListWidget::checkMoveToOtherViewer() { } QString ListWidget::tooltipText() const { - const auto item = (_overItem && _mouseAction == MouseAction::None) - ? _overItem->data().get() + const auto item = (_overElement && _mouseAction == MouseAction::None) + ? _overElement->data().get() : nullptr; - if (_mouseCursorState == HistoryInDateCursorState && item) { + if (_mouseCursorState == CursorState::Date && item) { return item->date.toString( QLocale::system().dateTimeFormat(QLocale::LongFormat)); - } else if (_mouseCursorState == HistoryInForwardedCursorState && item) { + } else if (_mouseCursorState == CursorState::Forwarded && item) { if (const auto forwarded = item->Get()) { return forwarded->text.originalText( AllTextSelection, @@ -730,7 +858,7 @@ std::unique_ptr ListWidget::elementCreate( bool ListWidget::elementUnderCursor( not_null view) { - return (_overItem == view); + return (_overElement == view); } void ListWidget::elementAnimationAutoplayAsync( @@ -974,11 +1102,17 @@ void ListWidget::applyDragSelection() { void ListWidget::applyDragSelection(SelectedMap &applyTo) const { if (_dragSelectAction == DragSelectAction::Selecting) { 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) { for (const auto itemId : _dragSelected) { - applyTo.remove(itemId); + removeFromSelection(applyTo, itemId); } } } @@ -1132,7 +1266,7 @@ void ListWidget::trySwitchToWordSelection() { && hasSelectedText(); auto willSelectSome = (_mouseAction == MouseAction::None) && !hasSelectedItems(); - auto checkSwitchToWordSelection = _overItem + auto checkSwitchToWordSelection = _overElement && (_mouseSelectType == TextSelectType::Letters) && (selectingSome || willSelectSome); if (checkSwitchToWordSelection) { @@ -1141,19 +1275,19 @@ void ListWidget::trySwitchToWordSelection() { } void ListWidget::switchToWordSelection() { - Expects(_overItem != nullptr); + Expects(_overElement != nullptr); - HistoryStateRequest request; + StateRequest request; request.flags |= Text::StateRequest::Flag::LookupSymbol; - auto dragState = _overItem->getState(_pressState.cursor, request); - if (dragState.cursor != HistoryInTextCursorState) { + auto dragState = _overElement->textState(_pressState.point, request); + if (dragState.cursor != CursorState::Text) { return; } _mouseTextSymbol = dragState.symbol; _mouseSelectType = TextSelectType::Words; if (_mouseAction == MouseAction::None) { _mouseAction = MouseAction::Selecting; - setTextSelection(_overItem, TextSelection( + setTextSelection(_overElement, TextSelection( dragState.symbol, dragState.symbol )); @@ -1184,8 +1318,10 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { ContextMenuRequest request; request.link = ClickHandler::getActive(); - request.view = _overItem; - request.overView = _overItem && _overState.inside; + request.view = _overElement; + // #TODO group part context menu using _overItemExact + request.overView = _overElement + && (_overState.pointState != PointState::Outside); request.selectedText = _selectedText; const auto itemId = request.view ? request.view->data()->fullId() @@ -1202,12 +1338,12 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { const auto pointInItem = mapPointToItem( mapFromGlobal(_mousePosition), request.view); - HistoryStateRequest stateRequest; + StateRequest stateRequest; stateRequest.flags |= Text::StateRequest::Flag::LookupSymbol; - const auto dragState = request.view->getState( + const auto dragState = request.view->textState( pointInItem, stateRequest); - if (dragState.cursor == HistoryInTextCursorState + if (dragState.cursor == CursorState::Text && base::in_range( dragState.symbol, _selectedTextRange.from, @@ -1257,10 +1393,10 @@ void ListWidget::enterEventHook(QEvent *e) { } void ListWidget::leaveEventHook(QEvent *e) { - if (const auto view = _overItem) { - if (_overState.inside) { + if (const auto view = _overElement) { + if (_overState.pointState != PointState::Outside) { repaintItem(view); - _overState.inside = false; + _overState.pointState = PointState::Outside; } } ClickHandler::clearActive(); @@ -1276,7 +1412,7 @@ void ListWidget::updateDragSelection() { if (!_overState.itemId || !_pressState.itemId) { clearDragSelection(); return; - } else if (_items.empty() || !_overItem || !_selectEnabled) { + } else if (_items.empty() || !_overElement || !_selectEnabled) { return; } const auto pressItem = App::histItemById(_pressState.itemId); @@ -1284,7 +1420,7 @@ void ListWidget::updateDragSelection() { return; } - const auto overView = _overItem; + const auto overView = _overElement; const auto pressView = viewForItem(pressItem); const auto selectingUp = _delegate->listIsLessInOrder( overView->data(), @@ -1309,14 +1445,37 @@ void ListWidget::updateDragSelection() { [](auto view) { return view.get(); }) : end(_items); Assert(from <= till); + const auto &groups = Auth().data().groups(); + const auto changeItem = [&](not_null item, bool add) { + const auto itemId = item->fullId(); + if (add) { + _dragSelected.emplace(itemId); + } else { + _dragSelected.remove(itemId); + } + }; + const auto changeGroup = [&](not_null 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 view, bool add) { + if (!view->isHiddenByGroup()) { + changeGroup(view->data(), add); + } + }; for (auto i = begin(_items); i != from; ++i) { - _dragSelected.remove((*i)->data()->fullId()); + changeView(*i, false); } for (auto i = from; i != till; ++i) { - _dragSelected.emplace((*i)->data()->fullId()); + changeView(*i, true); } for (auto i = till; i != end(_items); ++i) { - _dragSelected.remove((*i)->data()->fullId()); + changeView(*i, false); } _dragSelectAction = [&] { if (_dragSelected.empty()) { @@ -1363,7 +1522,7 @@ void ListWidget::mouseActionStart( _pressState = _overState; repaintItem(_overState.itemId); } - const auto pressedItem = _overItem; + const auto pressedView = _overElement; _mouseAction = MouseAction::None; _pressWasInactive = _controller->window()->wasInactivePress(); @@ -1371,18 +1530,24 @@ void ListWidget::mouseActionStart( if (ClickHandler::getPressed()) { _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(); - HistoryTextState dragState; + TextState dragState; auto startDistance = (globalPosition - _trippleClickPoint).manhattanLength(); auto validStartPoint = startDistance < QApplication::startDragDistance(); if (_trippleClickStartTime != 0 && validStartPoint) { - HistoryStateRequest request; + StateRequest request; request.flags = Text::StateRequest::Flag::LookupSymbol; - dragState = pressedItem->getState(_pressState.cursor, request); - if (dragState.cursor == HistoryInTextCursorState) { - setTextSelection(pressedItem, TextSelection( + dragState = pressedView->textState(_pressState.point, request); + if (dragState.cursor == CursorState::Text) { + setTextSelection(pressedView, TextSelection( dragState.symbol, dragState.symbol )); @@ -1392,23 +1557,22 @@ void ListWidget::mouseActionStart( mouseActionUpdate(); _trippleClickStartTime = getms(); } - } else if (pressedItem) { - HistoryStateRequest request; + } else if (pressedView) { + StateRequest request; request.flags = Text::StateRequest::Flag::LookupSymbol; - dragState = pressedItem->getState(_pressState.cursor, request); + dragState = pressedView->textState(_pressState.point, request); } if (_mouseSelectType != TextSelectType::Paragraphs) { _mouseTextSymbol = dragState.symbol; if (isPressInSelectedText(dragState)) { _mouseAction = MouseAction::PrepareDrag; // start text drag } else if (!_pressWasInactive) { - if (requiredToStartDragging(pressedItem)) { + if (requiredToStartDragging(pressedView)) { _mouseAction = MouseAction::PrepareDrag; } else { if (dragState.afterSymbol) ++_mouseTextSymbol; - ; if (!hasSelectedItems()) { - setTextSelection(pressedItem, TextSelection( + setTextSelection(pressedView, TextSelection( _mouseTextSymbol, _mouseTextSymbol)); _mouseAction = MouseAction::Selecting; @@ -1419,7 +1583,7 @@ void ListWidget::mouseActionStart( } } } - if (!pressedItem) { + if (!pressedView) { _mouseAction = MouseAction::None; } else if (_mouseAction == MouseAction::None) { mouseActionCancel(); @@ -1432,7 +1596,7 @@ void ListWidget::mouseActionUpdate(const QPoint &globalPosition) { } void ListWidget::mouseActionCancel() { - _pressState = CursorState(); + _pressState = MouseState(); _mouseAction = MouseAction::None; clearDragSelection(); _wasSelectedText = false; @@ -1444,33 +1608,63 @@ void ListWidget::mouseActionFinish( Qt::MouseButton button) { mouseActionUpdate(globalPosition); - auto activated = ClickHandler::unpressed(); - if (_mouseAction == MouseAction::Dragging) { - activated = nullptr; - } auto pressState = base::take(_pressState); 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 - && pressState.inside + && (pressState.pointState != PointState::Outside) && !_pressWasInactive && (button != Qt::RightButton) - && (_mouseAction == MouseAction::PrepareDrag - || _mouseAction == MouseAction::PrepareSelect); + && (_mouseAction == MouseAction::PrepareSelect + || _mouseAction == MouseAction::PrepareDrag); auto needItemSelectionToggle = simpleSelectionChange + && (!activated || toggleByHandler(activated)) && hasSelectedItems(); auto needTextSelectionClear = simpleSelectionChange && hasSelectedText(); _wasSelectedText = false; - if (activated) { + if (_mouseAction == MouseAction::Dragging + || _mouseAction == MouseAction::Selecting + || needItemSelectionToggle) { + activated = nullptr; + } else if (activated) { mouseActionCancel(); App::activateClickHandler(activated, button); return; } 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) { clearTextSelection(); } else if (_mouseAction == MouseAction::Selecting) { @@ -1506,26 +1700,26 @@ void ListWidget::mouseActionUpdate() { const auto view = strictFindItemByY(point.y()); const auto item = view ? view->data().get() : nullptr; const auto itemPoint = mapPointToItem(point, view); - _overState = CursorState{ + _overState = MouseState{ item ? item->fullId() : FullMsgId(), view ? view->height() : 0, itemPoint, - view ? view->hasPoint(itemPoint) : false + view ? view->pointState(itemPoint) : PointState::Outside }; - if (_overItem != view) { - repaintItem(_overItem); - _overItem = view; - repaintItem(_overItem); + if (_overElement != view) { + repaintItem(_overElement); + _overElement = view; + repaintItem(_overElement); } - HistoryTextState dragState; + TextState dragState; ClickHandlerHost *lnkhost = nullptr; - auto inTextSelection = _overState.inside + auto inTextSelection = (_overState.pointState != PointState::Outside) && (_overState.itemId == _pressState.itemId) && hasSelectedText(); if (view) { auto cursorDeltaLength = [&] { - auto cursorDelta = (_overState.cursor - _pressState.cursor); + auto cursorDelta = (_overState.point - _pressState.point); return cursorDelta.manhattanLength(); }; auto dragStartLength = [] { @@ -1540,14 +1734,15 @@ void ListWidget::mouseActionUpdate() { _mouseAction = MouseAction::Selecting; } } - HistoryStateRequest request; + StateRequest request; if (_mouseAction == MouseAction::Selecting) { request.flags |= Text::StateRequest::Flag::LookupSymbol; } else { inTextSelection = false; } // #TODO enumerate dates like HistoryInner - dragState = view->getState(itemPoint, request); + dragState = view->textState(itemPoint, request); + _overItemExact = App::histItemById(dragState.itemId); lnkhost = view; if (!dragState.link && itemPoint.x() >= st::historyPhotoLeft @@ -1564,7 +1759,10 @@ void ListWidget::mouseActionUpdate() { const auto message = view->data()->toHistoryMessage(); Assert(message != nullptr); - dragState.link = message->from()->openLink(); + dragState = TextState( + nullptr, + message->displayFrom()->openLink()); + _overItemExact = App::histItemById(dragState.itemId); lnkhost = view; return false; } @@ -1578,8 +1776,8 @@ void ListWidget::mouseActionUpdate() { Ui::Tooltip::Hide(); } if (dragState.link - || dragState.cursor == HistoryInDateCursorState - || dragState.cursor == HistoryInForwardedCursorState) { + || dragState.cursor == CursorState::Date + || dragState.cursor == CursorState::Forwarded) { Ui::Tooltip::Show(1000, this); } @@ -1617,7 +1815,8 @@ void ListWidget::mouseActionUpdate() { } // 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 view = viewForItem(item)) { auto adjustedPoint = mapPointToItem(point, view); @@ -1637,7 +1836,7 @@ style::cursor ListWidget::computeMouseCursor() const { if (ClickHandler::getPressed() || ClickHandler::getActive()) { return style::cur_pointer; } else if (!hasSelectedItems() - && (_mouseCursorState == HistoryInTextCursorState)) { + && (_mouseCursorState == CursorState::Text)) { return style::cur_text; } return style::cur_default; @@ -1651,10 +1850,10 @@ void ListWidget::performDrag() { // if (!_selected.isEmpty() && _selected.cbegin().value() == FullSelection) { // uponSelected = _selected.contains(_mouseActionItem); // } else { - // HistoryStateRequest request; + // StateRequest request; // request.flags |= Text::StateRequest::Flag::LookupSymbol; - // auto dragState = _mouseActionItem->getState(_dragStartPosition.x(), _dragStartPosition.y(), request); - // uponSelected = (dragState.cursor == HistoryInTextCursorState); + // auto dragState = _mouseActionItem->textState(_dragStartPosition.x(), _dragStartPosition.y(), request); + // uponSelected = (dragState.cursor == CursorState::Text); // if (uponSelected) { // if (_selected.isEmpty() || // _selected.cbegin().value() == FullSelection || @@ -1705,7 +1904,7 @@ void ListWidget::performDrag() { // auto pressedMedia = static_cast(nullptr); // if (auto pressedItem = App::pressedItem()) { // #TODO no App:: // pressedMedia = pressedItem->media(); - // if (_mouseCursorState == HistoryInDateCursorState + // if (_mouseCursorState == CursorState::Date // || (pressedMedia && pressedMedia->dragItem())) { // Auth().data().setMimeForwardIds( // Auth().data().itemOrItsGroup(pressedItem->data())); @@ -1779,7 +1978,8 @@ void ListWidget::refreshAttachmentsAtIndex(int index) { return index; }(); 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()) { return i + 1; } @@ -1835,13 +2035,16 @@ void ListWidget::refreshItem(not_null view) { void ListWidget::viewReplaced(not_null was, Element *now) { if (_visibleTopItem == was) _visibleTopItem = now; if (_scrollDateLastItem == was) _scrollDateLastItem = now; - if (_overItem == was) _overItem = now; + if (_overElement == was) _overElement = now; } void ListWidget::itemRemoved(not_null item) { if (_selectedTextItem == item) { clearTextSelection(); } + if (_overItemExact == item) { + _overItemExact = nullptr; + } const auto i = _views.find(item); if (i == end(_views)) { return; diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h index 8b06839f8..bffbd7d1d 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h @@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mtproto/sender.h" #include "base/timer.h" #include "data/data_messages.h" -#include "history/view/history_view_cursor_state.h" #include "history/view/history_view_element.h" namespace Ui { @@ -25,6 +24,10 @@ class Controller; namespace HistoryView { +struct TextState; +struct StateRequest; +enum class CursorState : char; +enum class PointState : char; enum class Context : char; struct SelectedItem { @@ -166,17 +169,24 @@ protected: int resizeGetHeight(int newWidth) override; private: - struct CursorState { + struct MouseState { + MouseState(); + MouseState( + FullMsgId itemId, + int height, + QPoint point, + PointState pointState); + FullMsgId itemId; int height = 0; - QPoint cursor; - bool inside = false; + QPoint point; + PointState pointState; - inline bool operator==(const CursorState &other) const { + inline bool operator==(const MouseState &other) const { 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); } @@ -192,6 +202,11 @@ private: PrepareSelect, Selecting, }; + enum class SelectAction { + Select, + Deselect, + Invert, + }; enum class EnumItemsDirection { TopToBottom, BottomToTop, @@ -202,6 +217,8 @@ private: Deselecting, }; using ScrollTopState = ListMemento::ScrollTopState; + using PointState = HistoryView::PointState; + using CursorState = HistoryView::CursorState; void refreshViewer(); void updateAroundPositionFromRows(); @@ -264,18 +281,42 @@ private: const SelectedMap::const_iterator &i); bool hasSelectedText() const; bool hasSelectedItems() const; + bool overSelectedItems() const; void clearTextSelection(); void clearSelected(); void setTextSelection( not_null view, TextSelection selection); - bool applyItemSelection(SelectedMap &applyTo, FullMsgId itemId) const; - void toggleItemSelection(FullMsgId itemId); + //bool applyItemSelection(SelectedMap &applyTo, FullMsgId itemId) const; + //void toggleItemSelection(FullMsgId itemId); + + bool isGoodForSelection( + SelectedMap &applyTo, + not_null item, + int &totalCount) const; + bool addToSelection( + SelectedMap &applyTo, + not_null item) const; + bool removeFromSelection( + SelectedMap &applyTo, + FullMsgId itemId) const; + void changeSelection( + SelectedMap &applyTo, + not_null item, + SelectAction action) const; + bool isSelectedAsGroup( + const SelectedMap &applyTo, + not_null item) const; + void changeSelectionAsGroup( + SelectedMap &applyTo, + not_null item, + SelectAction action) const; + SelectedMap::iterator itemUnderPressSelection(); SelectedMap::const_iterator itemUnderPressSelection() const; bool isItemUnderPressSelected() const; bool requiredToStartDragging(not_null view) const; - bool isPressInSelectedText(HistoryTextState state) const; + bool isPressInSelectedText(TextState state) const; void updateDragSelection(); void clearDragSelection(); void applyDragSelection(); @@ -345,10 +386,11 @@ private: MouseAction _mouseAction = MouseAction::None; TextSelectType _mouseSelectType = TextSelectType::Letters; QPoint _mousePosition; - CursorState _overState; - CursorState _pressState; - Element *_overItem = nullptr; - HistoryCursorState _mouseCursorState = HistoryDefaultCursorState; + MouseState _overState; + MouseState _pressState; + Element *_overElement = nullptr; + HistoryItem *_overItemExact = nullptr; + CursorState _mouseCursorState = CursorState(); uint16 _mouseTextSymbol = 0; bool _pressWasInactive = false; diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index ceaf9862d..86d3f41dc 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -435,31 +435,15 @@ void Message::draw( if (entry) { trect.setHeight(trect.height() - entry->height()); } - auto needDrawInfo = mediaOnBottom - ? !(entry - ? entry->customInfoLayout() - : media->customInfoLayout()) - : true; + paintText(p, trect, selection); if (mediaDisplayed) { - auto mediaAboveText = media->isAboveMessage(); auto mediaHeight = media->height(); auto mediaLeft = g.left(); - auto mediaTop = mediaAboveText ? trect.y() : (trect.y() + trect.height() - mediaHeight); - if (!mediaAboveText) { - paintText(p, trect, selection); - } + auto mediaTop = (trect.y() + trect.height() - mediaHeight); + p.translate(mediaLeft, mediaTop); media->draw(p, clip.translated(-mediaLeft, -mediaTop), skipTextSelection(selection), ms); 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) { auto entryLeft = g.left(); @@ -472,8 +456,13 @@ void Message::draw( entry->draw(p, clip.translated(-entryLeft, -entryTop), entrySelection, ms); p.translate(-entryLeft, -entryTop); } + const auto needDrawInfo = entry + ? !entry->customInfoLayout() + : (mediaDisplayed + ? !media->customInfoLayout() + : true); 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()) { 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); } -bool Message::hasPoint(QPoint point) const { +PointState Message::pointState(QPoint point) const { const auto g = countGeometry(); if (g.width() < 1) { - return false; + return PointState::Outside; } + const auto media = this->media(); const auto item = message(); if (drawBubble()) { - return g.contains(point); - } else if (const auto media = this->media()) { - return media->hasPoint(point - g.topLeft()); - } else { - return false; + if (!g.contains(point)) { + return PointState::Outside; + } + if (const auto mediaDisplayed = media && media->isDisplayed()) { + // 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 { @@ -661,13 +686,13 @@ bool Message::hasFromPhoto() const { Unexpected("Context in Message::hasFromPhoto."); } -HistoryTextState Message::getState( +TextState Message::textState( QPoint point, - HistoryStateRequest request) const { + StateRequest request) const { const auto item = message(); const auto media = this->media(); - auto result = HistoryTextState(item); + auto result = TextState(item); auto g = countGeometry(); if (g.width() < 1) { @@ -707,7 +732,7 @@ HistoryTextState Message::getState( auto entryLeft = g.left(); auto entryTop = trect.y() + trect.height(); if (point.y() >= entryTop && point.y() < entryTop + entryHeight) { - result = entry->getState( + result = entry->textState( point - QPoint(entryLeft, entryTop), request); result.symbol += item->_text.length() + (mediaDisplayed ? media->fullSelectionLength() : 0); @@ -720,28 +745,22 @@ HistoryTextState Message::getState( : media->customInfoLayout()) : true; if (mediaDisplayed) { - auto mediaAboveText = media->isAboveMessage(); auto mediaHeight = media->height(); 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) { - result = media->getState(point - QPoint(mediaLeft, mediaTop), request); + result = media->textState(point - QPoint(mediaLeft, mediaTop), request); result.symbol += item->_text.length(); - } else { - if (mediaAboveText) { - trect.setY(trect.y() + mediaHeight); - } - if (trect.contains(point)) { - getStateText(point, trect, &result, request); - } + } else if (trect.contains(point)) { + getStateText(point, trect, &result, request); } } else if (trect.contains(point)) { getStateText(point, trect, &result, request); } if (needDateCheck) { - if (pointInTime(g.left() + g.width(), g.top() + g.height(), point, InfoDisplayDefault)) { - result.cursor = HistoryInDateCursorState; + if (pointInTime(g.left() + g.width(), g.top() + g.height(), point, InfoDisplayType::Default)) { + result.cursor = CursorState::Date; } } if (displayRightAction()) { @@ -761,14 +780,14 @@ HistoryTextState Message::getState( } } } else if (media && media->isDisplayed()) { - result = media->getState(point - g.topLeft(), request); + result = media->textState(point - g.topLeft(), request); result.symbol += item->_text.length(); } if (keyboard && !item->isLogEntry()) { auto keyboardTop = g.top() + g.height() + st::msgBotKbButton.margin; 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; } } @@ -779,7 +798,7 @@ HistoryTextState Message::getState( bool Message::getStateFromName( QPoint point, QRect &trect, - not_null outResult) const { + not_null outResult) const { const auto item = message(); if (displayFromName()) { const auto replyWidth = [&] { @@ -828,8 +847,8 @@ bool Message::getStateFromName( bool Message::getStateForwardedInfo( QPoint point, QRect &trect, - not_null outResult, - HistoryStateRequest request) const { + not_null outResult, + StateRequest request) const { if (displayForwardedFrom()) { const auto item = message(); auto forwarded = item->Get(); @@ -840,16 +859,16 @@ bool Message::getStateForwardedInfo( if (breakEverywhere) { textRequest.flags |= Text::StateRequest::Flag::BreakEverywhere; } - *outResult = HistoryTextState(item, forwarded->text.getState( + *outResult = TextState(item, forwarded->text.getState( point - trect.topLeft(), trect.width(), textRequest)); outResult->symbol = 0; outResult->afterSymbol = false; if (breakEverywhere) { - outResult->cursor = HistoryInForwardedCursorState; + outResult->cursor = CursorState::Forwarded; } else { - outResult->cursor = HistoryDefaultCursorState; + outResult->cursor = CursorState::None; } return true; } @@ -861,7 +880,7 @@ bool Message::getStateForwardedInfo( bool Message::getStateReplyInfo( QPoint point, QRect &trect, - not_null outResult) const { + not_null outResult) const { const auto item = message(); if (auto reply = item->Get()) { int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); @@ -879,7 +898,7 @@ bool Message::getStateReplyInfo( bool Message::getStateViaBotIdInfo( QPoint point, QRect &trect, - not_null outResult) const { + not_null outResult) const { const auto item = message(); if (!displayFromName() && !item->Has()) { if (auto via = item->Get()) { @@ -896,14 +915,14 @@ bool Message::getStateViaBotIdInfo( bool Message::getStateText( QPoint point, QRect &trect, - not_null outResult, - HistoryStateRequest request) const { + not_null outResult, + StateRequest request) const { if (!hasVisibleText()) { return false; } const auto item = message(); if (trect.contains(point)) { - *outResult = HistoryTextState(item, item->_text.getState( + *outResult = TextState(item, item->_text.getState( point - trect.topLeft(), trect.width(), request.forText())); @@ -954,10 +973,9 @@ void Message::updatePressed(QPoint point) { auto needDateCheck = true; if (mediaDisplayed) { - auto mediaAboveText = media->isAboveMessage(); auto mediaHeight = media->height(); 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)); } } else { @@ -1054,23 +1072,23 @@ void Message::drawInfo( p.setFont(st::msgDateFont); bool outbg = hasOutLayout(); - bool invertedsprites = (type == InfoDisplayOverImage) - || (type == InfoDisplayOverBackground); + bool invertedsprites = (type == InfoDisplayType::Image) + || (type == InfoDisplayType::Background); int32 infoRight = right, infoBottom = bottom; switch (type) { - case InfoDisplayDefault: + case InfoDisplayType::Default: infoRight -= st::msgPadding.right() - st::msgDateDelta.x(); infoBottom -= st::msgPadding.bottom() - st::msgDateDelta.y(); p.setPen(selected ? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected) : (outbg ? st::msgOutDateFg : st::msgInDateFg)); break; - case InfoDisplayOverImage: + case InfoDisplayType::Image: infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x(); infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y(); p.setPen(st::msgDateImgFg); break; - case InfoDisplayOverBackground: + case InfoDisplayType::Background: infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x(); infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y(); p.setPen(st::msgServiceFg); @@ -1083,10 +1101,10 @@ void Message::drawInfo( auto dateX = infoRight - infoW; 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(); 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(); 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 infoBottom = bottom; switch (type) { - case InfoDisplayDefault: + case InfoDisplayType::Default: infoRight -= st::msgPadding.right() - st::msgDateDelta.x(); infoBottom -= st::msgPadding.bottom() - st::msgDateDelta.y(); break; - case InfoDisplayOverImage: + case InfoDisplayType::Image: infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x(); infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y(); break; @@ -1414,11 +1432,7 @@ void Message::updateMediaInBubbleState() { mediaHasSomethingAbove = getMediaHasSomethingAbove(); } if (hasVisibleText()) { - if (media->isAboveMessage()) { - mediaHasSomethingBelow = true; - } else { - mediaHasSomethingAbove = true; - } + mediaHasSomethingAbove = true; } const auto state = [&] { if (mediaHasSomethingAbove) { diff --git a/Telegram/SourceFiles/history/view/history_view_message.h b/Telegram/SourceFiles/history/view/history_view_message.h index eb42319a6..9286cadea 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.h +++ b/Telegram/SourceFiles/history/view/history_view_message.h @@ -37,10 +37,10 @@ public: QRect clip, TextSelection selection, TimeMs ms) const override; - bool hasPoint(QPoint point) const override; - HistoryTextState getState( + PointState pointState(QPoint point) const override; + TextState textState( QPoint point, - HistoryStateRequest request) const override; + StateRequest request) const override; void updatePressed(QPoint point) override; void drawInfo( Painter &p, @@ -104,25 +104,25 @@ private: bool getStateFromName( QPoint point, QRect &trect, - not_null outResult) const; + not_null outResult) const; bool getStateForwardedInfo( QPoint point, QRect &trect, - not_null outResult, - HistoryStateRequest request) const; + not_null outResult, + StateRequest request) const; bool getStateReplyInfo( QPoint point, QRect &trect, - not_null outResult) const; + not_null outResult) const; bool getStateViaBotIdInfo( QPoint point, QRect &trect, - not_null outResult) const; + not_null outResult) const; bool getStateText( QPoint point, QRect &trect, - not_null outResult, - HistoryStateRequest request) const; + not_null outResult, + StateRequest request) const; void updateMediaInBubbleState(); QRect countGeometry() const; diff --git a/Telegram/SourceFiles/history/view/history_view_service_message.cpp b/Telegram/SourceFiles/history/view/history_view_service_message.cpp index 6060aee7f..24800c013 100644 --- a/Telegram/SourceFiles/history/view/history_view_service_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_service_message.cpp @@ -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 media = this->media(); auto g = countGeometry(); if (g.width() < 1) { - return false; + return PointState::Outside; } if (const auto dateh = displayedDateHeight()) { @@ -454,14 +454,14 @@ bool Service::hasPoint(QPoint point) const { if (media) { 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 media = this->media(); - auto result = HistoryTextState(item); + auto result = TextState(item); auto g = countGeometry(); if (g.width() < 1) { @@ -485,21 +485,25 @@ HistoryTextState Service::getState(QPoint point, HistoryStateRequest request) co if (trect.contains(point)) { auto textRequest = request.forText(); textRequest.align = style::al_center; - result = HistoryTextState(item, item->_text.getState( + result = TextState(item, item->_text.getState( point - trect.topLeft(), trect.width(), textRequest)); if (auto gamescore = item->Get()) { - if (!result.link && result.cursor == HistoryInTextCursorState && g.contains(point)) { + if (!result.link + && result.cursor == CursorState::Text + && g.contains(point)) { result.link = gamescore->lnk; } } else if (auto payment = item->Get()) { - if (!result.link && result.cursor == HistoryInTextCursorState && g.contains(point)) { + if (!result.link + && result.cursor == CursorState::Text + && g.contains(point)) { result.link = payment->lnk; } } } 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; } diff --git a/Telegram/SourceFiles/history/view/history_view_service_message.h b/Telegram/SourceFiles/history/view/history_view_service_message.h index a47d21fa1..87c66f96a 100644 --- a/Telegram/SourceFiles/history/view/history_view_service_message.h +++ b/Telegram/SourceFiles/history/view/history_view_service_message.h @@ -24,10 +24,10 @@ public: QRect clip, TextSelection selection, TimeMs ms) const override; - bool hasPoint(QPoint point) const override; - HistoryTextState getState( + PointState pointState(QPoint point) const override; + TextState textState( QPoint point, - HistoryStateRequest request) const override; + StateRequest request) const override; void updatePressed(QPoint point) override; TextWithEntities selectedText(TextSelection selection) const override; TextSelection adjustSelection( diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp index 53d504645..6d4c7a904 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "history/history_item.h" #include "history/history.h" +#include "history/view/history_view_cursor_state.h" #include "window/themes/window_theme.h" #include "window/window_controller.h" #include "window/window_peer_menu.h" @@ -151,8 +152,8 @@ private: }; bool ListWidget::IsAfter( - const CursorState &a, - const CursorState &b) { + const MouseState &a, + const MouseState &b) { if (a.itemId != b.itemId) { return (a.itemId < b.itemId); } @@ -161,7 +162,7 @@ bool ListWidget::IsAfter( return (xAfter + yAfter >= 0); } -bool ListWidget::SkipSelectFromItem(const CursorState &state) { +bool ListWidget::SkipSelectFromItem(const MouseState &state) { if (state.cursor.y() >= state.size.height() || state.cursor.x() >= state.size.width()) { return true; @@ -169,7 +170,7 @@ bool ListWidget::SkipSelectFromItem(const CursorState &state) { return false; } -bool ListWidget::SkipSelectTillItem(const CursorState &state) { +bool ListWidget::SkipSelectTillItem(const MouseState &state) { if (state.cursor.x() < 0 || state.cursor.y() < 0) { return true; } @@ -1440,10 +1441,10 @@ void ListWidget::trySwitchToWordSelection() { void ListWidget::switchToWordSelection() { Expects(_overLayout != nullptr); - HistoryStateRequest request; + StateRequest request; request.flags |= Text::StateRequest::Flag::LookupSymbol; auto dragState = _overLayout->getState(_pressState.cursor, request); - if (dragState.cursor != HistoryInTextCursorState) { + if (dragState.cursor != CursorState::Text) { return; } _mouseTextSymbol = dragState.symbol; @@ -1535,15 +1536,15 @@ auto ListWidget::itemUnderPressSelection() const bool ListWidget::requiredToStartDragging( not_null layout) const { - if (_mouseCursorState == HistoryInDateCursorState) { + if (_mouseCursorState == CursorState::Date) { return true; } // return dynamic_cast(layout->getMedia()); return false; } -bool ListWidget::isPressInSelectedText(HistoryTextState state) const { - if (state.cursor != HistoryInTextCursorState) { +bool ListWidget::isPressInSelectedText(TextState state) const { + if (state.cursor != CursorState::Text) { return false; } if (!hasSelectedText() @@ -1616,7 +1617,7 @@ void ListWidget::mouseActionUpdate(const QPoint &globalPosition) { auto local = mapFromGlobal(_mousePosition); auto point = clampMousePosition(local); auto [layout, geometry, inside] = findItemByPoint(point); - auto state = CursorState { + auto state = MouseState{ GetUniversalId(layout), geometry.size(), point - geometry.topLeft(), @@ -1630,7 +1631,7 @@ void ListWidget::mouseActionUpdate(const QPoint &globalPosition) { } _overState = state; - HistoryTextState dragState; + TextState dragState; ClickHandlerHost *lnkhost = nullptr; auto inTextSelection = _overState.inside && (_overState.itemId == _pressState.itemId) @@ -1652,7 +1653,7 @@ void ListWidget::mouseActionUpdate(const QPoint &globalPosition) { _mouseAction = MouseAction::Selecting; } } - HistoryStateRequest request; + StateRequest request; if (_mouseAction == MouseAction::Selecting) { request.flags |= Text::StateRequest::Flag::LookupSymbol; } else { @@ -1709,7 +1710,7 @@ style::cursor ListWidget::computeMouseCursor() const { if (ClickHandler::getPressed() || ClickHandler::getActive()) { return style::cur_pointer; } else if (!hasSelectedItems() - && (_mouseCursorState == HistoryInTextCursorState)) { + && (_mouseCursorState == CursorState::Text)) { return style::cur_text; } return style::cur_default; @@ -1814,14 +1815,14 @@ void ListWidget::mouseActionStart( } if (_mouseAction == MouseAction::None && pressLayout) { validateTrippleClickStartTime(); - HistoryTextState dragState; + TextState dragState; auto startDistance = (globalPosition - _trippleClickPoint).manhattanLength(); auto validStartPoint = startDistance < QApplication::startDragDistance(); if (_trippleClickStartTime != 0 && validStartPoint) { - HistoryStateRequest request; + StateRequest request; request.flags = Text::StateRequest::Flag::LookupSymbol; dragState = pressLayout->getState(_pressState.cursor, request); - if (dragState.cursor == HistoryInTextCursorState) { + if (dragState.cursor == CursorState::Text) { TextSelection selStatus = { dragState.symbol, dragState.symbol }; if (selStatus != FullSelection && !hasSelectedItems()) { clearSelected(); @@ -1834,7 +1835,7 @@ void ListWidget::mouseActionStart( } } } else { - HistoryStateRequest request; + StateRequest request; request.flags = Text::StateRequest::Flag::LookupSymbol; dragState = pressLayout->getState(_pressState.cursor, request); } @@ -1873,7 +1874,7 @@ void ListWidget::mouseActionStart( } void ListWidget::mouseActionCancel() { - _pressState = CursorState(); + _pressState = MouseState(); _mouseAction = MouseAction::None; clearDragSelection(); _wasSelectedText = false; @@ -1889,7 +1890,7 @@ void ListWidget::performDrag() { uponSelected = isItemUnderPressSelected(); } else if (auto pressLayout = getExistingLayout( _pressState.itemId)) { - HistoryStateRequest request; + StateRequest request; request.flags |= Text::StateRequest::Flag::LookupSymbol; auto dragState = pressLayout->getState( _pressState.cursor, @@ -1932,7 +1933,7 @@ void ListWidget::performDrag() { // auto pressedMedia = static_cast(nullptr); // if (auto pressedItem = _pressState.layout) { // pressedMedia = pressedItem->getMedia(); - // if (_mouseCursorState == HistoryInDateCursorState || (pressedMedia && pressedMedia->dragItem())) { + // if (_mouseCursorState == CursorState::Date || (pressedMedia && pressedMedia->dragItem())) { // Auth().data().setMimeForwardIds(Auth().data().itemOrItsGroup(pressedItem)); // forwardMimeType = qsl("application/x-td-forward"); // } diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.h b/Telegram/SourceFiles/info/media/info_media_list_widget.h index 9f1d7d1e9..2940e16fe 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.h +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.h @@ -10,10 +10,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/rp_widget.h" #include "info/media/info_media_widget.h" #include "data/data_shared_media.h" -#include "history/view/history_view_cursor_state.h" class DeleteMessagesBox; +namespace HistoryView { +struct TextState; +struct StateRequest; +enum class CursorState : char; +enum class PointState : char; +} // namespace HistoryView + namespace Ui { class PopupMenu; } // namespace Ui @@ -80,6 +86,11 @@ protected: void leaveEventHook(QEvent *e) override; private: + struct Context; + class Section; + using CursorState = HistoryView::CursorState; + using TextState = HistoryView::TextState; + using StateRequest = HistoryView::StateRequest; enum class MouseAction { None, PrepareDrag, @@ -94,8 +105,6 @@ private: std::unique_ptr item; bool stale = false; }; - struct Context; - class Section; struct FoundItem { not_null layout; QRect geometry; @@ -118,17 +127,17 @@ private: Selecting, Deselecting, }; - struct CursorState { + struct MouseState { UniversalMsgId itemId = 0; QSize size; QPoint cursor; bool inside = false; - inline bool operator==(const CursorState &other) const { + inline bool operator==(const MouseState &other) const { return (itemId == other.itemId) && (cursor == other.cursor); } - inline bool operator!=(const CursorState &other) const { + inline bool operator!=(const MouseState &other) const { return !(*this == other); } @@ -198,7 +207,7 @@ private: SelectedMap::const_iterator itemUnderPressSelection() const; bool isItemUnderPressSelected() const; bool requiredToStartDragging(not_null layout) const; - bool isPressInSelectedText(HistoryTextState state) const; + bool isPressInSelectedText(TextState state) const; void applyDragSelection(); void applyDragSelection(SelectedMap &applyTo) const; bool changeItemSelection( @@ -207,10 +216,10 @@ private: TextSelection selection) const; static bool IsAfter( - const CursorState &a, - const CursorState &b); - static bool SkipSelectFromItem(const CursorState &state); - static bool SkipSelectTillItem(const CursorState &state); + const MouseState &a, + const MouseState &b); + static bool SkipSelectFromItem(const MouseState &state); + static bool SkipSelectTillItem(const MouseState &state); void markLayoutsStale(); void clearStaleLayouts(); @@ -281,11 +290,11 @@ private: MouseAction _mouseAction = MouseAction::None; TextSelectType _mouseSelectType = TextSelectType::Letters; QPoint _mousePosition; - CursorState _overState; - CursorState _pressState; + MouseState _overState; + MouseState _pressState; BaseLayout *_overLayout = nullptr; UniversalMsgId _contextUniversalId = 0; - HistoryCursorState _mouseCursorState = HistoryDefaultCursorState; + CursorState _mouseCursorState = CursorState(); uint16 _mouseTextSymbol = 0; bool _pressWasInactive = false; SelectedMap _selected; diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp index 3b73bec0c..ee5fa45fb 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp @@ -28,6 +28,8 @@ namespace InlineBots { namespace Layout { namespace internal { +using TextState = HistoryView::TextState; + FileBase::FileBase(not_null 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, - HistoryStateRequest request) const { + StateRequest request) const { if (QRect(0, 0, _width, st::inlineMediaHeight).contains(point)) { if (_delete && rtlpoint(point, _width).x() >= _width - st::stickerPanDeleteIconBg.width() && point.y() < st::stickerPanDeleteIconBg.height()) { 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, - HistoryStateRequest request) const { + StateRequest request) const { if (QRect(0, 0, _width, st::inlineMediaHeight).contains(point)) { 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, - HistoryStateRequest request) const { + StateRequest request) const { if (QRect(0, 0, _width, st::inlineMediaHeight).contains(point)) { 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, - HistoryStateRequest request) const { + StateRequest request) const { if (QRect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize).contains(point)) { 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, - HistoryStateRequest request) const { + StateRequest request) const { if (QRect(0, st::inlineRowMargin, st::msgFileSize, st::msgFileSize).contains(point)) { return { nullptr, getShownDocument()->loading() ? _cancel : _open }; } else { @@ -938,9 +940,9 @@ void Contact::paint(Painter &p, const QRect &clip, const PaintContext *context) } } -HistoryTextState Contact::getState( +TextState Contact::getState( QPoint point, - HistoryStateRequest request) const { + StateRequest request) const { if (!QRect(0, st::inlineRowMargin, st::msgFileSize, st::inlineThumbSize).contains(point)) { auto left = (st::msgFileSize + st::inlineThumbSkip); 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, - HistoryStateRequest request) const { + StateRequest request) const { if (_withThumb && QRect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize).contains(point)) { 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, - HistoryStateRequest request) const { + StateRequest request) const { int left = st::inlineThumbSize + st::inlineThumbSkip; if (QRect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize).contains(point)) { return { nullptr, _send }; diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h index 0518b0039..b6f51e1a0 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h @@ -60,9 +60,9 @@ public: } void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; - HistoryTextState getState( + TextState getState( QPoint point, - HistoryStateRequest request) const override; + StateRequest request) const override; // ClickHandlerHost interface 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; - HistoryTextState getState( + TextState getState( QPoint point, - HistoryStateRequest request) const override; + StateRequest request) const override; private: PhotoData *getShownPhoto() const; @@ -153,9 +153,9 @@ public: void preload() const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; - HistoryTextState getState( + TextState getState( QPoint point, - HistoryStateRequest request) const override; + StateRequest request) const override; // ClickHandlerHost interface void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override; @@ -179,9 +179,9 @@ public: void initDimensions() override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; - HistoryTextState getState( + TextState getState( QPoint point, - HistoryStateRequest request) const override; + StateRequest request) const override; private: ClickHandlerPtr _link; @@ -228,9 +228,9 @@ public: void initDimensions() override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; - HistoryTextState getState( + TextState getState( QPoint point, - HistoryStateRequest request) const override; + StateRequest request) const override; // ClickHandlerHost interface void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override; @@ -292,9 +292,9 @@ public: void initDimensions() override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; - HistoryTextState getState( + TextState getState( QPoint point, - HistoryStateRequest request) const override; + StateRequest request) const override; private: mutable QPixmap _thumb; @@ -312,9 +312,9 @@ public: int resizeGetHeight(int width) override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; - HistoryTextState getState( + TextState getState( QPoint point, - HistoryStateRequest request) const override; + StateRequest request) const override; private: ClickHandlerPtr _url, _link; @@ -337,9 +337,9 @@ public: void initDimensions() override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; - HistoryTextState getState( + TextState getState( QPoint point, - HistoryStateRequest request) const override; + StateRequest request) const override; private: void countFrameSize(); diff --git a/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp b/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp index c0cabf0f0..ebe4ed9dd 100644 --- a/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp @@ -607,14 +607,14 @@ void Inner::updateSelected() { int row = -1, col = -1, sel = -1; ClickHandlerPtr lnk; ClickHandlerHost *lnkhost = nullptr; - HistoryCursorState cursor = HistoryDefaultCursorState; + HistoryView::CursorState cursor = HistoryView::CursorState::None; if (sy >= 0) { row = 0; for (int rows = _rows.size(); row < rows; ++row) { - if (sy < _rows.at(row).height) { + if (sy < _rows[row].height) { break; } - sy -= _rows.at(row).height; + sy -= _rows[row].height; } } if (sx >= 0 && row >= 0 && row < _rows.size()) { @@ -632,7 +632,9 @@ void Inner::updateSelected() { } if (col < inlineItems.size()) { 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; cursor = result.cursor; lnkhost = inlineItems[col]; diff --git a/Telegram/SourceFiles/layout.cpp b/Telegram/SourceFiles/layout.cpp index f69e952f2..5685356e7 100644 --- a/Telegram/SourceFiles/layout.cpp +++ b/Telegram/SourceFiles/layout.cpp @@ -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); } -[[nodiscard]] HistoryTextState LayoutItemBase::getState( +[[nodiscard]] HistoryView::TextState LayoutItemBase::getState( QPoint point, - HistoryStateRequest request) const { + StateRequest request) const { return {}; } diff --git a/Telegram/SourceFiles/layout.h b/Telegram/SourceFiles/layout.h index 82cba4f3e..738f9b8a5 100644 --- a/Telegram/SourceFiles/layout.h +++ b/Telegram/SourceFiles/layout.h @@ -9,8 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/runtime_composer.h" -struct HistoryTextState; -struct HistoryStateRequest; +namespace HistoryView { +struct TextState; +struct StateRequest; +} // namespace HistoryView constexpr auto FullSelection = TextSelection { 0xFFFF, 0xFFFF }; @@ -82,6 +84,9 @@ class LayoutItemBase : public RuntimeComposer , public ClickHandlerHost { public: + using TextState = HistoryView::TextState; + using StateRequest = HistoryView::StateRequest; + LayoutItemBase() { } @@ -101,9 +106,9 @@ public: return _height; } - [[nodiscard]] virtual HistoryTextState getState( + [[nodiscard]] virtual TextState getState( QPoint point, - HistoryStateRequest request) const; + StateRequest request) const; [[nodiscard]] virtual TextSelection adjustSelection( TextSelection selection, TextSelectType type) const; diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp index d6e1635e7..af634ca8b 100644 --- a/Telegram/SourceFiles/overview/overview_layout.cpp +++ b/Telegram/SourceFiles/overview/overview_layout.cpp @@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "storage/localstorage.h" #include "history/history_item.h" #include "history/history_item_components.h" +#include "history/view/history_view_cursor_state.h" #include "ui/effects/round_checkbox.h" #include "ui/text_options.h" @@ -33,6 +34,8 @@ namespace Overview { namespace Layout { namespace { +using TextState = HistoryView::TextState; + TextParseOptions _documentNameOptions = { TextParseMultiline | TextParseRichText | TextParseLinks | TextParseMarkdown, // flags 0, // maxw @@ -350,9 +353,9 @@ void Photo::paint(Painter &p, const QRect &clip, TextSelection selection, const paintCheckbox(p, { checkLeft, checkTop }, selected, context); } -HistoryTextState Photo::getState( +TextState Photo::getState( QPoint point, - HistoryStateRequest request) const { + StateRequest request) const { if (hasPoint(point)) { return { parent(), _link }; } @@ -505,9 +508,9 @@ bool Video::iconAnimated() const { return true; } -HistoryTextState Video::getState( +TextState Video::getState( QPoint point, - HistoryStateRequest request) const { + StateRequest request) const { bool loaded = _data->loaded(); if (hasPoint(point)) { @@ -676,9 +679,9 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const paintCheckbox(p, { checkLeft, checkTop }, selected, context); } -HistoryTextState Voice::getState( +TextState Voice::getState( QPoint point, - HistoryStateRequest request) const { + StateRequest request) const { const auto loaded = _data->loaded(); const auto nameleft = _st.songPadding.left() @@ -702,7 +705,7 @@ HistoryTextState Voice::getState( : _openl; return { parent(), link }; } - auto result = HistoryTextState(parent()); + auto result = TextState(parent()); const auto statusmaxwidth = _width - nameleft - nameright; const auto statusrect = rtlrect( nameleft, @@ -714,7 +717,9 @@ HistoryTextState Voice::getState( if (_status.size() == FileStatusSizeLoaded || _status.size() == FileStatusSizeReady) { auto textState = _details.getStateLeft(point - QPoint(nameleft, statustop), _width, _width); 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( @@ -1000,9 +1005,9 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con paintCheckbox(p, { checkLeft, checkTop }, selected, context); } -HistoryTextState Document::getState( +TextState Document::getState( QPoint point, - HistoryStateRequest request) const { + StateRequest request) const { const auto loaded = _data->loaded() || Local::willStickerImageLoad(_data->mediaKey()); 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); } -HistoryTextState Link::getState( +TextState Link::getState( QPoint point, - HistoryStateRequest request) const { + StateRequest request) const { 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)) { return { parent(), _photol }; diff --git a/Telegram/SourceFiles/overview/overview_layout.h b/Telegram/SourceFiles/overview/overview_layout.h index 563148423..7fe98e701 100644 --- a/Telegram/SourceFiles/overview/overview_layout.h +++ b/Telegram/SourceFiles/overview/overview_layout.h @@ -12,8 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/effects/radial_animation.h" #include "styles/style_overview.h" -struct HistoryTextState; -struct HistoryStateRequest; class HistoryMedia; namespace style { @@ -202,9 +200,9 @@ public: void initDimensions() override; int32 resizeGetHeight(int32 width) override; void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override; - HistoryTextState getState( + TextState getState( QPoint point, - HistoryStateRequest request) const override; + StateRequest request) const override; private: not_null _data; @@ -224,9 +222,9 @@ public: void initDimensions() override; int32 resizeGetHeight(int32 width) override; void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override; - HistoryTextState getState( + TextState getState( QPoint point, - HistoryStateRequest request) const override; + StateRequest request) const override; protected: float64 dataProgress() const override; @@ -255,9 +253,9 @@ public: void initDimensions() override; void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override; - HistoryTextState getState( + TextState getState( QPoint point, - HistoryStateRequest request) const override; + StateRequest request) const override; protected: float64 dataProgress() const override; @@ -290,9 +288,9 @@ public: void initDimensions() override; void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override; - HistoryTextState getState( + TextState getState( QPoint point, - HistoryStateRequest request) const override; + StateRequest request) const override; virtual DocumentData *getDocument() const override { return _data; @@ -334,9 +332,9 @@ public: void initDimensions() override; int32 resizeGetHeight(int32 width) override; void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override; - HistoryTextState getState( + TextState getState( QPoint point, - HistoryStateRequest request) const override; + StateRequest request) const override; protected: const style::RoundCheckbox &checkboxStyle() const override;