322 lines
9.0 KiB
C++
322 lines
9.0 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), _fastph(false), _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) {
|
|
Painter 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(placeholderRect());
|
|
phRect.moveLeft(phRect.left() + a_phLeft.current());
|
|
phPrepare(p);
|
|
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::setPlaceholder(const QString &ph) {
|
|
_fullph = ph;
|
|
resizeEvent(0);
|
|
update();
|
|
}
|
|
|
|
void FlatInput::setPlaceholderFast(bool fast) {
|
|
_fastph = fast;
|
|
if (_fastph) {
|
|
a_phLeft = anim::ivalue(_phVisible ? 0 : _st.phShift, _phVisible ? 0 : _st.phShift);
|
|
a_phAlpha = anim::fvalue(_phVisible ? 1 : 0, _phVisible ? 1 : 0);
|
|
update();
|
|
}
|
|
}
|
|
|
|
void FlatInput::updatePlaceholder() {
|
|
bool vis = !text().length();
|
|
if (vis == _phVisible) return;
|
|
|
|
if (_fastph) {
|
|
a_phLeft = anim::ivalue(vis ? 0 : _st.phShift, vis ? 0 : _st.phShift);
|
|
a_phAlpha = anim::fvalue(vis ? 1 : 0, vis ? 1 : 0);
|
|
update();
|
|
} else {
|
|
a_phLeft.start(vis ? 0 : _st.phShift);
|
|
a_phAlpha.start(vis ? 1 : 0);
|
|
anim::start(this);
|
|
}
|
|
_phVisible = vis;
|
|
}
|
|
|
|
const QString &FlatInput::placeholder() const {
|
|
return _fullph;
|
|
}
|
|
|
|
QRect FlatInput::placeholderRect() const {
|
|
return QRect(_st.textMrg.left() + _st.phPos.x(), _st.textMrg.top() + _st.phPos.y(), width() - _st.textMrg.left() - _st.textMrg.right(), height() - _st.textMrg.top() - _st.textMrg.bottom());
|
|
}
|
|
|
|
void FlatInput::correctValue(QKeyEvent *e, const QString &was) {
|
|
}
|
|
|
|
void FlatInput::phPrepare(Painter &p) {
|
|
p.setFont(_st.font->f);
|
|
p.setPen(a_phColor.current());
|
|
}
|
|
|
|
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);
|
|
}
|