Shared media multiple items selection.

This commit is contained in:
John Preston 2017-10-13 22:07:04 +03:00
parent 66146c382d
commit 54cc3e6315
23 changed files with 1117 additions and 579 deletions

View File

@ -64,12 +64,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#error Please add support for your architecture in base/build_config.h #error Please add support for your architecture in base/build_config.h
#endif #endif
#if defined(COMPILER_GCC) || defined(COMPILER_CLANG)
#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#else
#define WARN_UNUSED_RESULT
#endif
#if defined(__GNUC__) #if defined(__GNUC__)
#define FORCE_INLINE inline __attribute__((always_inline)) #define FORCE_INLINE inline __attribute__((always_inline))
#elif defined(_MSC_VER) #elif defined(_MSC_VER)

View File

@ -109,7 +109,18 @@ public:
flat_multi_map_iterator_base_impl operator-(difference_type offset) const { flat_multi_map_iterator_base_impl operator-(difference_type offset) const {
return _impl - offset; return _impl - offset;
} }
difference_type operator-(const flat_multi_map_iterator_base_impl &right) const { template <
typename other_iterator_impl,
typename other_pointer_impl,
typename other_reference_impl>
difference_type operator-(
const flat_multi_map_iterator_base_impl<
Key,
Type,
Compare,
other_iterator_impl,
other_pointer_impl,
other_reference_impl> &right) const {
return _impl - right._impl; return _impl - right._impl;
} }
reference operator[](difference_type offset) { reference operator[](difference_type offset) {
@ -119,13 +130,46 @@ public:
return _impl[offset]; return _impl[offset];
} }
bool operator==(const flat_multi_map_iterator_base_impl &right) const { template <
typename other_iterator_impl,
typename other_pointer_impl,
typename other_reference_impl>
bool operator==(
const flat_multi_map_iterator_base_impl<
Key,
Type,
Compare,
other_iterator_impl,
other_pointer_impl,
other_reference_impl> &right) const {
return _impl == right._impl; return _impl == right._impl;
} }
bool operator!=(const flat_multi_map_iterator_base_impl &right) const { template <
typename other_iterator_impl,
typename other_pointer_impl,
typename other_reference_impl>
bool operator!=(
const flat_multi_map_iterator_base_impl<
Key,
Type,
Compare,
other_iterator_impl,
other_pointer_impl,
other_reference_impl> &right) const {
return _impl != right._impl; return _impl != right._impl;
} }
bool operator<(const flat_multi_map_iterator_base_impl &right) const { template <
typename other_iterator_impl,
typename other_pointer_impl,
typename other_reference_impl>
bool operator<(
const flat_multi_map_iterator_base_impl<
Key,
Type,
Compare,
other_iterator_impl,
other_pointer_impl,
other_reference_impl> &right) const {
return _impl < right._impl; return _impl < right._impl;
} }
@ -133,6 +177,15 @@ private:
iterator_impl _impl; iterator_impl _impl;
friend class flat_multi_map<Key, Type, Compare>; friend class flat_multi_map<Key, Type, Compare>;
template <
typename OtherKey,
typename OtherType,
typename OtherCompare,
typename other_iterator_impl,
typename other_pointer_impl,
typename other_reference_impl>
friend class flat_multi_map_iterator_base_impl;
}; };
template <typename Key, typename Type, typename Compare> template <typename Key, typename Type, typename Compare>
@ -418,10 +471,10 @@ public:
return (range.second - range.first); return (range.second - range.first);
} }
iterator erase(iterator where) { iterator erase(const_iterator where) {
return _impl.erase(where._impl); return _impl.erase(where._impl);
} }
iterator erase(iterator from, iterator till) { iterator erase(const_iterator from, const_iterator till) {
return _impl.erase(from._impl, till._impl); return _impl.erase(from._impl, till._impl);
} }
@ -525,37 +578,69 @@ public:
using parent::erase; using parent::erase;
using parent::contains; using parent::contains;
iterator insert(const value_type &value) { std::pair<iterator, bool> insert(const value_type &value) {
if (this->empty() || compare()(value.first, this->front().first)) { if (this->empty() || compare()(value.first, this->front().first)) {
this->_impl.push_front(value); this->_impl.push_front(value);
return this->begin(); return { this->begin(), true };
} else if (compare()(this->back().first, value.first)) { } else if (compare()(this->back().first, value.first)) {
this->_impl.push_back(value); this->_impl.push_back(value);
return (this->end() - 1); return { this->end() - 1, true };
} }
auto where = this->getLowerBound(value.first); auto where = this->getLowerBound(value.first);
if (compare()(value.first, where->first)) { if (compare()(value.first, where->first)) {
return this->_impl.insert(where, value); return { this->_impl.insert(where, value), true };
} }
return this->end(); return { where, false };
} }
iterator insert(value_type &&value) { std::pair<iterator, bool> insert(value_type &&value) {
if (this->empty() || compare()(value.first, this->front().first)) { if (this->empty() || compare()(value.first, this->front().first)) {
this->_impl.push_front(std::move(value)); this->_impl.push_front(std::move(value));
return this->begin(); return { this->begin(), true };
} else if (compare()(this->back().first, value.first)) { } else if (compare()(this->back().first, value.first)) {
this->_impl.push_back(std::move(value)); this->_impl.push_back(std::move(value));
return (this->end() - 1); return { this->end() - 1, true };
} }
auto where = this->getLowerBound(value.first); auto where = this->getLowerBound(value.first);
if (compare()(value.first, where->first)) { if (compare()(value.first, where->first)) {
return this->_impl.insert(where, std::move(value)); return { this->_impl.insert(where, std::move(value)), true };
} }
return this->end(); return { where, false };
} }
template <typename... Args> template <typename... Args>
iterator emplace(Args&&... args) { std::pair<iterator, bool> emplace(
return this->insert(value_type(std::forward<Args>(args)...)); const Key &key,
Args&&... args) {
return this->insert(value_type(
key,
Type(std::forward<Args>(args)...)));
}
template <typename... Args>
std::pair<iterator, bool> try_emplace(
const Key &key,
Args&&... args) {
if (this->empty() || compare()(key, this->front().first)) {
this->_impl.push_front(value_type(
key,
Type(std::forward<Args>(args)...)));
return { this->begin(), true };
} else if (compare()(this->back().first, key)) {
this->_impl.push_back(value_type(
key,
Type(std::forward<Args>(args)...)));
return { this->end() - 1, true };
}
auto where = this->getLowerBound(key);
if (compare()(key, where->first)) {
return {
this->_impl.insert(
where,
value_type(
key,
Type(std::forward<Args>(args)...))),
true
};
}
return { where, false };
} }
bool remove(const Key &key) { bool remove(const Key &key) {

View File

@ -47,6 +47,13 @@ public:
flat_multi_set_iterator_base_impl(iterator_impl impl = iterator_impl()) flat_multi_set_iterator_base_impl(iterator_impl impl = iterator_impl())
: _impl(impl) { : _impl(impl) {
} }
template <typename other_iterator_impl>
flat_multi_set_iterator_base_impl(
const flat_multi_set_iterator_base_impl<
Type,
Compare,
other_iterator_impl> &other) : _impl(other._impl) {
}
reference operator*() const { reference operator*() const {
return *_impl; return *_impl;
@ -82,20 +89,40 @@ public:
flat_multi_set_iterator_base_impl operator-(difference_type offset) const { flat_multi_set_iterator_base_impl operator-(difference_type offset) const {
return _impl - offset; return _impl - offset;
} }
difference_type operator-(const flat_multi_set_iterator_base_impl &right) const { template <typename other_iterator_impl>
difference_type operator-(
const flat_multi_set_iterator_base_impl<
Type,
Compare,
other_iterator_impl> &right) const {
return _impl - right._impl; return _impl - right._impl;
} }
reference operator[](difference_type offset) const { reference operator[](difference_type offset) const {
return _impl[offset]; return _impl[offset];
} }
bool operator==(const flat_multi_set_iterator_base_impl &right) const { template <typename other_iterator_impl>
bool operator==(
const flat_multi_set_iterator_base_impl<
Type,
Compare,
other_iterator_impl> &right) const {
return _impl == right._impl; return _impl == right._impl;
} }
bool operator!=(const flat_multi_set_iterator_base_impl &right) const { template <typename other_iterator_impl>
bool operator!=(
const flat_multi_set_iterator_base_impl<
Type,
Compare,
other_iterator_impl> &right) const {
return _impl != right._impl; return _impl != right._impl;
} }
bool operator<(const flat_multi_set_iterator_base_impl &right) const { template <typename other_iterator_impl>
bool operator<(
const flat_multi_set_iterator_base_impl<
Type,
Compare,
other_iterator_impl> &right) const {
return _impl < right._impl; return _impl < right._impl;
} }
@ -104,6 +131,12 @@ private:
friend class flat_multi_set<Type, Compare>; friend class flat_multi_set<Type, Compare>;
friend class flat_set<Type, Compare>; friend class flat_set<Type, Compare>;
template <
typename OtherType,
typename OtherCompare,
typename other_iterator_impl>
friend class flat_multi_set_iterator_base_impl;
Type &wrapped() { Type &wrapped() {
return _impl->wrapped(); return _impl->wrapped();
} }
@ -205,43 +238,24 @@ public:
using pointer = const Type*; using pointer = const Type*;
using reference = const Type&; using reference = const Type&;
class const_iterator;
class iterator : public iterator_base { class iterator : public iterator_base {
public: public:
using iterator_base::iterator_base; using iterator_base::iterator_base;
iterator(const iterator_base &other) : iterator_base(other) {
}
friend class const_iterator;
}; };
class const_iterator : public const_iterator_base { class const_iterator : public const_iterator_base {
public: public:
using const_iterator_base::const_iterator_base; using const_iterator_base::const_iterator_base;
const_iterator(const_iterator_base other) : const_iterator_base(other) {
}
const_iterator(const iterator &other) : const_iterator_base(other._impl) {
}
}; };
class const_reverse_iterator;
class reverse_iterator : public reverse_iterator_base { class reverse_iterator : public reverse_iterator_base {
public: public:
using reverse_iterator_base::reverse_iterator_base; using reverse_iterator_base::reverse_iterator_base;
reverse_iterator(reverse_iterator_base other)
: reverse_iterator_base(other) {
}
friend class const_reverse_iterator;
}; };
class const_reverse_iterator : public const_reverse_iterator_base { class const_reverse_iterator : public const_reverse_iterator_base {
public: public:
using const_reverse_iterator_base::const_reverse_iterator_base; using const_reverse_iterator_base::const_reverse_iterator_base;
const_reverse_iterator(const_reverse_iterator_base other)
: const_reverse_iterator_base(other) {
}
const_reverse_iterator(const reverse_iterator &other)
: const_reverse_iterator_base(other._impl) {
}
}; };
@ -366,10 +380,10 @@ public:
return (range.second - range.first); return (range.second - range.first);
} }
iterator erase(iterator where) { iterator erase(const_iterator where) {
return _impl.erase(where._impl); return _impl.erase(where._impl);
} }
iterator erase(iterator from, iterator till) { iterator erase(const_iterator from, const_iterator till) {
return _impl.erase(from._impl, till._impl); return _impl.erase(from._impl, till._impl);
} }

View File

@ -894,7 +894,9 @@ void GifsListWidget::updateSelected() {
} }
if (col < inlineItems.size()) { if (col < inlineItems.size()) {
sel = row * MatrixRowShift + col; sel = row * MatrixRowShift + col;
inlineItems.at(col)->getState(lnk, cursor, QPoint(sx, sy)); auto result = inlineItems[col]->getState(QPoint(sx, sy), HistoryStateRequest());
lnk = result.link;
cursor = result.cursor;
lnkhost = inlineItems.at(col); lnkhost = inlineItems.at(col);
} else { } else {
row = col = -1; row = col = -1;

View File

@ -1033,10 +1033,11 @@ void HistoryInner::itemRemoved(not_null<const HistoryItem*> item) {
void HistoryInner::mouseActionFinish(const QPoint &screenPos, Qt::MouseButton button) { void HistoryInner::mouseActionFinish(const QPoint &screenPos, Qt::MouseButton button) {
mouseActionUpdate(screenPos); mouseActionUpdate(screenPos);
ClickHandlerPtr activated = ClickHandler::unpressed(); auto pressedLinkItem = App::pressedLinkItem();
auto activated = ClickHandler::unpressed();
if (_mouseAction == MouseAction::Dragging) { if (_mouseAction == MouseAction::Dragging) {
activated.clear(); activated.clear();
} else if (auto pressed = App::pressedLinkItem()) { } else if (auto pressed = pressedLinkItem) {
// if we are in selecting items mode perhaps we want to // if we are in selecting items mode perhaps we want to
// toggle selection instead of activating the pressed link // toggle selection instead of activating the pressed link
if (_mouseAction == MouseAction::PrepareDrag && !_pressWasInactive && !_selected.empty() && _selected.cbegin()->second == FullSelection && button != Qt::RightButton) { if (_mouseAction == MouseAction::PrepareDrag && !_pressWasInactive && !_selected.empty() && _selected.cbegin()->second == FullSelection && button != Qt::RightButton) {
@ -2249,8 +2250,10 @@ void HistoryInner::onUpdateSelected() {
} }
} }
void HistoryInner::updateDragSelection(HistoryItem *dragSelFrom, HistoryItem *dragSelTo, bool dragSelecting, bool force) { void HistoryInner::updateDragSelection(HistoryItem *dragSelFrom, HistoryItem *dragSelTo, bool dragSelecting) {
if (_dragSelFrom != dragSelFrom || _dragSelTo != dragSelTo || _dragSelecting != dragSelecting) { if (_dragSelFrom == dragSelFrom && _dragSelTo == dragSelTo && _dragSelecting == dragSelecting) {
return;
}
_dragSelFrom = dragSelFrom; _dragSelFrom = dragSelFrom;
_dragSelTo = dragSelTo; _dragSelTo = dragSelTo;
int32 fromy = itemTop(_dragSelFrom), toy = itemTop(_dragSelTo); int32 fromy = itemTop(_dragSelFrom), toy = itemTop(_dragSelTo);
@ -2262,10 +2265,6 @@ void HistoryInner::updateDragSelection(HistoryItem *dragSelFrom, HistoryItem *dr
_wasSelectedText = true; _wasSelectedText = true;
setFocus(); setFocus();
} }
force = true;
}
if (!force) return;
update(); update();
} }

View File

@ -164,7 +164,7 @@ private:
void adjustCurrent(int32 y, History *history) const; void adjustCurrent(int32 y, History *history) const;
HistoryItem *prevItem(HistoryItem *item); HistoryItem *prevItem(HistoryItem *item);
HistoryItem *nextItem(HistoryItem *item); HistoryItem *nextItem(HistoryItem *item);
void updateDragSelection(HistoryItem *dragSelFrom, HistoryItem *dragSelTo, bool dragSelecting, bool force = false); void updateDragSelection(HistoryItem *dragSelFrom, HistoryItem *dragSelTo, bool dragSelecting);
void setToClipboard(const TextWithEntities &forClipboard, QClipboard::Mode mode = QClipboard::Clipboard); void setToClipboard(const TextWithEntities &forClipboard, QClipboard::Mode mode = QClipboard::Clipboard);

View File

@ -91,6 +91,8 @@ struct HistoryTextState {
symbol = state.symbol; symbol = state.symbol;
return *this; return *this;
} }
HistoryTextState(ClickHandlerPtr link) : link(link) {
}
HistoryCursorState cursor = HistoryDefaultCursorState; HistoryCursorState cursor = HistoryDefaultCursorState;
ClickHandlerPtr link; ClickHandlerPtr link;
bool afterSymbol = false; bool afterSymbol = false;
@ -656,11 +658,15 @@ public:
return false; return false;
} }
virtual HistoryTextState getState(QPoint point, HistoryStateRequest request) const WARN_UNUSED_RESULT = 0; [[nodiscard]] virtual HistoryTextState getState(
QPoint point,
HistoryStateRequest request) const = 0;
virtual void updatePressed(QPoint point) { virtual void updatePressed(QPoint point) {
} }
virtual TextSelection adjustSelection(TextSelection selection, TextSelectType type) const WARN_UNUSED_RESULT { [[nodiscard]] virtual TextSelection adjustSelection(
TextSelection selection,
TextSelectType type) const {
return selection; return selection;
} }
@ -1051,10 +1057,12 @@ protected:
return nullptr; return nullptr;
} }
TextSelection skipTextSelection(TextSelection selection) const WARN_UNUSED_RESULT { [[nodiscard]] TextSelection skipTextSelection(
TextSelection selection) const {
return internal::unshiftSelection(selection, _text); return internal::unshiftSelection(selection, _text);
} }
TextSelection unskipTextSelection(TextSelection selection) const WARN_UNUSED_RESULT { [[nodiscard]] TextSelection unskipTextSelection(
TextSelection selection) const {
return internal::shiftSelection(selection, _text); return internal::shiftSelection(selection, _text);
} }

View File

@ -93,27 +93,37 @@ public:
// if we are in selecting items mode perhaps we want to // if we are in selecting items mode perhaps we want to
// toggle selection instead of activating the pressed link // toggle selection instead of activating the pressed link
virtual bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const = 0; virtual bool toggleSelectionByHandlerClick(
const ClickHandlerPtr &p) const = 0;
// if we press and drag on this media should we drag the item // if we press and drag on this media should we drag the item
virtual bool dragItem() const WARN_UNUSED_RESULT { [[nodiscard]] virtual bool dragItem() const {
return false; return false;
} }
virtual TextSelection adjustSelection(TextSelection selection, TextSelectType type) const WARN_UNUSED_RESULT { [[nodiscard]] virtual TextSelection adjustSelection(
TextSelection selection,
TextSelectType type) const {
return selection; return selection;
} }
virtual bool consumeMessageText(const TextWithEntities &textWithEntities) WARN_UNUSED_RESULT { [[nodiscard]] virtual bool consumeMessageText(
const TextWithEntities &textWithEntities) {
return false; return false;
} }
virtual uint16 fullSelectionLength() const WARN_UNUSED_RESULT { [[nodiscard]] virtual uint16 fullSelectionLength() const {
return 0; return 0;
} }
TextSelection skipSelection(TextSelection selection) const WARN_UNUSED_RESULT { [[nodiscard]] TextSelection skipSelection(
return internal::unshiftSelection(selection, fullSelectionLength()); TextSelection selection) const {
return internal::unshiftSelection(
selection,
fullSelectionLength());
} }
TextSelection unskipSelection(TextSelection selection) const WARN_UNUSED_RESULT { [[nodiscard]] TextSelection unskipSelection(
return internal::shiftSelection(selection, fullSelectionLength()); TextSelection selection) const {
return internal::shiftSelection(
selection,
fullSelectionLength());
} }
// if we press and drag this link should we drag the item // if we press and drag this link should we drag the item

View File

@ -144,7 +144,9 @@ public:
void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override;
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; HistoryTextState getState(QPoint point, HistoryStateRequest request) const override;
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override WARN_UNUSED_RESULT { [[nodiscard]] TextSelection adjustSelection(
TextSelection selection,
TextSelectType type) const override {
return _caption.adjustSelection(selection, type); return _caption.adjustSelection(selection, type);
} }
uint16 fullSelectionLength() const override { uint16 fullSelectionLength() const override {
@ -230,7 +232,9 @@ public:
void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override;
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; HistoryTextState getState(QPoint point, HistoryStateRequest request) const override;
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override WARN_UNUSED_RESULT { [[nodiscard]] TextSelection adjustSelection(
TextSelection selection,
TextSelectType type) const override {
return _caption.adjustSelection(selection, type); return _caption.adjustSelection(selection, type);
} }
uint16 fullSelectionLength() const override { uint16 fullSelectionLength() const override {
@ -382,7 +386,9 @@ public:
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; HistoryTextState getState(QPoint point, HistoryStateRequest request) const override;
void updatePressed(QPoint point) override; void updatePressed(QPoint point) override;
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override WARN_UNUSED_RESULT { [[nodiscard]] TextSelection adjustSelection(
TextSelection selection,
TextSelectType type) const override {
if (auto captioned = Get<HistoryDocumentCaptioned>()) { if (auto captioned = Get<HistoryDocumentCaptioned>()) {
return captioned->_caption.adjustSelection(selection, type); return captioned->_caption.adjustSelection(selection, type);
} }
@ -495,7 +501,9 @@ public:
void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override;
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; HistoryTextState getState(QPoint point, HistoryStateRequest request) const override;
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override WARN_UNUSED_RESULT { [[nodiscard]] TextSelection adjustSelection(
TextSelection selection,
TextSelectType type) const override {
return _caption.adjustSelection(selection, type); return _caption.adjustSelection(selection, type);
} }
uint16 fullSelectionLength() const override { uint16 fullSelectionLength() const override {
@ -795,7 +803,9 @@ public:
void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override;
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; HistoryTextState getState(QPoint point, HistoryStateRequest request) const override;
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override WARN_UNUSED_RESULT; [[nodiscard]] TextSelection adjustSelection(
TextSelection selection,
TextSelectType type) const override;
uint16 fullSelectionLength() const override { uint16 fullSelectionLength() const override {
return _title.length() + _description.length(); return _title.length() + _description.length();
} }
@ -902,7 +912,9 @@ public:
void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override;
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; HistoryTextState getState(QPoint point, HistoryStateRequest request) const override;
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override WARN_UNUSED_RESULT; [[nodiscard]] TextSelection adjustSelection(
TextSelection selection,
TextSelectType type) const override;
uint16 fullSelectionLength() const override { uint16 fullSelectionLength() const override {
return _title.length() + _description.length(); return _title.length() + _description.length();
} }
@ -1016,7 +1028,9 @@ public:
void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override;
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; HistoryTextState getState(QPoint point, HistoryStateRequest request) const override;
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override WARN_UNUSED_RESULT; [[nodiscard]] TextSelection adjustSelection(
TextSelection selection,
TextSelectType type) const override;
uint16 fullSelectionLength() const override { uint16 fullSelectionLength() const override {
return _title.length() + _description.length(); return _title.length() + _description.length();
} }
@ -1102,7 +1116,9 @@ public:
void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override;
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; HistoryTextState getState(QPoint point, HistoryStateRequest request) const override;
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override WARN_UNUSED_RESULT; [[nodiscard]] TextSelection adjustSelection(
TextSelection selection,
TextSelectType type) const override;
uint16 fullSelectionLength() const override { uint16 fullSelectionLength() const override {
return _title.length() + _description.length(); return _title.length() + _description.length();
} }

View File

@ -88,7 +88,9 @@ public:
bool hasPoint(QPoint point) const override; bool hasPoint(QPoint point) const override;
HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; HistoryTextState getState(QPoint point, HistoryStateRequest request) const override;
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override WARN_UNUSED_RESULT { [[nodiscard]] TextSelection adjustSelection(
TextSelection selection,
TextSelectType type) const override {
return _text.adjustSelection(selection, type); return _text.adjustSelection(selection, type);
} }

File diff suppressed because it is too large Load Diff

View File

@ -66,6 +66,18 @@ public:
rpl::producer<int> scrollToRequests() const { rpl::producer<int> scrollToRequests() const {
return _scrollToRequests.events(); return _scrollToRequests.events();
} }
struct SelectedItem {
explicit SelectedItem(FullMsgId msgId) : msgId(msgId) {
}
FullMsgId msgId;
bool canDelete = false;
bool canForward = false;
};
using SelectedItems = std::vector<SelectedItem>;
rpl::producer<SelectedItems> selectedItemsValue() const {
return _selectedItemsStream.events();
}
~ListWidget(); ~ListWidget();
@ -98,19 +110,51 @@ private:
std::unique_ptr<BaseLayout> item; std::unique_ptr<BaseLayout> item;
bool stale = false; bool stale = false;
}; };
struct Context;
class Section; class Section;
struct FoundItem { struct FoundItem {
not_null<BaseLayout*> layout; not_null<BaseLayout*> layout;
QRect geometry; QRect geometry;
bool exact = false; bool exact = false;
}; };
struct SelectionData {
explicit SelectionData(TextSelection text) : text(text) {
}
TextSelection text;
bool canDelete = false;
bool canForward = false;
};
using SelectedMap = base::flat_map<
UniversalMsgId,
SelectionData,
std::less<>>;
enum class DragSelectAction {
None,
Selecting,
Deselecting,
};
struct CursorState {
UniversalMsgId itemId = 0;
QSize size;
QPoint cursor;
bool inside = false;
inline bool operator==(const CursorState &other) const {
return (itemId == other.itemId)
&& (cursor == other.cursor);
}
inline bool operator!=(const CursorState &other) const {
return !(*this == other);
}
};
void start(); void start();
int recountHeight(); int recountHeight();
void refreshHeight(); void refreshHeight();
QMargins padding() const; QMargins padding() const;
void updateSelected();
bool isMyItem(not_null<const HistoryItem*> item) const; bool isMyItem(not_null<const HistoryItem*> item) const;
bool isItemLayout( bool isItemLayout(
not_null<const HistoryItem*> item, not_null<const HistoryItem*> item,
@ -118,6 +162,7 @@ private:
void repaintItem(const HistoryItem *item); void repaintItem(const HistoryItem *item);
void repaintItem(UniversalMsgId msgId); void repaintItem(UniversalMsgId msgId);
void repaintItem(const BaseLayout *item); void repaintItem(const BaseLayout *item);
void repaintItem(QRect itemGeometry);
void itemRemoved(not_null<const HistoryItem*> item); void itemRemoved(not_null<const HistoryItem*> item);
void itemLayoutChanged(not_null<const HistoryItem*> item); void itemLayoutChanged(not_null<const HistoryItem*> item);
@ -126,12 +171,46 @@ private:
void refreshRows(); void refreshRows();
SharedMediaMergedSlice::Key sliceKey( SharedMediaMergedSlice::Key sliceKey(
UniversalMsgId universalId) const; UniversalMsgId universalId) const;
BaseLayout *getLayout(const FullMsgId &itemId); BaseLayout *getLayout(UniversalMsgId universalId);
BaseLayout *getExistingLayout(const FullMsgId &itemId) const; BaseLayout *getExistingLayout(UniversalMsgId universalId) const;
std::unique_ptr<BaseLayout> createLayout( std::unique_ptr<BaseLayout> createLayout(
const FullMsgId &itemId, UniversalMsgId universalId,
Type type); Type type);
SelectedItems collectSelectedItems() const;
void pushSelectedItems();
FullMsgId computeFullId(UniversalMsgId universalId) const;
bool hasSelected() const;
bool isSelectedItem(
const SelectedMap::const_iterator &i) const;
void removeItemSelection(
const SelectedMap::const_iterator &i);
bool hasSelectedText() const;
bool hasSelectedItems() const;
void clearSelected();
void applyItemSelection(
UniversalMsgId universalId,
TextSelection selection);
void toggleItemSelection(
UniversalMsgId universalId);
SelectedMap::iterator itemUnderPressSelection();
SelectedMap::const_iterator itemUnderPressSelection() const;
bool isItemUnderPressSelected() const;
bool requiredToStartDragging(not_null<BaseLayout*> layout) const;
bool isPressInSelectedText(HistoryTextState state) const;
void applyDragSelection();
void applyDragSelection(SelectedMap &applyTo) const;
bool changeItemSelection(
SelectedMap &selected,
UniversalMsgId universalId,
TextSelection selection) const;
static bool IsAfter(
const CursorState &a,
const CursorState &b);
static bool SkipSelectFromItem(const CursorState &state);
static bool SkipSelectTillItem(const CursorState &state);
void markLayoutsStale(); void markLayoutsStale();
void clearStaleLayouts(); void clearStaleLayouts();
std::vector<Section>::iterator findSectionByItem( std::vector<Section>::iterator findSectionByItem(
@ -157,11 +236,25 @@ private:
const QPoint &screenPos, const QPoint &screenPos,
Qt::MouseButton button); Qt::MouseButton button);
void mouseActionUpdate(const QPoint &screenPos); void mouseActionUpdate(const QPoint &screenPos);
void mouseActionUpdate();
void mouseActionFinish( void mouseActionFinish(
const QPoint &screenPos, const QPoint &screenPos,
Qt::MouseButton button); Qt::MouseButton button);
void mouseActionCancel(); void mouseActionCancel();
void performDrag(); void performDrag();
style::cursor computeMouseCursor() const;
void updateDragSelection();
void clearDragSelection();
void setDragSelection(
BaseLayout *dragSelectFrom,
BaseLayout *dragSelectTill,
DragSelectAction action);
void trySwitchToWordSelection();
void switchToWordSelection();
void validateTrippleClickStartTime();
void checkMoveToOtherViewer();
not_null<Window::Controller*> _controller; not_null<Window::Controller*> _controller;
not_null<PeerData*> _peer; not_null<PeerData*> _peer;
@ -183,29 +276,24 @@ private:
MouseAction _mouseAction = MouseAction::None; MouseAction _mouseAction = MouseAction::None;
TextSelectType _mouseSelectType = TextSelectType::Letters; TextSelectType _mouseSelectType = TextSelectType::Letters;
QPoint _dragStartPosition;
QPoint _mousePosition; QPoint _mousePosition;
BaseLayout *_itemNearestToCursor = nullptr; CursorState _overState;
BaseLayout *_itemUnderCursor = nullptr; CursorState _pressState;
BaseLayout *_itemUnderPress = nullptr; BaseLayout *_overLayout = nullptr;
HistoryCursorState _mouseCursorState = HistoryDefaultCursorState; HistoryCursorState _mouseCursorState = HistoryDefaultCursorState;
// uint16 _mouseTextSymbol = 0; uint16 _mouseTextSymbol = 0;
bool _pressWasInactive = false; bool _pressWasInactive = false;
using SelectedItems = std::map< SelectedMap _selected;
UniversalMsgId, SelectedMap _dragSelected;
TextSelection, rpl::event_stream<SelectedItems> _selectedItemsStream;
std::less<>>;
SelectedItems _selected;
style::cursor _cursor = style::cur_default; style::cursor _cursor = style::cur_default;
BaseLayout *_dragSelFrom = nullptr; DragSelectAction _dragSelectAction = DragSelectAction::None;
BaseLayout *_dragSelTo = nullptr;
// bool _dragSelecting = false;
bool _wasSelectedText = false; // was some text selected in current drag action bool _wasSelectedText = false; // was some text selected in current drag action
Ui::PopupMenu *_contextMenu = nullptr; Ui::PopupMenu *_contextMenu = nullptr;
ClickHandlerPtr _contextMenuLink; ClickHandlerPtr _contextMenuLink;
QPoint _trippleClickPoint; QPoint _trippleClickPoint;
QTimer _trippleClickTimer; TimeMs _trippleClickStartTime = 0;
rpl::lifetime _viewerLifetime; rpl::lifetime _viewerLifetime;

View File

@ -213,14 +213,17 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons
} }
} }
void Gif::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const { HistoryTextState Gif::getState(
QPoint point,
HistoryStateRequest request) const {
if (QRect(0, 0, _width, st::inlineMediaHeight).contains(point)) { if (QRect(0, 0, _width, st::inlineMediaHeight).contains(point)) {
if (_delete && rtlpoint(point, _width).x() >= _width - st::stickerPanDeleteIconBg.width() && point.y() < st::stickerPanDeleteIconBg.height()) { if (_delete && rtlpoint(point, _width).x() >= _width - st::stickerPanDeleteIconBg.width() && point.y() < st::stickerPanDeleteIconBg.height()) {
link = _delete; return _delete;
} else { } else {
link = _send; return _send;
} }
} }
return {};
} }
void Gif::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { void Gif::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
@ -404,10 +407,13 @@ void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context)
} }
} }
void Sticker::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const { HistoryTextState Sticker::getState(
QPoint point,
HistoryStateRequest request) const {
if (QRect(0, 0, _width, st::inlineMediaHeight).contains(point)) { if (QRect(0, 0, _width, st::inlineMediaHeight).contains(point)) {
link = _send; return _send;
} }
return {};
} }
void Sticker::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { void Sticker::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
@ -491,10 +497,13 @@ void Photo::paint(Painter &p, const QRect &clip, const PaintContext *context) co
} }
} }
void Photo::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const { HistoryTextState Photo::getState(
QPoint point,
HistoryStateRequest request) const {
if (QRect(0, 0, _width, st::inlineMediaHeight).contains(point)) { if (QRect(0, 0, _width, st::inlineMediaHeight).contains(point)) {
link = _send; return _send;
} }
return {};
} }
PhotoData *Photo::getShownPhoto() const { PhotoData *Photo::getShownPhoto() const {
@ -633,15 +642,16 @@ void Video::paint(Painter &p, const QRect &clip, const PaintContext *context) co
} }
} }
void Video::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const { HistoryTextState Video::getState(
QPoint point,
HistoryStateRequest request) const {
if (QRect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize).contains(point)) { if (QRect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize).contains(point)) {
link = _link; return _link;
return;
} }
if (QRect(st::inlineThumbSize + st::inlineThumbSkip, 0, _width - st::inlineThumbSize - st::inlineThumbSkip, _height).contains(point)) { if (QRect(st::inlineThumbSize + st::inlineThumbSkip, 0, _width - st::inlineThumbSize - st::inlineThumbSkip, _height).contains(point)) {
link = _send; return _send;
return;
} }
return {};
} }
void Video::prepareThumb(int32 width, int32 height) const { void Video::prepareThumb(int32 width, int32 height) const {
@ -773,16 +783,18 @@ void File::paint(Painter &p, const QRect &clip, const PaintContext *context) con
} }
} }
void File::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const { HistoryTextState File::getState(
QPoint point,
HistoryStateRequest request) const {
if (QRect(0, st::inlineRowMargin, st::msgFileSize, st::msgFileSize).contains(point)) { if (QRect(0, st::inlineRowMargin, st::msgFileSize, st::msgFileSize).contains(point)) {
link = getShownDocument()->loading() ? _cancel : _open; return getShownDocument()->loading() ? _cancel : _open;
return; } else {
}
auto left = st::msgFileSize + st::inlineThumbSkip; auto left = st::msgFileSize + st::inlineThumbSkip;
if (QRect(left, 0, _width - left, _height).contains(point)) { if (QRect(left, 0, _width - left, _height).contains(point)) {
link = _send; return _send;
return;
} }
}
return {};
} }
void File::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { void File::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
@ -933,15 +945,16 @@ void Contact::paint(Painter &p, const QRect &clip, const PaintContext *context)
} }
} }
void Contact::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const { HistoryTextState Contact::getState(
if (QRect(0, st::inlineRowMargin, st::msgFileSize, st::inlineThumbSize).contains(point)) { QPoint point,
return; HistoryStateRequest request) const {
} if (!QRect(0, st::inlineRowMargin, st::msgFileSize, st::inlineThumbSize).contains(point)) {
auto left = (st::msgFileSize + st::inlineThumbSkip); auto left = (st::msgFileSize + st::inlineThumbSkip);
if (QRect(left, 0, _width - left, _height).contains(point)) { if (QRect(left, 0, _width - left, _height).contains(point)) {
link = _send; return _send;
return;
} }
}
return {};
} }
void Contact::prepareThumb(int width, int height) const { void Contact::prepareThumb(int width, int height) const {
@ -1069,10 +1082,11 @@ void Article::paint(Painter &p, const QRect &clip, const PaintContext *context)
} }
} }
void Article::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const { HistoryTextState Article::getState(
QPoint point,
HistoryStateRequest request) const {
if (_withThumb && QRect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize).contains(point)) { if (_withThumb && QRect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize).contains(point)) {
link = _link; return _link;
return;
} }
auto left = _withThumb ? (st::inlineThumbSize + st::inlineThumbSkip) : 0; auto left = _withThumb ? (st::inlineThumbSize + st::inlineThumbSkip) : 0;
if (QRect(left, 0, _width - left, _height).contains(point)) { if (QRect(left, 0, _width - left, _height).contains(point)) {
@ -1082,13 +1096,12 @@ void Article::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint
auto descriptionLines = 2; auto descriptionLines = 2;
auto descriptionHeight = qMin(_description.countHeight(_width - left), st::normalFont->height * descriptionLines); auto descriptionHeight = qMin(_description.countHeight(_width - left), st::normalFont->height * descriptionLines);
if (rtlrect(left, st::inlineRowMargin + titleHeight + descriptionHeight, _urlWidth, st::normalFont->height, _width).contains(point)) { if (rtlrect(left, st::inlineRowMargin + titleHeight + descriptionHeight, _urlWidth, st::normalFont->height, _width).contains(point)) {
link = _url; return _url;
return;
} }
} }
link = _send; return _send;
return;
} }
return {};
} }
void Article::prepareThumb(int width, int height) const { void Article::prepareThumb(int width, int height) const {
@ -1253,16 +1266,17 @@ void Game::paint(Painter &p, const QRect &clip, const PaintContext *context) con
} }
} }
void Game::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const { HistoryTextState Game::getState(
QPoint point,
HistoryStateRequest request) const {
int left = st::inlineThumbSize + st::inlineThumbSkip; int left = st::inlineThumbSize + st::inlineThumbSkip;
if (QRect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize).contains(point)) { if (QRect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize).contains(point)) {
link = _send; return _send;
return;
} }
if (QRect(left, 0, _width - left, _height).contains(point)) { if (QRect(left, 0, _width - left, _height).contains(point)) {
link = _send; return _send;
return;
} }
return {};
} }
void Game::prepareThumb(int width, int height) const { void Game::prepareThumb(int width, int height) const {

View File

@ -73,7 +73,9 @@ public:
} }
void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const override; HistoryTextState getState(
QPoint point,
HistoryStateRequest request) const override;
// ClickHandlerHost interface // ClickHandlerHost interface
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override; void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
@ -130,7 +132,9 @@ public:
} }
void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const override; HistoryTextState getState(
QPoint point,
HistoryStateRequest request) const override;
private: private:
PhotoData *getShownPhoto() const; PhotoData *getShownPhoto() const;
@ -160,7 +164,9 @@ public:
void preload() const override; void preload() const override;
void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const override; HistoryTextState getState(
QPoint point,
HistoryStateRequest request) const override;
// ClickHandlerHost interface // ClickHandlerHost interface
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override; void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
@ -184,7 +190,9 @@ public:
void initDimensions() override; void initDimensions() override;
void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const override; HistoryTextState getState(
QPoint point,
HistoryStateRequest request) const override;
private: private:
ClickHandlerPtr _link; ClickHandlerPtr _link;
@ -231,7 +239,9 @@ public:
void initDimensions() override; void initDimensions() override;
void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const override; HistoryTextState getState(
QPoint point,
HistoryStateRequest request) const override;
// ClickHandlerHost interface // ClickHandlerHost interface
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override; void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
@ -294,7 +304,9 @@ public:
int resizeGetHeight(int width) override; int resizeGetHeight(int width) override;
void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const override; HistoryTextState getState(
QPoint point,
HistoryStateRequest request) const override;
private: private:
mutable QPixmap _thumb; mutable QPixmap _thumb;
@ -312,7 +324,9 @@ public:
int resizeGetHeight(int width) override; int resizeGetHeight(int width) override;
void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const override; HistoryTextState getState(
QPoint point,
HistoryStateRequest request) const override;
private: private:
ClickHandlerPtr _url, _link; ClickHandlerPtr _url, _link;
@ -335,7 +349,9 @@ public:
void initDimensions() override; void initDimensions() override;
void paint(Painter &p, const QRect &clip, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const override; HistoryTextState getState(
QPoint point,
HistoryStateRequest request) const override;
private: private:
void countFrameSize(); void countFrameSize();

View File

@ -644,8 +644,10 @@ void Inner::updateSelected() {
} }
if (col < inlineItems.size()) { if (col < inlineItems.size()) {
sel = row * MatrixRowShift + col; sel = row * MatrixRowShift + col;
inlineItems.at(col)->getState(lnk, cursor, QPoint(sx, sy)); auto result = inlineItems[col]->getState(QPoint(sx, sy), HistoryStateRequest());
lnkhost = inlineItems.at(col); lnk = result.link;
cursor = result.cursor;
lnkhost = inlineItems[col];
} else { } else {
row = col = -1; row = col = -1;
} }

View File

@ -119,14 +119,15 @@ public:
return _height; return _height;
} }
virtual void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const { [[nodiscard]] virtual HistoryTextState getState(
link.clear(); QPoint point,
cursor = HistoryDefaultCursorState; HistoryStateRequest request) const {
return {};
} }
virtual void getSymbol(uint16 &symbol, bool &after, bool &upon, QPoint point) const { // from text [[nodiscard]] virtual TextSelection adjustSelection(
upon = hasPoint(point); TextSelection selection,
symbol = upon ? 0xFFFF : 0; TextSelectType type) const {
after = false; return selection;
} }
int width() const { int width() const {

View File

@ -104,7 +104,9 @@ void ListWidget::mouseMoveEvent(QMouseEvent *e) {
if (y <= m.y()) { if (y <= m.y()) {
if (auto media = layout->toMediaItem()) { if (auto media = layout->toMediaItem()) {
item = media->getItem(); item = media->getItem();
media->getState(lnk, cursorState, m - QPoint(0, y)); auto result = media->getState(m - QPoint(0, y), HistoryStateRequest());
lnk = result.link;
cursorState = result.cursor;
lnkhost = media; lnkhost = media;
} }
} }

View File

@ -1153,7 +1153,11 @@ void MediaView::refreshMediaViewer() {
} }
void MediaView::showPhoto(not_null<PhotoData*> photo, HistoryItem *context) { void MediaView::showPhoto(not_null<PhotoData*> photo, HistoryItem *context) {
if (context) {
setContext(context); setContext(context);
} else {
setContext(base::none);
}
_firstOpenedPeerPhoto = false; _firstOpenedPeerPhoto = false;
_saveMsgStarted = 0; _saveMsgStarted = 0;

View File

@ -214,39 +214,39 @@ public:
SpecificRequestBuilder(SpecificRequestBuilder &&other) = default; SpecificRequestBuilder(SpecificRequestBuilder &&other) = default;
public: public:
SpecificRequestBuilder &toDC(ShiftedDcId dcId) noexcept WARN_UNUSED_RESULT { [[nodiscard]] SpecificRequestBuilder &toDC(ShiftedDcId dcId) noexcept {
setToDC(dcId); setToDC(dcId);
return *this; return *this;
} }
SpecificRequestBuilder &canWait(TimeMs ms) noexcept WARN_UNUSED_RESULT { [[nodiscard]] SpecificRequestBuilder &canWait(TimeMs ms) noexcept {
setCanWait(ms); setCanWait(ms);
return *this; return *this;
} }
SpecificRequestBuilder &done(base::lambda_once<void(const typename Request::ResponseType &result)> callback) WARN_UNUSED_RESULT { [[nodiscard]] SpecificRequestBuilder &done(base::lambda_once<void(const typename Request::ResponseType &result)> callback) {
setDoneHandler(MakeShared<DoneHandler<typename Request::ResponseType, DonePlainPolicy>>(sender(), std::move(callback))); setDoneHandler(MakeShared<DoneHandler<typename Request::ResponseType, DonePlainPolicy>>(sender(), std::move(callback)));
return *this; return *this;
} }
SpecificRequestBuilder &done(base::lambda_once<void(const typename Request::ResponseType &result, mtpRequestId requestId)> callback) WARN_UNUSED_RESULT { [[nodiscard]] SpecificRequestBuilder &done(base::lambda_once<void(const typename Request::ResponseType &result, mtpRequestId requestId)> callback) {
setDoneHandler(MakeShared<DoneHandler<typename Request::ResponseType, DoneRequestIdPolicy>>(sender(), std::move(callback))); setDoneHandler(MakeShared<DoneHandler<typename Request::ResponseType, DoneRequestIdPolicy>>(sender(), std::move(callback)));
return *this; return *this;
} }
SpecificRequestBuilder &fail(base::lambda_once<void(const RPCError &error)> callback) noexcept WARN_UNUSED_RESULT { [[nodiscard]] SpecificRequestBuilder &fail(base::lambda_once<void(const RPCError &error)> callback) noexcept {
setFailHandler(std::move(callback)); setFailHandler(std::move(callback));
return *this; return *this;
} }
SpecificRequestBuilder &fail(base::lambda_once<void(const RPCError &error, mtpRequestId requestId)> callback) noexcept WARN_UNUSED_RESULT { [[nodiscard]] SpecificRequestBuilder &fail(base::lambda_once<void(const RPCError &error, mtpRequestId requestId)> callback) noexcept {
setFailHandler(std::move(callback)); setFailHandler(std::move(callback));
return *this; return *this;
} }
SpecificRequestBuilder &handleFloodErrors() noexcept WARN_UNUSED_RESULT { [[nodiscard]] SpecificRequestBuilder &handleFloodErrors() noexcept {
setFailSkipPolicy(FailSkipPolicy::HandleFlood); setFailSkipPolicy(FailSkipPolicy::HandleFlood);
return *this; return *this;
} }
SpecificRequestBuilder &handleAllErrors() noexcept WARN_UNUSED_RESULT { [[nodiscard]] SpecificRequestBuilder &handleAllErrors() noexcept {
setFailSkipPolicy(FailSkipPolicy::HandleAll); setFailSkipPolicy(FailSkipPolicy::HandleAll);
return *this; return *this;
} }
SpecificRequestBuilder &after(mtpRequestId requestId) noexcept WARN_UNUSED_RESULT { [[nodiscard]] SpecificRequestBuilder &after(mtpRequestId requestId) noexcept {
setAfter(requestId); setAfter(requestId);
return *this; return *this;
} }
@ -280,11 +280,11 @@ public:
}; };
template <typename Request, typename = std::enable_if_t<std::is_rvalue_reference<Request&&>::value>, typename = typename Request::Unboxed> template <typename Request, typename = std::enable_if_t<std::is_rvalue_reference<Request&&>::value>, typename = typename Request::Unboxed>
SpecificRequestBuilder<Request> request(Request &&request) noexcept WARN_UNUSED_RESULT; [[nodiscard]] SpecificRequestBuilder<Request> request(Request &&request) noexcept;
SentRequestWrap request(mtpRequestId requestId) noexcept WARN_UNUSED_RESULT; [[nodiscard]] SentRequestWrap request(mtpRequestId requestId) noexcept;
decltype(auto) requestCanceller() noexcept WARN_UNUSED_RESULT { [[nodiscard]] decltype(auto) requestCanceller() noexcept {
return [this](mtpRequestId requestId) { return [this](mtpRequestId requestId) {
request(requestId).cancel(); request(requestId).cancel();
}; };

View File

@ -66,12 +66,16 @@ TextWithEntities ComposeNameWithEntities(DocumentData *document) {
} // namespace } // namespace
void ItemBase::clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) { void ItemBase::clickHandlerActiveChanged(
const ClickHandlerPtr &action,
bool active) {
App::hoveredLinkItem(active ? _parent.get() : nullptr); App::hoveredLinkItem(active ? _parent.get() : nullptr);
Auth().data().requestItemRepaint(_parent); Auth().data().requestItemRepaint(_parent);
} }
void ItemBase::clickHandlerPressedChanged(const ClickHandlerPtr &action, bool pressed) { void ItemBase::clickHandlerPressedChanged(
const ClickHandlerPtr &action,
bool pressed) {
App::pressedLinkItem(pressed ? _parent.get() : nullptr); App::pressedLinkItem(pressed ? _parent.get() : nullptr);
Auth().data().requestItemRepaint(_parent); Auth().data().requestItemRepaint(_parent);
} }
@ -306,10 +310,13 @@ void Photo::ensureCheckboxCreated() {
}); });
} }
void Photo::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const { HistoryTextState Photo::getState(
QPoint point,
HistoryStateRequest request) const {
if (hasPoint(point)) { if (hasPoint(point)) {
link = _link; return _link;
} }
return {};
} }
void Photo::clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) { void Photo::clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) {
@ -506,12 +513,15 @@ bool Video::iconAnimated() const {
return true; return true;
} }
void Video::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const { HistoryTextState Video::getState(
QPoint point,
HistoryStateRequest request) const {
bool loaded = _data->loaded(); bool loaded = _data->loaded();
if (hasPoint(point)) { if (hasPoint(point)) {
link = loaded ? _openl : (_data->loading() ? _cancell : _savel); return loaded ? _openl : (_data->loading() ? _cancell : _savel);
} }
return {};
} }
void Video::updateStatusText() { void Video::updateStatusText() {
@ -664,7 +674,9 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const
} }
} }
void Voice::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const { HistoryTextState Voice::getState(
QPoint point,
HistoryStateRequest request) const {
bool loaded = _data->loaded(); bool loaded = _data->loaded();
int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = 0; int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = 0;
@ -676,20 +688,20 @@ void Voice::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint p
auto inner = rtlrect(_st.songPadding.left(), _st.songPadding.top(), _st.songThumbSize, _st.songThumbSize, _width); auto inner = rtlrect(_st.songPadding.left(), _st.songPadding.top(), _st.songThumbSize, _st.songThumbSize, _width);
if (inner.contains(point)) { if (inner.contains(point)) {
link = loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _openl); return loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _openl);
return;
} }
auto result = HistoryTextState();
if (rtlrect(nameleft, statustop, _width - nameleft - nameright, st::normalFont->height, _width).contains(point)) { if (rtlrect(nameleft, statustop, _width - nameleft - nameright, st::normalFont->height, _width).contains(point)) {
if (_status.size() == FileStatusSizeLoaded || _status.size() == FileStatusSizeReady) { if (_status.size() == FileStatusSizeLoaded || _status.size() == FileStatusSizeReady) {
auto textState = _details.getStateLeft(point - QPoint(nameleft, statustop), _width, _width); auto textState = _details.getStateLeft(point - QPoint(nameleft, statustop), _width, _width);
link = textState.link; result.link = textState.link;
cursor = textState.uponSymbol ? HistoryInTextCursorState : HistoryDefaultCursorState; result.cursor = textState.uponSymbol ? HistoryInTextCursorState : HistoryDefaultCursorState;
} }
} }
if (hasPoint(point) && !link && !_data->loading()) { if (hasPoint(point) && !result.link && !_data->loading()) {
link = _namel; return _namel;
return;
} }
return result;
} }
float64 Voice::dataProgress() const { float64 Voice::dataProgress() const {
@ -954,7 +966,9 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con
} }
} }
void Document::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const { HistoryTextState Document::getState(
QPoint point,
HistoryStateRequest request) const {
bool loaded = _data->loaded() || Local::willStickerImageLoad(_data->mediaKey()); bool loaded = _data->loaded() || Local::willStickerImageLoad(_data->mediaKey());
int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = 0; int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = 0;
@ -968,12 +982,10 @@ void Document::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoin
auto inner = rtlrect(_st.songPadding.left(), _st.songPadding.top(), _st.songThumbSize, _st.songThumbSize, _width); auto inner = rtlrect(_st.songPadding.left(), _st.songPadding.top(), _st.songThumbSize, _st.songThumbSize, _width);
if (inner.contains(point)) { if (inner.contains(point)) {
link = loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _openl); return loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _openl);
return;
} }
if (hasPoint(point) && !_data->loading()) { if (hasPoint(point) && !_data->loading()) {
link = _namel; return _namel;
return;
} }
} else { } else {
nameleft = _st.fileThumbSize + _st.filePadding.right(); nameleft = _st.fileThumbSize + _st.filePadding.right();
@ -984,27 +996,24 @@ void Document::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoin
auto rthumb = rtlrect(0, st::linksBorder + _st.filePadding.top(), _st.fileThumbSize, _st.fileThumbSize, _width); auto rthumb = rtlrect(0, st::linksBorder + _st.filePadding.top(), _st.fileThumbSize, _st.fileThumbSize, _width);
if (rthumb.contains(point)) { if (rthumb.contains(point)) {
link = loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _savel); return loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _savel);
return;
} }
if (_data->status != FileUploadFailed) { if (_data->status != FileUploadFailed) {
if (rtlrect(nameleft, datetop, _datew, st::normalFont->height, _width).contains(point)) { if (rtlrect(nameleft, datetop, _datew, st::normalFont->height, _width).contains(point)) {
link = _msgl; return _msgl;
return;
} }
} }
if (!_data->loading() && _data->isValid()) { if (!_data->loading() && _data->isValid()) {
if (loaded && rtlrect(0, st::linksBorder, nameleft, _height - st::linksBorder, _width).contains(point)) { if (loaded && rtlrect(0, st::linksBorder, nameleft, _height - st::linksBorder, _width).contains(point)) {
link = _namel; return _namel;
return;
} }
if (rtlrect(nameleft, nametop, qMin(_width - nameleft - nameright, _name.maxWidth()), st::semiboldFont->height, _width).contains(point)) { if (rtlrect(nameleft, nametop, qMin(_width - nameleft - nameright, _name.maxWidth()), st::semiboldFont->height, _width).contains(point)) {
link = _namel; return _namel;
return;
} }
} }
} }
return {};
} }
float64 Document::dataProgress() const { float64 Document::dataProgress() const {
@ -1301,11 +1310,12 @@ void Link::paint(Painter &p, const QRect &clip, TextSelection selection, const P
} }
} }
void Link::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const { HistoryTextState Link::getState(
QPoint point,
HistoryStateRequest request) const {
int32 left = st::linksPhotoSize + st::linksPhotoPadding, top = st::linksMargin.top() + st::linksBorder, w = _width - left; int32 left = st::linksPhotoSize + st::linksPhotoPadding, top = st::linksMargin.top() + st::linksBorder, w = _width - left;
if (rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width).contains(point)) { if (rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width).contains(point)) {
link = _photol; return _photol;
return;
} }
if (!_title.isEmpty() && _text.isEmpty() && _links.size() == 1) { if (!_title.isEmpty() && _text.isEmpty() && _links.size() == 1) {
@ -1313,8 +1323,7 @@ void Link::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint po
} }
if (!_title.isEmpty()) { if (!_title.isEmpty()) {
if (rtlrect(left, top, qMin(w, _titlew), st::semiboldFont->height, _width).contains(point)) { if (rtlrect(left, top, qMin(w, _titlew), st::semiboldFont->height, _width).contains(point)) {
link = _photol; return _photol;
return;
} }
top += st::webPageTitleFont->height; top += st::webPageTitleFont->height;
} }
@ -1323,11 +1332,11 @@ void Link::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint po
} }
for (int32 i = 0, l = _links.size(); i < l; ++i) { for (int32 i = 0, l = _links.size(); i < l; ++i) {
if (rtlrect(left, top, qMin(w, _links.at(i).width), st::normalFont->height, _width).contains(point)) { if (rtlrect(left, top, qMin(w, _links.at(i).width), st::normalFont->height, _width).contains(point)) {
link = _links.at(i).lnk; return _links.at(i).lnk;
return;
} }
top += st::normalFont->height; top += st::normalFont->height;
} }
return {};
} }
Link::LinkEntry::LinkEntry(const QString &url, const QString &text) Link::LinkEntry::LinkEntry(const QString &url, const QString &text)

View File

@ -189,7 +189,9 @@ public:
void initDimensions() override; void initDimensions() override;
int32 resizeGetHeight(int32 width) override; int32 resizeGetHeight(int32 width) override;
void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override; void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const override; HistoryTextState getState(
QPoint point,
HistoryStateRequest request) const override;
void clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) override; void clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) override;
void clickHandlerPressedChanged(const ClickHandlerPtr &action, bool pressed) override; void clickHandlerPressedChanged(const ClickHandlerPtr &action, bool pressed) override;
@ -220,7 +222,9 @@ public:
void initDimensions() override; void initDimensions() override;
int32 resizeGetHeight(int32 width) override; int32 resizeGetHeight(int32 width) override;
void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override; void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const override; HistoryTextState getState(
QPoint point,
HistoryStateRequest request) const override;
void clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) override; void clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) override;
void clickHandlerPressedChanged(const ClickHandlerPtr &action, bool pressed) override; void clickHandlerPressedChanged(const ClickHandlerPtr &action, bool pressed) override;
@ -260,7 +264,9 @@ public:
void initDimensions() override; void initDimensions() override;
void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override; void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const override; HistoryTextState getState(
QPoint point,
HistoryStateRequest request) const override;
protected: protected:
float64 dataProgress() const override; float64 dataProgress() const override;
@ -292,7 +298,9 @@ public:
void initDimensions() override; void initDimensions() override;
void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override; void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const override; HistoryTextState getState(
QPoint point,
HistoryStateRequest request) const override;
virtual DocumentData *getDocument() const override { virtual DocumentData *getDocument() const override {
return _data; return _data;
@ -333,7 +341,9 @@ public:
void initDimensions() override; void initDimensions() override;
int32 resizeGetHeight(int32 width) override; int32 resizeGetHeight(int32 width) override;
void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override; void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, QPoint point) const override; HistoryTextState getState(
QPoint point,
HistoryStateRequest request) const override;
private: private:
ClickHandlerPtr _photol; ClickHandlerPtr _photol;

View File

@ -900,7 +900,9 @@ void OverviewInner::onUpdateSelected() {
item = media->getItem(); item = media->getItem();
index = i; index = i;
if (upon) { if (upon) {
media->getState(lnk, cursorState, m - QPoint(col * w + st::overviewPhotoSkip, _marginTop + row * vsize + st::overviewPhotoSkip)); auto result = media->getState(m - QPoint(col * w + st::overviewPhotoSkip, _marginTop + row * vsize + st::overviewPhotoSkip), HistoryStateRequest());
lnk = result.link;
cursorState = result.cursor;
lnkhost = media; lnkhost = media;
} }
} }
@ -936,7 +938,9 @@ void OverviewInner::onUpdateSelected() {
if (auto media = _items.at(i)->toMediaItem()) { if (auto media = _items.at(i)->toMediaItem()) {
item = media->getItem(); item = media->getItem();
index = i; index = i;
media->getState(lnk, cursorState, m - QPoint(_rowsLeft, _marginTop + top)); auto result = media->getState(m - QPoint(_rowsLeft, _marginTop + top), HistoryStateRequest());
lnk = result.link;
cursorState = result.cursor;
lnkhost = media; lnkhost = media;
} }
break; break;

View File

@ -165,7 +165,7 @@ public:
return getStateElided(rtlpoint(point, outerw), width, request); return getStateElided(rtlpoint(point, outerw), width, request);
} }
TextSelection adjustSelection(TextSelection selection, TextSelectType selectType) const WARN_UNUSED_RESULT; [[nodiscard]] TextSelection adjustSelection(TextSelection selection, TextSelectType selectType) const;
bool isFullSelection(TextSelection selection) const { bool isFullSelection(TextSelection selection) const {
return (selection.from == 0) && (selection.to >= _text.size()); return (selection.from == 0) && (selection.to >= _text.size());
} }