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
 | 
