summary refs log tree commit diff
path: root/src/ui/TextField.cpp
diff options
context:
space:
mode:
authorKonstantinos Sideris <sideris.konstantin@gmail.com>2018-07-17 16:37:25 +0300
committerKonstantinos Sideris <sideris.konstantin@gmail.com>2018-07-17 16:37:25 +0300
commit0e814da91c8e041897a4c3f7e6e9234bbc7c6f7a (patch)
tree21f655d30630fe77ba48d07e4b357e2b6c6a5730 /src/ui/TextField.cpp
parentMerge pull request #372 from bebehei/notification (diff)
downloadnheko-0e814da91c8e041897a4c3f7e6e9234bbc7c6f7a.tar.xz
Move all files under src/
Diffstat (limited to 'src/ui/TextField.cpp')
-rw-r--r--src/ui/TextField.cpp363
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());
+}