diff options
author | Konstantinos Sideris <sideris.konstantin@gmail.com> | 2018-07-17 16:37:25 +0300 |
---|---|---|
committer | Konstantinos Sideris <sideris.konstantin@gmail.com> | 2018-07-17 16:37:25 +0300 |
commit | 0e814da91c8e041897a4c3f7e6e9234bbc7c6f7a (patch) | |
tree | 21f655d30630fe77ba48d07e4b357e2b6c6a5730 /src/ui/TextField.cpp | |
parent | Merge pull request #372 from bebehei/notification (diff) | |
download | nheko-0e814da91c8e041897a4c3f7e6e9234bbc7c6f7a.tar.xz |
Move all files under src/
Diffstat (limited to 'src/ui/TextField.cpp')
-rw-r--r-- | src/ui/TextField.cpp | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/src/ui/TextField.cpp b/src/ui/TextField.cpp new file mode 100644 index 00000000..0c936e69 --- /dev/null +++ b/src/ui/TextField.cpp @@ -0,0 +1,363 @@ +#include "TextField.h" + +#include <QApplication> +#include <QEventTransition> +#include <QFontDatabase> +#include <QPaintEvent> +#include <QPainter> +#include <QPropertyAnimation> + +TextField::TextField(QWidget *parent) + : QLineEdit(parent) +{ + // Get rid of the focus border on macOS. + setAttribute(Qt::WA_MacShowFocusRect, 0); + + state_machine_ = new TextFieldStateMachine(this); + label_ = 0; + label_font_size_ = 15; + show_label_ = false; + background_color_ = QColor("white"); + + setFrame(false); + setAttribute(Qt::WA_Hover); + setMouseTracking(true); + setTextMargins(0, 4, 0, 6); + + QFont font("Open Sans"); + font.setPixelSize(14); + setFont(font); + + state_machine_->start(); + QCoreApplication::processEvents(); +} + +void +TextField::setBackgroundColor(const QColor &color) +{ + background_color_ = color; +} + +QColor +TextField::backgroundColor() const +{ + return background_color_; +} + +void +TextField::setShowLabel(bool value) +{ + 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); + } +} + +bool +TextField::hasLabel() const +{ + return show_label_; +} + +void +TextField::setLabelFontSize(qreal size) +{ + label_font_size_ = size; + + if (label_) { + QFont font(label_->font()); + font.setPixelSize(size); + label_->setFont(font); + label_->update(); + } +} + +qreal +TextField::labelFontSize() const +{ + return label_font_size_; +} + +void +TextField::setLabel(const QString &label) +{ + label_text_ = label; + setShowLabel(true); + label_->update(); +} + +QString +TextField::label() const +{ + return label_text_; +} + +void +TextField::setTextColor(const QColor &color) +{ + text_color_ = color; + setStyleSheet(QString("QLineEdit { color: %1; }").arg(color.name())); +} + +QColor +TextField::textColor() const +{ + if (!text_color_.isValid()) { + return QColor("black"); + } + + return text_color_; +} + +void +TextField::setLabelColor(const QColor &color) +{ + label_color_ = color; + update(); +} + +QColor +TextField::labelColor() const +{ + if (!label_color_.isValid()) { + return QColor("#abb"); // TODO: Move this into Theme.h + } + + return label_color_; +} + +void +TextField::setInkColor(const QColor &color) +{ + ink_color_ = color; + update(); +} + +QColor +TextField::inkColor() const +{ + if (!ink_color_.isValid()) { + return QColor("black"); + } + + return ink_color_; +} + +void +TextField::setUnderlineColor(const QColor &color) +{ + underline_color_ = color; + update(); +} + +QColor +TextField::underlineColor() const +{ + if (!underline_color_.isValid()) { + return QColor("black"); + } + + return underline_color_; +} + +bool +TextField::event(QEvent *event) +{ + switch (event->type()) { + case QEvent::Resize: + case QEvent::Move: { + if (label_) + label_->setGeometry(rect()); + break; + } + default: + break; + } + + return QLineEdit::event(event); +} + +void +TextField::paintEvent(QPaintEvent *event) +{ + 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); + } +} + +TextFieldStateMachine::TextFieldStateMachine(TextField *parent) + : QStateMachine(parent) + , text_field_(parent) +{ + normal_state_ = new QState; + focused_state_ = new QState; + + label_ = 0; + offset_anim_ = 0; + color_anim_ = 0; + progress_ = 0.0; + + addState(normal_state_); + addState(focused_state_); + + setInitialState(normal_state_); + + QEventTransition *transition; + QPropertyAnimation *animation; + + transition = new QEventTransition(parent, QEvent::FocusIn); + transition->setTargetState(focused_state_); + normal_state_->addTransition(transition); + + animation = new QPropertyAnimation(this, "progress", this); + animation->setEasingCurve(QEasingCurve::InCubic); + animation->setDuration(310); + transition->addAnimation(animation); + + transition = new QEventTransition(parent, QEvent::FocusOut); + transition->setTargetState(normal_state_); + focused_state_->addTransition(transition); + + animation = new QPropertyAnimation(this, "progress", this); + animation->setEasingCurve(QEasingCurve::OutCubic); + animation->setDuration(310); + transition->addAnimation(animation); + + normal_state_->assignProperty(this, "progress", 0); + focused_state_->assignProperty(this, "progress", 1); + + setupProperties(); + + connect(text_field_, SIGNAL(textChanged(QString)), this, SLOT(setupProperties())); +} + +void +TextFieldStateMachine::setLabel(TextFieldLabel *label) +{ + 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(); +} + +void +TextFieldStateMachine::setupProperties() +{ + 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(); +} + +TextFieldLabel::TextFieldLabel(TextField *parent) + : QWidget(parent) + , text_field_(parent) +{ + x_ = 0; + y_ = 26; + scale_ = 1; + color_ = parent->labelColor(); + + QFont font("Open Sans SemiBold"); + font.setPixelSize(parent->labelFontSize()); + font.setLetterSpacing(QFont::PercentageSpacing, 102); + setFont(font); +} + +void +TextFieldLabel::paintEvent(QPaintEvent *) +{ + if (!text_field_->hasLabel()) + return; + + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + painter.scale(scale_, scale_); + painter.setPen(color_); + painter.setOpacity(1); + + QPointF pos(2 + x_, height() - 36 + y_); + painter.drawText(pos.x(), pos.y(), text_field_->label()); +} |