mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 02:01:40 -05:00
Fix / improve support for album items selection.
This commit is contained in:
parent
722264f634
commit
2fdc3169ce
34 changed files with 983 additions and 598 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<HistoryMessageForwarded>()) {
|
||||
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<HistoryMedia*>(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(
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<const Element*> view) {
|
||||
repaintItem(view);
|
||||
}, lifetime());
|
||||
Auth().data().viewLayoutChanged(
|
||||
) | rpl::filter([](not_null<const Element*> view) {
|
||||
return (view == view->data()->mainView()) && view->isUnderCursor();
|
||||
}) | rpl::start_with_next([this](not_null<const Element*> view) {
|
||||
mouseActionUpdate();
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void HistoryInner::messagesReceived(PeerData *peer, const QVector<MTPMessage> &messages) {
|
||||
|
@ -423,6 +429,10 @@ void HistoryInner::enumerateDates(Method method) {
|
|||
TextSelection HistoryInner::computeRenderSelection(
|
||||
not_null<const SelectedItems*> selected,
|
||||
not_null<Element*> view) const {
|
||||
if (view->isHiddenByGroup()) {
|
||||
return TextSelection();
|
||||
}
|
||||
const auto item = view->data();
|
||||
const auto itemSelection = [&](not_null<HistoryItem*> 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<HistoryView::Group>()) {
|
||||
// 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<HistorySticker*>(App::pressedItem()->media()) || _mouseCursorState == HistoryInDateCursorState) {
|
||||
if (dynamic_cast<HistorySticker*>(App::pressedItem()->media())
|
||||
|| _mouseCursorState == CursorState::Date) {
|
||||
_mouseAction = MouseAction::PrepareDrag; // start sticker drag or by-date drag
|
||||
} 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<HistoryMedia*>(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<const HistoryItem*> 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<HistoryMessage*>(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<DateClickHandler*>(_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<HistoryMessageForwarded>()) {
|
||||
return forwarded->text.originalText(AllTextSelection, ExpandLinksNone);
|
||||
|
|
|
@ -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<HistoryItem*, TextSelection, std::less<>>;
|
||||
|
@ -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 <typename Method>
|
||||
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<HistoryItem*> 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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.");
|
||||
}
|
||||
|
|
|
@ -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<SharedMediaType>;
|
||||
} // 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<Element*> 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<HistoryItem*> 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<QPixmap*> 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<HistoryMedia> 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<HistoryItem*> item) const;
|
||||
|
||||
|
|
|
@ -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<HistoryItem*> 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);
|
||||
|
|
|
@ -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<HistoryMedia*> main() const;
|
||||
bool validateGroupParts(
|
||||
const std::vector<not_null<HistoryItem*>> &items) const;
|
||||
HistoryTextState getPartState(
|
||||
TextState getPartState(
|
||||
QPoint point,
|
||||
HistoryStateRequest request) const;
|
||||
StateRequest request) const;
|
||||
|
||||
Text _caption;
|
||||
std::vector<Part> _parts;
|
||||
|
|
|
@ -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<HistoryDocumentCaptioned>()) {
|
||||
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);
|
||||
|
|
|
@ -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<uint64*> cacheKey,
|
||||
not_null<QPixmap*> 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<uint64*> cacheKey,
|
||||
not_null<QPixmap*> 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<HistoryItem*> 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<HistoryItem*> 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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<const HistoryItem*> item)
|
||||
namespace HistoryView {
|
||||
|
||||
TextState::TextState(not_null<const HistoryItem*> item)
|
||||
: itemId(item->fullId()) {
|
||||
}
|
||||
|
||||
HistoryTextState::HistoryTextState(
|
||||
TextState::TextState(
|
||||
not_null<const HistoryItem*> 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<const HistoryItem*> item,
|
||||
ClickHandlerPtr link)
|
||||
: itemId(item->fullId())
|
||||
, link(link) {
|
||||
}
|
||||
|
||||
|
||||
HistoryTextState::HistoryTextState(
|
||||
TextState::TextState(
|
||||
not_null<const HistoryView::Element*> view)
|
||||
: HistoryTextState(view->data()) {
|
||||
: TextState(view->data()) {
|
||||
}
|
||||
|
||||
HistoryTextState::HistoryTextState(
|
||||
TextState::TextState(
|
||||
not_null<const HistoryView::Element*> view,
|
||||
const Text::StateResult &state)
|
||||
: HistoryTextState(view->data(), state) {
|
||||
: TextState(view->data(), state) {
|
||||
}
|
||||
|
||||
HistoryTextState::HistoryTextState(
|
||||
TextState::TextState(
|
||||
not_null<const HistoryView::Element*> 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
|
||||
|
|
|
@ -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<const HistoryItem*> item);
|
||||
HistoryTextState(
|
||||
struct TextState {
|
||||
TextState() = default;
|
||||
TextState(not_null<const HistoryItem*> item);
|
||||
TextState(
|
||||
not_null<const HistoryItem*> item,
|
||||
const Text::StateResult &state);
|
||||
HistoryTextState(
|
||||
TextState(
|
||||
not_null<const HistoryItem*> item,
|
||||
ClickHandlerPtr link);
|
||||
HistoryTextState(not_null<const HistoryView::Element*> view);
|
||||
HistoryTextState(
|
||||
TextState(not_null<const HistoryView::Element*> view);
|
||||
TextState(
|
||||
not_null<const HistoryView::Element*> view,
|
||||
const Text::StateResult &state);
|
||||
HistoryTextState(
|
||||
TextState(
|
||||
not_null<const HistoryView::Element*> 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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 <ListWidget::EnumItemsDirection direction, typename Method>
|
||||
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<HistoryItem*> item) const {
|
||||
if (const auto group = Auth().data().groups().find(item)) {
|
||||
for (const auto other : group->items) {
|
||||
if (!applyTo.contains(other->fullId())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return applyTo.contains(item->fullId());
|
||||
}
|
||||
|
||||
bool ListWidget::isGoodForSelection(
|
||||
SelectedMap &applyTo,
|
||||
not_null<HistoryItem*> item,
|
||||
int &totalCount) const {
|
||||
if (!IsServerMsgId(item->id) || item->serviceMsg()) {
|
||||
return false;
|
||||
} else if (!applyTo.contains(item->fullId())) {
|
||||
++totalCount;
|
||||
}
|
||||
return (totalCount <= MaxSelectedItems);
|
||||
}
|
||||
|
||||
bool ListWidget::addToSelection(
|
||||
SelectedMap &applyTo,
|
||||
not_null<HistoryItem*> item) const {
|
||||
const auto itemId = item->fullId();
|
||||
auto [iterator, ok] = applyTo.try_emplace(
|
||||
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<HistoryItem*> item,
|
||||
SelectAction action) const {
|
||||
const auto itemId = item->fullId();
|
||||
if (action == SelectAction::Invert) {
|
||||
action = applyTo.contains(itemId)
|
||||
? SelectAction::Deselect
|
||||
: SelectAction::Select;
|
||||
}
|
||||
if (action == SelectAction::Select) {
|
||||
auto already = int(applyTo.size());
|
||||
if (isGoodForSelection(applyTo, item, already)) {
|
||||
addToSelection(applyTo, item);
|
||||
}
|
||||
} else {
|
||||
removeItemSelection(it);
|
||||
removeFromSelection(applyTo, itemId);
|
||||
}
|
||||
}
|
||||
|
||||
void ListWidget::changeSelectionAsGroup(
|
||||
SelectedMap &applyTo,
|
||||
not_null<HistoryItem*> item,
|
||||
SelectAction action) const {
|
||||
const auto group = Auth().data().groups().find(item);
|
||||
if (!group) {
|
||||
return changeSelection(applyTo, item, action);
|
||||
}
|
||||
if (action == SelectAction::Invert) {
|
||||
action = isSelectedAsGroup(applyTo, item)
|
||||
? SelectAction::Deselect
|
||||
: SelectAction::Select;
|
||||
}
|
||||
auto already = int(applyTo.size());
|
||||
const auto canSelect = [&] {
|
||||
for (const auto other : group->items) {
|
||||
if (!isGoodForSelection(applyTo, other, already)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}();
|
||||
if (action == SelectAction::Select && canSelect) {
|
||||
for (const auto other : group->items) {
|
||||
addToSelection(applyTo, other);
|
||||
}
|
||||
} else {
|
||||
for (const auto other : group->items) {
|
||||
removeFromSelection(applyTo, other->fullId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -543,21 +669,23 @@ bool ListWidget::isItemUnderPressSelected() const {
|
|||
}
|
||||
|
||||
auto ListWidget::itemUnderPressSelection() -> SelectedMap::iterator {
|
||||
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<Element*> 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<HistoryMessageForwarded>()) {
|
||||
return forwarded->text.originalText(
|
||||
AllTextSelection,
|
||||
|
@ -730,7 +858,7 @@ std::unique_ptr<Element> ListWidget::elementCreate(
|
|||
|
||||
bool ListWidget::elementUnderCursor(
|
||||
not_null<const HistoryView::Element*> 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<HistoryItem*> item, bool add) {
|
||||
const auto itemId = item->fullId();
|
||||
if (add) {
|
||||
_dragSelected.emplace(itemId);
|
||||
} else {
|
||||
_dragSelected.remove(itemId);
|
||||
}
|
||||
};
|
||||
const auto changeGroup = [&](not_null<HistoryItem*> item, bool add) {
|
||||
if (const auto group = groups.find(item)) {
|
||||
for (const auto item : group->items) {
|
||||
changeItem(item, add);
|
||||
}
|
||||
} else {
|
||||
changeItem(item, add);
|
||||
}
|
||||
};
|
||||
const auto changeView = [&](not_null<Element*> view, bool add) {
|
||||
if (!view->isHiddenByGroup()) {
|
||||
changeGroup(view->data(), add);
|
||||
}
|
||||
};
|
||||
for (auto i = begin(_items); i != from; ++i) {
|
||||
_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<HistoryMedia*>(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<const Element*> view) {
|
|||
void ListWidget::viewReplaced(not_null<const Element*> 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<const HistoryItem*> item) {
|
||||
if (_selectedTextItem == item) {
|
||||
clearTextSelection();
|
||||
}
|
||||
if (_overItemExact == item) {
|
||||
_overItemExact = nullptr;
|
||||
}
|
||||
const auto i = _views.find(item);
|
||||
if (i == end(_views)) {
|
||||
return;
|
||||
|
|
|
@ -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<Element*> 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<HistoryItem*> item,
|
||||
int &totalCount) const;
|
||||
bool addToSelection(
|
||||
SelectedMap &applyTo,
|
||||
not_null<HistoryItem*> item) const;
|
||||
bool removeFromSelection(
|
||||
SelectedMap &applyTo,
|
||||
FullMsgId itemId) const;
|
||||
void changeSelection(
|
||||
SelectedMap &applyTo,
|
||||
not_null<HistoryItem*> item,
|
||||
SelectAction action) const;
|
||||
bool isSelectedAsGroup(
|
||||
const SelectedMap &applyTo,
|
||||
not_null<HistoryItem*> item) const;
|
||||
void changeSelectionAsGroup(
|
||||
SelectedMap &applyTo,
|
||||
not_null<HistoryItem*> item,
|
||||
SelectAction action) const;
|
||||
|
||||
SelectedMap::iterator itemUnderPressSelection();
|
||||
SelectedMap::const_iterator itemUnderPressSelection() const;
|
||||
bool isItemUnderPressSelected() const;
|
||||
bool requiredToStartDragging(not_null<Element*> 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;
|
||||
|
||||
|
|
|
@ -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<HistoryTextState*> outResult) const {
|
||||
not_null<TextState*> 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<HistoryTextState*> outResult,
|
||||
HistoryStateRequest request) const {
|
||||
not_null<TextState*> outResult,
|
||||
StateRequest request) const {
|
||||
if (displayForwardedFrom()) {
|
||||
const auto item = message();
|
||||
auto forwarded = item->Get<HistoryMessageForwarded>();
|
||||
|
@ -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<HistoryTextState*> outResult) const {
|
||||
not_null<TextState*> outResult) const {
|
||||
const auto item = message();
|
||||
if (auto reply = item->Get<HistoryMessageReply>()) {
|
||||
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<HistoryTextState*> outResult) const {
|
||||
not_null<TextState*> outResult) const {
|
||||
const auto item = message();
|
||||
if (!displayFromName() && !item->Has<HistoryMessageForwarded>()) {
|
||||
if (auto via = item->Get<HistoryMessageVia>()) {
|
||||
|
@ -896,14 +915,14 @@ bool Message::getStateViaBotIdInfo(
|
|||
bool Message::getStateText(
|
||||
QPoint point,
|
||||
QRect &trect,
|
||||
not_null<HistoryTextState*> outResult,
|
||||
HistoryStateRequest request) const {
|
||||
not_null<TextState*> 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) {
|
||||
|
|
|
@ -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<HistoryTextState*> outResult) const;
|
||||
not_null<TextState*> outResult) const;
|
||||
bool getStateForwardedInfo(
|
||||
QPoint point,
|
||||
QRect &trect,
|
||||
not_null<HistoryTextState*> outResult,
|
||||
HistoryStateRequest request) const;
|
||||
not_null<TextState*> outResult,
|
||||
StateRequest request) const;
|
||||
bool getStateReplyInfo(
|
||||
QPoint point,
|
||||
QRect &trect,
|
||||
not_null<HistoryTextState*> outResult) const;
|
||||
not_null<TextState*> outResult) const;
|
||||
bool getStateViaBotIdInfo(
|
||||
QPoint point,
|
||||
QRect &trect,
|
||||
not_null<HistoryTextState*> outResult) const;
|
||||
not_null<TextState*> outResult) const;
|
||||
bool getStateText(
|
||||
QPoint point,
|
||||
QRect &trect,
|
||||
not_null<HistoryTextState*> outResult,
|
||||
HistoryStateRequest request) const;
|
||||
not_null<TextState*> outResult,
|
||||
StateRequest request) const;
|
||||
|
||||
void updateMediaInBubbleState();
|
||||
QRect countGeometry() const;
|
||||
|
|
|
@ -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<HistoryServiceGameScore>()) {
|
||||
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<HistoryServicePayment>()) {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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<BaseLayout*> layout) const {
|
||||
if (_mouseCursorState == HistoryInDateCursorState) {
|
||||
if (_mouseCursorState == CursorState::Date) {
|
||||
return true;
|
||||
}
|
||||
// return dynamic_cast<HistorySticker*>(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<HistoryMedia*>(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");
|
||||
// }
|
||||
|
|
|
@ -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<BaseLayout> item;
|
||||
bool stale = false;
|
||||
};
|
||||
struct Context;
|
||||
class Section;
|
||||
struct FoundItem {
|
||||
not_null<BaseLayout*> 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<BaseLayout*> 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;
|
||||
|
|
|
@ -28,6 +28,8 @@ namespace InlineBots {
|
|||
namespace Layout {
|
||||
namespace internal {
|
||||
|
||||
using TextState = HistoryView::TextState;
|
||||
|
||||
FileBase::FileBase(not_null<Context*> context, Result *result) : ItemBase(context, result) {
|
||||
}
|
||||
|
||||
|
@ -208,9 +210,9 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons
|
|||
}
|
||||
}
|
||||
|
||||
HistoryTextState Gif::getState(
|
||||
TextState Gif::getState(
|
||||
QPoint point,
|
||||
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 };
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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 {};
|
||||
}
|
||||
|
||||
|
|
|
@ -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<LayoutItemBase>
|
||||
, 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;
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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<PhotoData*> _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;
|
||||
|
|
Loading…
Add table
Reference in a new issue