548 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			548 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// This file is part of Desktop App Toolkit,
 | 
						|
// a set of libraries for developing nice desktop applications.
 | 
						|
//
 | 
						|
// For license and copyright information please follow this link:
 | 
						|
// https://github.com/desktop-app/legal/blob/master/LEGAL
 | 
						|
//
 | 
						|
#include "ui/widgets/fields/masked_input_field.h"
 | 
						|
 | 
						|
#include "base/qt/qt_common_adapters.h"
 | 
						|
#include "ui/painter.h"
 | 
						|
#include "ui/widgets/popup_menu.h"
 | 
						|
#include "styles/palette.h"
 | 
						|
#include "styles/style_widgets.h"
 | 
						|
 | 
						|
#include <QtWidgets/QCommonStyle>
 | 
						|
#include <QtWidgets/QApplication>
 | 
						|
#include <QtGui/QClipboard>
 | 
						|
 | 
						|
namespace Ui {
 | 
						|
namespace {
 | 
						|
 | 
						|
class InputStyle final : public QCommonStyle {
 | 
						|
public:
 | 
						|
	InputStyle() {
 | 
						|
		setParent(QCoreApplication::instance());
 | 
						|
	}
 | 
						|
 | 
						|
	void drawPrimitive(
 | 
						|
		PrimitiveElement element,
 | 
						|
		const QStyleOption *option,
 | 
						|
		QPainter *painter,
 | 
						|
		const QWidget *widget = nullptr) const override {
 | 
						|
	}
 | 
						|
 | 
						|
	static InputStyle *instance() {
 | 
						|
		if (!_instance) {
 | 
						|
			if (!QGuiApplication::instance()) {
 | 
						|
				return nullptr;
 | 
						|
			}
 | 
						|
			_instance = new InputStyle();
 | 
						|
		}
 | 
						|
		return _instance;
 | 
						|
	}
 | 
						|
 | 
						|
	~InputStyle() {
 | 
						|
		_instance = nullptr;
 | 
						|
	}
 | 
						|
 | 
						|
private:
 | 
						|
	static InputStyle *_instance;
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
InputStyle *InputStyle::_instance = nullptr;
 | 
						|
 | 
						|
} // namespace
 | 
						|
 | 
						|
MaskedInputField::MaskedInputField(
 | 
						|
	QWidget *parent,
 | 
						|
	const style::InputField &st,
 | 
						|
	rpl::producer<QString> placeholder,
 | 
						|
	const QString &val)
 | 
						|
: Parent(val, parent)
 | 
						|
, _st(st)
 | 
						|
, _oldtext(val)
 | 
						|
, _placeholderFull(std::move(placeholder)) {
 | 
						|
	resize(_st.width, _st.heightMin);
 | 
						|
 | 
						|
	setFont(_st.font);
 | 
						|
	setAlignment(_st.textAlign);
 | 
						|
 | 
						|
	_placeholderFull.value(
 | 
						|
	) | rpl::start_with_next([=](const QString &text) {
 | 
						|
		refreshPlaceholder(text);
 | 
						|
	}, lifetime());
 | 
						|
 | 
						|
	style::PaletteChanged(
 | 
						|
	) | rpl::start_with_next([=] {
 | 
						|
		updatePalette();
 | 
						|
	}, lifetime());
 | 
						|
	updatePalette();
 | 
						|
 | 
						|
	setAttribute(Qt::WA_OpaquePaintEvent);
 | 
						|
 | 
						|
	connect(this, SIGNAL(textChanged(QString)), this, SLOT(onTextChange(QString)));
 | 
						|
	connect(this, SIGNAL(cursorPositionChanged(int,int)), this, SLOT(onCursorPositionChanged(int,int)));
 | 
						|
 | 
						|
	connect(this, SIGNAL(textEdited(QString)), this, SLOT(onTextEdited()));
 | 
						|
	connect(this, &MaskedInputField::selectionChanged, [] {
 | 
						|
		Integration::Instance().textActionsUpdated();
 | 
						|
	});
 | 
						|
 | 
						|
	setStyle(InputStyle::instance());
 | 
						|
	QLineEdit::setTextMargins(0, 0, 0, 0);
 | 
						|
	setContentsMargins(_textMargins + QMargins(-2, -1, -2, -1));
 | 
						|
	setFrame(false);
 | 
						|
 | 
						|
	setAttribute(Qt::WA_AcceptTouchEvents);
 | 
						|
	_touchTimer.setSingleShot(true);
 | 
						|
	connect(&_touchTimer, SIGNAL(timeout()), this, SLOT(onTouchTimer()));
 | 
						|
 | 
						|
	setTextMargins(_st.textMargins);
 | 
						|
 | 
						|
	startPlaceholderAnimation();
 | 
						|
	startBorderAnimation();
 | 
						|
	finishAnimating();
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::updatePalette() {
 | 
						|
	auto p = palette();
 | 
						|
	p.setColor(QPalette::Text, _st.textFg->c);
 | 
						|
	p.setColor(QPalette::Highlight, st::msgInBgSelected->c);
 | 
						|
	p.setColor(QPalette::HighlightedText, st::historyTextInFgSelected->c);
 | 
						|
	setPalette(p);
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::setCorrectedText(QString &now, int &nowCursor, const QString &newText, int newPos) {
 | 
						|
	if (newPos < 0 || newPos > newText.size()) {
 | 
						|
		newPos = newText.size();
 | 
						|
	}
 | 
						|
	auto updateText = (newText != now);
 | 
						|
	if (updateText) {
 | 
						|
		now = newText;
 | 
						|
		setText(now);
 | 
						|
		startPlaceholderAnimation();
 | 
						|
	}
 | 
						|
	auto updateCursorPosition = (newPos != nowCursor) || updateText;
 | 
						|
	if (updateCursorPosition) {
 | 
						|
		nowCursor = newPos;
 | 
						|
		setCursorPosition(nowCursor);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::customUpDown(bool custom) {
 | 
						|
	_customUpDown = custom;
 | 
						|
}
 | 
						|
 | 
						|
int MaskedInputField::borderAnimationStart() const {
 | 
						|
	return _borderAnimationStart;
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::setTextMargins(const QMargins &mrg) {
 | 
						|
	_textMargins = mrg;
 | 
						|
	setContentsMargins(_textMargins + QMargins(-2, -1, -2, -1));
 | 
						|
	refreshPlaceholder(_placeholderFull.current());
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::onTouchTimer() {
 | 
						|
	_touchRightButton = true;
 | 
						|
}
 | 
						|
 | 
						|
bool MaskedInputField::eventHook(QEvent *e) {
 | 
						|
	auto type = e->type();
 | 
						|
	if (type == QEvent::TouchBegin
 | 
						|
		|| type == QEvent::TouchUpdate
 | 
						|
		|| type == QEvent::TouchEnd
 | 
						|
		|| type == QEvent::TouchCancel) {
 | 
						|
		auto event = static_cast<QTouchEvent*>(e);
 | 
						|
		if (event->device()->type() == base::TouchDevice::TouchScreen) {
 | 
						|
			touchEvent(event);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return Parent::eventHook(e);
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::touchEvent(QTouchEvent *e) {
 | 
						|
	switch (e->type()) {
 | 
						|
	case QEvent::TouchBegin: {
 | 
						|
		if (_touchPress || e->touchPoints().isEmpty()) {
 | 
						|
			return;
 | 
						|
		}
 | 
						|
		_touchTimer.start(QApplication::startDragTime());
 | 
						|
		_touchPress = true;
 | 
						|
		_touchMove = _touchRightButton = _mousePressedInTouch = false;
 | 
						|
		_touchStart = e->touchPoints().cbegin()->screenPos().toPoint();
 | 
						|
	} break;
 | 
						|
 | 
						|
	case QEvent::TouchUpdate: {
 | 
						|
		if (!e->touchPoints().isEmpty()) {
 | 
						|
			touchUpdate(e->touchPoints().cbegin()->screenPos().toPoint());
 | 
						|
		}
 | 
						|
	} break;
 | 
						|
 | 
						|
	case QEvent::TouchEnd: {
 | 
						|
		touchFinish();
 | 
						|
	} break;
 | 
						|
 | 
						|
	case QEvent::TouchCancel: {
 | 
						|
		_touchPress = false;
 | 
						|
		_touchTimer.stop();
 | 
						|
	} break;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
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);
 | 
						|
 | 
						|
	auto r = rect().intersected(e->rect());
 | 
						|
	p.fillRect(r, _st.textBg);
 | 
						|
	if (_st.border) {
 | 
						|
		p.fillRect(0, height() - _st.border, width(), _st.border, _st.borderFg->b);
 | 
						|
	}
 | 
						|
	auto errorDegree = _a_error.value(_error ? 1. : 0.);
 | 
						|
	auto focusedDegree = _a_focused.value(_focused ? 1. : 0.);
 | 
						|
	auto borderShownDegree = _a_borderShown.value(1.);
 | 
						|
	auto borderOpacity = _a_borderOpacity.value(_borderVisible ? 1. : 0.);
 | 
						|
	if (_st.borderActive && (borderOpacity > 0.)) {
 | 
						|
		auto borderStart = std::clamp(_borderAnimationStart, 0, width());
 | 
						|
		auto borderFrom = qRound(borderStart * (1. - borderShownDegree));
 | 
						|
		auto borderTo = borderStart + qRound((width() - borderStart) * borderShownDegree);
 | 
						|
		if (borderTo > borderFrom) {
 | 
						|
			auto borderFg = anim::brush(_st.borderFgActive, _st.borderFgError, errorDegree);
 | 
						|
			p.setOpacity(borderOpacity);
 | 
						|
			p.fillRect(borderFrom, height() - _st.borderActive, borderTo - borderFrom, _st.borderActive, borderFg);
 | 
						|
			p.setOpacity(1);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	p.setClipRect(r);
 | 
						|
	if (_st.placeholderScale > 0. && !_placeholderPath.isEmpty()) {
 | 
						|
		auto placeholderShiftDegree = _a_placeholderShifted.value(_placeholderShifted ? 1. : 0.);
 | 
						|
		p.save();
 | 
						|
		p.setClipRect(r);
 | 
						|
 | 
						|
		auto placeholderTop = anim::interpolate(0, _st.placeholderShift, placeholderShiftDegree);
 | 
						|
 | 
						|
		QRect r(rect().marginsRemoved(_textMargins + _st.placeholderMargins));
 | 
						|
		r.moveTop(r.top() + placeholderTop);
 | 
						|
		if (style::RightToLeft()) r.moveLeft(width() - r.left() - r.width());
 | 
						|
 | 
						|
		auto placeholderScale = 1. - (1. - _st.placeholderScale) * placeholderShiftDegree;
 | 
						|
		auto placeholderFg = anim::color(_st.placeholderFg, _st.placeholderFgActive, focusedDegree);
 | 
						|
		placeholderFg = anim::color(placeholderFg, _st.placeholderFgError, errorDegree);
 | 
						|
 | 
						|
		PainterHighQualityEnabler hq(p);
 | 
						|
		p.setPen(Qt::NoPen);
 | 
						|
		p.setBrush(placeholderFg);
 | 
						|
		p.translate(r.topLeft());
 | 
						|
		p.scale(placeholderScale, placeholderScale);
 | 
						|
		p.drawPath(_placeholderPath);
 | 
						|
 | 
						|
		p.restore();
 | 
						|
	} else if (!_placeholder.isEmpty()) {
 | 
						|
		auto placeholderHiddenDegree = _a_placeholderShifted.value(_placeholderShifted ? 1. : 0.);
 | 
						|
		if (placeholderHiddenDegree < 1.) {
 | 
						|
			p.setOpacity(1. - placeholderHiddenDegree);
 | 
						|
			p.save();
 | 
						|
			p.setClipRect(r);
 | 
						|
 | 
						|
			auto placeholderLeft = anim::interpolate(0, -_st.placeholderShift, placeholderHiddenDegree);
 | 
						|
 | 
						|
			QRect r(rect().marginsRemoved(_textMargins + _st.placeholderMargins));
 | 
						|
			r.moveLeft(r.left() + placeholderLeft);
 | 
						|
			if (style::RightToLeft()) r.moveLeft(width() - r.left() - r.width());
 | 
						|
 | 
						|
			p.setFont(_st.placeholderFont);
 | 
						|
			p.setPen(anim::pen(_st.placeholderFg, _st.placeholderFgActive, focusedDegree));
 | 
						|
			p.drawText(r, _placeholder, _st.placeholderAlign);
 | 
						|
 | 
						|
			p.restore();
 | 
						|
			p.setOpacity(1.);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	paintAdditionalPlaceholder(p);
 | 
						|
	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);
 | 
						|
}
 | 
						|
 | 
						|
QString MaskedInputField::getDisplayedText() const {
 | 
						|
	auto result = getLastText();
 | 
						|
	if (!_lastPreEditText.isEmpty()) {
 | 
						|
		result = result.mid(0, _oldcursor)
 | 
						|
			+ _lastPreEditText
 | 
						|
			+ result.mid(_oldcursor);
 | 
						|
	}
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::startBorderAnimation() {
 | 
						|
	auto borderVisible = (_error || _focused);
 | 
						|
	if (_borderVisible != borderVisible) {
 | 
						|
		_borderVisible = borderVisible;
 | 
						|
		if (_borderVisible) {
 | 
						|
			if (_a_borderOpacity.animating()) {
 | 
						|
				_a_borderOpacity.start([this] { update(); }, 0., 1., _st.duration);
 | 
						|
			} else {
 | 
						|
				_a_borderShown.start([this] { update(); }, 0., 1., _st.duration);
 | 
						|
			}
 | 
						|
		} else if (qFuzzyCompare(_a_borderShown.value(1.), 0.)) {
 | 
						|
			_a_borderShown.stop();
 | 
						|
			_a_borderOpacity.stop();
 | 
						|
		} else {
 | 
						|
			_a_borderOpacity.start([this] { update(); }, 1., 0., _st.duration);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::focusInEvent(QFocusEvent *e) {
 | 
						|
	_borderAnimationStart = (e->reason() == Qt::MouseFocusReason) ? mapFromGlobal(QCursor::pos()).x() : (width() / 2);
 | 
						|
	setFocused(true);
 | 
						|
	QLineEdit::focusInEvent(e);
 | 
						|
	focused();
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::focusOutEvent(QFocusEvent *e) {
 | 
						|
	setFocused(false);
 | 
						|
	QLineEdit::focusOutEvent(e);
 | 
						|
	blurred();
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::setFocused(bool focused) {
 | 
						|
	if (_focused != focused) {
 | 
						|
		_focused = focused;
 | 
						|
		_a_focused.start([this] { update(); }, _focused ? 0. : 1., _focused ? 1. : 0., _st.duration);
 | 
						|
		startPlaceholderAnimation();
 | 
						|
		startBorderAnimation();
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::resizeEvent(QResizeEvent *e) {
 | 
						|
	refreshPlaceholder(_placeholderFull.current());
 | 
						|
	_borderAnimationStart = width() / 2;
 | 
						|
	QLineEdit::resizeEvent(e);
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::refreshPlaceholder(const QString &text) {
 | 
						|
	const auto availableWidth = width() - _textMargins.left() - _textMargins.right() - _st.placeholderMargins.left() - _st.placeholderMargins.right() - 1;
 | 
						|
	if (_st.placeholderScale > 0.) {
 | 
						|
		auto placeholderFont = _st.placeholderFont->f;
 | 
						|
		placeholderFont.setStyleStrategy(QFont::PreferMatch);
 | 
						|
		const auto metrics = QFontMetrics(placeholderFont);
 | 
						|
		_placeholder = metrics.elidedText(text, Qt::ElideRight, availableWidth);
 | 
						|
		_placeholderPath = QPainterPath();
 | 
						|
		if (!_placeholder.isEmpty()) {
 | 
						|
			const auto result = style::FindAdjustResult(placeholderFont);
 | 
						|
			const auto ascent = result ? result->iascent : metrics.ascent();
 | 
						|
			_placeholderPath.addText(0, ascent, placeholderFont, _placeholder);
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		_placeholder = _st.placeholderFont->elided(text, availableWidth);
 | 
						|
	}
 | 
						|
	update();
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::setPlaceholder(rpl::producer<QString> placeholder) {
 | 
						|
	_placeholderFull = std::move(placeholder);
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::contextMenuEvent(QContextMenuEvent *e) {
 | 
						|
	if (const auto menu = createStandardContextMenu()) {
 | 
						|
		_contextMenu = base::make_unique_q<PopupMenu>(this, menu);
 | 
						|
		_contextMenu->popup(e->globalPos());
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::inputMethodEvent(QInputMethodEvent *e) {
 | 
						|
	QLineEdit::inputMethodEvent(e);
 | 
						|
	_lastPreEditText = e->preeditString();
 | 
						|
	update();
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::showError() {
 | 
						|
	showErrorNoFocus();
 | 
						|
	if (!hasFocus()) {
 | 
						|
		setFocus();
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::showErrorNoFocus() {
 | 
						|
	setErrorShown(true);
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::hideError() {
 | 
						|
	setErrorShown(false);
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::setErrorShown(bool error) {
 | 
						|
	if (_error != error) {
 | 
						|
		_error = error;
 | 
						|
		_a_error.start([this] { update(); }, _error ? 0. : 1., _error ? 1. : 0., _st.duration);
 | 
						|
		startBorderAnimation();
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
QSize MaskedInputField::sizeHint() const {
 | 
						|
	return geometry().size();
 | 
						|
}
 | 
						|
 | 
						|
QSize MaskedInputField::minimumSizeHint() const {
 | 
						|
	return geometry().size();
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::setDisplayFocused(bool focused) {
 | 
						|
	setFocused(focused);
 | 
						|
	finishAnimating();
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::finishAnimating() {
 | 
						|
	_a_focused.stop();
 | 
						|
	_a_error.stop();
 | 
						|
	_a_placeholderShifted.stop();
 | 
						|
	_a_borderShown.stop();
 | 
						|
	_a_borderOpacity.stop();
 | 
						|
	update();
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::setPlaceholderHidden(bool forcePlaceholderHidden) {
 | 
						|
	_forcePlaceholderHidden = forcePlaceholderHidden;
 | 
						|
	startPlaceholderAnimation();
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::startPlaceholderAnimation() {
 | 
						|
	auto placeholderShifted = _forcePlaceholderHidden || (_focused && _st.placeholderScale > 0.) || !getLastText().isEmpty();
 | 
						|
	if (_placeholderShifted != placeholderShifted) {
 | 
						|
		_placeholderShifted = placeholderShifted;
 | 
						|
		_a_placeholderShifted.start([this] { update(); }, _placeholderShifted ? 0. : 1., _placeholderShifted ? 1. : 0., _st.duration);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
QRect MaskedInputField::placeholderRect() const {
 | 
						|
	return rect().marginsRemoved(_textMargins + _st.placeholderMargins);
 | 
						|
}
 | 
						|
 | 
						|
style::font MaskedInputField::phFont() {
 | 
						|
	return _st.font;
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::placeholderAdditionalPrepare(QPainter &p) {
 | 
						|
	p.setFont(_st.font);
 | 
						|
	p.setPen(_st.placeholderFg);
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::keyPressEvent(QKeyEvent *e) {
 | 
						|
	QString wasText(_oldtext);
 | 
						|
	int32 wasCursor(_oldcursor);
 | 
						|
 | 
						|
	if (_customUpDown && (e->key() == Qt::Key_Up || e->key() == Qt::Key_Down || e->key() == Qt::Key_PageUp || e->key() == Qt::Key_PageDown)) {
 | 
						|
		e->ignore();
 | 
						|
	} else {
 | 
						|
		QLineEdit::keyPressEvent(e);
 | 
						|
	}
 | 
						|
 | 
						|
	auto newText = text();
 | 
						|
	auto newCursor = cursorPosition();
 | 
						|
	if (wasText == newText && wasCursor == newCursor) { // call correct manually
 | 
						|
		correctValue(wasText, wasCursor, newText, newCursor);
 | 
						|
		_oldtext = newText;
 | 
						|
		_oldcursor = newCursor;
 | 
						|
		if (wasText != _oldtext) changed();
 | 
						|
		startPlaceholderAnimation();
 | 
						|
	}
 | 
						|
	if (e->key() == Qt::Key_Escape) {
 | 
						|
		e->ignore();
 | 
						|
		cancelled();
 | 
						|
	} else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
 | 
						|
		submitted(e->modifiers());
 | 
						|
#ifdef Q_OS_MAC
 | 
						|
	} else if (e->key() == Qt::Key_E && e->modifiers().testFlag(Qt::ControlModifier)) {
 | 
						|
		auto selected = selectedText();
 | 
						|
		if (!selected.isEmpty() && echoMode() == QLineEdit::Normal) {
 | 
						|
			QGuiApplication::clipboard()->setText(selected, QClipboard::FindBuffer);
 | 
						|
		}
 | 
						|
#endif // Q_OS_MAC
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::onTextEdited() {
 | 
						|
	QString wasText(_oldtext), newText(text());
 | 
						|
	int32 wasCursor(_oldcursor), newCursor(cursorPosition());
 | 
						|
 | 
						|
	correctValue(wasText, wasCursor, newText, newCursor);
 | 
						|
	_oldtext = newText;
 | 
						|
	_oldcursor = newCursor;
 | 
						|
	if (wasText != _oldtext) changed();
 | 
						|
	startPlaceholderAnimation();
 | 
						|
 | 
						|
	Integration::Instance().textActionsUpdated();
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::onTextChange(const QString &text) {
 | 
						|
	_oldtext = QLineEdit::text();
 | 
						|
	setErrorShown(false);
 | 
						|
	Integration::Instance().textActionsUpdated();
 | 
						|
}
 | 
						|
 | 
						|
void MaskedInputField::onCursorPositionChanged(int oldPosition, int position) {
 | 
						|
	_oldcursor = position;
 | 
						|
}
 | 
						|
 | 
						|
} // namespace Ui
 |