287 lines
		
	
	
	
		
			8.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			287 lines
		
	
	
	
		
			8.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
This file is part of Telegram Desktop,
 | 
						|
the official desktop version of Telegram messaging app, see https://telegram.org
 | 
						|
 | 
						|
Telegram Desktop is free software: you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation, either version 3 of the License, or
 | 
						|
(at your option) any later version.
 | 
						|
 | 
						|
It is distributed in the hope that it will be useful,
 | 
						|
but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
						|
GNU General Public License for more details.
 | 
						|
 | 
						|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
 | 
						|
Copyright (c) 2014 John Preston, https://desktop.telegram.org
 | 
						|
*/
 | 
						|
#include "stdafx.h"
 | 
						|
#include "style.h"
 | 
						|
 | 
						|
#include "flatinput.h"
 | 
						|
#include "window.h"
 | 
						|
 | 
						|
namespace {
 | 
						|
	class FlatInputStyle : public QCommonStyle {
 | 
						|
	public:
 | 
						|
		FlatInputStyle() {
 | 
						|
		}
 | 
						|
 | 
						|
		void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const {
 | 
						|
		}
 | 
						|
		QRect subElementRect(SubElement r, const QStyleOption *opt, const QWidget *widget = 0) const {
 | 
						|
			switch (r) {
 | 
						|
				case SE_LineEditContents:
 | 
						|
					const FlatInput *w = widget ? qobject_cast<const FlatInput*>(widget) : 0;
 | 
						|
					return w ? w->getTextRect() : QCommonStyle::subElementRect(r, opt, widget);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
			return QCommonStyle::subElementRect(r, opt, widget);
 | 
						|
		}
 | 
						|
	};
 | 
						|
	FlatInputStyle _flatInputStyle;
 | 
						|
}
 | 
						|
 | 
						|
FlatInput::FlatInput(QWidget *parent, const style::flatInput &st, const QString &pholder, const QString &v) : QLineEdit(v, parent), _fullph(pholder), _oldtext(v), _kev(0), _customUpDown(false), _phVisible(!v.length()),
 | 
						|
	a_phLeft(_phVisible ? 0 : st.phShift), a_phAlpha(_phVisible ? 1 : 0), a_phColor(st.phColor->c),
 | 
						|
    a_borderColor(st.borderColor->c), a_bgColor(st.bgColor->c), _notingBene(0), _st(st) {
 | 
						|
	resize(_st.width, _st.height);
 | 
						|
	
 | 
						|
	setFont(_st.font->f);
 | 
						|
	setAlignment(_st.align);
 | 
						|
 | 
						|
	QPalette p(palette());
 | 
						|
	p.setColor(QPalette::Text, _st.textColor->c);
 | 
						|
	setPalette(p);
 | 
						|
 | 
						|
	connect(this, SIGNAL(textChanged(const QString &)), this, SLOT(onTextChange(const QString &)));
 | 
						|
	connect(this, SIGNAL(textEdited(const QString &)), this, SLOT(onTextEdited()));
 | 
						|
	if (App::wnd()) connect(this, SIGNAL(selectionChanged()), App::wnd(), SLOT(updateGlobalMenu()));
 | 
						|
 | 
						|
	setStyle(&_flatInputStyle);
 | 
						|
	setTextMargins(0, 0, 0, 0);
 | 
						|
	setContentsMargins(0, 0, 0, 0);
 | 
						|
 | 
						|
	setAttribute(Qt::WA_AcceptTouchEvents);
 | 
						|
	_touchTimer.setSingleShot(true);
 | 
						|
	connect(&_touchTimer, SIGNAL(timeout()), this, SLOT(onTouchTimer()));
 | 
						|
}
 | 
						|
 | 
						|
void FlatInput::customUpDown(bool custom) {
 | 
						|
	_customUpDown = custom;
 | 
						|
}
 | 
						|
 | 
						|
void FlatInput::onTouchTimer() {
 | 
						|
	_touchRightButton = true;
 | 
						|
}
 | 
						|
 | 
						|
bool FlatInput::event(QEvent *e) {
 | 
						|
	if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) {
 | 
						|
		QTouchEvent *ev = static_cast<QTouchEvent*>(e);
 | 
						|
		if (ev->device()->type() == QTouchDevice::TouchScreen) {
 | 
						|
			touchEvent(ev);
 | 
						|
			return QLineEdit::event(e);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return QLineEdit::event(e);
 | 
						|
}
 | 
						|
 | 
						|
void FlatInput::touchEvent(QTouchEvent *e) {
 | 
						|
	switch (e->type()) {
 | 
						|
	case QEvent::TouchBegin:
 | 
						|
		if (_touchPress || e->touchPoints().isEmpty()) return;
 | 
						|
		_touchTimer.start(QApplication::startDragTime());
 | 
						|
		_touchPress = true;
 | 
						|
		_touchMove = _touchRightButton = 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;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
 | 
						|
	case QEvent::TouchEnd:
 | 
						|
		if (!_touchPress) return;
 | 
						|
		if (!_touchMove && window()) {
 | 
						|
			Qt::MouseButton btn(_touchRightButton ? Qt::RightButton : Qt::LeftButton);
 | 
						|
			QPoint mapped(mapFromGlobal(_touchStart)), winMapped(window()->mapFromGlobal(_touchStart));
 | 
						|
 | 
						|
			if (_touchRightButton) {
 | 
						|
				QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart);
 | 
						|
				contextMenuEvent(&contextEvent);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		_touchTimer.stop();
 | 
						|
		_touchPress = _touchMove = _touchRightButton = false;
 | 
						|
		break;
 | 
						|
 | 
						|
	case QEvent::TouchCancel:
 | 
						|
		_touchPress = false;
 | 
						|
		_touchTimer.stop();
 | 
						|
		break;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
QRect FlatInput::getTextRect() const {
 | 
						|
	return rect().marginsRemoved(_st.textMrg + QMargins(-2, -1, -2, -1));
 | 
						|
}
 | 
						|
 | 
						|
void FlatInput::paintEvent(QPaintEvent *e) {
 | 
						|
	QPainter p(this);
 | 
						|
	p.fillRect(rect(), a_bgColor.current());
 | 
						|
	if (_st.borderWidth) {
 | 
						|
		QBrush b(a_borderColor.current());
 | 
						|
		p.fillRect(0, 0, width() - _st.borderWidth, _st.borderWidth, b);
 | 
						|
		p.fillRect(width() - _st.borderWidth, 0, _st.borderWidth, height() - _st.borderWidth, b);
 | 
						|
		p.fillRect(_st.borderWidth, height() - _st.borderWidth, width() - _st.borderWidth, _st.borderWidth, b);
 | 
						|
		p.fillRect(0, _st.borderWidth, _st.borderWidth, height() - _st.borderWidth, b);
 | 
						|
	}
 | 
						|
	if (_st.imgRect.pxWidth()) {
 | 
						|
		p.drawPixmap(_st.imgPos, App::sprite(), _st.imgRect);
 | 
						|
	}
 | 
						|
 | 
						|
	bool phDraw = _phVisible;
 | 
						|
	if (animating()) {
 | 
						|
		p.setOpacity(a_phAlpha.current());
 | 
						|
		phDraw = true;
 | 
						|
	}
 | 
						|
	if (phDraw) {
 | 
						|
		p.save();
 | 
						|
		p.setClipRect(rect());
 | 
						|
		QRect phRect(_st.textMrg.left() + _st.phPos.x() + a_phLeft.current(), _st.textMrg.top() + _st.phPos.y(), width() - _st.textMrg.left() - _st.textMrg.right(), height() - _st.textMrg.top() - _st.textMrg.bottom());
 | 
						|
		p.setFont(_st.font->f);
 | 
						|
		p.setPen(a_phColor.current());
 | 
						|
		p.drawText(phRect, _ph, QTextOption(_st.phAlign));
 | 
						|
		p.restore();
 | 
						|
	}
 | 
						|
	QLineEdit::paintEvent(e);
 | 
						|
}
 | 
						|
 | 
						|
void FlatInput::focusInEvent(QFocusEvent *e) {
 | 
						|
	a_phColor.start(_st.phFocusColor->c);
 | 
						|
	if (_notingBene <= 0) {
 | 
						|
		a_borderColor.start(_st.borderActive->c);
 | 
						|
	}
 | 
						|
	a_bgColor.start(_st.bgActive->c);
 | 
						|
	anim::start(this);
 | 
						|
	QLineEdit::focusInEvent(e);
 | 
						|
	emit focused();
 | 
						|
}
 | 
						|
 | 
						|
void FlatInput::focusOutEvent(QFocusEvent *e) {
 | 
						|
	a_phColor.start(_st.phColor->c);
 | 
						|
	if (_notingBene <= 0) {
 | 
						|
		a_borderColor.start(_st.borderColor->c);
 | 
						|
	}
 | 
						|
	a_bgColor.start(_st.bgColor->c);
 | 
						|
	anim::start(this);
 | 
						|
	QLineEdit::focusOutEvent(e);
 | 
						|
	emit blurred();
 | 
						|
}
 | 
						|
 | 
						|
void FlatInput::resizeEvent(QResizeEvent *e) {
 | 
						|
	int32 availw = width() - _st.textMrg.left() - _st.textMrg.right() - _st.phPos.x() - 1;
 | 
						|
	if (_st.font->m.width(_fullph) > availw) {
 | 
						|
		_ph = _st.font->m.elidedText(_fullph, Qt::ElideRight, availw);
 | 
						|
	} else {
 | 
						|
		_ph = _fullph;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
QSize FlatInput::sizeHint() const {
 | 
						|
	return geometry().size();
 | 
						|
}
 | 
						|
 | 
						|
QSize FlatInput::minimumSizeHint() const {
 | 
						|
	return geometry().size();
 | 
						|
}
 | 
						|
 | 
						|
bool FlatInput::animStep(float64 ms) {
 | 
						|
	float dt = ms / _st.phDuration;
 | 
						|
	bool res = true;
 | 
						|
	if (dt >= 1) {
 | 
						|
		res = false;
 | 
						|
		a_phLeft.finish();
 | 
						|
		a_phAlpha.finish();
 | 
						|
		a_phColor.finish();
 | 
						|
		a_bgColor.finish();
 | 
						|
		if (_notingBene > 0) {
 | 
						|
			_notingBene = -1;
 | 
						|
			a_borderColor.start((hasFocus() ? _st.borderActive : _st.borderColor)->c);
 | 
						|
			anim::start(this);
 | 
						|
			return true;
 | 
						|
		} else if (_notingBene) {
 | 
						|
			_notingBene = 0;
 | 
						|
		}
 | 
						|
		a_borderColor.finish();
 | 
						|
	} else {
 | 
						|
		a_phLeft.update(dt, _st.phLeftFunc);
 | 
						|
		a_phAlpha.update(dt, _st.phAlphaFunc);
 | 
						|
		a_phColor.update(dt, _st.phColorFunc);
 | 
						|
		a_bgColor.update(dt, _st.phColorFunc);
 | 
						|
		a_borderColor.update(dt, _st.phColorFunc);
 | 
						|
	}
 | 
						|
	update();
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
void FlatInput::updatePlaceholder() {
 | 
						|
	bool vis = !text().length();
 | 
						|
	if (vis == _phVisible) return;
 | 
						|
 | 
						|
	a_phLeft.start(vis ? 0 : _st.phShift);
 | 
						|
	a_phAlpha.start(vis ? 1 : 0);
 | 
						|
	anim::start(this);
 | 
						|
 | 
						|
	_phVisible = vis;
 | 
						|
}
 | 
						|
 | 
						|
void FlatInput::correctValue(QKeyEvent *e, const QString &was) {
 | 
						|
}
 | 
						|
 | 
						|
void FlatInput::keyPressEvent(QKeyEvent *e) {
 | 
						|
	QString was(text());
 | 
						|
	_kev = e;
 | 
						|
	if (_customUpDown && (e->key() == Qt::Key_Up || e->key() == Qt::Key_Down)) {
 | 
						|
		e->ignore();
 | 
						|
	} else {
 | 
						|
		QLineEdit::keyPressEvent(e);
 | 
						|
	}
 | 
						|
 | 
						|
	if (was == text()) { // call correct manually
 | 
						|
		correctValue(_kev, was);
 | 
						|
		_oldtext = text();
 | 
						|
		if (was != _oldtext) emit changed();
 | 
						|
		updatePlaceholder();
 | 
						|
	}
 | 
						|
	if (e->key() == Qt::Key_Escape) {
 | 
						|
		emit cancelled();
 | 
						|
	} else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
 | 
						|
		emit accepted();
 | 
						|
	}
 | 
						|
	_kev = 0;
 | 
						|
}
 | 
						|
 | 
						|
void FlatInput::onTextEdited() {
 | 
						|
	QString was(_oldtext);
 | 
						|
	correctValue(_kev, was);
 | 
						|
	_oldtext = text();
 | 
						|
	if (was != _oldtext) emit changed();
 | 
						|
	updatePlaceholder();
 | 
						|
	if (App::wnd()) App::wnd()->updateGlobalMenu();
 | 
						|
}
 | 
						|
 | 
						|
void FlatInput::onTextChange(const QString &text) {
 | 
						|
	_oldtext = text;
 | 
						|
	if (App::wnd()) App::wnd()->updateGlobalMenu();
 | 
						|
}
 | 
						|
 | 
						|
void FlatInput::notaBene() {
 | 
						|
	_notingBene = 1;
 | 
						|
	setFocus();
 | 
						|
	a_borderColor.start(_st.borderError->c);
 | 
						|
	anim::start(this);
 | 
						|
}
 |