2
0
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:
John Preston
2016-03-29 20:17:00 +03:00
parent 2c6f74f923
commit 7f6cf32cdd
40 changed files with 1976 additions and 1446 deletions

View File

@@ -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);