mirror of
https://github.com/kotatogram/kotatogram-desktop
synced 2025-08-31 06:35:14 +00:00
ITextLink moved to ClickHandler, TextLinkPtr > ClickHandlerPtr.
Global methods textlnkOver/Down/DrawOver were replaced by static members of ClickHandler, now global state consists of the handler pointer + host pointer, who declares callbacks for the active and pressed handler changed events. This will allow to use ClickHandler from different hosts simultaneously (like HistoryItem / BotDescription / BotKeyboard). Not yet tested.
This commit is contained in:
@@ -309,69 +309,199 @@ private:
|
||||
friend class TextPainter;
|
||||
};
|
||||
|
||||
class ITextLink {
|
||||
public:
|
||||
class ClickHandler;
|
||||
using ClickHandlerPtr = QSharedPointer<ClickHandler>;
|
||||
|
||||
virtual void onClick(Qt::MouseButton) const = 0;
|
||||
virtual const QString &text() const {
|
||||
static const QString _tmp;
|
||||
return _tmp;
|
||||
class ClickHandlerHost {
|
||||
protected:
|
||||
|
||||
virtual void clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) {
|
||||
}
|
||||
virtual const QString &readable() const {
|
||||
static const QString _tmp;
|
||||
return _tmp;
|
||||
}
|
||||
virtual bool fullDisplayed() const {
|
||||
return true;
|
||||
}
|
||||
virtual void setFullDisplayed(bool full) {
|
||||
}
|
||||
virtual QString encoded() const {
|
||||
return QString();
|
||||
}
|
||||
virtual const QLatin1String &type() const = 0;
|
||||
virtual ~ITextLink() {
|
||||
virtual void clickHandlerPressedChanged(const ClickHandlerPtr &action, bool pressed) {
|
||||
}
|
||||
virtual ~ClickHandlerHost() = 0;
|
||||
friend class ClickHandler;
|
||||
|
||||
};
|
||||
|
||||
#define TEXT_LINK_CLASS(ClassName) public: \
|
||||
const QLatin1String &type() const { \
|
||||
static const QLatin1String _type(qstr(#ClassName)); \
|
||||
return _type; \
|
||||
}
|
||||
|
||||
typedef QSharedPointer<ITextLink> TextLinkPtr;
|
||||
|
||||
class TextLink : public ITextLink {
|
||||
TEXT_LINK_CLASS(TextLink)
|
||||
|
||||
class ClickHandler {
|
||||
public:
|
||||
|
||||
TextLink(const QString &url, bool fullDisplayed = true) : _url(url), _fullDisplayed(fullDisplayed) {
|
||||
QUrl u(_url), good(u.isValid() ? u.toEncoded() : QString());
|
||||
_readable = good.isValid() ? good.toDisplayString() : _url;
|
||||
virtual void onClick(Qt::MouseButton) const = 0;
|
||||
|
||||
virtual QString tooltip() const {
|
||||
return QString();
|
||||
}
|
||||
virtual void copyToClipboard() const {
|
||||
}
|
||||
virtual QString copyToClipboardContextItem() const {
|
||||
return QString();
|
||||
}
|
||||
virtual QString text() const {
|
||||
return QString();
|
||||
}
|
||||
virtual QString dragText() const {
|
||||
return text();
|
||||
}
|
||||
|
||||
const QString &text() const {
|
||||
return _url;
|
||||
virtual ~ClickHandler() {
|
||||
}
|
||||
|
||||
void onClick(Qt::MouseButton button) const;
|
||||
// this method should be called on mouse over a click handler
|
||||
// it returns true if something was changed or false otherwise
|
||||
static bool setActive(const ClickHandlerPtr &p, ClickHandlerHost *host = nullptr);
|
||||
|
||||
const QString &readable() const {
|
||||
return _readable;
|
||||
// this method should be called when mouse leaves the host
|
||||
// it returns true if something was changed or false otherwise
|
||||
static bool clearActive(ClickHandlerHost *host = nullptr) {
|
||||
if (host && _activeHost != host) {
|
||||
return false;
|
||||
}
|
||||
return setActive(ClickHandlerPtr(), host);
|
||||
}
|
||||
|
||||
bool fullDisplayed() const {
|
||||
return _fullDisplayed;
|
||||
// this method should be called on mouse pressed
|
||||
static void pressed() {
|
||||
unpressed();
|
||||
if (!_active || !*_active) {
|
||||
return;
|
||||
}
|
||||
if (!_pressed) {
|
||||
_pressed = new ClickHandlerPtr(); // won't be deleted
|
||||
}
|
||||
*_pressed = *_active;
|
||||
if ((_pressedHost = _activeHost)) {
|
||||
_pressedHost->clickHandlerPressedChanged(*_pressed, true);
|
||||
}
|
||||
}
|
||||
|
||||
// this method should be called on mouse released
|
||||
// the activated click handler is returned
|
||||
static ClickHandlerPtr unpressed() {
|
||||
if (_pressed && *_pressed) {
|
||||
bool activated = (_active && *_active == *_pressed);
|
||||
ClickHandlerPtr waspressed = *_pressed;
|
||||
(*_pressed).clear();
|
||||
if (_pressedHost) {
|
||||
_pressedHost->clickHandlerPressedChanged(waspressed, false);
|
||||
_pressedHost = nullptr;
|
||||
}
|
||||
|
||||
if (activated) {
|
||||
return *_active;
|
||||
} else if (_active && *_active && _activeHost) {
|
||||
// emit clickHandlerActiveChanged for current active
|
||||
// click handler, which we didn't emit while we has
|
||||
// a pressed click handler
|
||||
_activeHost->clickHandlerActiveChanged(*_active, true);
|
||||
}
|
||||
}
|
||||
return ClickHandlerPtr();
|
||||
}
|
||||
|
||||
static ClickHandlerPtr getActive() {
|
||||
return _active ? *_active : ClickHandlerPtr();
|
||||
}
|
||||
static ClickHandlerPtr getPressed() {
|
||||
return _pressed ? *_pressed : ClickHandlerPtr();
|
||||
}
|
||||
|
||||
static bool showAsActive(const ClickHandlerPtr &p) {
|
||||
if (!p || !_active || p != *_active) {
|
||||
return false;
|
||||
}
|
||||
return !_pressed || !*_pressed || (p == *_pressed);
|
||||
}
|
||||
static bool showAsPressed(const ClickHandlerPtr &p) {
|
||||
if (!p || !_active || p != *_active) {
|
||||
return false;
|
||||
}
|
||||
return _pressed && (p == *_pressed);
|
||||
}
|
||||
static void hostDestroyed(ClickHandlerHost *host) {
|
||||
if (_activeHost == host) {
|
||||
_activeHost = nullptr;
|
||||
} else if (_pressedHost == host) {
|
||||
_pressedHost = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static ClickHandlerPtr *_active;
|
||||
static ClickHandlerPtr *_pressed;
|
||||
static ClickHandlerHost *_activeHost;
|
||||
static ClickHandlerHost *_pressedHost;
|
||||
|
||||
};
|
||||
|
||||
class LeftButtonClickHandler : public ClickHandler {
|
||||
public:
|
||||
void onClick(Qt::MouseButton button) const override final {
|
||||
if (button != Qt::LeftButton) return;
|
||||
onClickImpl();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void onClickImpl() const = 0;
|
||||
|
||||
};
|
||||
|
||||
class TextClickHandler : public ClickHandler {
|
||||
public:
|
||||
|
||||
TextClickHandler(bool fullDisplayed = true) : _fullDisplayed(fullDisplayed) {
|
||||
}
|
||||
|
||||
void copyToClipboard() const override {
|
||||
QString u = url();
|
||||
if (!u.isEmpty()) {
|
||||
QApplication::clipboard()->setText(u);
|
||||
}
|
||||
}
|
||||
|
||||
QString tooltip() const override {
|
||||
return _fullDisplayed ? QString() : readable();
|
||||
}
|
||||
|
||||
void setFullDisplayed(bool full) {
|
||||
_fullDisplayed = full;
|
||||
}
|
||||
|
||||
QString encoded() const {
|
||||
protected:
|
||||
virtual QString url() const = 0;
|
||||
virtual QString readable() const {
|
||||
return url();
|
||||
}
|
||||
|
||||
bool _fullDisplayed;
|
||||
|
||||
};
|
||||
|
||||
class UrlClickHandler : public TextClickHandler {
|
||||
public:
|
||||
UrlClickHandler(const QString &url, bool fullDisplayed = true) : TextClickHandler(fullDisplayed), _url(url) {
|
||||
QUrl u(_url), good(u.isValid() ? u.toEncoded() : QString());
|
||||
_readable = good.isValid() ? good.toDisplayString() : _url;
|
||||
}
|
||||
QString copyToClipboardContextItem() const override;
|
||||
|
||||
QString text() const override {
|
||||
return _url;
|
||||
}
|
||||
QString dragText() const override {
|
||||
return url();
|
||||
}
|
||||
|
||||
static void doOpen(QString url);
|
||||
void onClick(Qt::MouseButton button) const override {
|
||||
if (button == Qt::LeftButton || button == Qt::MiddleButton) {
|
||||
doOpen(url());
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
QString url() const override {
|
||||
QUrl u(_url), good(u.isValid() ? u.toEncoded() : QString());
|
||||
QString result(good.isValid() ? QString::fromUtf8(good.toEncoded()) : _url);
|
||||
|
||||
@@ -380,46 +510,47 @@ public:
|
||||
}
|
||||
return result;
|
||||
}
|
||||
QString readable() const override {
|
||||
return _readable;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
QString _url, _readable;
|
||||
bool _fullDisplayed;
|
||||
|
||||
};
|
||||
typedef QSharedPointer<TextClickHandler> TextClickHandlerPtr;
|
||||
|
||||
class HiddenUrlClickHandler : public UrlClickHandler {
|
||||
public:
|
||||
HiddenUrlClickHandler(QString url) : UrlClickHandler(url, false) {
|
||||
}
|
||||
void onClick(Qt::MouseButton button) const override;
|
||||
|
||||
};
|
||||
|
||||
class CustomTextLink : public TextLink {
|
||||
class EmailClickHandler : public TextClickHandler {
|
||||
public:
|
||||
|
||||
CustomTextLink(const QString &url) : TextLink(url, false) {
|
||||
EmailClickHandler(const QString &email) : _email(email) {
|
||||
}
|
||||
void onClick(Qt::MouseButton button) const;
|
||||
};
|
||||
QString copyToClipboardContextItem() const override;
|
||||
|
||||
class EmailLink : public ITextLink {
|
||||
TEXT_LINK_CLASS(EmailLink)
|
||||
|
||||
public:
|
||||
|
||||
EmailLink(const QString &email) : _email(email) {
|
||||
}
|
||||
|
||||
const QString &text() const {
|
||||
QString text() const override {
|
||||
return _email;
|
||||
}
|
||||
|
||||
void onClick(Qt::MouseButton button) const;
|
||||
|
||||
const QString &readable() const {
|
||||
return _email;
|
||||
static void doOpen(QString email);
|
||||
void onClick(Qt::MouseButton button) const override {
|
||||
if (button == Qt::LeftButton || button == Qt::MiddleButton) {
|
||||
doOpen(_email);
|
||||
}
|
||||
}
|
||||
|
||||
QString encoded() const {
|
||||
protected:
|
||||
QString url() const override {
|
||||
return _email;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
QString _email;
|
||||
|
||||
};
|
||||
@@ -441,26 +572,20 @@ inline uint qHash(const LocationCoords &t, uint seed = 0) {
|
||||
return qHash(QtPrivate::QHashCombine().operator()(qHash(t.lat), t.lon), seed);
|
||||
}
|
||||
|
||||
class LocationLink : public ITextLink {
|
||||
TEXT_LINK_CLASS(LocationLink)
|
||||
|
||||
class LocationClickHandler : public TextClickHandler {
|
||||
public:
|
||||
|
||||
LocationLink(const LocationCoords &coords) : _coords(coords) {
|
||||
LocationClickHandler(const LocationCoords &coords) : _coords(coords) {
|
||||
setup();
|
||||
}
|
||||
QString copyToClipboardContextItem() const override;
|
||||
|
||||
const QString &text() const {
|
||||
QString text() const override {
|
||||
return _text;
|
||||
}
|
||||
void onClick(Qt::MouseButton button) const override;
|
||||
|
||||
void onClick(Qt::MouseButton button) const;
|
||||
|
||||
const QString &readable() const {
|
||||
return _text;
|
||||
}
|
||||
|
||||
QString encoded() const {
|
||||
protected:
|
||||
QString url() const override {
|
||||
return _text;
|
||||
}
|
||||
|
||||
@@ -472,86 +597,63 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class MentionLink : public ITextLink {
|
||||
TEXT_LINK_CLASS(MentionLink)
|
||||
|
||||
class MentionClickHandler : public TextClickHandler {
|
||||
public:
|
||||
|
||||
MentionLink(const QString &tag) : _tag(tag) {
|
||||
MentionClickHandler(const QString &tag) : _tag(tag) {
|
||||
}
|
||||
QString copyToClipboardContextItem() const override;
|
||||
|
||||
const QString &text() const {
|
||||
QString text() const override {
|
||||
return _tag;
|
||||
}
|
||||
void onClick(Qt::MouseButton button) const override;
|
||||
|
||||
void onClick(Qt::MouseButton button) const;
|
||||
|
||||
const QString &readable() const {
|
||||
return _tag;
|
||||
}
|
||||
|
||||
QString encoded() const {
|
||||
protected:
|
||||
QString url() const override {
|
||||
return _tag;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
QString _tag;
|
||||
|
||||
};
|
||||
|
||||
class HashtagLink : public ITextLink {
|
||||
TEXT_LINK_CLASS(HashtagLink)
|
||||
|
||||
class HashtagClickHandler : public TextClickHandler {
|
||||
public:
|
||||
|
||||
HashtagLink(const QString &tag) : _tag(tag) {
|
||||
HashtagClickHandler(const QString &tag) : _tag(tag) {
|
||||
}
|
||||
QString copyToClipboardContextItem() const override;
|
||||
|
||||
const QString &text() const {
|
||||
QString text() const override {
|
||||
return _tag;
|
||||
}
|
||||
void onClick(Qt::MouseButton button) const override;
|
||||
|
||||
void onClick(Qt::MouseButton button) const;
|
||||
|
||||
const QString &readable() const {
|
||||
return _tag;
|
||||
}
|
||||
|
||||
QString encoded() const {
|
||||
protected:
|
||||
QString url() const override {
|
||||
return _tag;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
QString _tag;
|
||||
|
||||
};
|
||||
|
||||
class BotCommandLink : public ITextLink {
|
||||
TEXT_LINK_CLASS(BotCommandLink)
|
||||
|
||||
class BotCommandClickHandler : public TextClickHandler {
|
||||
public:
|
||||
|
||||
BotCommandLink(const QString &cmd) : _cmd(cmd) {
|
||||
BotCommandClickHandler(const QString &cmd) : _cmd(cmd) {
|
||||
}
|
||||
|
||||
const QString &text() const {
|
||||
QString text() const override {
|
||||
return _cmd;
|
||||
}
|
||||
void onClick(Qt::MouseButton button) const override;
|
||||
|
||||
void onClick(Qt::MouseButton button) const;
|
||||
|
||||
const QString &readable() const {
|
||||
return _cmd;
|
||||
}
|
||||
|
||||
QString encoded() const {
|
||||
protected:
|
||||
QString url() const override {
|
||||
return _cmd;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
QString _cmd;
|
||||
|
||||
};
|
||||
@@ -608,7 +710,7 @@ public:
|
||||
void setRichText(style::font font, const QString &text, TextParseOptions options = _defaultOptions, const TextCustomTagsMap &custom = TextCustomTagsMap());
|
||||
void setMarkedText(style::font font, const QString &text, const EntitiesInText &entities, const TextParseOptions &options = _defaultOptions);
|
||||
|
||||
void setLink(uint16 lnkIndex, const TextLinkPtr &lnk);
|
||||
void setLink(uint16 lnkIndex, const ClickHandlerPtr &lnk);
|
||||
bool hasLinks() const;
|
||||
|
||||
bool hasSkipBlock() const {
|
||||
@@ -641,12 +743,12 @@ public:
|
||||
drawElided(p, rtl() ? right : (outerw - right - width), top, width, lines, align, yFrom, yTo, removeFromEnd, breakEverywhere);
|
||||
}
|
||||
|
||||
const TextLinkPtr &link(int32 x, int32 y, int32 width, style::align align = style::al_left) const;
|
||||
const TextLinkPtr &linkLeft(int32 x, int32 y, int32 width, int32 outerw, style::align align = style::al_left) const {
|
||||
const ClickHandlerPtr &link(int32 x, int32 y, int32 width, style::align align = style::al_left) const;
|
||||
const ClickHandlerPtr &linkLeft(int32 x, int32 y, int32 width, int32 outerw, style::align align = style::al_left) const {
|
||||
return link(rtl() ? (outerw - x - width) : x, y, width, align);
|
||||
}
|
||||
void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, int32 width, style::align align = style::al_left, bool breakEverywhere = false) const;
|
||||
void getStateLeft(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, int32 width, int32 outerw, style::align align = style::al_left, bool breakEverywhere = false) const {
|
||||
void getState(ClickHandlerPtr &lnk, bool &inText, int32 x, int32 y, int32 width, style::align align = style::al_left, bool breakEverywhere = false) const;
|
||||
void getStateLeft(ClickHandlerPtr &lnk, bool &inText, int32 x, int32 y, int32 width, int32 outerw, style::align align = style::al_left, bool breakEverywhere = false) const {
|
||||
return getState(lnk, inText, rtl() ? (outerw - x - width) : x, y, width, align, breakEverywhere);
|
||||
}
|
||||
void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y, int32 width, style::align align = style::al_left) const;
|
||||
@@ -710,7 +812,7 @@ private:
|
||||
typedef QVector<ITextBlock*> TextBlocks;
|
||||
TextBlocks _blocks;
|
||||
|
||||
typedef QVector<TextLinkPtr> TextLinks;
|
||||
typedef QVector<ClickHandlerPtr> TextLinks;
|
||||
TextLinks _links;
|
||||
|
||||
Qt::LayoutDirection _startDir;
|
||||
@@ -737,15 +839,6 @@ inline void textstyleRestore() {
|
||||
textstyleSet(0);
|
||||
}
|
||||
|
||||
// textlnk
|
||||
void textlnkOver(const TextLinkPtr &lnk);
|
||||
const TextLinkPtr &textlnkOver();
|
||||
|
||||
void textlnkDown(const TextLinkPtr &lnk);
|
||||
const TextLinkPtr &textlnkDown();
|
||||
|
||||
bool textlnkDrawOver(const TextLinkPtr &lnk);
|
||||
|
||||
// textcmd
|
||||
QString textcmdSkipBlock(ushort w, ushort h);
|
||||
QString textcmdStartLink(ushort lnkIndex);
|
||||
|
Reference in New Issue
Block a user