2014-05-30 08:53:19 +00:00
|
|
|
/*
|
|
|
|
This file is part of Telegram Desktop,
|
2018-01-03 10:23:14 +00:00
|
|
|
the official desktop application for the Telegram messaging service.
|
2014-05-30 08:53:19 +00:00
|
|
|
|
2018-01-03 10:23:14 +00:00
|
|
|
For license and copyright information please follow this link:
|
|
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
2014-05-30 08:53:19 +00:00
|
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
|
2017-11-03 12:03:00 +00:00
|
|
|
#include "ui/rp_widget.h"
|
2019-02-04 13:34:50 +00:00
|
|
|
#include "ui/effects/animations.h"
|
2016-11-15 11:56:49 +00:00
|
|
|
#include "styles/style_widgets.h"
|
|
|
|
|
|
|
|
class UserData;
|
|
|
|
|
|
|
|
namespace Ui {
|
|
|
|
|
2018-05-25 20:31:18 +00:00
|
|
|
class PopupMenu;
|
|
|
|
|
2018-05-21 21:31:46 +00:00
|
|
|
void InsertEmojiAtCursor(QTextCursor cursor, EmojiPtr emoji);
|
2016-11-15 11:56:49 +00:00
|
|
|
|
2018-05-20 17:42:30 +00:00
|
|
|
struct InstantReplaces {
|
|
|
|
struct Node {
|
|
|
|
QString text;
|
|
|
|
std::map<QChar, Node> tail;
|
|
|
|
};
|
|
|
|
|
|
|
|
void add(const QString &what, const QString &with);
|
|
|
|
|
|
|
|
static const InstantReplaces &Default();
|
|
|
|
|
|
|
|
int maxLength = 0;
|
|
|
|
Node reverseMap;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2018-09-29 12:18:26 +00:00
|
|
|
enum class InputSubmitSettings {
|
|
|
|
Enter,
|
|
|
|
CtrlEnter,
|
|
|
|
Both,
|
|
|
|
None,
|
|
|
|
};
|
|
|
|
|
2017-02-11 11:24:37 +00:00
|
|
|
class FlatInput : public TWidgetHelper<QLineEdit>, private base::Subscriber {
|
2019-01-18 11:26:43 +00:00
|
|
|
// The Q_OBJECT meta info is used for qobject_cast!
|
2014-05-30 08:53:19 +00:00
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
public:
|
2017-10-30 19:24:20 +00:00
|
|
|
FlatInput(
|
|
|
|
QWidget *parent,
|
|
|
|
const style::FlatInput &st,
|
2018-06-04 15:35:11 +00:00
|
|
|
Fn<QString()> placeholderFactory = nullptr,
|
2017-10-30 19:24:20 +00:00
|
|
|
const QString &val = QString());
|
2014-05-30 08:53:19 +00:00
|
|
|
|
|
|
|
void updatePlaceholder();
|
2018-06-04 15:35:11 +00:00
|
|
|
void setPlaceholder(Fn<QString()> placeholderFactory);
|
2015-07-21 14:55:23 +00:00
|
|
|
QRect placeholderRect() const;
|
2014-05-30 08:53:19 +00:00
|
|
|
|
2017-08-06 17:11:22 +00:00
|
|
|
void setTextMrg(const QMargins &textMrg);
|
2014-05-30 08:53:19 +00:00
|
|
|
QRect getTextRect() const;
|
|
|
|
|
2016-04-14 13:03:03 +00:00
|
|
|
QSize sizeHint() const override;
|
|
|
|
QSize minimumSizeHint() const override;
|
2014-05-30 08:53:19 +00:00
|
|
|
|
2014-06-20 07:06:21 +00:00
|
|
|
void customUpDown(bool isCustom);
|
2015-10-06 19:49:23 +00:00
|
|
|
const QString &getLastText() const {
|
|
|
|
return _oldtext;
|
2015-09-03 13:15:07 +00:00
|
|
|
}
|
2014-06-20 07:06:21 +00:00
|
|
|
|
2016-11-24 19:28:23 +00:00
|
|
|
public slots:
|
2014-05-30 08:53:19 +00:00
|
|
|
void onTextChange(const QString &text);
|
|
|
|
void onTextEdited();
|
|
|
|
|
|
|
|
void onTouchTimer();
|
|
|
|
|
|
|
|
signals:
|
|
|
|
void changed();
|
|
|
|
void cancelled();
|
2018-05-31 12:20:28 +00:00
|
|
|
void submitted(Qt::KeyboardModifiers);
|
2014-05-30 08:53:19 +00:00
|
|
|
void focused();
|
|
|
|
void blurred();
|
|
|
|
|
|
|
|
protected:
|
2016-10-18 10:32:33 +00:00
|
|
|
bool event(QEvent *e) override;
|
|
|
|
void touchEvent(QTouchEvent *e);
|
|
|
|
void paintEvent(QPaintEvent *e) override;
|
|
|
|
void focusInEvent(QFocusEvent *e) override;
|
|
|
|
void focusOutEvent(QFocusEvent *e) override;
|
|
|
|
void keyPressEvent(QKeyEvent *e) override;
|
|
|
|
void resizeEvent(QResizeEvent *e) override;
|
|
|
|
void contextMenuEvent(QContextMenuEvent *e) override;
|
2017-05-26 15:50:25 +00:00
|
|
|
void inputMethodEvent(QInputMethodEvent *e) override;
|
2016-10-18 10:32:33 +00:00
|
|
|
|
2015-10-06 19:49:23 +00:00
|
|
|
virtual void correctValue(const QString &was, QString &now);
|
2014-05-30 08:53:19 +00:00
|
|
|
|
2015-07-21 14:55:23 +00:00
|
|
|
style::font phFont() {
|
|
|
|
return _st.font;
|
|
|
|
}
|
|
|
|
|
2016-12-02 19:16:35 +00:00
|
|
|
void phPrepare(Painter &p, float64 placeholderFocused);
|
2015-07-21 14:55:23 +00:00
|
|
|
|
2014-05-30 08:53:19 +00:00
|
|
|
private:
|
2016-12-31 13:34:41 +00:00
|
|
|
void updatePalette();
|
2017-05-30 15:21:05 +00:00
|
|
|
void refreshPlaceholder();
|
2014-05-30 08:53:19 +00:00
|
|
|
|
2017-05-30 15:21:05 +00:00
|
|
|
QString _oldtext;
|
|
|
|
QString _placeholder;
|
2018-06-04 15:35:11 +00:00
|
|
|
Fn<QString()> _placeholderFactory;
|
2014-05-30 08:53:19 +00:00
|
|
|
|
2016-12-02 19:16:35 +00:00
|
|
|
bool _customUpDown = false;
|
2014-06-20 07:06:21 +00:00
|
|
|
|
2017-01-14 18:50:16 +00:00
|
|
|
bool _focused = false;
|
2016-12-02 19:16:35 +00:00
|
|
|
bool _placeholderVisible = true;
|
2019-02-04 13:34:50 +00:00
|
|
|
Animations::Simple _a_placeholderFocused;
|
|
|
|
Animations::Simple _a_placeholderVisible;
|
2017-05-26 15:50:25 +00:00
|
|
|
bool _lastPreEditTextNotEmpty = false;
|
2014-05-30 08:53:19 +00:00
|
|
|
|
2016-11-15 11:56:49 +00:00
|
|
|
const style::FlatInput &_st;
|
2017-08-06 17:11:22 +00:00
|
|
|
QMargins _textMrg;
|
2014-05-30 08:53:19 +00:00
|
|
|
|
|
|
|
QTimer _touchTimer;
|
|
|
|
bool _touchPress, _touchRightButton, _touchMove;
|
|
|
|
QPoint _touchStart;
|
|
|
|
};
|
2015-06-19 17:04:09 +00:00
|
|
|
|
2018-05-20 17:42:30 +00:00
|
|
|
class InputField : public RpWidget, private base::Subscriber {
|
2015-10-06 19:49:23 +00:00
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
public:
|
2018-05-20 17:42:30 +00:00
|
|
|
enum class Mode {
|
|
|
|
SingleLine,
|
|
|
|
MultiLine,
|
|
|
|
};
|
|
|
|
using TagList = TextWithTags::Tags;
|
|
|
|
|
2018-05-31 18:28:37 +00:00
|
|
|
struct MarkdownTag {
|
2018-06-07 19:00:46 +00:00
|
|
|
// With each emoji being QChar::ObjectReplacementCharacter.
|
|
|
|
int internalStart = 0;
|
|
|
|
int internalLength = 0;
|
|
|
|
|
|
|
|
// Adjusted by emoji to match _lastTextWithTags.
|
|
|
|
int adjustedStart = 0;
|
|
|
|
int adjustedLength = 0;
|
|
|
|
|
2018-05-31 18:28:37 +00:00
|
|
|
bool closed = false;
|
2018-05-22 19:09:13 +00:00
|
|
|
QString tag;
|
|
|
|
};
|
|
|
|
static const QString kTagBold;
|
|
|
|
static const QString kTagItalic;
|
|
|
|
static const QString kTagCode;
|
|
|
|
static const QString kTagPre;
|
|
|
|
|
2018-05-20 17:42:30 +00:00
|
|
|
InputField(
|
2017-11-10 15:45:10 +00:00
|
|
|
QWidget *parent,
|
|
|
|
const style::InputField &st,
|
2018-06-04 15:35:11 +00:00
|
|
|
Fn<QString()> placeholderFactory,
|
2018-05-20 17:42:30 +00:00
|
|
|
const QString &value = QString());
|
|
|
|
InputField(
|
|
|
|
QWidget *parent,
|
|
|
|
const style::InputField &st,
|
|
|
|
Mode mode,
|
2018-06-04 15:35:11 +00:00
|
|
|
Fn<QString()> placeholderFactory,
|
2018-05-20 17:42:30 +00:00
|
|
|
const QString &value);
|
|
|
|
InputField(
|
|
|
|
QWidget *parent,
|
|
|
|
const style::InputField &st,
|
|
|
|
Mode mode = Mode::SingleLine,
|
2018-06-04 15:35:11 +00:00
|
|
|
Fn<QString()> placeholderFactory = nullptr,
|
2018-05-20 17:42:30 +00:00
|
|
|
const TextWithTags &value = TextWithTags());
|
2015-10-06 19:49:23 +00:00
|
|
|
|
|
|
|
void showError();
|
|
|
|
|
2018-05-21 21:31:46 +00:00
|
|
|
void setMaxLength(int maxLength);
|
|
|
|
void setMinHeight(int minHeight);
|
|
|
|
void setMaxHeight(int maxHeight);
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2018-05-21 21:31:46 +00:00
|
|
|
const TextWithTags &getTextWithTags() const {
|
|
|
|
return _lastTextWithTags;
|
|
|
|
}
|
2018-05-31 18:28:37 +00:00
|
|
|
const std::vector<MarkdownTag> &getMarkdownTags() const {
|
|
|
|
return _lastMarkdownTags;
|
|
|
|
}
|
2018-05-21 21:31:46 +00:00
|
|
|
TextWithTags getTextWithTagsPart(int start, int end = -1) const;
|
2018-05-31 18:28:37 +00:00
|
|
|
TextWithTags getTextWithAppliedMarkdown() const;
|
2018-05-21 21:31:46 +00:00
|
|
|
void insertTag(const QString &text, QString tagId = QString());
|
|
|
|
bool empty() const {
|
|
|
|
return _lastTextWithTags.text.isEmpty();
|
|
|
|
}
|
2018-05-20 17:42:30 +00:00
|
|
|
enum class HistoryAction {
|
|
|
|
NewEntry,
|
|
|
|
MergeEntry,
|
|
|
|
Clear,
|
|
|
|
};
|
|
|
|
void setTextWithTags(
|
|
|
|
const TextWithTags &textWithTags,
|
|
|
|
HistoryAction historyAction = HistoryAction::NewEntry);
|
|
|
|
|
2018-05-21 21:31:46 +00:00
|
|
|
// If you need to make some preparations of tags before putting them to QMimeData
|
|
|
|
// (and then to clipboard or to drag-n-drop object), here is a strategy for that.
|
|
|
|
class TagMimeProcessor {
|
|
|
|
public:
|
|
|
|
virtual QString mimeTagFromTag(const QString &tagId) = 0;
|
|
|
|
virtual QString tagFromMimeTag(const QString &mimeTag) = 0;
|
|
|
|
virtual ~TagMimeProcessor() {
|
|
|
|
}
|
|
|
|
};
|
|
|
|
void setTagMimeProcessor(std::unique_ptr<TagMimeProcessor> &&processor);
|
|
|
|
|
2018-05-26 14:58:21 +00:00
|
|
|
struct EditLinkSelection {
|
|
|
|
int from = 0;
|
|
|
|
int till = 0;
|
|
|
|
};
|
|
|
|
enum class EditLinkAction {
|
|
|
|
Check,
|
|
|
|
Edit,
|
|
|
|
};
|
|
|
|
void setEditLinkCallback(
|
2018-06-04 15:35:11 +00:00
|
|
|
Fn<bool(
|
2018-05-26 14:58:21 +00:00
|
|
|
EditLinkSelection selection,
|
|
|
|
QString text,
|
|
|
|
QString link,
|
|
|
|
EditLinkAction action)> callback);
|
|
|
|
|
2018-05-22 19:09:13 +00:00
|
|
|
void setAdditionalMargin(int margin);
|
|
|
|
|
2018-05-20 17:42:30 +00:00
|
|
|
void setInstantReplaces(const InstantReplaces &replaces);
|
2018-05-24 13:03:21 +00:00
|
|
|
void setInstantReplacesEnabled(rpl::producer<bool> enabled);
|
|
|
|
void setMarkdownReplacesEnabled(rpl::producer<bool> enabled);
|
2019-01-21 07:02:20 +00:00
|
|
|
void commitInstantReplacement(int from, int till, const QString &with);
|
2018-05-26 14:58:21 +00:00
|
|
|
void commitMarkdownLinkEdit(
|
|
|
|
EditLinkSelection selection,
|
|
|
|
const QString &text,
|
|
|
|
const QString &link);
|
|
|
|
static bool IsValidMarkdownLink(const QString &link);
|
2018-05-20 17:42:30 +00:00
|
|
|
|
2015-10-06 19:49:23 +00:00
|
|
|
const QString &getLastText() const {
|
2018-05-20 17:42:30 +00:00
|
|
|
return _lastTextWithTags.text;
|
2015-10-06 19:49:23 +00:00
|
|
|
}
|
2018-05-21 21:31:46 +00:00
|
|
|
void setPlaceholder(
|
2018-06-04 15:35:11 +00:00
|
|
|
Fn<QString()> placeholderFactory,
|
2018-05-21 21:31:46 +00:00
|
|
|
int afterSymbols = 0);
|
2018-05-20 17:42:30 +00:00
|
|
|
void setPlaceholderHidden(bool forcePlaceholderHidden);
|
2016-12-13 17:07:56 +00:00
|
|
|
void setDisplayFocused(bool focused);
|
2017-09-30 19:20:40 +00:00
|
|
|
void finishAnimating();
|
2016-12-20 13:03:51 +00:00
|
|
|
void setFocusFast() {
|
|
|
|
setDisplayFocused(true);
|
|
|
|
setFocus();
|
|
|
|
}
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2016-10-22 14:35:37 +00:00
|
|
|
QSize sizeHint() const override;
|
|
|
|
QSize minimumSizeHint() const override;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
|
|
|
bool hasText() const;
|
2018-05-20 17:42:30 +00:00
|
|
|
void selectAll();
|
2015-10-06 19:49:23 +00:00
|
|
|
|
|
|
|
bool isUndoAvailable() const;
|
|
|
|
bool isRedoAvailable() const;
|
|
|
|
|
2018-09-29 12:18:26 +00:00
|
|
|
using SubmitSettings = InputSubmitSettings;
|
2018-05-21 21:31:46 +00:00
|
|
|
void setSubmitSettings(SubmitSettings settings);
|
2018-10-08 14:08:17 +00:00
|
|
|
static bool ShouldSubmit(
|
|
|
|
SubmitSettings settings,
|
|
|
|
Qt::KeyboardModifiers modifiers);
|
2015-10-06 19:49:23 +00:00
|
|
|
void customUpDown(bool isCustom);
|
2018-05-24 13:03:21 +00:00
|
|
|
void customTab(bool isCustom);
|
2018-04-10 16:22:27 +00:00
|
|
|
int borderAnimationStart() const;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2018-05-21 21:31:46 +00:00
|
|
|
not_null<QTextDocument*> document();
|
|
|
|
not_null<const QTextDocument*> document() const;
|
2018-05-20 17:42:30 +00:00
|
|
|
void setTextCursor(const QTextCursor &cursor);
|
|
|
|
void setCursorPosition(int position);
|
|
|
|
QTextCursor textCursor() const;
|
|
|
|
void setText(const QString &text);
|
|
|
|
void clear();
|
|
|
|
bool hasFocus() const;
|
|
|
|
void setFocus();
|
|
|
|
void clearFocus();
|
2018-11-14 08:33:09 +00:00
|
|
|
void ensureCursorVisible();
|
2018-05-21 21:31:46 +00:00
|
|
|
not_null<QTextEdit*> rawTextEdit();
|
|
|
|
not_null<const QTextEdit*> rawTextEdit() const;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2017-12-29 17:02:23 +00:00
|
|
|
enum class MimeAction {
|
|
|
|
Check,
|
|
|
|
Insert,
|
|
|
|
};
|
2018-06-04 15:35:11 +00:00
|
|
|
using MimeDataHook = Fn<bool(
|
2017-12-29 17:02:23 +00:00
|
|
|
not_null<const QMimeData*> data,
|
|
|
|
MimeAction action)>;
|
|
|
|
void setMimeDataHook(MimeDataHook hook) {
|
|
|
|
_mimeDataHook = std::move(hook);
|
|
|
|
}
|
|
|
|
|
2018-05-21 21:31:46 +00:00
|
|
|
const rpl::variable<int> &scrollTop() const;
|
|
|
|
int scrollTopMax() const;
|
|
|
|
void scrollTo(int top);
|
|
|
|
|
2018-07-18 19:22:07 +00:00
|
|
|
~InputField();
|
|
|
|
|
2016-12-09 18:56:01 +00:00
|
|
|
private slots:
|
2015-10-06 19:49:23 +00:00
|
|
|
void onTouchTimer();
|
|
|
|
|
|
|
|
void onDocumentContentsChange(int position, int charsRemoved, int charsAdded);
|
2018-05-27 10:48:30 +00:00
|
|
|
void onCursorPositionChanged();
|
2015-10-06 19:49:23 +00:00
|
|
|
|
|
|
|
void onUndoAvailable(bool avail);
|
|
|
|
void onRedoAvailable(bool avail);
|
|
|
|
|
2016-12-09 18:56:01 +00:00
|
|
|
void onFocusInner();
|
|
|
|
|
2015-10-06 19:49:23 +00:00
|
|
|
signals:
|
|
|
|
void changed();
|
2018-05-31 12:20:28 +00:00
|
|
|
void submitted(Qt::KeyboardModifiers);
|
2015-10-06 19:49:23 +00:00
|
|
|
void cancelled();
|
|
|
|
void tabbed();
|
|
|
|
void focused();
|
|
|
|
void blurred();
|
|
|
|
void resized();
|
|
|
|
|
|
|
|
protected:
|
2016-12-09 18:56:01 +00:00
|
|
|
void startPlaceholderAnimation();
|
|
|
|
void startBorderAnimation();
|
|
|
|
|
2016-10-20 15:26:55 +00:00
|
|
|
void paintEvent(QPaintEvent *e) override;
|
|
|
|
void focusInEvent(QFocusEvent *e) override;
|
|
|
|
void mousePressEvent(QMouseEvent *e) override;
|
|
|
|
void contextMenuEvent(QContextMenuEvent *e) override;
|
|
|
|
void resizeEvent(QResizeEvent *e) override;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2016-10-20 15:26:55 +00:00
|
|
|
private:
|
2018-05-20 17:42:30 +00:00
|
|
|
class Inner;
|
2016-10-21 12:28:26 +00:00
|
|
|
friend class Inner;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2018-05-22 19:09:13 +00:00
|
|
|
void handleContentsChanged();
|
2018-05-20 17:42:30 +00:00
|
|
|
bool viewportEventInner(QEvent *e);
|
|
|
|
void handleTouchEvent(QTouchEvent *e);
|
|
|
|
|
2016-12-31 13:34:41 +00:00
|
|
|
void updatePalette();
|
2017-05-30 15:21:05 +00:00
|
|
|
void refreshPlaceholder();
|
2018-05-21 21:31:46 +00:00
|
|
|
int placeholderSkipWidth() const;
|
2016-12-31 13:34:41 +00:00
|
|
|
|
2016-12-09 18:56:01 +00:00
|
|
|
bool heightAutoupdated();
|
|
|
|
void checkContentHeight();
|
|
|
|
void setErrorShown(bool error);
|
|
|
|
|
2018-05-20 17:42:30 +00:00
|
|
|
void focusInEventInner(QFocusEvent *e);
|
|
|
|
void focusOutEventInner(QFocusEvent *e);
|
2016-12-13 17:07:56 +00:00
|
|
|
void setFocused(bool focused);
|
2018-05-20 17:42:30 +00:00
|
|
|
void keyPressEventInner(QKeyEvent *e);
|
|
|
|
void contextMenuEventInner(QContextMenuEvent *e);
|
2018-05-21 21:31:46 +00:00
|
|
|
void dropEventInner(QDropEvent *e);
|
2018-05-25 18:04:07 +00:00
|
|
|
void inputMethodEventInner(QInputMethodEvent *e);
|
2018-05-20 17:42:30 +00:00
|
|
|
|
|
|
|
QMimeData *createMimeDataFromSelectionInner() const;
|
|
|
|
bool canInsertFromMimeDataInner(const QMimeData *source) const;
|
|
|
|
void insertFromMimeDataInner(const QMimeData *source);
|
2018-05-26 14:58:21 +00:00
|
|
|
TextWithTags getTextWithTagsSelected() const;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2018-05-21 21:31:46 +00:00
|
|
|
// "start" and "end" are in coordinates of text where emoji are replaced
|
|
|
|
// by ObjectReplacementCharacter. If "end" = -1 means get text till the end.
|
|
|
|
QString getTextPart(
|
|
|
|
int start,
|
|
|
|
int end,
|
|
|
|
TagList &outTagsList,
|
2018-05-22 19:09:13 +00:00
|
|
|
bool &outTagsChanged,
|
2018-05-31 18:28:37 +00:00
|
|
|
std::vector<MarkdownTag> *outMarkdownTags = nullptr) const;
|
2018-05-21 21:31:46 +00:00
|
|
|
|
|
|
|
// After any characters added we must postprocess them. This includes:
|
|
|
|
// 1. Replacing font family to semibold for ~ characters, if we used Open Sans 13px.
|
|
|
|
// 2. Replacing font family from semibold for all non-~ characters, if we used ...
|
|
|
|
// 3. Replacing emoji code sequences by ObjectReplacementCharacters with emoji pics.
|
|
|
|
// 4. Interrupting tags in which the text was inserted by any char except a letter.
|
|
|
|
// 5. Applying tags from "_insertedTags" in case we pasted text with tags, not just text.
|
|
|
|
// Rule 4 applies only if we inserted chars not in the middle of a tag (but at the end).
|
|
|
|
void processFormatting(int changedPosition, int changedEnd);
|
|
|
|
|
|
|
|
void chopByMaxLength(int insertPosition, int insertLength);
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2018-05-22 19:09:13 +00:00
|
|
|
bool processMarkdownReplaces(const QString &appended);
|
2018-05-31 18:28:37 +00:00
|
|
|
//bool processMarkdownReplace(const QString &tag);
|
2018-05-26 14:58:21 +00:00
|
|
|
void addMarkdownActions(not_null<QMenu*> menu, QContextMenuEvent *e);
|
2018-05-25 20:31:18 +00:00
|
|
|
void addMarkdownMenuAction(
|
|
|
|
not_null<QMenu*> menu,
|
|
|
|
not_null<QAction*> action);
|
|
|
|
bool handleMarkdownKey(QKeyEvent *e);
|
2018-05-22 19:09:13 +00:00
|
|
|
|
2018-05-20 17:42:30 +00:00
|
|
|
// We don't want accidentally detach InstantReplaces map.
|
|
|
|
// So we access it only by const reference from this method.
|
|
|
|
const InstantReplaces &instantReplaces() const;
|
2018-05-22 19:09:13 +00:00
|
|
|
void processInstantReplaces(const QString &appended);
|
2018-05-20 17:42:30 +00:00
|
|
|
void applyInstantReplace(const QString &what, const QString &with);
|
2018-05-22 19:09:13 +00:00
|
|
|
|
2018-05-26 14:58:21 +00:00
|
|
|
struct EditLinkData {
|
|
|
|
int from = 0;
|
|
|
|
int till = 0;
|
|
|
|
QString link;
|
|
|
|
};
|
|
|
|
EditLinkData selectionEditLinkData(EditLinkSelection selection) const;
|
|
|
|
EditLinkSelection editLinkSelection(QContextMenuEvent *e) const;
|
|
|
|
void editMarkdownLink(EditLinkSelection selection);
|
|
|
|
|
2019-01-21 07:02:20 +00:00
|
|
|
void commitInstantReplacement(
|
|
|
|
int from,
|
|
|
|
int till,
|
|
|
|
const QString &with,
|
|
|
|
std::optional<QString> checkOriginal,
|
|
|
|
bool checkIfInMonospace);
|
|
|
|
bool commitMarkdownReplacement(
|
|
|
|
int from,
|
|
|
|
int till,
|
|
|
|
const QString &tag,
|
|
|
|
const QString &edge = QString());
|
|
|
|
void toggleSelectionMarkdown(const QString &tag);
|
|
|
|
void clearSelectionMarkdown();
|
|
|
|
|
2018-05-22 19:09:13 +00:00
|
|
|
bool revertFormatReplace();
|
2018-05-20 17:42:30 +00:00
|
|
|
|
2018-05-31 18:28:37 +00:00
|
|
|
void highlightMarkdown();
|
|
|
|
|
2016-12-09 18:56:01 +00:00
|
|
|
const style::InputField &_st;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2018-05-20 17:42:30 +00:00
|
|
|
Mode _mode = Mode::SingleLine;
|
2016-12-09 18:56:01 +00:00
|
|
|
int _maxLength = -1;
|
2018-05-21 21:31:46 +00:00
|
|
|
int _minHeight = -1;
|
|
|
|
int _maxHeight = -1;
|
2018-05-20 17:42:30 +00:00
|
|
|
bool _forcePlaceholderHidden = false;
|
2018-05-25 17:52:27 +00:00
|
|
|
bool _reverseMarkdownReplacement = false;
|
2016-12-09 18:56:01 +00:00
|
|
|
|
2018-07-18 19:22:07 +00:00
|
|
|
const std::unique_ptr<Inner> _inner;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2018-05-20 17:42:30 +00:00
|
|
|
TextWithTags _lastTextWithTags;
|
2018-05-31 18:28:37 +00:00
|
|
|
std::vector<MarkdownTag> _lastMarkdownTags;
|
2018-05-25 18:04:07 +00:00
|
|
|
QString _lastPreEditText;
|
2018-06-04 15:35:11 +00:00
|
|
|
Fn<bool(
|
2018-05-26 14:58:21 +00:00
|
|
|
EditLinkSelection selection,
|
|
|
|
QString text,
|
|
|
|
QString link,
|
|
|
|
EditLinkAction action)> _editLinkCallback;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2018-05-21 21:31:46 +00:00
|
|
|
// Tags list which we should apply while setText() call or insert from mime data.
|
|
|
|
TagList _insertedTags;
|
|
|
|
bool _insertedTagsAreFromMime;
|
|
|
|
|
|
|
|
// Override insert position and charsAdded from complex text editing
|
|
|
|
// (like drag-n-drop in the same text edit field).
|
|
|
|
int _realInsertPosition = -1;
|
|
|
|
int _realCharsAdded = 0;
|
|
|
|
|
|
|
|
std::unique_ptr<TagMimeProcessor> _tagMimeProcessor;
|
|
|
|
|
|
|
|
SubmitSettings _submitSettings = SubmitSettings::Enter;
|
2018-05-22 19:09:13 +00:00
|
|
|
bool _markdownEnabled = false;
|
2016-12-09 18:56:01 +00:00
|
|
|
bool _undoAvailable = false;
|
|
|
|
bool _redoAvailable = false;
|
2018-05-21 21:31:46 +00:00
|
|
|
bool _inDrop = false;
|
2016-12-09 18:56:01 +00:00
|
|
|
bool _inHeightCheck = false;
|
2018-05-22 19:09:13 +00:00
|
|
|
int _additionalMargin = 0;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2016-12-09 18:56:01 +00:00
|
|
|
bool _customUpDown = false;
|
2018-05-24 13:03:21 +00:00
|
|
|
bool _customTab = false;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2016-12-09 18:56:01 +00:00
|
|
|
QString _placeholder;
|
2018-06-04 15:35:11 +00:00
|
|
|
Fn<QString()> _placeholderFactory;
|
2018-05-21 21:31:46 +00:00
|
|
|
int _placeholderAfterSymbols = 0;
|
2016-12-09 18:56:01 +00:00
|
|
|
Animation _a_placeholderShifted;
|
|
|
|
bool _placeholderShifted = false;
|
|
|
|
QPainterPath _placeholderPath;
|
2016-12-05 11:01:08 +00:00
|
|
|
|
2016-12-09 18:56:01 +00:00
|
|
|
Animation _a_borderShown;
|
|
|
|
int _borderAnimationStart = 0;
|
|
|
|
Animation _a_borderOpacity;
|
|
|
|
bool _borderVisible = false;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2016-12-09 18:56:01 +00:00
|
|
|
Animation _a_focused;
|
|
|
|
Animation _a_error;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2016-12-09 18:56:01 +00:00
|
|
|
bool _focused = false;
|
|
|
|
bool _error = false;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
|
|
|
QTimer _touchTimer;
|
2016-12-09 18:56:01 +00:00
|
|
|
bool _touchPress = false;
|
|
|
|
bool _touchRightButton = false;
|
|
|
|
bool _touchMove = false;
|
2015-10-06 19:49:23 +00:00
|
|
|
QPoint _touchStart;
|
|
|
|
|
2016-12-09 18:56:01 +00:00
|
|
|
bool _correcting = false;
|
2017-12-29 17:02:23 +00:00
|
|
|
MimeDataHook _mimeDataHook;
|
2018-05-25 20:31:18 +00:00
|
|
|
base::unique_qptr<Ui::PopupMenu> _contextMenu;
|
2016-10-20 15:26:55 +00:00
|
|
|
|
2018-05-20 17:42:30 +00:00
|
|
|
QTextCharFormat _defaultCharFormat;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2018-05-21 21:31:46 +00:00
|
|
|
rpl::variable<int> _scrollTop;
|
|
|
|
|
2018-05-20 17:42:30 +00:00
|
|
|
InstantReplaces _mutableInstantReplaces;
|
|
|
|
bool _instantReplacesEnabled = true;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
|
|
|
};
|
|
|
|
|
2017-11-10 15:45:10 +00:00
|
|
|
class MaskedInputField
|
|
|
|
: public RpWidgetWrap<QLineEdit>
|
|
|
|
, private base::Subscriber {
|
2019-01-18 11:26:43 +00:00
|
|
|
// The Q_OBJECT meta info is used for qobject_cast!
|
2015-10-06 19:49:23 +00:00
|
|
|
Q_OBJECT
|
|
|
|
|
2017-11-10 15:45:10 +00:00
|
|
|
using Parent = RpWidgetWrap<QLineEdit>;
|
2015-10-06 19:49:23 +00:00
|
|
|
public:
|
2018-06-04 15:35:11 +00:00
|
|
|
MaskedInputField(QWidget *parent, const style::InputField &st, Fn<QString()> placeholderFactory = Fn<QString()>(), const QString &val = QString());
|
2015-10-06 19:49:23 +00:00
|
|
|
|
|
|
|
void showError();
|
|
|
|
|
|
|
|
QRect getTextRect() const;
|
|
|
|
|
2016-04-14 13:03:03 +00:00
|
|
|
QSize sizeHint() const override;
|
|
|
|
QSize minimumSizeHint() const override;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
|
|
|
void customUpDown(bool isCustom);
|
2018-04-10 16:22:27 +00:00
|
|
|
int borderAnimationStart() const;
|
|
|
|
|
2015-10-06 19:49:23 +00:00
|
|
|
const QString &getLastText() const {
|
|
|
|
return _oldtext;
|
|
|
|
}
|
2018-06-04 15:35:11 +00:00
|
|
|
void setPlaceholder(Fn<QString()> placeholderFactory);
|
2016-12-09 18:56:01 +00:00
|
|
|
void setPlaceholderHidden(bool forcePlaceholderHidden);
|
2016-12-13 17:07:56 +00:00
|
|
|
void setDisplayFocused(bool focused);
|
2017-09-30 19:20:40 +00:00
|
|
|
void finishAnimating();
|
2016-12-20 13:03:51 +00:00
|
|
|
void setFocusFast() {
|
|
|
|
setDisplayFocused(true);
|
|
|
|
setFocus();
|
|
|
|
}
|
2016-12-09 18:56:01 +00:00
|
|
|
|
2015-10-06 19:49:23 +00:00
|
|
|
void setText(const QString &text) {
|
|
|
|
QLineEdit::setText(text);
|
2016-12-09 18:56:01 +00:00
|
|
|
startPlaceholderAnimation();
|
2015-10-06 19:49:23 +00:00
|
|
|
}
|
|
|
|
void clear() {
|
|
|
|
QLineEdit::clear();
|
2016-12-09 18:56:01 +00:00
|
|
|
startPlaceholderAnimation();
|
2015-10-06 19:49:23 +00:00
|
|
|
}
|
|
|
|
|
2016-11-24 19:28:23 +00:00
|
|
|
public slots:
|
2015-10-06 19:49:23 +00:00
|
|
|
void onTextChange(const QString &text);
|
|
|
|
void onCursorPositionChanged(int oldPosition, int position);
|
|
|
|
|
|
|
|
void onTextEdited();
|
|
|
|
|
|
|
|
void onTouchTimer();
|
|
|
|
|
|
|
|
signals:
|
|
|
|
void changed();
|
|
|
|
void cancelled();
|
2018-05-31 12:20:28 +00:00
|
|
|
void submitted(Qt::KeyboardModifiers);
|
2015-10-06 19:49:23 +00:00
|
|
|
void focused();
|
|
|
|
void blurred();
|
|
|
|
|
|
|
|
protected:
|
2017-05-26 15:50:25 +00:00
|
|
|
QString getDisplayedText() const {
|
|
|
|
auto result = getLastText();
|
|
|
|
if (!_lastPreEditText.isEmpty()) {
|
|
|
|
result = result.mid(0, _oldcursor) + _lastPreEditText + result.mid(_oldcursor);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2016-12-09 18:56:01 +00:00
|
|
|
void startBorderAnimation();
|
|
|
|
void startPlaceholderAnimation();
|
|
|
|
|
2017-11-10 15:45:10 +00:00
|
|
|
bool eventHook(QEvent *e) override;
|
2016-11-24 19:28:23 +00:00
|
|
|
void touchEvent(QTouchEvent *e);
|
|
|
|
void paintEvent(QPaintEvent *e) override;
|
|
|
|
void focusInEvent(QFocusEvent *e) override;
|
|
|
|
void focusOutEvent(QFocusEvent *e) override;
|
|
|
|
void keyPressEvent(QKeyEvent *e) override;
|
|
|
|
void resizeEvent(QResizeEvent *e) override;
|
|
|
|
void contextMenuEvent(QContextMenuEvent *e) override;
|
2017-05-26 15:50:25 +00:00
|
|
|
void inputMethodEvent(QInputMethodEvent *e) override;
|
2016-11-24 19:28:23 +00:00
|
|
|
|
2017-11-05 17:07:27 +00:00
|
|
|
virtual void correctValue(
|
|
|
|
const QString &was,
|
|
|
|
int wasCursor,
|
|
|
|
QString &now,
|
|
|
|
int &nowCursor) {
|
2016-11-24 19:28:23 +00:00
|
|
|
}
|
|
|
|
void setCorrectedText(QString &now, int &nowCursor, const QString &newText, int newPos);
|
|
|
|
|
2019-02-19 06:57:53 +00:00
|
|
|
virtual void paintAdditionalPlaceholder(Painter &p, crl::time ms) {
|
2016-12-09 18:56:01 +00:00
|
|
|
}
|
2015-10-06 19:49:23 +00:00
|
|
|
|
|
|
|
style::font phFont() {
|
|
|
|
return _st.font;
|
|
|
|
}
|
|
|
|
|
2019-02-19 06:57:53 +00:00
|
|
|
void placeholderAdditionalPrepare(Painter &p, crl::time ms);
|
2015-10-06 19:49:23 +00:00
|
|
|
QRect placeholderRect() const;
|
|
|
|
|
|
|
|
void setTextMargins(const QMargins &mrg);
|
|
|
|
const style::InputField &_st;
|
|
|
|
|
|
|
|
private:
|
2016-12-31 13:34:41 +00:00
|
|
|
void updatePalette();
|
2017-05-30 15:21:05 +00:00
|
|
|
void refreshPlaceholder();
|
2016-12-09 18:56:01 +00:00
|
|
|
void setErrorShown(bool error);
|
2016-12-13 17:07:56 +00:00
|
|
|
|
|
|
|
void setFocused(bool focused);
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2016-12-09 18:56:01 +00:00
|
|
|
int _maxLength = -1;
|
|
|
|
bool _forcePlaceholderHidden = false;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
|
|
|
QString _oldtext;
|
2016-12-09 18:56:01 +00:00
|
|
|
int _oldcursor = 0;
|
2017-05-26 15:50:25 +00:00
|
|
|
QString _lastPreEditText;
|
2016-12-09 18:56:01 +00:00
|
|
|
|
|
|
|
bool _undoAvailable = false;
|
|
|
|
bool _redoAvailable = false;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2016-12-09 18:56:01 +00:00
|
|
|
bool _customUpDown = false;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2016-12-09 18:56:01 +00:00
|
|
|
QString _placeholder;
|
2018-06-04 15:35:11 +00:00
|
|
|
Fn<QString()> _placeholderFactory;
|
2016-12-09 18:56:01 +00:00
|
|
|
Animation _a_placeholderShifted;
|
|
|
|
bool _placeholderShifted = false;
|
|
|
|
QPainterPath _placeholderPath;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2016-12-09 18:56:01 +00:00
|
|
|
Animation _a_borderShown;
|
|
|
|
int _borderAnimationStart = 0;
|
|
|
|
Animation _a_borderOpacity;
|
|
|
|
bool _borderVisible = false;
|
2016-12-05 11:01:08 +00:00
|
|
|
|
2016-12-09 18:56:01 +00:00
|
|
|
Animation _a_focused;
|
|
|
|
Animation _a_error;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2016-12-09 18:56:01 +00:00
|
|
|
bool _focused = false;
|
|
|
|
bool _error = false;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
|
|
|
style::margins _textMargins;
|
2015-06-19 17:04:09 +00:00
|
|
|
|
|
|
|
QTimer _touchTimer;
|
2016-12-09 18:56:01 +00:00
|
|
|
bool _touchPress = false;
|
|
|
|
bool _touchRightButton = false;
|
|
|
|
bool _touchMove = false;
|
2015-06-19 17:04:09 +00:00
|
|
|
QPoint _touchStart;
|
2015-10-06 19:49:23 +00:00
|
|
|
};
|
|
|
|
|
2016-11-24 19:28:23 +00:00
|
|
|
class CountryCodeInput : public MaskedInputField {
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
public:
|
|
|
|
CountryCodeInput(QWidget *parent, const style::InputField &st);
|
|
|
|
|
|
|
|
public slots:
|
|
|
|
void startErasing(QKeyEvent *e);
|
|
|
|
void codeSelected(const QString &code);
|
|
|
|
|
|
|
|
signals:
|
|
|
|
void codeChanged(const QString &code);
|
|
|
|
void addedToNumber(const QString &added);
|
|
|
|
|
|
|
|
protected:
|
2017-11-05 17:07:27 +00:00
|
|
|
void correctValue(
|
|
|
|
const QString &was,
|
|
|
|
int wasCursor,
|
|
|
|
QString &now,
|
|
|
|
int &nowCursor) override;
|
2016-11-24 19:28:23 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
bool _nosignal;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
class PhonePartInput : public MaskedInputField {
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
public:
|
|
|
|
PhonePartInput(QWidget *parent, const style::InputField &st);
|
|
|
|
|
|
|
|
public slots:
|
|
|
|
void addedToNumber(const QString &added);
|
|
|
|
void onChooseCode(const QString &code);
|
|
|
|
|
|
|
|
signals:
|
|
|
|
void voidBackspace(QKeyEvent *e);
|
|
|
|
|
|
|
|
protected:
|
|
|
|
void keyPressEvent(QKeyEvent *e) override;
|
|
|
|
|
2017-11-05 17:07:27 +00:00
|
|
|
void correctValue(
|
|
|
|
const QString &was,
|
|
|
|
int wasCursor,
|
|
|
|
QString &now,
|
|
|
|
int &nowCursor) override;
|
2019-02-19 06:57:53 +00:00
|
|
|
void paintAdditionalPlaceholder(Painter &p, crl::time ms) override;
|
2016-11-24 19:28:23 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
QVector<int> _pattern;
|
2016-12-09 18:56:01 +00:00
|
|
|
QString _additionalPlaceholder;
|
2016-11-24 19:28:23 +00:00
|
|
|
|
|
|
|
};
|
|
|
|
|
2016-11-15 11:56:49 +00:00
|
|
|
class PasswordInput : public MaskedInputField {
|
2015-10-11 08:37:24 +00:00
|
|
|
public:
|
2018-06-04 15:35:11 +00:00
|
|
|
PasswordInput(QWidget *parent, const style::InputField &st, Fn<QString()> placeholderFactory = Fn<QString()>(), const QString &val = QString());
|
2015-10-11 08:37:24 +00:00
|
|
|
|
|
|
|
};
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2015-10-11 08:37:24 +00:00
|
|
|
class PortInput : public MaskedInputField {
|
2015-10-06 19:49:23 +00:00
|
|
|
public:
|
2018-06-04 15:35:11 +00:00
|
|
|
PortInput(QWidget *parent, const style::InputField &st, Fn<QString()> placeholderFactory, const QString &val);
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2018-04-28 15:58:22 +00:00
|
|
|
protected:
|
|
|
|
void correctValue(
|
|
|
|
const QString &was,
|
|
|
|
int wasCursor,
|
|
|
|
QString &now,
|
|
|
|
int &nowCursor) override;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
class HexInput : public MaskedInputField {
|
|
|
|
public:
|
2018-06-04 15:35:11 +00:00
|
|
|
HexInput(QWidget *parent, const style::InputField &st, Fn<QString()> placeholderFactory, const QString &val);
|
2018-04-28 15:58:22 +00:00
|
|
|
|
2015-10-06 19:49:23 +00:00
|
|
|
protected:
|
2017-11-05 17:07:27 +00:00
|
|
|
void correctValue(
|
|
|
|
const QString &was,
|
|
|
|
int wasCursor,
|
|
|
|
QString &now,
|
|
|
|
int &nowCursor) override;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
class UsernameInput : public MaskedInputField {
|
|
|
|
public:
|
2018-06-04 15:35:11 +00:00
|
|
|
UsernameInput(QWidget *parent, const style::InputField &st, Fn<QString()> placeholderFactory, const QString &val, bool isLink);
|
2015-10-06 19:49:23 +00:00
|
|
|
|
2017-08-05 20:01:20 +00:00
|
|
|
void setLinkPlaceholder(const QString &placeholder);
|
|
|
|
|
2015-10-06 19:49:23 +00:00
|
|
|
protected:
|
2017-11-05 17:07:27 +00:00
|
|
|
void correctValue(
|
|
|
|
const QString &was,
|
|
|
|
int wasCursor,
|
|
|
|
QString &now,
|
|
|
|
int &nowCursor) override;
|
2019-02-19 06:57:53 +00:00
|
|
|
void paintAdditionalPlaceholder(Painter &p, crl::time ms) override;
|
2015-10-06 19:49:23 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
QString _linkPlaceholder;
|
2015-08-18 16:10:01 +00:00
|
|
|
|
2015-06-19 17:04:09 +00:00
|
|
|
};
|
2015-10-11 08:37:24 +00:00
|
|
|
|
|
|
|
class PhoneInput : public MaskedInputField {
|
|
|
|
public:
|
2018-06-04 15:35:11 +00:00
|
|
|
PhoneInput(QWidget *parent, const style::InputField &st, Fn<QString()> placeholderFactory, const QString &val);
|
2015-10-11 08:37:24 +00:00
|
|
|
|
|
|
|
void clearText();
|
|
|
|
|
|
|
|
protected:
|
2016-10-20 15:26:55 +00:00
|
|
|
void focusInEvent(QFocusEvent *e) override;
|
2015-10-11 08:37:24 +00:00
|
|
|
|
2017-11-05 17:07:27 +00:00
|
|
|
void correctValue(
|
|
|
|
const QString &was,
|
|
|
|
int wasCursor,
|
|
|
|
QString &now,
|
|
|
|
int &nowCursor) override;
|
2019-02-19 06:57:53 +00:00
|
|
|
void paintAdditionalPlaceholder(Painter &p, crl::time ms) override;
|
2015-10-11 08:37:24 +00:00
|
|
|
|
|
|
|
private:
|
2016-10-20 15:26:55 +00:00
|
|
|
QVector<int> _pattern;
|
2016-12-09 18:56:01 +00:00
|
|
|
QString _additionalPlaceholder;
|
2015-10-11 08:37:24 +00:00
|
|
|
|
|
|
|
};
|
2016-11-15 11:56:49 +00:00
|
|
|
|
|
|
|
} // namespace Ui
|