An attempt to improve input fields touch-screen support.

This commit is contained in:
John Preston 2022-09-19 14:18:59 +04:00
parent 13e59e27eb
commit e72b521618
2 changed files with 234 additions and 64 deletions

View file

@ -976,6 +976,16 @@ protected:
return outer()->paintEventInner(e);
}
void mousePressEvent(QMouseEvent *e) override {
return outer()->mousePressEventInner(e);
}
void mouseReleaseEvent(QMouseEvent *e) override {
return outer()->mouseReleaseEventInner(e);
}
void mouseMoveEvent(QMouseEvent *e) override {
return outer()->mouseMoveEventInner(e);
}
bool canInsertFromMimeData(const QMimeData *source) const override {
return outer()->canInsertFromMimeDataInner(source);
}
@ -1147,41 +1157,27 @@ bool FlatInput::eventHook(QEvent *e) {
void FlatInput::touchEvent(QTouchEvent *e) {
switch (e->type()) {
case QEvent::TouchBegin: {
if (_touchPress || e->touchPoints().isEmpty()) return;
if (_touchPress || e->touchPoints().isEmpty()) {
return;
}
_touchTimer.start(QApplication::startDragTime());
_touchPress = true;
_touchMove = _touchRightButton = false;
_touchMove = _touchRightButton = _mousePressedInTouch = false;
_touchStart = e->touchPoints().cbegin()->screenPos().toPoint();
} break;
case QEvent::TouchUpdate: {
if (!_touchPress || e->touchPoints().isEmpty()) return;
if (!_touchMove && (e->touchPoints().cbegin()->screenPos().toPoint() - _touchStart).manhattanLength() >= QApplication::startDragDistance()) {
_touchMove = true;
if (!e->touchPoints().isEmpty()) {
touchUpdate(e->touchPoints().cbegin()->screenPos().toPoint());
}
} break;
case QEvent::TouchEnd: {
if (!_touchPress) return;
auto weak = MakeWeak(this);
if (!_touchMove && window()) {
QPoint mapped(mapFromGlobal(_touchStart));
if (_touchRightButton) {
QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart);
contextMenuEvent(&contextEvent);
} else {
QGuiApplication::inputMethod()->show();
}
}
if (weak) {
_touchTimer.stop();
_touchPress = _touchMove = _touchRightButton = false;
}
touchFinish();
} break;
case QEvent::TouchCancel: {
_touchPress = false;
_touchPress = _mousePressedInTouch = false;
_touchTimer.stop();
} break;
}
@ -1323,6 +1319,64 @@ void FlatInput::inputMethodEvent(QInputMethodEvent *e) {
}
}
void FlatInput::mousePressEvent(QMouseEvent *e) {
if (_touchPress && e->button() == Qt::LeftButton) {
_mousePressedInTouch = true;
_touchStart = e->globalPos();
}
return QLineEdit::mousePressEvent(e);
}
void FlatInput::mouseReleaseEvent(QMouseEvent *e) {
if (_mousePressedInTouch) {
touchFinish();
}
return QLineEdit::mouseReleaseEvent(e);
}
void FlatInput::mouseMoveEvent(QMouseEvent *e) {
if (_mousePressedInTouch) {
touchUpdate(e->globalPos());
}
return QLineEdit::mouseMoveEvent(e);
}
void FlatInput::touchUpdate(QPoint globalPosition) {
if (_touchPress
&& !_touchMove
&& ((globalPosition - _touchStart).manhattanLength()
>= QApplication::startDragDistance())) {
_touchMove = true;
}
}
void FlatInput::touchFinish() {
if (!_touchPress) {
return;
}
const auto weak = MakeWeak(this);
if (!_touchMove && window()) {
QPoint mapped(mapFromGlobal(_touchStart));
if (_touchRightButton) {
QContextMenuEvent contextEvent(
QContextMenuEvent::Mouse,
mapped,
_touchStart);
contextMenuEvent(&contextEvent);
} else {
QGuiApplication::inputMethod()->show();
}
}
if (weak) {
_touchTimer.stop();
_touchPress
= _touchMove
= _touchRightButton
= _mousePressedInTouch = false;
}
}
QRect FlatInput::placeholderRect() const {
return QRect(_textMrg.left() + _st.phPos.x(), _textMrg.top() + _st.phPos.y(), width() - _textMrg.left() - _textMrg.right(), height() - _textMrg.top() - _textMrg.bottom());
}
@ -1572,6 +1626,7 @@ bool InputField::viewportEventInner(QEvent *e) {
const auto ev = static_cast<QTouchEvent*>(e);
if (ev->device()->type() == base::TouchDevice::TouchScreen) {
handleTouchEvent(ev);
return false;
}
} else if (e->type() == QEvent::Paint && _customEmojiObject) {
_customEmojiObject->setNow(crl::now());
@ -1846,7 +1901,9 @@ void InputField::checkContentHeight() {
void InputField::handleTouchEvent(QTouchEvent *e) {
switch (e->type()) {
case QEvent::TouchBegin: {
if (_touchPress || e->touchPoints().isEmpty()) return;
if (_touchPress || e->touchPoints().isEmpty()) {
return;
}
_touchTimer.start(QApplication::startDragTime());
_touchPress = true;
_touchMove = _touchRightButton = false;
@ -1854,29 +1911,13 @@ void InputField::handleTouchEvent(QTouchEvent *e) {
} break;
case QEvent::TouchUpdate: {
if (!_touchPress || e->touchPoints().isEmpty()) return;
if (!_touchMove && (e->touchPoints().cbegin()->screenPos().toPoint() - _touchStart).manhattanLength() >= QApplication::startDragDistance()) {
_touchMove = true;
if (!e->touchPoints().isEmpty()) {
touchUpdate(e->touchPoints().cbegin()->screenPos().toPoint());
}
} break;
case QEvent::TouchEnd: {
if (!_touchPress) return;
auto weak = MakeWeak(this);
if (!_touchMove && window()) {
QPoint mapped(mapFromGlobal(_touchStart));
if (_touchRightButton) {
QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart);
contextMenuEvent(&contextEvent);
} else {
QGuiApplication::inputMethod()->show();
}
}
if (weak) {
_touchTimer.stop();
_touchPress = _touchMove = _touchRightButton = false;
}
touchFinish();
} break;
case QEvent::TouchCancel: {
@ -1886,6 +1927,42 @@ void InputField::handleTouchEvent(QTouchEvent *e) {
}
}
void InputField::touchUpdate(QPoint globalPosition) {
if (_touchPress
&& !_touchMove
&& ((globalPosition - _touchStart).manhattanLength()
>= QApplication::startDragDistance())) {
_touchMove = true;
}
}
void InputField::touchFinish() {
if (!_touchPress) {
return;
}
const auto weak = MakeWeak(this);
if (!_touchMove && window()) {
QPoint mapped(mapFromGlobal(_touchStart));
if (_touchRightButton) {
QContextMenuEvent contextEvent(
QContextMenuEvent::Mouse,
mapped,
_touchStart);
contextMenuEvent(&contextEvent);
} else {
QGuiApplication::inputMethod()->show();
}
}
if (weak) {
_touchTimer.stop();
_touchPress
= _touchMove
= _touchRightButton
= _mousePressedInTouch = false;
}
}
void InputField::paintEvent(QPaintEvent *e) {
auto p = QPainter(this);
@ -2006,6 +2083,29 @@ void InputField::mousePressEvent(QMouseEvent *e) {
InvokeQueued(this, [=] { onFocusInner(); });
}
void InputField::mousePressEventInner(QMouseEvent *e) {
if (_touchPress && e->button() == Qt::LeftButton) {
_mousePressedInTouch = true;
_touchStart = e->globalPos();
}
_inner->QTextEdit::mousePressEvent(e);
}
void InputField::mouseReleaseEventInner(QMouseEvent *e) {
if (_mousePressedInTouch) {
touchFinish();
} else {
_inner->QTextEdit::mouseReleaseEvent(e);
}
}
void InputField::mouseMoveEventInner(QMouseEvent *e) {
if (_mousePressedInTouch) {
touchUpdate(e->globalPos());
}
_inner->QTextEdit::mouseMoveEvent(e);
}
void InputField::onFocusInner() {
auto borderStart = _borderAnimationStart;
_inner->setFocus();
@ -4165,37 +4265,23 @@ bool MaskedInputField::eventHook(QEvent *e) {
void MaskedInputField::touchEvent(QTouchEvent *e) {
switch (e->type()) {
case QEvent::TouchBegin: {
if (_touchPress || e->touchPoints().isEmpty()) return;
if (_touchPress || e->touchPoints().isEmpty()) {
return;
}
_touchTimer.start(QApplication::startDragTime());
_touchPress = true;
_touchMove = _touchRightButton = false;
_touchMove = _touchRightButton = _mousePressedInTouch = false;
_touchStart = e->touchPoints().cbegin()->screenPos().toPoint();
} break;
case QEvent::TouchUpdate: {
if (!_touchPress || e->touchPoints().isEmpty()) return;
if (!_touchMove && (e->touchPoints().cbegin()->screenPos().toPoint() - _touchStart).manhattanLength() >= QApplication::startDragDistance()) {
_touchMove = true;
if (!e->touchPoints().isEmpty()) {
touchUpdate(e->touchPoints().cbegin()->screenPos().toPoint());
}
} break;
case QEvent::TouchEnd: {
if (!_touchPress) return;
auto weak = MakeWeak(this);
if (!_touchMove && window()) {
QPoint mapped(mapFromGlobal(_touchStart));
if (_touchRightButton) {
QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart);
contextMenuEvent(&contextEvent);
} else {
QGuiApplication::inputMethod()->show();
}
}
if (weak) {
_touchTimer.stop();
_touchPress = _touchMove = _touchRightButton = false;
}
touchFinish();
} break;
case QEvent::TouchCancel: {
@ -4205,6 +4291,42 @@ void MaskedInputField::touchEvent(QTouchEvent *e) {
}
}
void MaskedInputField::touchUpdate(QPoint globalPosition) {
if (_touchPress
&& !_touchMove
&& ((globalPosition - _touchStart).manhattanLength()
>= QApplication::startDragDistance())) {
_touchMove = true;
}
}
void MaskedInputField::touchFinish() {
if (!_touchPress) {
return;
}
const auto weak = MakeWeak(this);
if (!_touchMove && window()) {
QPoint mapped(mapFromGlobal(_touchStart));
if (_touchRightButton) {
QContextMenuEvent contextEvent(
QContextMenuEvent::Mouse,
mapped,
_touchStart);
contextMenuEvent(&contextEvent);
} else {
QGuiApplication::inputMethod()->show();
}
}
if (weak) {
_touchTimer.stop();
_touchPress
= _touchMove
= _touchRightButton
= _mousePressedInTouch = false;
}
}
void MaskedInputField::paintEvent(QPaintEvent *e) {
auto p = QPainter(this);
@ -4279,6 +4401,28 @@ void MaskedInputField::paintEvent(QPaintEvent *e) {
QLineEdit::paintEvent(e);
}
void MaskedInputField::mousePressEvent(QMouseEvent *e) {
if (_touchPress && e->button() == Qt::LeftButton) {
_mousePressedInTouch = true;
_touchStart = e->globalPos();
}
return QLineEdit::mousePressEvent(e);
}
void MaskedInputField::mouseReleaseEvent(QMouseEvent *e) {
if (_mousePressedInTouch) {
touchFinish();
}
return QLineEdit::mouseReleaseEvent(e);
}
void MaskedInputField::mouseMoveEvent(QMouseEvent *e) {
if (_mousePressedInTouch) {
touchUpdate(e->globalPos());
}
return QLineEdit::mouseMoveEvent(e);
}
void MaskedInputField::startBorderAnimation() {
auto borderVisible = (_error || _focused);
if (_borderVisible != borderVisible) {

View file

@ -118,6 +118,10 @@ protected:
void contextMenuEvent(QContextMenuEvent *e) override;
void inputMethodEvent(QInputMethodEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
virtual void correctValue(const QString &was, QString &now);
style::font phFont() {
@ -130,6 +134,9 @@ private:
void updatePalette();
void refreshPlaceholder(const QString &text);
void touchUpdate(QPoint globalPosition);
void touchFinish();
QString _oldtext;
rpl::variable<QString> _placeholderFull;
QString _placeholder;
@ -146,7 +153,10 @@ private:
QMargins _textMrg;
QTimer _touchTimer;
bool _touchPress, _touchRightButton, _touchMove;
bool _touchPress = false;
bool _touchRightButton = false;
bool _touchMove = false;
bool _mousePressedInTouch = false;
QPoint _touchStart;
base::unique_qptr<PopupMenu> _contextMenu;
@ -448,6 +458,10 @@ private:
void inputMethodEventInner(QInputMethodEvent *e);
void paintEventInner(QPaintEvent *e);
void mousePressEventInner(QMouseEvent *e);
void mouseReleaseEventInner(QMouseEvent *e);
void mouseMoveEventInner(QMouseEvent *e);
QMimeData *createMimeDataFromSelectionInner() const;
bool canInsertFromMimeDataInner(const QMimeData *source) const;
void insertFromMimeDataInner(const QMimeData *source);
@ -522,6 +536,9 @@ private:
void customEmojiRepaint();
void highlightMarkdown();
void touchUpdate(QPoint globalPosition);
void touchFinish();
const style::InputField &_st;
Mode _mode = Mode::SingleLine;
@ -594,6 +611,7 @@ private:
bool _touchPress = false;
bool _touchRightButton = false;
bool _touchMove = false;
bool _mousePressedInTouch = false;
QPoint _touchStart;
bool _correcting = false;
@ -690,6 +708,10 @@ protected:
void contextMenuEvent(QContextMenuEvent *e) override;
void inputMethodEvent(QInputMethodEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
virtual void correctValue(
const QString &was,
int wasCursor,
@ -716,6 +738,9 @@ private:
void refreshPlaceholder(const QString &text);
void setErrorShown(bool error);
void touchUpdate(QPoint globalPosition);
void touchFinish();
void setFocused(bool focused);
int _maxLength = -1;
@ -753,6 +778,7 @@ private:
bool _touchPress = false;
bool _touchRightButton = false;
bool _touchMove = false;
bool _mousePressedInTouch = false;
QPoint _touchStart;
base::unique_qptr<PopupMenu> _contextMenu;