matrixion/src/ui/TextField.cc

370 lines
8.7 KiB
C++
Raw Normal View History

2017-04-06 02:06:42 +03:00
#include "TextField.h"
#include <QApplication>
#include <QEventTransition>
#include <QFontDatabase>
#include <QPaintEvent>
#include <QPainter>
#include <QPropertyAnimation>
TextField::TextField(QWidget *parent)
2017-08-20 13:47:22 +03:00
: QLineEdit(parent)
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
// Get rid of the focus border on macOS.
setAttribute(Qt::WA_MacShowFocusRect, 0);
state_machine_ = new TextFieldStateMachine(this);
label_ = 0;
2017-11-25 16:14:37 +03:00
label_font_size_ = 15;
2017-09-10 12:59:21 +03:00
show_label_ = false;
background_color_ = QColor("white");
setFrame(false);
setAttribute(Qt::WA_Hover);
setMouseTracking(true);
setTextMargins(0, 4, 0, 6);
QFont font("Open Sans");
2017-11-25 16:14:37 +03:00
font.setPixelSize(14);
2017-09-10 12:59:21 +03:00
setFont(font);
state_machine_->start();
QCoreApplication::processEvents();
2017-04-06 02:06:42 +03:00
}
2017-10-01 12:11:33 +03:00
TextField::~TextField() {}
2017-04-06 02:06:42 +03:00
2017-08-20 13:47:22 +03:00
void
TextField::setBackgroundColor(const QColor &color)
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
background_color_ = color;
2017-04-06 02:06:42 +03:00
}
2017-08-20 13:47:22 +03:00
QColor
TextField::backgroundColor() const
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
return background_color_;
2017-04-06 02:06:42 +03:00
}
2017-08-20 13:47:22 +03:00
void
TextField::setShowLabel(bool value)
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
if (show_label_ == value) {
return;
}
show_label_ = value;
if (!label_ && value) {
label_ = new TextFieldLabel(this);
state_machine_->setLabel(label_);
}
if (value) {
setContentsMargins(0, 23, 0, 0);
} else {
setContentsMargins(0, 0, 0, 0);
}
2017-04-06 02:06:42 +03:00
}
2017-08-20 13:47:22 +03:00
bool
TextField::hasLabel() const
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
return show_label_;
2017-04-06 02:06:42 +03:00
}
2017-08-20 13:47:22 +03:00
void
TextField::setLabelFontSize(qreal size)
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
label_font_size_ = size;
if (label_) {
QFont font(label_->font());
font.setPixelSize(size);
label_->setFont(font);
label_->update();
}
2017-04-06 02:06:42 +03:00
}
2017-08-20 13:47:22 +03:00
qreal
TextField::labelFontSize() const
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
return label_font_size_;
2017-04-06 02:06:42 +03:00
}
2017-08-20 13:47:22 +03:00
void
TextField::setLabel(const QString &label)
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
label_text_ = label;
setShowLabel(true);
label_->update();
2017-04-06 02:06:42 +03:00
}
2017-08-20 13:47:22 +03:00
QString
TextField::label() const
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
return label_text_;
2017-04-06 02:06:42 +03:00
}
2017-08-20 13:47:22 +03:00
void
TextField::setTextColor(const QColor &color)
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
text_color_ = color;
setStyleSheet(QString("QLineEdit { color: %1; }").arg(color.name()));
2017-04-06 02:06:42 +03:00
}
2017-08-20 13:47:22 +03:00
QColor
TextField::textColor() const
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
if (!text_color_.isValid()) {
return QColor("black");
}
2017-04-06 02:06:42 +03:00
2017-09-10 12:59:21 +03:00
return text_color_;
2017-04-06 02:06:42 +03:00
}
2017-08-20 13:47:22 +03:00
void
TextField::setLabelColor(const QColor &color)
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
label_color_ = color;
2017-12-10 16:22:01 +03:00
update();
2017-04-06 02:06:42 +03:00
}
2017-08-20 13:47:22 +03:00
QColor
TextField::labelColor() const
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
if (!label_color_.isValid()) {
return QColor("#abb"); // TODO: Move this into Theme.h
}
2017-04-06 02:06:42 +03:00
2017-09-10 12:59:21 +03:00
return label_color_;
2017-04-06 02:06:42 +03:00
}
2017-08-20 13:47:22 +03:00
void
TextField::setInkColor(const QColor &color)
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
ink_color_ = color;
2017-12-10 16:22:01 +03:00
update();
2017-04-06 02:06:42 +03:00
}
2017-08-20 13:47:22 +03:00
QColor
TextField::inkColor() const
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
if (!ink_color_.isValid()) {
return QColor("black");
}
2017-04-06 02:06:42 +03:00
2017-09-10 12:59:21 +03:00
return ink_color_;
2017-04-06 02:06:42 +03:00
}
2017-08-20 13:47:22 +03:00
void
TextField::setUnderlineColor(const QColor &color)
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
underline_color_ = color;
2017-12-10 16:22:01 +03:00
update();
2017-04-06 02:06:42 +03:00
}
2017-08-20 13:47:22 +03:00
QColor
TextField::underlineColor() const
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
if (!underline_color_.isValid()) {
return QColor("black");
}
2017-04-06 02:06:42 +03:00
2017-09-10 12:59:21 +03:00
return underline_color_;
2017-04-06 02:06:42 +03:00
}
2017-08-20 13:47:22 +03:00
bool
TextField::event(QEvent *event)
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
switch (event->type()) {
case QEvent::Resize:
case QEvent::Move: {
if (label_)
label_->setGeometry(rect());
break;
}
default:
break;
}
return QLineEdit::event(event);
2017-04-06 02:06:42 +03:00
}
2017-08-20 13:47:22 +03:00
void
TextField::paintEvent(QPaintEvent *event)
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
QLineEdit::paintEvent(event);
QPainter painter(this);
if (text().isEmpty()) {
painter.setOpacity(1 - state_machine_->progress());
painter.fillRect(rect(), backgroundColor());
}
const int y = height() - 1;
const int wd = width() - 5;
QPen pen;
pen.setWidth(1);
pen.setColor(underlineColor());
painter.setPen(pen);
painter.setOpacity(1);
painter.drawLine(2, y, wd, y);
QBrush brush;
brush.setStyle(Qt::SolidPattern);
brush.setColor(inkColor());
const qreal progress = state_machine_->progress();
if (progress > 0) {
painter.setPen(Qt::NoPen);
painter.setBrush(brush);
const int w = (1 - progress) * static_cast<qreal>(wd / 2);
painter.drawRect(w + 2.5, height() - 2, wd - 2 * w, 2);
}
2017-04-06 02:06:42 +03:00
}
TextFieldStateMachine::TextFieldStateMachine(TextField *parent)
2017-08-20 13:47:22 +03:00
: QStateMachine(parent)
, text_field_(parent)
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
normal_state_ = new QState;
focused_state_ = new QState;
2017-04-06 02:06:42 +03:00
2017-09-10 12:59:21 +03:00
label_ = 0;
offset_anim_ = 0;
color_anim_ = 0;
progress_ = 0.0;
2017-04-06 02:06:42 +03:00
2017-09-10 12:59:21 +03:00
addState(normal_state_);
addState(focused_state_);
2017-04-06 02:06:42 +03:00
2017-09-10 12:59:21 +03:00
setInitialState(normal_state_);
2017-04-06 02:06:42 +03:00
2017-09-10 12:59:21 +03:00
QEventTransition *transition;
QPropertyAnimation *animation;
2017-04-06 02:06:42 +03:00
2017-09-10 12:59:21 +03:00
transition = new QEventTransition(parent, QEvent::FocusIn);
transition->setTargetState(focused_state_);
normal_state_->addTransition(transition);
2017-04-06 02:06:42 +03:00
2017-09-10 12:59:21 +03:00
animation = new QPropertyAnimation(this, "progress", this);
animation->setEasingCurve(QEasingCurve::InCubic);
animation->setDuration(310);
transition->addAnimation(animation);
2017-04-06 02:06:42 +03:00
2017-09-10 12:59:21 +03:00
transition = new QEventTransition(parent, QEvent::FocusOut);
transition->setTargetState(normal_state_);
focused_state_->addTransition(transition);
2017-04-06 02:06:42 +03:00
2017-09-10 12:59:21 +03:00
animation = new QPropertyAnimation(this, "progress", this);
animation->setEasingCurve(QEasingCurve::OutCubic);
animation->setDuration(310);
transition->addAnimation(animation);
2017-04-06 02:06:42 +03:00
2017-09-10 12:59:21 +03:00
normal_state_->assignProperty(this, "progress", 0);
focused_state_->assignProperty(this, "progress", 1);
2017-04-06 02:06:42 +03:00
2017-09-10 12:59:21 +03:00
setupProperties();
2017-04-06 02:06:42 +03:00
2017-09-10 12:59:21 +03:00
connect(text_field_, SIGNAL(textChanged(QString)), this, SLOT(setupProperties()));
2017-04-06 02:06:42 +03:00
}
2017-10-01 12:11:33 +03:00
TextFieldStateMachine::~TextFieldStateMachine() {}
2017-04-06 02:06:42 +03:00
2017-08-20 13:47:22 +03:00
void
TextFieldStateMachine::setLabel(TextFieldLabel *label)
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
if (label_) {
delete label_;
}
if (offset_anim_) {
removeDefaultAnimation(offset_anim_);
delete offset_anim_;
}
if (color_anim_) {
removeDefaultAnimation(color_anim_);
delete color_anim_;
}
label_ = label;
if (label_) {
offset_anim_ = new QPropertyAnimation(label_, "offset", this);
offset_anim_->setDuration(210);
offset_anim_->setEasingCurve(QEasingCurve::OutCubic);
addDefaultAnimation(offset_anim_);
color_anim_ = new QPropertyAnimation(label_, "color", this);
color_anim_->setDuration(210);
addDefaultAnimation(color_anim_);
}
setupProperties();
2017-04-06 02:06:42 +03:00
}
2017-08-20 13:47:22 +03:00
void
TextFieldStateMachine::setupProperties()
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
if (label_) {
const int m = text_field_->textMargins().top();
if (text_field_->text().isEmpty()) {
normal_state_->assignProperty(label_, "offset", QPointF(0, 26));
} else {
normal_state_->assignProperty(label_, "offset", QPointF(0, 0 - m));
}
focused_state_->assignProperty(label_, "offset", QPointF(0, 0 - m));
focused_state_->assignProperty(label_, "color", text_field_->inkColor());
normal_state_->assignProperty(label_, "color", text_field_->labelColor());
if (0 != label_->offset().y() && !text_field_->text().isEmpty()) {
label_->setOffset(QPointF(0, 0 - m));
} else if (!text_field_->hasFocus() && label_->offset().y() <= 0 &&
text_field_->text().isEmpty()) {
label_->setOffset(QPointF(0, 26));
}
}
text_field_->update();
2017-04-06 02:06:42 +03:00
}
TextFieldLabel::TextFieldLabel(TextField *parent)
2017-08-20 13:47:22 +03:00
: QWidget(parent)
, text_field_(parent)
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
x_ = 0;
y_ = 26;
scale_ = 1;
color_ = parent->labelColor();
2017-11-25 16:14:37 +03:00
QFont font("Open Sans SemiBold");
font.setPixelSize(parent->labelFontSize());
2017-09-10 12:59:21 +03:00
font.setLetterSpacing(QFont::PercentageSpacing, 102);
setFont(font);
2017-04-06 02:06:42 +03:00
}
2017-10-01 12:11:33 +03:00
TextFieldLabel::~TextFieldLabel() {}
2017-04-06 02:06:42 +03:00
2017-08-20 13:47:22 +03:00
void
TextFieldLabel::paintEvent(QPaintEvent *)
2017-04-06 02:06:42 +03:00
{
2017-09-10 12:59:21 +03:00
if (!text_field_->hasLabel())
return;
2017-04-06 02:06:42 +03:00
2017-09-10 12:59:21 +03:00
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.scale(scale_, scale_);
painter.setPen(color_);
painter.setOpacity(1);
2017-04-06 02:06:42 +03:00
2017-09-10 12:59:21 +03:00
QPointF pos(2 + x_, height() - 36 + y_);
painter.drawText(pos.x(), pos.y(), text_field_->label());
2017-04-06 02:06:42 +03:00
}