diff options
Diffstat (limited to 'SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.cpp')
| -rw-r--r-- | SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.cpp | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.cpp b/SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.cpp new file mode 100644 index 0000000..c6823e4 --- /dev/null +++ b/SQLiteStudio3/guiSQLiteStudio/common/widgetstateindicator.cpp @@ -0,0 +1,412 @@ +#include "widgetstateindicator.h" +#include "iconmanager.h" +#include "common/unused.h" +#include "uiutils.h" +#include "mdichild.h" +#include <QLabel> +#include <QCheckBox> +#include <QGroupBox> +#include <QEvent> +#include <QHBoxLayout> +#include <QGraphicsDropShadowEffect> +#include <QSequentialAnimationGroup> +#include <QPropertyAnimation> +#include <QDebug> +#include <QScrollArea> + +QHash<QWidget*,WidgetStateIndicator*> WidgetStateIndicator::instances; + +WidgetStateIndicator::WidgetStateIndicator(QWidget *widget) : + QObject(widget), widget(widget) +{ + widget->installEventFilter(this); + detectWindowParent(); + initPositionMode(); + initEffects(); + initLabel(); + updateMode(); + updatePosition(); + finalInit(); +} + +WidgetStateIndicator::~WidgetStateIndicator() +{ + instances.remove(widget); + widget->removeEventFilter(this); + windowParent->removeEventFilter(this); +} + +void WidgetStateIndicator::initLabel() +{ + label = new QLabel(); + label->setMargin(0); + label->installEventFilter(this); + label->setGraphicsEffect(highlightingEffect); + + labelParent = new QWidget(windowParent); + labelParent->setLayout(new QHBoxLayout()); + labelParent->layout()->setMargin(0); + labelParent->layout()->addWidget(label); + labelParent->setGraphicsEffect(glowEffect); +} + +void WidgetStateIndicator::initEffects() +{ + initGlowEffects(); + initHighlightingEffects(); + initAnimations(); +} + +void WidgetStateIndicator::initGlowEffects() +{ + glowEffect = new QGraphicsDropShadowEffect(); + glowEffect->setBlurRadius(10.0); + glowEffect->setOffset(0.0); + glowEffect->setEnabled(true); +} + +void WidgetStateIndicator::initHighlightingEffects() +{ + highlightingEffect = new QGraphicsColorizeEffect(); + highlightingEffect->setColor(Qt::white); + highlightingEffect->setStrength(0.3); + highlightingEffect->setEnabled(false); +} + +void WidgetStateIndicator::initAnimations() +{ + animation = new QSequentialAnimationGroup(this); + animation->setLoopCount(-1); + + // Animation of glow efect + QPropertyAnimation* varAnim = new QPropertyAnimation(glowEffect, "blurRadius"); + varAnim->setStartValue(3.0); + varAnim->setEndValue(14.0); + varAnim->setEasingCurve(QEasingCurve::InOutCubic); + varAnim->setDuration(300); + animation->addAnimation(varAnim); + + varAnim = new QPropertyAnimation(glowEffect, "blurRadius"); + varAnim->setStartValue(14.0); + varAnim->setEndValue(3.0); + varAnim->setEasingCurve(QEasingCurve::InOutCubic); + varAnim->setDuration(300); + animation->addAnimation(varAnim); +} + +void WidgetStateIndicator::initPositionMode() +{ + if (dynamic_cast<QGroupBox*>(widget)) + positionMode = PositionMode::GROUP_BOX; + else if (dynamic_cast<QLabel*>(widget)) + positionMode = PositionMode::LABEL; + else if (dynamic_cast<QCheckBox*>(widget)) + positionMode = PositionMode::CHECK_BOX; +} + +void WidgetStateIndicator::finalInit() +{ + label->setFixedSize(label->pixmap()->size()); + labelParent->setFixedSize(label->pixmap()->size()); + widgetVisible = widget->isVisible(); + labelParent->setVisible(false); +} + +void WidgetStateIndicator::setMessage(const QString& msg) +{ + static const QString paraTpl = QStringLiteral("<p>%1</p>"); + if (msg.startsWith("<p>") && msg.endsWith("</p>")) + message = msg; + else + message = paraTpl.arg(msg); + + label->setToolTip(message); + if (!msg.isNull()) + label->setCursor(Qt::WhatsThisCursor); + else + label->unsetCursor(); +} + +void WidgetStateIndicator::clearMessage() +{ + message = QString::null; + label->setToolTip(message); + label->unsetCursor(); +} + +void WidgetStateIndicator::detectWindowParent() +{ + if (windowParent) + windowParent->removeEventFilter(this); + + windowParent = findParentWindow(widget); + windowParent->installEventFilter(this); + if (labelParent) + labelParent->setParent(windowParent); +} + +void WidgetStateIndicator::setMode(WidgetStateIndicator::Mode mode) +{ + this->mode = mode; + updateMode(); +} + +void WidgetStateIndicator::show(const QString& msg, bool animated) +{ + visibilityRequested = true; + setMessage(msg); + if (animated && animation->state() != QAbstractAnimation::Running) + animation->start(); + + updateVisibility(); +} + +void WidgetStateIndicator::hide() +{ + visibilityRequested = false; + clearMessage(); + if (animation->state() == QAbstractAnimation::Running) + animation->stop(); + + updateVisibility(); +} + +void WidgetStateIndicator::setVisible(bool visible, const QString& msg) +{ + if (visible) + show(msg); + else + hide(); +} + +void WidgetStateIndicator::release() +{ + setVisible(false); + instances.remove(widget); + deleteLater(); +} + +void WidgetStateIndicator::info(const QString& msg, bool animated) +{ + setMode(Mode::INFO); + show(msg, animated); +} + +void WidgetStateIndicator::warn(const QString& msg, bool animated) +{ + setMode(Mode::WARNING); + show(msg, animated); +} + +void WidgetStateIndicator::error(const QString& msg, bool animated) +{ + setMode(Mode::ERROR); + show(msg, animated); +} + +void WidgetStateIndicator::hint(const QString& msg, bool animated) +{ + setMode(Mode::HINT); + show(msg, animated); +} + +bool WidgetStateIndicator::exists(QWidget* widget) +{ + return instances.contains(widget); +} + +WidgetStateIndicator* WidgetStateIndicator::getInstance(QWidget* widget) +{ + if (!instances.contains(widget)) + instances[widget] = new WidgetStateIndicator(widget); + + return instances[widget]; +} + +bool WidgetStateIndicator::eventFilter(QObject* obj, QEvent* ev) +{ + if (obj == widget) + { + switch (ev->type()) + { + case QEvent::Move: + case QEvent::Resize: + case QEvent::Scroll: + updatePosition(); + break; + case QEvent::Show: + widgetVisible = true; + updateVisibility(); + break; + case QEvent::Hide: + widgetVisible = false; + updateVisibility(); + break; + case QEvent::EnabledChange: + updateVisibility(); + break; + default: + break; + } + } + else if (obj == windowParent) + { + switch (ev->type()) + { + case QEvent::ParentChange: + detectWindowParent(); + break; + default: + break; + } + } + else if (obj == label) + { + if (ev->type() == QEvent::Enter) + highlightingEffect->setEnabled(true); + else if (ev->type() == QEvent::Leave) + highlightingEffect->setEnabled(false); + } + + return false; +} + +void WidgetStateIndicator::updateMode() +{ + switch (mode) + { + case Mode::ERROR: + label->setPixmap(ICONS.INDICATOR_ERROR); + glowEffect->setColor(Qt::red); + break; + case Mode::WARNING: + label->setPixmap(ICONS.INDICATOR_WARN); + glowEffect->setColor(Qt::darkYellow); + break; + case Mode::INFO: + label->setPixmap(ICONS.INDICATOR_INFO); + glowEffect->setColor(Qt::blue); + break; + case Mode::HINT: + label->setPixmap(ICONS.INDICATOR_HINT); + glowEffect->setColor(Qt::darkCyan); + break; + } +} + +void WidgetStateIndicator::updatePosition() +{ + switch (positionMode) + { + case PositionMode::DEFAULT: + updatePositionDefault(); + break; + case PositionMode::GROUP_BOX: + updatePositionGroupBox(); + break; + case PositionMode::LABEL: + updatePositionLabel(); + break; + case PositionMode::CHECK_BOX: + updatePositionCheckBox(); + break; + } +} + +void WidgetStateIndicator::updatePositionDefault() +{ + QPoint xy = widget->mapTo(windowParent, QPoint(0,0)); + labelParent->move(xy + QPoint(-4, -4)); +} + +void WidgetStateIndicator::updatePositionGroupBox() +{ + QPoint xy = widget->mapTo(windowParent, QPoint(0,0)); + + QGroupBox* gb = dynamic_cast<QGroupBox*>(widget); + + QFont font = gb->font(); + QFontMetrics fm(font); + QString txt = gb->title(); + QPoint diff(fm.width(txt), 2); + + labelParent->move(xy + diff); +} + +void WidgetStateIndicator::updatePositionLabel() +{ + updatePositionCheckBox(); // currently they're equal +} + +void WidgetStateIndicator::updatePositionCheckBox() +{ + QPoint xy = widget->mapTo(windowParent, QPoint(0,0)); + labelParent->move(xy + QPoint(-6, -2)); +} + +void WidgetStateIndicator::updateVisibility() +{ + if (shouldHide()) + { + labelParent->setVisible(false); + } + else if (shouldShow()) + { + updatePosition(); + labelParent->setVisible(true); + } +} + +bool WidgetStateIndicator::shouldHide() +{ + if (!labelParent->isVisible()) + return false; + + if (!widgetVisible) + return true; + + if (!visibilityRequested) + return true; + + if (!widget->isEnabled()) + return true; + + return false; +} + +bool WidgetStateIndicator::shouldShow() +{ + if (labelParent->isVisible()) + return false; + + if (!widget->isEnabled()) + return false; + + if (!widgetVisible) + return false; + + if (!visibilityRequested) + return false; + + return true; +} +WidgetStateIndicator::PositionMode WidgetStateIndicator::getPositionMode() const +{ + return positionMode; +} + +void WidgetStateIndicator::setPositionMode(const PositionMode& value) +{ + positionMode = value; +} + +QWidget* WidgetStateIndicator::findParentWindow(QWidget* w) +{ + while (w && !w->windowFlags().testFlag(Qt::Window) && !dynamic_cast<QScrollArea*>(w) && !dynamic_cast<MdiChild*>(w)) + w = w->parentWidget(); + + if (dynamic_cast<QScrollArea*>(w)) + return dynamic_cast<QScrollArea*>(w)->widget(); + + return w; +} |
