2018-01-11 19:33:26 +00:00
|
|
|
/*
|
|
|
|
This file is part of Telegram Desktop,
|
|
|
|
the official desktop application for the Telegram messaging service.
|
|
|
|
|
|
|
|
For license and copyright information please follow this link:
|
|
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
|
2018-01-13 12:45:11 +00:00
|
|
|
#include "history/view/history_view_object.h"
|
2018-01-11 19:33:26 +00:00
|
|
|
#include "base/runtime_composer.h"
|
2018-01-13 12:45:11 +00:00
|
|
|
#include "base/flags.h"
|
2018-01-11 19:33:26 +00:00
|
|
|
|
2019-09-13 06:06:02 +00:00
|
|
|
class History;
|
2018-01-13 12:45:11 +00:00
|
|
|
class HistoryBlock;
|
2018-01-11 19:33:26 +00:00
|
|
|
class HistoryItem;
|
2018-01-17 16:21:01 +00:00
|
|
|
class HistoryMessage;
|
|
|
|
class HistoryService;
|
2018-01-11 19:33:26 +00:00
|
|
|
|
|
|
|
namespace HistoryView {
|
|
|
|
|
2018-01-27 13:59:24 +00:00
|
|
|
enum class PointState : char;
|
|
|
|
enum class InfoDisplayType : char;
|
|
|
|
struct StateRequest;
|
|
|
|
struct TextState;
|
2019-08-02 13:21:09 +00:00
|
|
|
class Media;
|
2018-01-27 13:59:24 +00:00
|
|
|
|
2018-01-19 17:10:58 +00:00
|
|
|
enum class Context : char {
|
|
|
|
History,
|
2019-04-15 11:54:03 +00:00
|
|
|
//Feed, // #feed
|
2018-10-05 16:02:33 +00:00
|
|
|
AdminLog,
|
|
|
|
ContactPreview
|
2018-01-19 17:10:58 +00:00
|
|
|
};
|
|
|
|
|
2018-01-17 16:21:01 +00:00
|
|
|
class Element;
|
|
|
|
class ElementDelegate {
|
|
|
|
public:
|
2018-01-19 17:10:58 +00:00
|
|
|
virtual Context elementContext() = 0;
|
2018-01-17 16:21:01 +00:00
|
|
|
virtual std::unique_ptr<Element> elementCreate(
|
|
|
|
not_null<HistoryMessage*> message) = 0;
|
|
|
|
virtual std::unique_ptr<Element> elementCreate(
|
|
|
|
not_null<HistoryService*> message) = 0;
|
2018-01-26 15:40:11 +00:00
|
|
|
virtual bool elementUnderCursor(not_null<const Element*> view) = 0;
|
2018-01-21 14:49:42 +00:00
|
|
|
virtual void elementAnimationAutoplayAsync(
|
|
|
|
not_null<const Element*> element) = 0;
|
2019-02-19 06:57:53 +00:00
|
|
|
virtual crl::time elementHighlightTime(
|
2018-02-16 17:59:35 +00:00
|
|
|
not_null<const Element*> element) = 0;
|
2018-03-08 21:21:27 +00:00
|
|
|
virtual bool elementInSelectionMode() = 0;
|
2019-05-14 09:50:44 +00:00
|
|
|
virtual bool elementIntersectsRange(
|
|
|
|
not_null<const Element*> view,
|
|
|
|
int from,
|
|
|
|
int till) = 0;
|
2019-08-01 12:55:14 +00:00
|
|
|
virtual void elementStartStickerLoop(not_null<const Element*> view) = 0;
|
2020-01-14 11:55:18 +00:00
|
|
|
virtual void elementShowPollResults(
|
|
|
|
not_null<PollData*> poll,
|
|
|
|
FullMsgId context) = 0;
|
2018-01-17 16:21:01 +00:00
|
|
|
|
|
|
|
};
|
|
|
|
|
2019-05-14 09:50:44 +00:00
|
|
|
class SimpleElementDelegate : public ElementDelegate {
|
|
|
|
public:
|
|
|
|
std::unique_ptr<Element> elementCreate(
|
|
|
|
not_null<HistoryMessage*> message) override;
|
|
|
|
std::unique_ptr<Element> elementCreate(
|
|
|
|
not_null<HistoryService*> message) override;
|
|
|
|
bool elementUnderCursor(not_null<const Element*> view) override;
|
|
|
|
void elementAnimationAutoplayAsync(
|
|
|
|
not_null<const Element*> element) override;
|
|
|
|
crl::time elementHighlightTime(
|
|
|
|
not_null<const Element*> element) override;
|
|
|
|
bool elementInSelectionMode() override;
|
|
|
|
bool elementIntersectsRange(
|
|
|
|
not_null<const Element*> view,
|
|
|
|
int from,
|
|
|
|
int till) override;
|
2019-08-01 12:55:14 +00:00
|
|
|
void elementStartStickerLoop(not_null<const Element*> view) override;
|
2020-01-14 11:55:18 +00:00
|
|
|
void elementShowPollResults(
|
|
|
|
not_null<PollData*> poll,
|
|
|
|
FullMsgId context) override;
|
2019-08-01 11:42:24 +00:00
|
|
|
|
2019-05-14 09:50:44 +00:00
|
|
|
};
|
|
|
|
|
2018-01-14 16:02:25 +00:00
|
|
|
TextSelection UnshiftItemSelection(
|
|
|
|
TextSelection selection,
|
|
|
|
uint16 byLength);
|
|
|
|
TextSelection ShiftItemSelection(
|
|
|
|
TextSelection selection,
|
|
|
|
uint16 byLength);
|
|
|
|
TextSelection UnshiftItemSelection(
|
|
|
|
TextSelection selection,
|
2019-06-12 13:26:04 +00:00
|
|
|
const Ui::Text::String &byText);
|
2018-01-14 16:02:25 +00:00
|
|
|
TextSelection ShiftItemSelection(
|
|
|
|
TextSelection selection,
|
2019-06-12 13:26:04 +00:00
|
|
|
const Ui::Text::String &byText);
|
2018-01-14 16:02:25 +00:00
|
|
|
|
2018-01-21 19:21:08 +00:00
|
|
|
// Any HistoryView::Element can have this Component for
|
|
|
|
// displaying the unread messages bar above the message.
|
|
|
|
struct UnreadBar : public RuntimeComponent<UnreadBar, Element> {
|
2020-02-20 14:16:42 +00:00
|
|
|
void init();
|
2018-01-21 19:21:08 +00:00
|
|
|
|
|
|
|
static int height();
|
|
|
|
static int marginTop();
|
|
|
|
|
|
|
|
void paint(Painter &p, int y, int w) const;
|
|
|
|
|
|
|
|
QString text;
|
|
|
|
int width = 0;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2018-01-23 11:47:38 +00:00
|
|
|
// Any HistoryView::Element can have this Component for
|
|
|
|
// displaying the day mark above the message.
|
|
|
|
struct DateBadge : public RuntimeComponent<DateBadge, Element> {
|
2020-01-14 22:23:16 +00:00
|
|
|
void init(const QString &date);
|
2018-01-23 11:47:38 +00:00
|
|
|
|
|
|
|
int height() const;
|
|
|
|
void paint(Painter &p, int y, int w) const;
|
|
|
|
|
|
|
|
QString text;
|
|
|
|
int width = 0;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2018-01-11 19:33:26 +00:00
|
|
|
class Element
|
2018-01-13 12:45:11 +00:00
|
|
|
: public Object
|
2018-01-14 16:02:25 +00:00
|
|
|
, public RuntimeComposer<Element>
|
2018-01-11 19:33:26 +00:00
|
|
|
, public ClickHandlerHost {
|
|
|
|
public:
|
2018-01-19 17:10:58 +00:00
|
|
|
Element(
|
|
|
|
not_null<ElementDelegate*> delegate,
|
|
|
|
not_null<HistoryItem*> data);
|
2018-01-11 19:33:26 +00:00
|
|
|
|
2018-01-13 12:45:11 +00:00
|
|
|
enum class Flag : uchar {
|
|
|
|
NeedsResize = 0x01,
|
|
|
|
AttachedToPrevious = 0x02,
|
|
|
|
AttachedToNext = 0x04,
|
2018-01-14 16:02:25 +00:00
|
|
|
HiddenByGroup = 0x08,
|
2018-01-13 12:45:11 +00:00
|
|
|
};
|
|
|
|
using Flags = base::flags<Flag>;
|
|
|
|
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
|
|
|
|
2018-01-19 17:10:58 +00:00
|
|
|
not_null<ElementDelegate*> delegate() const;
|
2018-01-11 19:33:26 +00:00
|
|
|
not_null<HistoryItem*> data() const;
|
2019-01-03 12:36:01 +00:00
|
|
|
not_null<History*> history() const;
|
2019-08-02 13:21:09 +00:00
|
|
|
Media *media() const;
|
2018-01-13 12:45:11 +00:00
|
|
|
Context context() const;
|
2018-01-14 16:02:25 +00:00
|
|
|
void refreshDataId();
|
2018-01-11 19:33:26 +00:00
|
|
|
|
2018-02-03 19:52:35 +00:00
|
|
|
QDateTime dateTime() const;
|
|
|
|
|
2018-01-13 12:45:11 +00:00
|
|
|
int y() const;
|
|
|
|
void setY(int y);
|
|
|
|
|
2018-02-16 17:59:35 +00:00
|
|
|
virtual int marginTop() const = 0;
|
|
|
|
virtual int marginBottom() const = 0;
|
|
|
|
|
2018-01-13 12:45:11 +00:00
|
|
|
void setPendingResize();
|
|
|
|
bool pendingResize() const;
|
2018-01-14 16:02:25 +00:00
|
|
|
bool isUnderCursor() const;
|
2018-01-13 12:45:11 +00:00
|
|
|
|
2020-02-26 11:25:51 +00:00
|
|
|
bool isLastAndSelfMessage() const;
|
|
|
|
|
2018-01-13 12:45:11 +00:00
|
|
|
bool isAttachedToPrevious() const;
|
|
|
|
bool isAttachedToNext() const;
|
|
|
|
|
2018-01-14 16:02:25 +00:00
|
|
|
int skipBlockWidth() const;
|
|
|
|
int skipBlockHeight() const;
|
|
|
|
QString skipBlock() const;
|
|
|
|
virtual int infoWidth() const;
|
|
|
|
|
|
|
|
bool isHiddenByGroup() const;
|
2018-01-30 13:17:50 +00:00
|
|
|
virtual bool isHidden() const;
|
2018-01-14 16:02:25 +00:00
|
|
|
|
2018-01-13 12:45:11 +00:00
|
|
|
// For blocks context this should be called only from recountAttachToPreviousInBlocks().
|
|
|
|
void setAttachToPrevious(bool attachToNext);
|
|
|
|
|
|
|
|
// For blocks context this should be called only from recountAttachToPreviousInBlocks()
|
2018-01-19 17:10:58 +00:00
|
|
|
// of the next item or when the next item is removed through nextInBlocksRemoved() call.
|
2018-01-13 12:45:11 +00:00
|
|
|
void setAttachToNext(bool attachToNext);
|
|
|
|
|
|
|
|
// For blocks context this should be called only from recountDisplayDate().
|
|
|
|
void setDisplayDate(bool displayDate);
|
|
|
|
|
|
|
|
bool computeIsAttachToPrevious(not_null<Element*> previous);
|
|
|
|
|
2020-02-20 14:16:42 +00:00
|
|
|
void createUnreadBar();
|
2018-01-21 19:21:08 +00:00
|
|
|
void destroyUnreadBar();
|
|
|
|
|
2018-01-23 11:47:38 +00:00
|
|
|
int displayedDateHeight() const;
|
|
|
|
bool displayDate() const;
|
|
|
|
bool isInOneDayWithPrevious() const;
|
|
|
|
|
2018-01-13 12:45:11 +00:00
|
|
|
virtual void draw(
|
|
|
|
Painter &p,
|
|
|
|
QRect clip,
|
|
|
|
TextSelection selection,
|
2019-02-19 06:57:53 +00:00
|
|
|
crl::time ms) const = 0;
|
2018-01-27 13:59:24 +00:00
|
|
|
[[nodiscard]] virtual PointState pointState(QPoint point) const = 0;
|
|
|
|
[[nodiscard]] virtual TextState textState(
|
2018-01-13 12:45:11 +00:00
|
|
|
QPoint point,
|
2018-01-27 13:59:24 +00:00
|
|
|
StateRequest request) const = 0;
|
2018-01-13 12:45:11 +00:00
|
|
|
virtual void updatePressed(QPoint point) = 0;
|
2018-01-14 16:02:25 +00:00
|
|
|
virtual void drawInfo(
|
|
|
|
Painter &p,
|
|
|
|
int right,
|
|
|
|
int bottom,
|
|
|
|
int width,
|
|
|
|
bool selected,
|
|
|
|
InfoDisplayType type) const;
|
|
|
|
virtual bool pointInTime(
|
|
|
|
int right,
|
|
|
|
int bottom,
|
|
|
|
QPoint point,
|
|
|
|
InfoDisplayType type) const;
|
2019-04-08 15:10:06 +00:00
|
|
|
virtual TextForMimeData selectedText(
|
2018-01-14 16:02:25 +00:00
|
|
|
TextSelection selection) const = 0;
|
|
|
|
[[nodiscard]] virtual TextSelection adjustSelection(
|
|
|
|
TextSelection selection,
|
|
|
|
TextSelectType type) const;
|
2018-01-11 19:33:26 +00:00
|
|
|
|
2018-01-13 12:45:11 +00:00
|
|
|
// ClickHandlerHost interface.
|
2018-01-11 19:33:26 +00:00
|
|
|
void clickHandlerActiveChanged(
|
|
|
|
const ClickHandlerPtr &handler,
|
|
|
|
bool active) override;
|
|
|
|
void clickHandlerPressedChanged(
|
|
|
|
const ClickHandlerPtr &handler,
|
|
|
|
bool pressed) override;
|
|
|
|
|
2018-01-13 12:45:11 +00:00
|
|
|
// hasFromPhoto() returns true even if we don't display the photo
|
|
|
|
// but we need to skip a place at the left side for this photo
|
|
|
|
virtual bool hasFromPhoto() const;
|
2018-01-14 16:02:25 +00:00
|
|
|
virtual bool displayFromPhoto() const;
|
2018-01-13 12:45:11 +00:00
|
|
|
virtual bool hasFromName() const;
|
|
|
|
virtual bool displayFromName() const;
|
2018-01-14 16:02:25 +00:00
|
|
|
virtual bool displayForwardedFrom() const;
|
|
|
|
virtual bool hasOutLayout() const;
|
|
|
|
virtual bool drawBubble() const;
|
|
|
|
virtual bool hasBubble() const;
|
|
|
|
virtual bool hasFastReply() const;
|
|
|
|
virtual bool displayFastReply() const;
|
|
|
|
virtual bool displayRightAction() const;
|
|
|
|
virtual void drawRightAction(
|
|
|
|
Painter &p,
|
|
|
|
int left,
|
|
|
|
int top,
|
|
|
|
int outerWidth) const;
|
|
|
|
virtual ClickHandlerPtr rightActionLink() const;
|
|
|
|
virtual bool displayEditedBadge() const;
|
2018-02-03 19:52:35 +00:00
|
|
|
virtual TimeId displayedEditDate() const;
|
2018-01-18 13:59:22 +00:00
|
|
|
virtual bool hasVisibleText() const;
|
2018-01-13 12:45:11 +00:00
|
|
|
|
2020-01-24 09:50:20 +00:00
|
|
|
struct VerticalRepaintRange {
|
|
|
|
int top = 0;
|
|
|
|
int height = 0;
|
|
|
|
};
|
|
|
|
[[nodiscard]] virtual VerticalRepaintRange verticalRepaintRange() const;
|
|
|
|
|
2019-05-14 09:50:44 +00:00
|
|
|
virtual void unloadHeavyPart();
|
|
|
|
|
2018-01-13 12:45:11 +00:00
|
|
|
// Legacy blocks structure.
|
|
|
|
HistoryBlock *block();
|
|
|
|
const HistoryBlock *block() const;
|
|
|
|
void attachToBlock(not_null<HistoryBlock*> block, int index);
|
|
|
|
void removeFromBlock();
|
2018-01-18 13:59:22 +00:00
|
|
|
void refreshInBlock();
|
2018-01-13 12:45:11 +00:00
|
|
|
void setIndexInBlock(int index);
|
|
|
|
int indexInBlock() const;
|
|
|
|
Element *previousInBlocks() const;
|
|
|
|
Element *nextInBlocks() const;
|
|
|
|
void previousInBlocksChanged();
|
2018-01-19 17:10:58 +00:00
|
|
|
void nextInBlocksRemoved();
|
2018-01-13 12:45:11 +00:00
|
|
|
|
2018-01-11 19:33:26 +00:00
|
|
|
virtual ~Element();
|
|
|
|
|
2018-01-13 12:45:11 +00:00
|
|
|
protected:
|
2018-02-16 17:59:35 +00:00
|
|
|
void paintHighlight(
|
|
|
|
Painter &p,
|
|
|
|
int geometryHeight) const;
|
2018-01-13 12:45:11 +00:00
|
|
|
|
2018-06-28 15:20:05 +00:00
|
|
|
virtual void refreshDataIdHook();
|
|
|
|
|
2018-01-11 19:33:26 +00:00
|
|
|
private:
|
2018-01-13 12:45:11 +00:00
|
|
|
// This should be called only from previousInBlocksChanged()
|
|
|
|
// to add required bits to the Composer mask
|
2018-01-23 11:47:38 +00:00
|
|
|
// after that always use Has<DateBadge>().
|
2018-01-13 12:45:11 +00:00
|
|
|
void recountDisplayDateInBlocks();
|
|
|
|
|
|
|
|
// This should be called only from previousInBlocksChanged() or when
|
2018-01-23 11:47:38 +00:00
|
|
|
// DateBadge or UnreadBar bit is changed in the Composer mask
|
|
|
|
// then the result should be cached in a client side flag
|
|
|
|
// MTPDmessage_ClientFlag::f_attach_to_previous.
|
2018-01-13 12:45:11 +00:00
|
|
|
void recountAttachToPreviousInBlocks();
|
|
|
|
|
|
|
|
QSize countOptimalSize() final override;
|
|
|
|
QSize countCurrentSize(int newWidth) final override;
|
|
|
|
|
|
|
|
virtual QSize performCountOptimalSize() = 0;
|
|
|
|
virtual QSize performCountCurrentSize(int newWidth) = 0;
|
|
|
|
|
2018-01-17 16:21:01 +00:00
|
|
|
void refreshMedia();
|
2018-01-14 16:02:25 +00:00
|
|
|
|
2018-01-19 17:10:58 +00:00
|
|
|
const not_null<ElementDelegate*> _delegate;
|
2018-01-11 19:33:26 +00:00
|
|
|
const not_null<HistoryItem*> _data;
|
2019-08-02 13:21:09 +00:00
|
|
|
std::unique_ptr<Media> _media;
|
2020-01-14 22:23:16 +00:00
|
|
|
bool _isScheduledUntilOnline = false;
|
2018-02-03 19:52:35 +00:00
|
|
|
const QDateTime _dateTime;
|
2018-01-14 16:02:25 +00:00
|
|
|
|
2018-01-11 19:33:26 +00:00
|
|
|
int _y = 0;
|
2018-02-03 19:52:35 +00:00
|
|
|
Context _context = Context();
|
2018-01-11 19:33:26 +00:00
|
|
|
|
2018-01-13 12:45:11 +00:00
|
|
|
Flags _flags = Flag::NeedsResize;
|
|
|
|
|
2018-01-11 19:33:26 +00:00
|
|
|
HistoryBlock *_block = nullptr;
|
|
|
|
int _indexInBlock = -1;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace HistoryView
|