#include "AnimatedLineEdit.h" //static const int ANIMATION_DURATION {200}; const QString AnimatedLineEdit::LABEL_OBJECT_NAME("label"); /** @brief constructor * @param a_parent object parent */ AnimatedLineEdit::AnimatedLineEdit(QWidget *a_parent) : QLineEdit(a_parent), m_label("text", this), m_stateMachine(QState::ParallelStates, this), m_st_content(new QState(&m_stateMachine)), m_st_content_filled(new QState(m_st_content)), m_st_content_empty(new QState(m_st_content)), m_st_state(new QState(&m_stateMachine)), m_st_state_focus(new QState(m_st_state)), m_st_state_notFocus(new QState(m_st_state)) { m_label.setObjectName(LABEL_OBJECT_NAME); m_label.setAlignment(Qt::AlignTop); setAlignment(Qt::AlignBottom); setupStateMachine(); connect(this, &AnimatedLineEdit::focusOut, [this]{ if (text().isEmpty()) emit focusOutEmpty(); else emit focusOutFilled(); }); } /** @brief Reimplemented QLineEdit::setPlaceholderText method. Sets the text of label. * @param a_text New text */ void AnimatedLineEdit::setPlaceholderText(const QString &a_text) { m_label.setText(a_text); } /** @brief Reimplemented QLineEdit::setObjectName method. Updates assigned properties. * @param a_objName new object name */ void AnimatedLineEdit::setObjectName(QString a_objName) { QLineEdit::setObjectName(a_objName); updateLabelProperties(); } /** @brief Reimplemented QLineEdit::resizeEvent method. Updates label sizes. * @param a_event Resize event */ void AnimatedLineEdit::resizeEvent(QResizeEvent *a_event) { QLineEdit::resizeEvent(a_event); updateLabelPositionProperty(); } /** @brief Reimplemented QLineEdit::focusInEvent method. Emit focusIn signal. * @param a_event Focus event */ void AnimatedLineEdit::focusInEvent(QFocusEvent *a_event) { emit focusIn(); QLineEdit::focusInEvent(a_event); } /** @brief Reimplemented QLineEdit::focusOutEvent method. Emit focusOut signal. * @param a_event Focus event */ void AnimatedLineEdit::focusOutEvent(QFocusEvent *a_event) { emit focusOut(); QLineEdit::focusOutEvent(a_event); } /** @brief Reimplemented QLineEdit::showEvent method. Sets up initial state and start state machine. * @param a_event Show event */ void AnimatedLineEdit::showEvent(QShowEvent *a_event) { m_labelFontSize = m_label.font().pixelSize(); m_st_content->setInitialState(text().isEmpty() ? m_st_content_empty : m_st_content_filled); m_stateMachine.start(); QLineEdit::showEvent(a_event); } /** @brief Reimplemented QLineEdit::hideEvent method. Stops state machine. * @param a_event Hide event */ void AnimatedLineEdit::hideEvent(QHideEvent *a_event) { QLineEdit::hideEvent(a_event); m_stateMachine.stop(); } /** @brief Setup state machine. Is called from constructor */ void AnimatedLineEdit::setupStateMachine() { m_st_state ->setInitialState(m_st_state_notFocus); // ======================= Animations =========================== QPropertyAnimation *anLabelColor = new QPropertyAnimation(this, "labelColor"); QPropertyAnimation *anLabelFontSize = new QPropertyAnimation(this, "labelFontSize"); QPropertyAnimation *anLabelPosition = new QPropertyAnimation(&m_label, "pos"); for (auto curAnimation :{anLabelColor, anLabelFontSize, anLabelPosition}) { curAnimation->setDuration(ANIMATION_DURATION); curAnimation->setEasingCurve(QEasingCurve::OutCirc); } QParallelAnimationGroup *anParallelGrp = new QParallelAnimationGroup(this); anParallelGrp->addAnimation(anLabelFontSize); anParallelGrp->addAnimation(anLabelPosition); // ====================== Transitions ============================ m_st_content_filled->addTransition(this, SIGNAL(focusOutEmpty()), m_st_content_empty)->addAnimation(anParallelGrp); m_st_content_empty ->addTransition(this, SIGNAL(focusIn()) , m_st_content_filled)->addAnimation(anParallelGrp); m_st_state_focus ->addTransition(this, SIGNAL(focusOut()) , m_st_state_notFocus)->addAnimation(anLabelColor); m_st_state_notFocus->addTransition(this, SIGNAL(focusIn()) , m_st_state_focus)->addAnimation(anLabelColor); // =============================================================== m_st_content_filled->assignProperty(&m_label, "pos", QPoint(0, 0)); } /** @brief Update position of label when LineEdit isn't filled . Call when sizes have changed */ void AnimatedLineEdit::updateLabelPositionProperty() { int labelPosY = height() - m_label.height(); m_st_content_empty->assignProperty(&m_label, "pos", QPoint(0, labelPosY)); } /** @brief Getter for labelFontSize property * @return labelFontSize */ int AnimatedLineEdit::labelFontSize() const { return m_labelFontSize; } /** @brief Setter for labelFontSize property. * @details Sets stylesheet with font size for label */ void AnimatedLineEdit::setLabelFontSize(int a_labelFontSize) { QString fontSizeStylesheet = QString("#%1{font-size:%2px}") .arg(LABEL_OBJECT_NAME) .arg(a_labelFontSize); setStyleSheet(fontSizeStylesheet); m_labelFontSize = a_labelFontSize; } /** @brief Getter for labelColor property * @return labelColor */ QColor AnimatedLineEdit::labelColor() const { return m_labelColor; } /** @brief Setter for labelColor property. * @details Sets stylesheet with text color for label */ void AnimatedLineEdit::setLabelColor(const QColor &a_labelColor) { m_label.setStyleSheet("color:" + a_labelColor.name()); m_labelColor = a_labelColor; } /** @brief Get from stylesheet properties font-size and color for different states of label and assign to States. * * @todo First search with #objectName. Then by class name */ void AnimatedLineEdit::updateLabelProperties() { QString objName; if (!objectName().isEmpty()) { objName = "(?:#%1|.%2|\\s?%2)"; objName = objName.arg(objectName()); } else objName = ".%1"; objName = objName.arg(metaObject()->className()); // Not focus properties ====================== StyleSheatSearchPar labelSearchPar; labelSearchPar.widgetName = objName; labelSearchPar.subcontrol = "label"; QString labelStyleSheet = AppStyleSheetHandler::getWidgetStyleSheet(labelSearchPar); QString strColor = AppStyleSheetHandler::getValueFromStylesheet(labelStyleSheet, "color"); m_st_state_notFocus->assignProperty(this, "labelColor", QColor(strColor)); // Focus properties ====================== labelSearchPar.pseudoClass = "focus"; QString labelFocusStyleSheet = AppStyleSheetHandler::getWidgetStyleSheet(labelSearchPar); strColor = AppStyleSheetHandler::getValueFromStylesheet(labelFocusStyleSheet, "color"); m_st_state_focus->assignProperty(this, "labelColor", QColor(strColor)); // Filled properties ====================== assignFontSizeFromStylesheet(labelStyleSheet, m_st_content_filled); // Empty properties ====================== QString lineEditStyleSheet = AppStyleSheetHandler::getWidgetStyleSheet(objName); assignFontSizeFromStylesheet(lineEditStyleSheet, m_st_content_empty); } /** @brief Find in a_stylesheet the value of font-size property and assign it to a_state * @param a_stylesheet Stylesheet withowt "{}" * @param a_state state for what property will assign */ void AnimatedLineEdit::assignFontSizeFromStylesheet(const QString &a_stylesheet, QState *a_state) { QString strFontSize = AppStyleSheetHandler::getValueFromStylesheet(a_stylesheet, "font-size"); int fontSize = 0; //find number QRegExp regExp("(\\d+)"); if (regExp.indexIn(strFontSize, 0) != -1) fontSize = regExp.cap(1).toInt(); if (fontSize) a_state->assignProperty(this, "labelFontSize", fontSize); else qWarning()<< "font-size of AnimatedLineEdit is not found or incorrect"; };