diff --git a/components/components.pro b/components/components.pro index 74bf6f4..dd68afe 100644 --- a/components/components.pro +++ b/components/components.pro @@ -10,7 +10,12 @@ SOURCES = \ lib/qtmaterialcheckable_internal.cpp \ lib/qtmaterialcheckable.cpp \ lib/qtmaterialripple.cpp \ - lib/qtmaterialrippleoverlay.cpp + lib/qtmaterialrippleoverlay.cpp \ + qtmaterialfab.cpp \ + qtmaterialraisedbutton.cpp \ + qtmaterialflatbutton_internal.cpp \ + qtmaterialflatbutton.cpp \ + lib/qtmaterialstatetransition.cpp HEADERS = \ qtmaterialavatar_p.h \ qtmaterialavatar.h \ @@ -27,6 +32,15 @@ HEADERS = \ lib/qtmaterialcheckable_p.h \ lib/qtmaterialripple.h \ lib/qtmaterialrippleoverlay.h \ - lib/qtmaterialcheckable.h + lib/qtmaterialcheckable.h \ + qtmaterialfab_p.h \ + qtmaterialfab.h \ + qtmaterialraisedbutton_p.h \ + qtmaterialraisedbutton.h \ + qtmaterialflatbutton_internal.h \ + qtmaterialflatbutton_p.h \ + qtmaterialflatbutton.h \ + lib/qtmaterialstatetransition.h \ + lib/qtmaterialstatetransitionevent.h RESOURCES += \ resources.qrc diff --git a/components/lib/qtmaterialstatetransition.cpp b/components/lib/qtmaterialstatetransition.cpp new file mode 100644 index 0000000..75f1faf --- /dev/null +++ b/components/lib/qtmaterialstatetransition.cpp @@ -0,0 +1,19 @@ +#include "lib/qtmaterialstatetransition.h" + +QtMaterialStateTransition::QtMaterialStateTransition(QtMaterialStateTransitionType type) + : m_type(type) +{ +} + +bool QtMaterialStateTransition::eventTest(QEvent *event) +{ + if (event->type() != QEvent::Type(QEvent::User + 1)) { + return false; + } + QtMaterialStateTransitionEvent *transition = static_cast(event); + return (m_type == transition->type); +} + +void QtMaterialStateTransition::onTransition(QEvent *) +{ +} diff --git a/components/lib/qtmaterialstatetransition.h b/components/lib/qtmaterialstatetransition.h new file mode 100644 index 0000000..d501302 --- /dev/null +++ b/components/lib/qtmaterialstatetransition.h @@ -0,0 +1,22 @@ +#ifndef QTMATERIALSTATETRANSITION_H +#define QTMATERIALSTATETRANSITION_H + +#include +#include "lib/qtmaterialstatetransitionevent.h" + +class QtMaterialStateTransition : public QAbstractTransition +{ + Q_OBJECT + +public: + QtMaterialStateTransition(QtMaterialStateTransitionType type); + +protected: + virtual bool eventTest(QEvent *event); + virtual void onTransition(QEvent *); + +private: + QtMaterialStateTransitionType m_type; +}; + +#endif // QTMATERIALSTATETRANSITION_H diff --git a/components/lib/qtmaterialstatetransitionevent.h b/components/lib/qtmaterialstatetransitionevent.h new file mode 100644 index 0000000..1c64ec6 --- /dev/null +++ b/components/lib/qtmaterialstatetransitionevent.h @@ -0,0 +1,42 @@ +#ifndef QTMATERIALSTATETRANSITIONEVENT_H +#define QTMATERIALSTATETRANSITIONEVENT_H + +#include + +enum QtMaterialStateTransitionType { + // Snackbar + SnackbarShowTransition = 1, + SnackbarHideTransition, + SnackbarWaitTransition, + SnackbarNextTransition, + // FlatButton + FlatButtonPressedTransition, + FlatButtonCheckedTransition, + FlatButtonUncheckedTransition, + // CollapsibleMenu + CollapsibleMenuExpand, + CollapsibleMenuCollapse, + // Slider + SliderChangedToMinimum, + SliderChangedFromMinimum, + SliderNoFocusMouseEnter, + SliderNoFocusMouseLeave, + // Dialog + DialogShowTransition, + DialogHideTransition, + // + MaxTransitionType = 65535 +}; + +struct QtMaterialStateTransitionEvent : public QEvent +{ + QtMaterialStateTransitionEvent(QtMaterialStateTransitionType type) + : QEvent(QEvent::Type(QEvent::User + 1)), + type(type) + { + } + + QtMaterialStateTransitionType type; +}; + +#endif // QTMATERIALSTATETRANSITIONEVENT_H diff --git a/components/qtmaterialfab.cpp b/components/qtmaterialfab.cpp new file mode 100644 index 0000000..3c3de8a --- /dev/null +++ b/components/qtmaterialfab.cpp @@ -0,0 +1,321 @@ +#include "qtmaterialfab.h" +#include "qtmaterialfab_p.h" +#include +#include +#include +#include +#include "lib/qtmaterialrippleoverlay.h" + +/*! + * \class QtMaterialFloatingActionButtonPrivate + * \internal + */ + +/*! + * \internal + */ +QtMaterialFloatingActionButtonPrivate::QtMaterialFloatingActionButtonPrivate(QtMaterialFloatingActionButton *q) + : QtMaterialRaisedButtonPrivate(q) +{ +} + +/*! + * \internal + */ +QtMaterialFloatingActionButtonPrivate::~QtMaterialFloatingActionButtonPrivate() +{ +} + +/*! + * \internal + */ +void QtMaterialFloatingActionButtonPrivate::init() +{ + Q_Q(QtMaterialFloatingActionButton); + + corner = Qt::BottomRightCorner; + mini = false; + offsX = 34; + offsY = 36; + + q->setRole(Material::Primary); + q->setFixedSize(DefaultDiameter, DefaultDiameter); + q->setGeometry(fabGeometry()); + + setupProperties(); + + if (q->parentWidget()) { + q->parentWidget()->installEventFilter(q); + } + + q->setFixedRippleRadius(50); +} + +/*! + * \internal + */ +QRect QtMaterialFloatingActionButtonPrivate::fabGeometry() const +{ + Q_Q(const QtMaterialFloatingActionButton); + + QWidget *parent = q->parentWidget(); + if (!parent) { + return QRect(); + } + + const int s = mini ? MiniDiameter : DefaultDiameter; + + switch (corner) + { + case Qt::TopLeftCorner: + return QRect(offsX, offsY, s, s); + case Qt::TopRightCorner: + return QRect(parent->width()-(offsX+s), offsY, s, s); + case Qt::BottomLeftCorner: + return QRect(offsX, parent->height()-(offsY+s), s, s); + case Qt::BottomRightCorner: + default: + break; + } + return QRect(parent->width()-(offsX+s), parent->height()-(offsY+s), s, s); +} + +/*! + * \internal + */ +void QtMaterialFloatingActionButtonPrivate::setupProperties() +{ + if (mini) { + effect->setColor(QColor(0, 0, 0, 80)); + normalState->assignProperty(effect, "offset", QPointF(0, 3)); + normalState->assignProperty(effect, "blurRadius", 13); + pressedState->assignProperty(effect, "offset", QPointF(0, 7)); + pressedState->assignProperty(effect, "blurRadius", 20); + } else { + effect->setColor(QColor(0, 0, 0, 105)); + normalState->assignProperty(effect, "offset", QPointF(0, 6)); + normalState->assignProperty(effect, "blurRadius", 16); + pressedState->assignProperty(effect, "offset", QPointF(0, 11)); + pressedState->assignProperty(effect, "blurRadius", 28); + } +} + +/*! + * \class QtMaterialFloatingActionButton + */ + +QtMaterialFloatingActionButton::QtMaterialFloatingActionButton(const QIcon &icon, QWidget *parent) + : QtMaterialRaisedButton(*new QtMaterialFloatingActionButtonPrivate(this), parent) +{ + d_func()->init(); + + setIcon(icon); +} + +QtMaterialFloatingActionButton::~QtMaterialFloatingActionButton() +{ +} + +/*! + * \reimp + */ +QSize QtMaterialFloatingActionButton::sizeHint() const +{ + Q_D(const QtMaterialFloatingActionButton); + + if (d->mini) { + return QSize(QtMaterialFloatingActionButtonPrivate::MiniDiameter, + QtMaterialFloatingActionButtonPrivate::MiniDiameter); + } else { + return QSize(QtMaterialFloatingActionButtonPrivate::DefaultDiameter, + QtMaterialFloatingActionButtonPrivate::DefaultDiameter); + } +} + +void QtMaterialFloatingActionButton::setMini(bool state) +{ + Q_D(QtMaterialFloatingActionButton); + + if (d->mini == state) { + return; + } + + d->mini = state; + + setFixedSize(d->diameter(), d->diameter()); + setFixedRippleRadius(state ? 30 : 50); + + d->setupProperties(); + updateClipPath(); + setGeometry(d->fabGeometry()); + update(); +} + +bool QtMaterialFloatingActionButton::isMini() const +{ + Q_D(const QtMaterialFloatingActionButton); + + return d->mini; +} + +void QtMaterialFloatingActionButton::setCorner(Qt::Corner corner) +{ + Q_D(QtMaterialFloatingActionButton); + + if (d->corner == corner) { + return; + } + + d->corner = corner; + setGeometry(d->fabGeometry()); + update(); +} + +Qt::Corner QtMaterialFloatingActionButton::corner() const +{ + Q_D(const QtMaterialFloatingActionButton); + + return d->corner; +} + +void QtMaterialFloatingActionButton::setOffset(int x, int y) +{ + Q_D(QtMaterialFloatingActionButton); + + d->offsX = x; + d->offsY = y; + setGeometry(d->fabGeometry()); + update(); +} + +QSize QtMaterialFloatingActionButton::offset() const +{ + Q_D(const QtMaterialFloatingActionButton); + + return QSize(d->offsX, d->offsY); +} + +void QtMaterialFloatingActionButton::setXOffset(int x) +{ + Q_D(QtMaterialFloatingActionButton); + + d->offsX = x; + setGeometry(d->fabGeometry()); + update(); +} + +int QtMaterialFloatingActionButton::xOffset() const +{ + Q_D(const QtMaterialFloatingActionButton); + + return d->offsX; +} + +void QtMaterialFloatingActionButton::setYOffset(int y) +{ + Q_D(QtMaterialFloatingActionButton); + + d->offsY = y; + setGeometry(d->fabGeometry()); + update(); +} + +int QtMaterialFloatingActionButton::yOffset() const +{ + Q_D(const QtMaterialFloatingActionButton); + + return d->offsY; +} + +/*! + * \reimp + */ +bool QtMaterialFloatingActionButton::event(QEvent *event) +{ + Q_D(QtMaterialFloatingActionButton); + + if (!parent()) { + return QtMaterialRaisedButton::event(event); + } + switch (event->type()) + { + case QEvent::ParentChange: + { + parent()->installEventFilter(this); + setGeometry(d->fabGeometry()); + break; + } + case QEvent::ParentAboutToChange: + { + parent()->removeEventFilter(this); + break; + } + default: + break; + } + return QtMaterialRaisedButton::event(event); +} + +/*! + * \reimp + */ +bool QtMaterialFloatingActionButton::eventFilter(QObject *obj, QEvent *event) +{ + const QEvent::Type type = event->type(); + + if (QEvent::Move == type || QEvent::Resize == type) + { + Q_D(QtMaterialFloatingActionButton); + setGeometry(d->fabGeometry()); + } + + return QtMaterialRaisedButton::eventFilter(obj, event); +} + +/*! + * \reimp + */ +void QtMaterialFloatingActionButton::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event) + + Q_D(QtMaterialFloatingActionButton); + + QRect square = QRect(0, 0, d->diameter(), d->diameter()); + square.moveCenter(rect().center()); + + QPainter painter(this); + painter.setRenderHints(QPainter::Antialiasing); + + QBrush brush; + brush.setStyle(Qt::SolidPattern); + + if (isEnabled()) { + brush.setColor(backgroundColor()); + } else { + brush.setColor(disabledBackgroundColor()); + } + + painter.setBrush(brush); + painter.setPen(Qt::NoPen); + painter.drawEllipse(square); + + QRect iconGeometry(0, 0, d->iconSize(), d->iconSize()); + iconGeometry.moveCenter(square.center()); + + QPixmap pixmap = icon().pixmap(QSize(d->iconSize(), d->iconSize())); + QPainter icon(&pixmap); + icon.setCompositionMode(QPainter::CompositionMode_SourceIn); + icon.fillRect(pixmap.rect(), isEnabled() ? foregroundColor() + : disabledForegroundColor()); + painter.drawPixmap(iconGeometry, pixmap); +} + +void QtMaterialFloatingActionButton::updateClipPath() +{ + Q_D(QtMaterialFloatingActionButton); + + QPainterPath path; + path.addEllipse(0, 0, d->diameter(), d->diameter()); + d->rippleOverlay->setClipPath(path); +} diff --git a/components/qtmaterialfab.h b/components/qtmaterialfab.h new file mode 100644 index 0000000..78838b1 --- /dev/null +++ b/components/qtmaterialfab.h @@ -0,0 +1,46 @@ +#ifndef QTMATERIALFAB_H +#define QTMATERIALFAB_H + +#include "qtmaterialraisedbutton.h" + +class QtMaterialFloatingActionButtonPrivate; + +class QtMaterialFloatingActionButton : public QtMaterialRaisedButton +{ + Q_OBJECT + +public: + explicit QtMaterialFloatingActionButton(const QIcon &icon, QWidget *parent = 0); + ~QtMaterialFloatingActionButton(); + + QSize sizeHint() const Q_DECL_OVERRIDE; + + void setMini(bool state); + bool isMini() const; + + void setCorner(Qt::Corner corner); + Qt::Corner corner() const; + + void setOffset(int x, int y); + QSize offset() const; + + void setXOffset(int x); + int xOffset() const; + + void setYOffset(int y); + int yOffset() const; + +protected: + bool event(QEvent *event) Q_DECL_OVERRIDE; + bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE; + void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; + + void updateClipPath() Q_DECL_OVERRIDE; + +private: + Q_DISABLE_COPY(QtMaterialFloatingActionButton) + Q_DECLARE_PRIVATE(QtMaterialFloatingActionButton) + +}; + +#endif // QTMATERIALFAB_H diff --git a/components/qtmaterialfab_p.h b/components/qtmaterialfab_p.h new file mode 100644 index 0000000..fae2d3a --- /dev/null +++ b/components/qtmaterialfab_p.h @@ -0,0 +1,50 @@ +#ifndef QTMATERIALFAB_P_H +#define QTMATERIALFAB_P_H + +#include "qtmaterialraisedbutton_p.h" + +class QtMaterialFloatingActionButton; + +class QtMaterialFloatingActionButtonPrivate : public QtMaterialRaisedButtonPrivate +{ + Q_DISABLE_COPY(QtMaterialFloatingActionButtonPrivate) + Q_DECLARE_PUBLIC(QtMaterialFloatingActionButton) + +public: + enum { + DefaultDiameter = 56, + MiniDiameter = 40 + }; + + enum { + DefaultIconSize = 24, + MiniIconSize = 18 + }; + + QtMaterialFloatingActionButtonPrivate(QtMaterialFloatingActionButton *q); + ~QtMaterialFloatingActionButtonPrivate(); + + void init(); + QRect fabGeometry() const; + void setupProperties(); + + inline int diameter() const; + inline int iconSize() const; + + Qt::Corner corner; + bool mini; + int offsX; + int offsY; +}; + +inline int QtMaterialFloatingActionButtonPrivate::diameter() const +{ + return mini ? MiniDiameter : DefaultDiameter; +} + +inline int QtMaterialFloatingActionButtonPrivate::iconSize() const +{ + return mini ? MiniIconSize : DefaultIconSize; +} + +#endif // QTMATERIALFAB_P_H diff --git a/components/qtmaterialflatbutton.cpp b/components/qtmaterialflatbutton.cpp new file mode 100644 index 0000000..4a2debe --- /dev/null +++ b/components/qtmaterialflatbutton.cpp @@ -0,0 +1,724 @@ +#include "qtmaterialflatbutton.h" +#include "qtmaterialflatbutton_p.h" +#include +#include +#include +#include +#include +#include +#include +#include "lib/qtmaterialrippleoverlay.h" +#include "lib/qtmaterialripple.h" +#include "lib/qtmaterialstyle.h" +#include "qtmaterialflatbutton_internal.h" + +/*! + * \class QtMaterialFlatButtonPrivate + * \internal + */ + +/*! + * \internal + */ +QtMaterialFlatButtonPrivate::QtMaterialFlatButtonPrivate(QtMaterialFlatButton *q) + : q_ptr(q) +{ +} + +/*! + * \internal + */ +QtMaterialFlatButtonPrivate::~QtMaterialFlatButtonPrivate() +{ +} + +/*! + * \internal + */ +void QtMaterialFlatButtonPrivate::init() +{ + Q_Q(QtMaterialFlatButton); + + rippleOverlay = new QtMaterialRippleOverlay(q); + stateMachine = new QtMaterialFlatButtonStateMachine(q); + role = Material::Default; + rippleStyle = Material::PositionedRipple; + iconPlacement = Material::LeftIcon; + overlayStyle = Material::GrayOverlay; + bgMode = Qt::TransparentMode; + fixedRippleRadius = 64; + cornerRadius = 3; + baseOpacity = 0.13; + fontSize = 10; // 10.5; + useThemeColors = true; + useFixedRippleRadius = false; + haloVisible = true; + + q->setStyle(&QtMaterialStyle::instance()); + q->setAttribute(Qt::WA_Hover); + q->setMouseTracking(true); + + QFontDatabase db; + QFont font(db.font("Roboto", "Medium", fontSize)); + font.setCapitalization(QFont::AllUppercase); + q->setFont(font); + + QPainterPath path; + path.addRoundedRect(q->rect(), cornerRadius, cornerRadius); + rippleOverlay->setClipPath(path); + rippleOverlay->setClipping(true); + + stateMachine->setupProperties(); + stateMachine->startAnimations(); +} + +/*! + * \class QtMaterialFlatButton + */ + +QtMaterialFlatButton::QtMaterialFlatButton(QWidget *parent, Material::ButtonPreset preset) + : QPushButton(parent), + d_ptr(new QtMaterialFlatButtonPrivate(this)) +{ + d_func()->init(); + + applyPreset(preset); +} + +QtMaterialFlatButton::QtMaterialFlatButton(const QString &text, QWidget *parent, Material::ButtonPreset preset) + : QPushButton(text, parent), + d_ptr(new QtMaterialFlatButtonPrivate(this)) +{ + d_func()->init(); + + applyPreset(preset); +} + +QtMaterialFlatButton::QtMaterialFlatButton(const QString &text, Material::Role role, QWidget *parent, Material::ButtonPreset preset) + : QPushButton(text, parent), + d_ptr(new QtMaterialFlatButtonPrivate(this)) +{ + d_func()->init(); + + applyPreset(preset); + setRole(role); +} + +QtMaterialFlatButton::~QtMaterialFlatButton() +{ +} + +void QtMaterialFlatButton::applyPreset(Material::ButtonPreset preset) +{ + switch (preset) + { + case Material::FlatPreset: + setOverlayStyle(Material::NoOverlay); + break; + case Material::CheckablePreset: + setOverlayStyle(Material::NoOverlay); + setCheckable(true); + setHaloVisible(false); + break; + default: + break; + } +} + +void QtMaterialFlatButton::setUseThemeColors(bool value) +{ + Q_D(QtMaterialFlatButton); + + if (d->useThemeColors == value) { + return; + } + + d->useThemeColors = value; + d->stateMachine->setupProperties(); +} + +bool QtMaterialFlatButton::useThemeColors() const +{ + Q_D(const QtMaterialFlatButton); + + return d->useThemeColors; +} + +void QtMaterialFlatButton::setRole(Material::Role role) +{ + Q_D(QtMaterialFlatButton); + + d->role = role; + d->stateMachine->setupProperties(); +} + +Material::Role QtMaterialFlatButton::role() const +{ + Q_D(const QtMaterialFlatButton); + + return d->role; +} + +void QtMaterialFlatButton::setForegroundColor(const QColor &color) +{ + Q_D(QtMaterialFlatButton); + + d->foregroundColor = color; + + MATERIAL_DISABLE_THEME_COLORS + update(); +} + +QColor QtMaterialFlatButton::foregroundColor() const +{ + Q_D(const QtMaterialFlatButton); + + if (d->useThemeColors || !d->foregroundColor.isValid()) + { + if (Qt::OpaqueMode == d->bgMode) { + return QtMaterialStyle::instance().themeColor("canvas"); + } + switch (d->role) + { + case Material::Primary: + return QtMaterialStyle::instance().themeColor("primary1"); + case Material::Secondary: + return QtMaterialStyle::instance().themeColor("accent1"); + case Material::Default: + default: + return QtMaterialStyle::instance().themeColor("text"); + } + } + return d->foregroundColor; +} + +void QtMaterialFlatButton::setBackgroundColor(const QColor &color) +{ + Q_D(QtMaterialFlatButton); + + d->backgroundColor = color; + + MATERIAL_DISABLE_THEME_COLORS + update(); +} + +QColor QtMaterialFlatButton::backgroundColor() const +{ + Q_D(const QtMaterialFlatButton); + + if (d->useThemeColors || !d->backgroundColor.isValid()) + { + switch (d->role) + { + case Material::Primary: + return QtMaterialStyle::instance().themeColor("primary1"); + case Material::Secondary: + return QtMaterialStyle::instance().themeColor("accent1"); + case Material::Default: + default: + return QtMaterialStyle::instance().themeColor("text"); + } + } + return d->backgroundColor; +} + +void QtMaterialFlatButton::setOverlayColor(const QColor &color) +{ + Q_D(QtMaterialFlatButton); + + d->overlayColor = color; + + MATERIAL_DISABLE_THEME_COLORS + + setOverlayStyle(Material::TintedOverlay); + update(); +} + +QColor QtMaterialFlatButton::overlayColor() const +{ + Q_D(const QtMaterialFlatButton); + + if (d->useThemeColors || !d->overlayColor.isValid()) { + return foregroundColor(); + } + return d->overlayColor; +} + +void QtMaterialFlatButton::setDisabledForegroundColor(const QColor &color) +{ + Q_D(QtMaterialFlatButton); + + d->disabledColor = color; + + MATERIAL_DISABLE_THEME_COLORS + update(); +} + +QColor QtMaterialFlatButton::disabledForegroundColor() const +{ + Q_D(const QtMaterialFlatButton); + + if (d->useThemeColors || !d->disabledColor.isValid()) { + return QtMaterialStyle::instance().themeColor("disabled"); + } else { + return d->disabledColor; + } +} + +void QtMaterialFlatButton::setDisabledBackgroundColor(const QColor &color) +{ + Q_D(QtMaterialFlatButton); + + d->disabledBackgroundColor = color; + + MATERIAL_DISABLE_THEME_COLORS + update(); +} + +QColor QtMaterialFlatButton::disabledBackgroundColor() const +{ + Q_D(const QtMaterialFlatButton); + + if (d->useThemeColors || !d->disabledBackgroundColor.isValid()) { + return QtMaterialStyle::instance().themeColor("disabled3"); + } else { + return d->disabledBackgroundColor; + } +} + +void QtMaterialFlatButton::setFontSize(qreal size) +{ + Q_D(QtMaterialFlatButton); + + d->fontSize = size; + + QFont f(font()); + f.setPointSizeF(size); + setFont(f); + + update(); +} + +qreal QtMaterialFlatButton::fontSize() const +{ + Q_D(const QtMaterialFlatButton); + + return d->fontSize; +} + +void QtMaterialFlatButton::setHaloVisible(bool visible) +{ + Q_D(QtMaterialFlatButton); + + d->haloVisible = visible; + update(); +} + +bool QtMaterialFlatButton::isHaloVisible() const +{ + Q_D(const QtMaterialFlatButton); + + return d->haloVisible; +} + +void QtMaterialFlatButton::setOverlayStyle(Material::OverlayStyle style) +{ + Q_D(QtMaterialFlatButton); + + d->overlayStyle = style; + update(); +} + +Material::OverlayStyle QtMaterialFlatButton::overlayStyle() const +{ + Q_D(const QtMaterialFlatButton); + + return d->overlayStyle; +} + +void QtMaterialFlatButton::setRippleStyle(Material::RippleStyle style) +{ + Q_D(QtMaterialFlatButton); + + d->rippleStyle = style; +} + +Material::RippleStyle QtMaterialFlatButton::rippleStyle() const +{ + Q_D(const QtMaterialFlatButton); + + return d->rippleStyle; +} + +void QtMaterialFlatButton::setIconPlacement(Material::ButtonIconPlacement placement) +{ + Q_D(QtMaterialFlatButton); + + d->iconPlacement = placement; + update(); +} + +Material::ButtonIconPlacement QtMaterialFlatButton::iconPlacement() const +{ + Q_D(const QtMaterialFlatButton); + + return d->iconPlacement; +} + +void QtMaterialFlatButton::setCornerRadius(qreal radius) +{ + Q_D(QtMaterialFlatButton); + + d->cornerRadius = radius; + updateClipPath(); + update(); +} + +qreal QtMaterialFlatButton::cornerRadius() const +{ + Q_D(const QtMaterialFlatButton); + + return d->cornerRadius; +} + +void QtMaterialFlatButton::setBackgroundMode(Qt::BGMode mode) +{ + Q_D(QtMaterialFlatButton); + + d->bgMode = mode; + d->stateMachine->setupProperties(); +} + +Qt::BGMode QtMaterialFlatButton::backgroundMode() const +{ + Q_D(const QtMaterialFlatButton); + + return d->bgMode; +} + +void QtMaterialFlatButton::setBaseOpacity(qreal opacity) +{ + Q_D(QtMaterialFlatButton); + + d->baseOpacity = opacity; + d->stateMachine->setupProperties(); +} + +qreal QtMaterialFlatButton::baseOpacity() const +{ + Q_D(const QtMaterialFlatButton); + + return d->baseOpacity; +} + +void QtMaterialFlatButton::setCheckable(bool value) +{ + Q_D(QtMaterialFlatButton); + + d->stateMachine->updateCheckedStatus(); + + QPushButton::setCheckable(value); +} + +void QtMaterialFlatButton::setHasFixedRippleRadius(bool value) +{ + Q_D(QtMaterialFlatButton); + + d->useFixedRippleRadius = value; +} + +bool QtMaterialFlatButton::hasFixedRippleRadius() const +{ + Q_D(const QtMaterialFlatButton); + + return d->useFixedRippleRadius; +} + +void QtMaterialFlatButton::setFixedRippleRadius(qreal radius) +{ + Q_D(QtMaterialFlatButton); + + d->fixedRippleRadius = radius; + setHasFixedRippleRadius(true); +} + +/*! + * \reimp + */ +QSize QtMaterialFlatButton::sizeHint() const +{ + ensurePolished(); + + QSize label(fontMetrics().size(Qt::TextSingleLine, text())); + + int w = 20 + label.width(); + int h = label.height(); + if (!icon().isNull()) { + w += iconSize().width() + QtMaterialFlatButton::IconPadding; + h = qMax(h, iconSize().height()); + } + return QSize(w, 20 + h); +} + +QtMaterialFlatButton::QtMaterialFlatButton(QtMaterialFlatButtonPrivate &d,QWidget *parent, Material::ButtonPreset preset) + : QPushButton(parent), + d_ptr(&d) +{ + d_func()->init(); + + applyPreset(preset); +} + +/*! + * \reimp + */ +void QtMaterialFlatButton::checkStateSet() +{ + Q_D(QtMaterialFlatButton); + + d->stateMachine->updateCheckedStatus(); + + QPushButton::checkStateSet(); +} + +/*! + * \reimp + */ +void QtMaterialFlatButton::mousePressEvent(QMouseEvent *event) +{ + Q_D(QtMaterialFlatButton); + + if (Material::NoRipple != d->rippleStyle) + { + QPoint pos; + qreal radiusEndValue; + + if (Material::CenteredRipple == d->rippleStyle) { + pos = rect().center(); + } else { + pos = event->pos(); + } + + if (d->useFixedRippleRadius) { + radiusEndValue = d->fixedRippleRadius; + } else { + radiusEndValue = static_cast(width())/2; + } + + QtMaterialRipple *ripple = new QtMaterialRipple(pos); + + ripple->setRadiusEndValue(radiusEndValue); + ripple->setOpacityStartValue(0.35); + ripple->setColor(foregroundColor()); + ripple->radiusAnimation()->setDuration(600); + ripple->opacityAnimation()->setDuration(1300); + + d->rippleOverlay->addRipple(ripple); + } + + QPushButton::mousePressEvent(event); +} + +/*! + * \reimp + */ +void QtMaterialFlatButton::mouseReleaseEvent(QMouseEvent *event) +{ + Q_D(QtMaterialFlatButton); + + QPushButton::mouseReleaseEvent(event); + + d->stateMachine->updateCheckedStatus(); +} + +void QtMaterialFlatButton::resizeEvent(QResizeEvent *event) +{ + QPushButton::resizeEvent(event); + + updateClipPath(); +} + +/*! + * \reimp + */ +void QtMaterialFlatButton::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event) + + Q_D(QtMaterialFlatButton); + + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + + const qreal cr = d->cornerRadius; + + if (cr > 0) + { + QPainterPath path; + path.addRoundedRect(rect(), cr, cr); + + painter.setClipPath(path); + painter.setClipping(true); + } + + paintBackground(&painter); + paintHalo(&painter); + + painter.setOpacity(1); + painter.setClipping(false); + + paintForeground(&painter); +} + +/*! + * \internal + */ +void QtMaterialFlatButton::paintBackground(QPainter *painter) +{ + Q_D(QtMaterialFlatButton); + + const qreal overlayOpacity = d->stateMachine->overlayOpacity(); + const qreal checkedProgress = d->stateMachine->checkedOverlayProgress(); + + if (Qt::OpaqueMode == d->bgMode) { + QBrush brush; + brush.setStyle(Qt::SolidPattern); + if (isEnabled()) { + brush.setColor(backgroundColor()); + } else { + brush.setColor(disabledBackgroundColor()); + } + painter->setOpacity(1); + painter->setBrush(brush); + painter->setPen(Qt::NoPen); + painter->drawRect(rect()); + } + + QBrush brush; + brush.setStyle(Qt::SolidPattern); + painter->setPen(Qt::NoPen); + + if (!isEnabled()) { + return; + } + + if ((Material::NoOverlay != d->overlayStyle) && (overlayOpacity > 0)) { + if (Material::TintedOverlay == d->overlayStyle) { + brush.setColor(overlayColor()); + } else { + brush.setColor(Qt::gray); + } + painter->setOpacity(overlayOpacity); + painter->setBrush(brush); + painter->drawRect(rect()); + } + + if (isCheckable() && checkedProgress > 0) { + const qreal q = Qt::TransparentMode == d->bgMode ? 0.45 : 0.7; + brush.setColor(foregroundColor()); + painter->setOpacity(q*checkedProgress); + painter->setBrush(brush); + QRect r(rect()); + r.setHeight(static_cast(r.height())*checkedProgress); + painter->drawRect(r); + } +} + +/*! + * \internal + */ +void QtMaterialFlatButton::paintHalo(QPainter *painter) +{ + Q_D(QtMaterialFlatButton); + + if (!d->haloVisible) { + return; + } + + const qreal opacity = d->stateMachine->haloOpacity(); + const qreal s = d->stateMachine->haloScaleFactor()*d->stateMachine->haloSize(); + const qreal radius = static_cast(width())*s; + + if (isEnabled() && opacity > 0) { + QBrush brush; + brush.setStyle(Qt::SolidPattern); + brush.setColor(foregroundColor()); + painter->setOpacity(opacity); + painter->setBrush(brush); + painter->setPen(Qt::NoPen); + const QPointF center = rect().center(); + painter->drawEllipse(center, radius, radius); + } +} + +#define COLOR_INTERPOLATE(CH) (1-progress)*source.CH() + progress*dest.CH() + +/*! + * \internal + */ +void QtMaterialFlatButton::paintForeground(QPainter *painter) +{ + Q_D(QtMaterialFlatButton); + + if (isEnabled()) { + painter->setPen(foregroundColor()); + const qreal progress = d->stateMachine->checkedOverlayProgress(); + if (isCheckable() && progress > 0) { + QColor source = foregroundColor(); + QColor dest = Qt::TransparentMode == d->bgMode ? Qt::white + : backgroundColor(); + if (qFuzzyCompare(1, progress)) { + painter->setPen(dest); + } else { + painter->setPen(QColor(COLOR_INTERPOLATE(red), + COLOR_INTERPOLATE(green), + COLOR_INTERPOLATE(blue), + COLOR_INTERPOLATE(alpha))); + } + } + } else { + painter->setPen(disabledForegroundColor()); + } + + if (icon().isNull()) { + painter->drawText(rect(), Qt::AlignCenter, text()); + return; + } + + QSize textSize(fontMetrics().size(Qt::TextSingleLine, text())); + QSize base(size()-textSize); + + const int iw = iconSize().width() + IconPadding; + QPoint pos((base.width()-iw)/2, 0); + + QRect textGeometry(pos + QPoint(0, base.height()/2), textSize); + QRect iconGeometry(pos + QPoint(0, (height()-iconSize().height())/2), iconSize()); + + if (Material::LeftIcon == d->iconPlacement) { + textGeometry.translate(iw, 0); + } else { + iconGeometry.translate(textSize.width() + IconPadding, 0); + } + + painter->drawText(textGeometry, Qt::AlignCenter, text()); + + QPixmap pixmap = icon().pixmap(iconSize()); + QPainter icon(&pixmap); + icon.setCompositionMode(QPainter::CompositionMode_SourceIn); + icon.fillRect(pixmap.rect(), painter->pen().color()); + painter->drawPixmap(iconGeometry, pixmap); +} + +/*! + * \internal + */ +void QtMaterialFlatButton::updateClipPath() +{ + Q_D(QtMaterialFlatButton); + + const qreal radius = d->cornerRadius; + + QPainterPath path; + path.addRoundedRect(rect(), radius, radius); + d->rippleOverlay->setClipPath(path); +} diff --git a/components/qtmaterialflatbutton.h b/components/qtmaterialflatbutton.h new file mode 100644 index 0000000..4ce0eed --- /dev/null +++ b/components/qtmaterialflatbutton.h @@ -0,0 +1,109 @@ +#ifndef QTMATERIALFLATBUTTON_H +#define QTMATERIALFLATBUTTON_H + +#include +#include +#include "lib/qtmaterialtheme.h" + +class QtMaterialFlatButtonPrivate; + +class QtMaterialFlatButton : public QPushButton +{ + Q_OBJECT + + Q_PROPERTY(QColor foregroundColor WRITE setForegroundColor READ foregroundColor) + Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor) + Q_PROPERTY(QColor overlayColor WRITE setOverlayColor READ overlayColor) + Q_PROPERTY(QColor disabledForegroundColor WRITE setDisabledForegroundColor READ disabledForegroundColor) + Q_PROPERTY(QColor disabledBackgroundColor WRITE setDisabledBackgroundColor READ disabledBackgroundColor) + Q_PROPERTY(qreal fontSize WRITE setFontSize READ fontSize) + +public: + explicit QtMaterialFlatButton(QWidget *parent = 0, Material::ButtonPreset preset = Material::FlatPreset); + explicit QtMaterialFlatButton(const QString &text, QWidget *parent = 0, Material::ButtonPreset preset = Material::FlatPreset); + QtMaterialFlatButton(const QString &text, Material::Role role, QWidget *parent = 0, Material::ButtonPreset preset = Material::FlatPreset); + ~QtMaterialFlatButton(); + + void applyPreset(Material::ButtonPreset preset); + + void setUseThemeColors(bool value); + bool useThemeColors() const; + + void setRole(Material::Role role); + Material::Role role() const; + + void setForegroundColor(const QColor &color); + QColor foregroundColor() const; + + void setBackgroundColor(const QColor &color); + QColor backgroundColor() const; + + void setOverlayColor(const QColor &color); + QColor overlayColor() const; + + void setDisabledForegroundColor(const QColor &color); + QColor disabledForegroundColor() const; + + void setDisabledBackgroundColor(const QColor &color); + QColor disabledBackgroundColor() const; + + void setFontSize(qreal size); + qreal fontSize() const; + + void setHaloVisible(bool visible); + bool isHaloVisible() const; + + void setOverlayStyle(Material::OverlayStyle style); + Material::OverlayStyle overlayStyle() const; + + void setRippleStyle(Material::RippleStyle style); + Material::RippleStyle rippleStyle() const; + + void setIconPlacement(Material::ButtonIconPlacement placement); + Material::ButtonIconPlacement iconPlacement() const; + + void setCornerRadius(qreal radius); + qreal cornerRadius() const; + + void setBackgroundMode(Qt::BGMode mode); + Qt::BGMode backgroundMode() const; + + void setBaseOpacity(qreal opacity); + qreal baseOpacity() const; + + void setCheckable(bool value); + + void setHasFixedRippleRadius(bool value); + bool hasFixedRippleRadius() const; + + void setFixedRippleRadius(qreal radius); + + QSize sizeHint() const Q_DECL_OVERRIDE; + +protected: + enum { + IconPadding = 12 + }; + + QtMaterialFlatButton(QtMaterialFlatButtonPrivate &d, QWidget *parent = 0, Material::ButtonPreset preset = Material::FlatPreset); + + void checkStateSet() Q_DECL_OVERRIDE; + void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE; + void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; + + virtual void paintBackground(QPainter *painter); + virtual void paintHalo(QPainter *painter); + virtual void paintForeground(QPainter *painter); + + virtual void updateClipPath(); + + const QScopedPointer d_ptr; + +private: + Q_DISABLE_COPY(QtMaterialFlatButton) + Q_DECLARE_PRIVATE(QtMaterialFlatButton) +}; + +#endif // QTMATERIALFLATBUTTON_H diff --git a/components/qtmaterialflatbutton_internal.cpp b/components/qtmaterialflatbutton_internal.cpp new file mode 100644 index 0000000..0709a45 --- /dev/null +++ b/components/qtmaterialflatbutton_internal.cpp @@ -0,0 +1,232 @@ +#include "qtmaterialflatbutton_internal.h" +#include +#include +#include +#include +#include "qtmaterialflatbutton.h" +#include "lib/qtmaterialstatetransition.h" + +/*! + * \class QtMaterialFlatButtonStateMachine + * \internal + */ + +QtMaterialFlatButtonStateMachine::QtMaterialFlatButtonStateMachine(QtMaterialFlatButton *parent) + : QStateMachine(parent), + m_button(parent), + m_topLevelState(new QState(QState::ParallelStates)), + m_configState(new QState(m_topLevelState)), + m_checkableState(new QState(m_topLevelState)), + m_checkedState(new QState(m_checkableState)), + m_uncheckedState(new QState(m_checkableState)), + m_neutralState(new QState(m_configState)), + m_neutralFocusedState(new QState(m_configState)), + m_hoveredState(new QState(m_configState)), + m_hoveredFocusedState(new QState(m_configState)), + m_pressedState(new QState(m_configState)), + m_haloAnimation(new QSequentialAnimationGroup(this)), + m_overlayOpacity(0), + m_checkedOverlayProgress(parent->isChecked() ? 1 : 0), + m_haloOpacity(0), + m_haloSize(0.8), + m_haloScaleFactor(1), + m_wasChecked(false) +{ + Q_ASSERT(parent); + + parent->installEventFilter(this); + + m_configState->setInitialState(m_neutralState); + addState(m_topLevelState); + setInitialState(m_topLevelState); + + m_checkableState->setInitialState(parent->isChecked() ? m_checkedState + : m_uncheckedState); + QtMaterialStateTransition *transition; + QPropertyAnimation *animation; + + transition = new QtMaterialStateTransition(FlatButtonCheckedTransition); + transition->setTargetState(m_checkedState); + m_uncheckedState->addTransition(transition); + + animation = new QPropertyAnimation(this, "checkedOverlayProgress", this); + animation->setDuration(200); + transition->addAnimation(animation); + + transition = new QtMaterialStateTransition(FlatButtonUncheckedTransition); + transition->setTargetState(m_uncheckedState); + m_checkedState->addTransition(transition); + + animation = new QPropertyAnimation(this, "checkedOverlayProgress", this); + animation->setDuration(200); + transition->addAnimation(animation); + + addTransition(m_button, QEvent::FocusIn, m_neutralState, m_neutralFocusedState); + addTransition(m_button, QEvent::FocusOut, m_neutralFocusedState, m_neutralState); + addTransition(m_button, QEvent::Enter, m_neutralState, m_hoveredState); + addTransition(m_button, QEvent::Leave, m_hoveredState, m_neutralState); + addTransition(m_button, QEvent::Enter, m_neutralFocusedState, m_hoveredFocusedState); + addTransition(m_button, QEvent::Leave, m_hoveredFocusedState, m_neutralFocusedState); + addTransition(m_button, QEvent::FocusIn, m_hoveredState, m_hoveredFocusedState); + addTransition(m_button, QEvent::FocusOut, m_hoveredFocusedState, m_hoveredState); + + transition = new QtMaterialStateTransition(FlatButtonPressedTransition); + transition->setTargetState(m_pressedState); + m_hoveredState->addTransition(transition); + + addTransition(m_button, QEvent::Leave, m_pressedState, m_neutralFocusedState); + addTransition(m_button, QEvent::FocusOut, m_pressedState, m_hoveredState); + + m_neutralState->assignProperty(this, "haloSize", 0); + m_neutralFocusedState->assignProperty(this, "haloSize", 0.7); + m_hoveredState->assignProperty(this, "haloSize", 0); + m_pressedState->assignProperty(this, "haloSize", 4); + m_hoveredFocusedState->assignProperty(this, "haloSize", 0.7); + + QPropertyAnimation *grow = new QPropertyAnimation(this); + QPropertyAnimation *shrink = new QPropertyAnimation(this); + + grow->setTargetObject(this); + grow->setPropertyName("haloScaleFactor"); + grow->setStartValue(0.56); + grow->setEndValue(0.63); + grow->setEasingCurve(QEasingCurve::InOutSine); + grow->setDuration(840); + + shrink->setTargetObject(this); + shrink->setPropertyName("haloScaleFactor"); + shrink->setStartValue(0.63); + shrink->setEndValue(0.56); + shrink->setEasingCurve(QEasingCurve::InOutSine); + shrink->setDuration(840); + + m_haloAnimation->addAnimation(grow); + m_haloAnimation->addAnimation(shrink); + m_haloAnimation->setLoopCount(-1); +} + +QtMaterialFlatButtonStateMachine::~QtMaterialFlatButtonStateMachine() +{ +} + +void QtMaterialFlatButtonStateMachine::setOverlayOpacity(qreal opacity) +{ + m_overlayOpacity = opacity; + m_button->update(); +} + +void QtMaterialFlatButtonStateMachine::setCheckedOverlayProgress(qreal progress) +{ + m_checkedOverlayProgress = progress; + m_button->update(); +} + +void QtMaterialFlatButtonStateMachine::setHaloOpacity(qreal opacity) +{ + m_haloOpacity = opacity; + m_button->update(); +} + +void QtMaterialFlatButtonStateMachine::setHaloSize(qreal size) +{ + m_haloSize = size; + m_button->update(); +} + +void QtMaterialFlatButtonStateMachine::setHaloScaleFactor(qreal factor) +{ + m_haloScaleFactor = factor; + m_button->update(); +} + +void QtMaterialFlatButtonStateMachine::startAnimations() +{ + m_haloAnimation->start(); + start(); +} + +void QtMaterialFlatButtonStateMachine::setupProperties() +{ + QColor overlayColor; + + if (Qt::TransparentMode == m_button->backgroundMode()) { + overlayColor = m_button->backgroundColor(); + } else { + overlayColor = m_button->foregroundColor(); + } + + const qreal baseOpacity = m_button->baseOpacity(); + + m_neutralState->assignProperty(this, "overlayOpacity", 0); + m_neutralState->assignProperty(this, "haloOpacity", 0); + m_neutralFocusedState->assignProperty(this, "overlayOpacity", 0); + m_neutralFocusedState->assignProperty(this, "haloOpacity", baseOpacity); + m_hoveredState->assignProperty(this, "overlayOpacity", baseOpacity); + m_hoveredState->assignProperty(this, "haloOpacity", 0); + m_hoveredFocusedState->assignProperty(this, "overlayOpacity", baseOpacity); + m_hoveredFocusedState->assignProperty(this, "haloOpacity", baseOpacity); + m_pressedState->assignProperty(this, "overlayOpacity", baseOpacity); + m_pressedState->assignProperty(this, "haloOpacity", 0); + m_checkedState->assignProperty(this, "checkedOverlayProgress", 1); + m_uncheckedState->assignProperty(this, "checkedOverlayProgress", 0); + + m_button->update(); +} + +void QtMaterialFlatButtonStateMachine::updateCheckedStatus() +{ + const bool checked = m_button->isChecked(); + if (m_wasChecked != checked) { + m_wasChecked = checked; + if (checked) { + postEvent(new QtMaterialStateTransitionEvent(FlatButtonCheckedTransition)); + } else { + postEvent(new QtMaterialStateTransitionEvent(FlatButtonUncheckedTransition)); + } + } +} + +bool QtMaterialFlatButtonStateMachine::eventFilter(QObject *watched, + QEvent *event) +{ + if (QEvent::FocusIn == event->type()) { + QFocusEvent *focusEvent = static_cast(event); + if (focusEvent && Qt::MouseFocusReason == focusEvent->reason()) { + postEvent(new QtMaterialStateTransitionEvent(FlatButtonPressedTransition)); + return true; + } + } + return QStateMachine::eventFilter(watched, event); +} + +void QtMaterialFlatButtonStateMachine::addTransition(QObject *object, + QEvent::Type eventType, + QState *fromState, + QState *toState) +{ + addTransition(new QEventTransition(object, eventType), fromState, toState); +} + +void QtMaterialFlatButtonStateMachine::addTransition(QAbstractTransition *transition, + QState *fromState, + QState *toState) +{ + transition->setTargetState(toState); + + QPropertyAnimation *animation; + + animation = new QPropertyAnimation(this, "overlayOpacity", this); + animation->setDuration(150); + transition->addAnimation(animation); + + animation = new QPropertyAnimation(this, "haloOpacity", this); + animation->setDuration(170); + transition->addAnimation(animation); + + animation = new QPropertyAnimation(this, "haloSize", this); + animation->setDuration(350); + animation->setEasingCurve(QEasingCurve::OutCubic); + transition->addAnimation(animation); + + fromState->addTransition(transition); +} diff --git a/components/qtmaterialflatbutton_internal.h b/components/qtmaterialflatbutton_internal.h new file mode 100644 index 0000000..ff93972 --- /dev/null +++ b/components/qtmaterialflatbutton_internal.h @@ -0,0 +1,103 @@ +#ifndef QTMATERIALFLATBUTTON_INTERNAL_H +#define QTMATERIALFLATBUTTON_INTERNAL_H + +#include +#include + +class QtMaterialFlatButton; +class QSequentialAnimationGroup; + +class QtMaterialFlatButtonStateMachine : public QStateMachine +{ + Q_OBJECT + + Q_PROPERTY(qreal overlayOpacity WRITE setOverlayOpacity READ overlayOpacity) + Q_PROPERTY(qreal checkedOverlayProgress WRITE setCheckedOverlayProgress READ checkedOverlayProgress) + Q_PROPERTY(qreal haloOpacity WRITE setHaloOpacity READ haloOpacity) + Q_PROPERTY(qreal haloSize WRITE setHaloSize READ haloSize) + Q_PROPERTY(qreal haloScaleFactor WRITE setHaloScaleFactor READ haloScaleFactor) + +public: + explicit QtMaterialFlatButtonStateMachine(QtMaterialFlatButton *parent); + ~QtMaterialFlatButtonStateMachine(); + + void setOverlayOpacity(qreal opacity); + inline qreal overlayOpacity() const; + + void setCheckedOverlayProgress(qreal progress); + inline qreal checkedOverlayProgress() const; + + void setHaloOpacity(qreal opacity); + inline qreal haloOpacity() const; + + void setHaloSize(qreal size); + inline qreal haloSize() const; + + void setHaloScaleFactor(qreal factor); + inline qreal haloScaleFactor() const; + + void startAnimations(); + void setupProperties(); + void updateCheckedStatus(); + +signals: + void buttonPressed(); + void buttonChecked(); + void buttonUnchecked(); + +protected: + bool eventFilter(QObject *watched, QEvent *event) Q_DECL_OVERRIDE; + +private: + Q_DISABLE_COPY(QtMaterialFlatButtonStateMachine) + + void addTransition(QObject *object, QEvent::Type eventType, QState *fromState, QState *toState); + void addTransition(QAbstractTransition *transition, QState *fromState, QState *toState); + + QtMaterialFlatButton *const m_button; + QState *const m_topLevelState; + QState *const m_configState; + QState *const m_checkableState; + QState *const m_checkedState; + QState *const m_uncheckedState; + QState *const m_neutralState; + QState *const m_neutralFocusedState; + QState *const m_hoveredState; + QState *const m_hoveredFocusedState; + QState *const m_pressedState; + QSequentialAnimationGroup + *const m_haloAnimation; + qreal m_overlayOpacity; + qreal m_checkedOverlayProgress; + qreal m_haloOpacity; + qreal m_haloSize; + qreal m_haloScaleFactor; + bool m_wasChecked; +}; + +inline qreal QtMaterialFlatButtonStateMachine::overlayOpacity() const +{ + return m_overlayOpacity; +} + +inline qreal QtMaterialFlatButtonStateMachine::checkedOverlayProgress() const +{ + return m_checkedOverlayProgress; +} + +inline qreal QtMaterialFlatButtonStateMachine::haloOpacity() const +{ + return m_haloOpacity; +} + +inline qreal QtMaterialFlatButtonStateMachine::haloSize() const +{ + return m_haloSize; +} + +inline qreal QtMaterialFlatButtonStateMachine::haloScaleFactor() const +{ + return m_haloScaleFactor; +} + +#endif // QTMATERIALFLATBUTTON_INTERNAL_H diff --git a/components/qtmaterialflatbutton_p.h b/components/qtmaterialflatbutton_p.h new file mode 100644 index 0000000..3700c12 --- /dev/null +++ b/components/qtmaterialflatbutton_p.h @@ -0,0 +1,45 @@ +#ifndef QTMATERIALFLATBUTTON_P_H +#define QTMATERIALFLATBUTTON_P_H + +#include +#include +#include "lib/qtmaterialtheme.h" + +class QtMaterialFlatButton; +class QtMaterialRippleOverlay; +class QtMaterialFlatButtonStateMachine; + +class QtMaterialFlatButtonPrivate +{ + Q_DISABLE_COPY(QtMaterialFlatButtonPrivate) + Q_DECLARE_PUBLIC(QtMaterialFlatButton) + +public: + QtMaterialFlatButtonPrivate(QtMaterialFlatButton *q); + virtual ~QtMaterialFlatButtonPrivate(); + + void init(); + + QtMaterialFlatButton *const q_ptr; + QtMaterialRippleOverlay *rippleOverlay; + QtMaterialFlatButtonStateMachine *stateMachine; + Material::Role role; + Material::RippleStyle rippleStyle; + Material::ButtonIconPlacement iconPlacement; + Material::OverlayStyle overlayStyle; + Qt::BGMode bgMode; + QColor backgroundColor; + QColor foregroundColor; + QColor overlayColor; + QColor disabledColor; + QColor disabledBackgroundColor; + qreal fixedRippleRadius; + qreal cornerRadius; + qreal baseOpacity; + qreal fontSize; + bool useThemeColors; + bool useFixedRippleRadius; + bool haloVisible; +}; + +#endif // QTMATERIALFLATBUTTON_P_H diff --git a/components/qtmaterialraisedbutton.cpp b/components/qtmaterialraisedbutton.cpp new file mode 100644 index 0000000..1607c70 --- /dev/null +++ b/components/qtmaterialraisedbutton.cpp @@ -0,0 +1,128 @@ +#include "qtmaterialraisedbutton.h" +#include "qtmaterialraisedbutton_p.h" +#include +#include +#include +#include + +/*! + * \class QtMaterialRaisedButtonPrivate + * \internal + */ + +/*! + * \internal + */ +QtMaterialRaisedButtonPrivate::QtMaterialRaisedButtonPrivate(QtMaterialRaisedButton *q) + : QtMaterialFlatButtonPrivate(q) +{ +} + +/*! + * \internal + */ +QtMaterialRaisedButtonPrivate::~QtMaterialRaisedButtonPrivate() +{ +} + +/*! + * \internal + */ +void QtMaterialRaisedButtonPrivate::init() +{ + Q_Q(QtMaterialRaisedButton); + + shadowStateMachine = new QStateMachine(q); + normalState = new QState; + pressedState = new QState; + effect = new QGraphicsDropShadowEffect; + + effect->setBlurRadius(7); + effect->setOffset(QPointF(0, 2)); + effect->setColor(QColor(0, 0, 0, 75)); + + q->setBackgroundMode(Qt::OpaqueMode); + q->setMinimumHeight(42); + q->setGraphicsEffect(effect); + q->setBaseOpacity(0.3); + + shadowStateMachine->addState(normalState); + shadowStateMachine->addState(pressedState); + + normalState->assignProperty(effect, "offset", QPointF(0, 2)); + normalState->assignProperty(effect, "blurRadius", 7); + + pressedState->assignProperty(effect, "offset", QPointF(0, 5)); + pressedState->assignProperty(effect, "blurRadius", 29); + + QAbstractTransition *transition; + + transition = new QEventTransition(q, QEvent::MouseButtonPress); + transition->setTargetState(pressedState); + normalState->addTransition(transition); + + transition = new QEventTransition(q, QEvent::MouseButtonDblClick); + transition->setTargetState(pressedState); + normalState->addTransition(transition); + + transition = new QEventTransition(q, QEvent::MouseButtonRelease); + transition->setTargetState(normalState); + pressedState->addTransition(transition); + + QPropertyAnimation *animation; + + animation = new QPropertyAnimation(effect, "offset", q); + animation->setDuration(100); + shadowStateMachine->addDefaultAnimation(animation); + + animation = new QPropertyAnimation(effect, "blurRadius", q); + animation->setDuration(100); + shadowStateMachine->addDefaultAnimation(animation); + + shadowStateMachine->setInitialState(normalState); + shadowStateMachine->start(); +} + +/*! + * \class QtMaterialRaisedButton + */ + +QtMaterialRaisedButton::QtMaterialRaisedButton(QWidget *parent) + : QtMaterialFlatButton(*new QtMaterialRaisedButtonPrivate(this), parent) +{ + d_func()->init(); +} + +QtMaterialRaisedButton::QtMaterialRaisedButton(const QString &text, QWidget *parent) + : QtMaterialFlatButton(*new QtMaterialRaisedButtonPrivate(this), parent) +{ + d_func()->init(); + + setText(text); +} + +QtMaterialRaisedButton::~QtMaterialRaisedButton() +{ +} + +QtMaterialRaisedButton::QtMaterialRaisedButton(QtMaterialRaisedButtonPrivate &d, QWidget *parent) + : QtMaterialFlatButton(d, parent) +{ + d_func()->init(); +} + +bool QtMaterialRaisedButton::event(QEvent *event) +{ + Q_D(QtMaterialRaisedButton); + + if (QEvent::EnabledChange == event->type()) { + if (isEnabled()) { + d->shadowStateMachine->start(); + d->effect->setEnabled(true); + } else { + d->shadowStateMachine->stop(); + d->effect->setEnabled(false); + } + } + return QtMaterialFlatButton::event(event); +} diff --git a/components/qtmaterialraisedbutton.h b/components/qtmaterialraisedbutton.h new file mode 100644 index 0000000..d8b4ef9 --- /dev/null +++ b/components/qtmaterialraisedbutton.h @@ -0,0 +1,27 @@ +#ifndef QTMATERIALRAISEDBUTTON_H +#define QTMATERIALRAISEDBUTTON_H + +#include "qtmaterialflatbutton.h" + +class QtMaterialRaisedButtonPrivate; + +class QtMaterialRaisedButton : public QtMaterialFlatButton +{ + Q_OBJECT + +public: + explicit QtMaterialRaisedButton(QWidget *parent = 0); + explicit QtMaterialRaisedButton(const QString &text, QWidget *parent = 0); + ~QtMaterialRaisedButton(); + +protected: + QtMaterialRaisedButton(QtMaterialRaisedButtonPrivate &d, QWidget *parent = 0); + + bool event(QEvent *event) Q_DECL_OVERRIDE; + +private: + Q_DISABLE_COPY(QtMaterialRaisedButton) + Q_DECLARE_PRIVATE(QtMaterialRaisedButton) +}; + +#endif // QTMATERIALRAISEDBUTTON_H diff --git a/components/qtmaterialraisedbutton_p.h b/components/qtmaterialraisedbutton_p.h new file mode 100644 index 0000000..12df43c --- /dev/null +++ b/components/qtmaterialraisedbutton_p.h @@ -0,0 +1,28 @@ +#ifndef QTMATERIALRAISEDBUTTON_P_H +#define QTMATERIALRAISEDBUTTON_P_H + +#include "qtmaterialflatbutton_p.h" + +class QStateMachine; +class QState; +class QGraphicsDropShadowEffect; +class QtMaterialRaisedButton; + +class QtMaterialRaisedButtonPrivate : public QtMaterialFlatButtonPrivate +{ + Q_DISABLE_COPY(QtMaterialRaisedButtonPrivate) + Q_DECLARE_PUBLIC(QtMaterialRaisedButton) + +public: + QtMaterialRaisedButtonPrivate(QtMaterialRaisedButton *q); + ~QtMaterialRaisedButtonPrivate(); + + void init(); + + QStateMachine *shadowStateMachine; + QState *normalState; + QState *pressedState; + QGraphicsDropShadowEffect *effect; +}; + +#endif // QTMATERIALRAISEDBUTTON_P_H diff --git a/examples/examples.pro b/examples/examples.pro index 8b9e262..63d0c29 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -4,11 +4,17 @@ SOURCES = mainwindow.cpp \ main.cpp \ avatarsettingseditor.cpp \ badgesettingseditor.cpp \ - checkboxsettingseditor.cpp + checkboxsettingseditor.cpp \ + fabsettingseditor.cpp \ + raisedbuttonsettingseditor.cpp \ + flatbuttonsettingseditor.cpp HEADERS = mainwindow.h \ avatarsettingseditor.h \ badgesettingseditor.h \ - checkboxsettingseditor.h + checkboxsettingseditor.h \ + fabsettingseditor.h \ + raisedbuttonsettingseditor.h \ + flatbuttonsettingseditor.h LIBS += ../components/libcomponents.a INCLUDEPATH += ../components/ TARGET = ../examples-exe @@ -19,4 +25,6 @@ RESOURCES += \ FORMS += \ avatarsettingsform.ui \ badgesettingsform.ui \ - checkboxsettingsform.ui + checkboxsettingsform.ui \ + fabsettingsform.ui \ + flatbuttonsettingsform.ui diff --git a/examples/fabsettingseditor.cpp b/examples/fabsettingseditor.cpp new file mode 100644 index 0000000..c68beaa --- /dev/null +++ b/examples/fabsettingseditor.cpp @@ -0,0 +1,183 @@ +#include "fabsettingseditor.h" +#include +#include +#include +#include "qtmaterialfab.h" + +FloatingActionButtonSettingsEditor::FloatingActionButtonSettingsEditor(QWidget *parent) + : QWidget(parent), + ui(new Ui::FloatingActionButtonSettingsForm), + m_fab(new QtMaterialFloatingActionButton(QtMaterialTheme::icon("toggle", "star"))) +{ + QVBoxLayout *layout = new QVBoxLayout; + setLayout(layout); + + QWidget *widget = new QWidget; + layout->addWidget(widget); + + QWidget *canvas = new QWidget; + canvas->setStyleSheet("QWidget { background: white; }"); + layout->addWidget(canvas); + + ui->setupUi(widget); + layout->setContentsMargins(20, 20, 20, 20); + + m_fab->setParent(canvas); + + setupForm(); + + connect(ui->disabledCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateWidget())); + connect(ui->buttonRoleComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateWidget())); + connect(ui->cornerComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateWidget())); + connect(ui->horizontalOffsetSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateWidget())); + connect(ui->verticalOffsetSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateWidget())); + connect(ui->miniCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateWidget())); + connect(ui->rippleStyleComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateWidget())); + connect(ui->useThemeColorsCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateWidget())); + connect(ui->foregroundColorToolButton, SIGNAL(clicked(bool)), this, SLOT(selectColor())); + connect(ui->backgroundColorToolButton, SIGNAL(clicked(bool)), this, SLOT(selectColor())); + connect(ui->disabledFgColorToolButton, SIGNAL(clicked(bool)), this, SLOT(selectColor())); + connect(ui->disabledBgColorToolButton, SIGNAL(clicked(bool)), this, SLOT(selectColor())); +} + +FloatingActionButtonSettingsEditor::~FloatingActionButtonSettingsEditor() +{ + delete ui; +} + +void FloatingActionButtonSettingsEditor::setupForm() +{ + switch (m_fab->role()) + { + case Material::Default: + ui->buttonRoleComboBox->setCurrentIndex(0); + break; + case Material::Primary: + ui->buttonRoleComboBox->setCurrentIndex(1); + break; + case Material::Secondary: + ui->buttonRoleComboBox->setCurrentIndex(2); + break; + default: + break; + } + + switch (m_fab->corner()) + { + case Qt::TopLeftCorner: + ui->cornerComboBox->setCurrentIndex(0); + break; + case Qt::TopRightCorner: + ui->cornerComboBox->setCurrentIndex(1); + break; + case Qt::BottomLeftCorner: + ui->cornerComboBox->setCurrentIndex(2); + break; + case Qt::BottomRightCorner: + ui->cornerComboBox->setCurrentIndex(3); + break; + default: + break; + } + + switch (m_fab->rippleStyle()) + { + case Material::CenteredRipple: + ui->rippleStyleComboBox->setCurrentIndex(0); + break; + case Material::PositionedRipple: + ui->rippleStyleComboBox->setCurrentIndex(1); + break; + case Material::NoRipple: + ui->rippleStyleComboBox->setCurrentIndex(2); + break; + default: + break; + } + + ui->disabledCheckBox->setChecked(!m_fab->isEnabled()); + ui->horizontalOffsetSpinBox->setValue(m_fab->xOffset()); + ui->verticalOffsetSpinBox->setValue(m_fab->yOffset()); + ui->miniCheckBox->setChecked(m_fab->isMini()); + ui->useThemeColorsCheckBox->setChecked(m_fab->useThemeColors()); +} + +void FloatingActionButtonSettingsEditor::updateWidget() +{ + switch (ui->buttonRoleComboBox->currentIndex()) + { + case 0: + m_fab->setRole(Material::Default); + break; + case 1: + m_fab->setRole(Material::Primary); + break; + case 2: + m_fab->setRole(Material::Secondary); + break; + default: + break; + } + + switch (ui->cornerComboBox->currentIndex()) + { + case 0: + m_fab->setCorner(Qt::TopLeftCorner); + break; + case 1: + m_fab->setCorner(Qt::TopRightCorner); + break; + case 2: + m_fab->setCorner(Qt::BottomLeftCorner); + break; + case 3: + m_fab->setCorner(Qt::BottomRightCorner); + break; + default: + break; + } + + switch (ui->rippleStyleComboBox->currentIndex()) + { + case 0: + m_fab->setRippleStyle(Material::CenteredRipple); + break; + case 1: + m_fab->setRippleStyle(Material::PositionedRipple); + break; + case 2: + m_fab->setRippleStyle(Material::NoRipple); + break; + default: + break; + } + + m_fab->setDisabled(ui->disabledCheckBox->isChecked()); + m_fab->setXOffset(ui->horizontalOffsetSpinBox->value()); + m_fab->setYOffset(ui->verticalOffsetSpinBox->value()); + m_fab->setMini(ui->miniCheckBox->isChecked()); + m_fab->setUseThemeColors(ui->useThemeColorsCheckBox->isChecked()); +} + +void FloatingActionButtonSettingsEditor::selectColor() +{ + QColorDialog dialog; + if (dialog.exec()) { + QColor color = dialog.selectedColor(); + QString senderName = sender()->objectName(); + if ("foregroundColorToolButton" == senderName) { + m_fab->setForegroundColor(color); + ui->foregroundColorLineEdit->setText(color.name(QColor::HexRgb)); + } else if ("backgroundColorToolButton" == senderName) { + m_fab->setBackgroundColor(color); + ui->backgroundColorLineEdit->setText(color.name(QColor::HexRgb)); + } else if ("disabledFgColorToolButton" == senderName) { + m_fab->setDisabledForegroundColor(color); + ui->disabledFgColorLineEdit->setText(color.name(QColor::HexRgb)); + } else if ("disabledBgColorToolButton" == senderName) { + m_fab->setDisabledBackgroundColor(color); + ui->disabledBgColorLineEdit->setText(color.name(QColor::HexRgb)); + } + } + setupForm(); +} diff --git a/examples/fabsettingseditor.h b/examples/fabsettingseditor.h new file mode 100644 index 0000000..2d815f4 --- /dev/null +++ b/examples/fabsettingseditor.h @@ -0,0 +1,27 @@ +#ifndef FABSETTINGSEDITOR_H +#define FABSETTINGSEDITOR_H + +#include +#include "ui_fabsettingsform.h" + +class QtMaterialFloatingActionButton; + +class FloatingActionButtonSettingsEditor : public QWidget +{ + Q_OBJECT + +public: + explicit FloatingActionButtonSettingsEditor(QWidget *parent = 0); + ~FloatingActionButtonSettingsEditor(); + +protected slots: + void setupForm(); + void updateWidget(); + void selectColor(); + +private: + Ui::FloatingActionButtonSettingsForm *const ui; + QtMaterialFloatingActionButton *const m_fab; +}; + +#endif // FABSETTINGSEDITOR_H diff --git a/examples/fabsettingsform.ui b/examples/fabsettingsform.ui new file mode 100644 index 0000000..2e4b025 --- /dev/null +++ b/examples/fabsettingsform.ui @@ -0,0 +1,267 @@ + + + FloatingActionButtonSettingsForm + + + + 0 + 0 + 599 + 418 + + + + Form + + + + + 0 + 0 + 234 + 391 + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + Disabled + + + + + + + + + + Corner + + + + + + + + Top Left + + + + + Top Right + + + + + Bottom Left + + + + + Bottom Right + + + + + + + + Button role + + + + + + + + Default + + + + + Primary + + + + + Secondary + + + + + + + + Horizontal offset + + + + + + + + + + Vertical offset + + + + + + + + + + Mini + + + + + + + + + + Ripple style + + + + + + + + Centered + + + + + Positioned + + + + + No Ripple + + + + + + + + Use theme colors + + + + + + + + + + Background color + + + + + + + + + false + + + + + + + ... + + + + + + + + + Foreground color + + + + + + + Disabled bg color + + + + + + + Disabled fg color + + + + + + + + + false + + + + + + + ... + + + + + + + + + + + false + + + + + + + ... + + + + + + + + + + + false + + + + + + + ... + + + + + + + + + + + diff --git a/examples/flatbuttonsettingseditor.cpp b/examples/flatbuttonsettingseditor.cpp new file mode 100644 index 0000000..e4d03c2 --- /dev/null +++ b/examples/flatbuttonsettingseditor.cpp @@ -0,0 +1,294 @@ +#include "flatbuttonsettingseditor.h" +#include +#include "qtmaterialflatbutton.h" + +FlatButtonSettingsEditor::FlatButtonSettingsEditor(QWidget *parent) + : QWidget(parent), + ui(new Ui::FlatButtonSettingsForm), + m_button(new QtMaterialFlatButton("I'm flat")) +{ + init(); +} + +FlatButtonSettingsEditor::~FlatButtonSettingsEditor() +{ + delete ui; +} + +FlatButtonSettingsEditor::FlatButtonSettingsEditor(QtMaterialFlatButton *button, QWidget *parent) + : QWidget(parent), + ui(new Ui::FlatButtonSettingsForm), + m_button(button) +{ + init(); +} + +void FlatButtonSettingsEditor::setupForm() +{ + switch (m_button->role()) + { + case Material::Default: + ui->buttonRoleComboBox->setCurrentIndex(0); + break; + case Material::Primary: + ui->buttonRoleComboBox->setCurrentIndex(1); + break; + case Material::Secondary: + ui->buttonRoleComboBox->setCurrentIndex(2); + break; + default: + break; + } + + switch (m_button->overlayStyle()) + { + case Material::NoOverlay: + ui->hoverStyleComboBox->setCurrentIndex(0); + break; + case Material::TintedOverlay: + ui->hoverStyleComboBox->setCurrentIndex(1); + break; + case Material::GrayOverlay: + ui->hoverStyleComboBox->setCurrentIndex(2); + break; + default: + break; + } + + switch (m_button->rippleStyle()) + { + case Material::CenteredRipple: + ui->rippleStyleComboBox->setCurrentIndex(0); + break; + case Material::PositionedRipple: + ui->rippleStyleComboBox->setCurrentIndex(1); + break; + case Material::NoRipple: + ui->rippleStyleComboBox->setCurrentIndex(2); + break; + default: + break; + } + + switch (m_button->iconPlacement()) + { + case Material::LeftIcon: + ui->iconPlacementComboBox->setCurrentIndex(0); + break; + case Material::RightIcon: + ui->iconPlacementComboBox->setCurrentIndex(1); + break; + } + + ui->checkedCheckBox->setEnabled(m_button->isCheckable()); + + ui->disabledCheckBox->setChecked(!m_button->isEnabled()); + ui->checkableCheckBox->setChecked(m_button->isCheckable()); + ui->checkedCheckBox->setChecked(m_button->isChecked()); + ui->showHaloCheckBox->setChecked(m_button->isHaloVisible()); + ui->iconCheckBox->setChecked(!m_button->icon().isNull()); + ui->useThemeColorsCheckBox->setChecked(m_button->useThemeColors()); + ui->transparentCheckBox->setChecked(Qt::TransparentMode == m_button->backgroundMode()); + ui->cornerRadiusSpinBox->setValue(m_button->cornerRadius()); + ui->overlayOpacityDoubleSpinBox->setValue(m_button->baseOpacity()); + ui->iconSizeSpinBox->setValue(m_button->iconSize().width()); + ui->fontSizeDoubleSpinBox->setValue(m_button->fontSize()); + ui->buttonTextLineEdit->setText(m_button->text()); +} + +void FlatButtonSettingsEditor::updateWidget() +{ + switch (ui->buttonRoleComboBox->currentIndex()) + { + case 0: + m_button->setRole(Material::Default); + break; + case 1: + m_button->setRole(Material::Primary); + break; + case 2: + m_button->setRole(Material::Secondary); + break; + default: + break; + } + + switch (ui->hoverStyleComboBox->currentIndex()) + { + case 0: + m_button->setOverlayStyle(Material::NoOverlay); + break; + case 1: + m_button->setOverlayStyle(Material::TintedOverlay); + break; + case 2: + m_button->setOverlayStyle(Material::GrayOverlay); + break; + default: + break; + } + + switch (ui->rippleStyleComboBox->currentIndex()) + { + case 0: + m_button->setRippleStyle(Material::CenteredRipple); + break; + case 1: + m_button->setRippleStyle(Material::PositionedRipple); + break; + case 2: + m_button->setRippleStyle(Material::NoRipple); + break; + default: + break; + } + + switch (ui->iconPlacementComboBox->currentIndex()) + { + case 0: + m_button->setIconPlacement(Material::LeftIcon); + break; + case 1: + m_button->setIconPlacement(Material::RightIcon); + break; + default: + break; + } + + m_button->setDisabled(ui->disabledCheckBox->isChecked()); + m_button->setCheckable(ui->checkableCheckBox->isChecked()); + m_button->setChecked(ui->checkedCheckBox->isChecked()); + m_button->setHaloVisible(ui->showHaloCheckBox->isChecked()); + m_button->setIcon(ui->iconCheckBox->isChecked() ? QtMaterialTheme::icon("toggle", "star") + : QIcon()); + m_button->setUseThemeColors(ui->useThemeColorsCheckBox->isChecked()); + m_button->setBackgroundMode(ui->transparentCheckBox->isChecked() + ? Qt::TransparentMode : Qt::OpaqueMode); + m_button->setCornerRadius(ui->cornerRadiusSpinBox->value()); + m_button->setBaseOpacity(ui->overlayOpacityDoubleSpinBox->value()); + m_button->setIconSize(QSize(ui->iconSizeSpinBox->value(), ui->iconSizeSpinBox->value())); + m_button->setFontSize(ui->fontSizeDoubleSpinBox->value()); + m_button->setText(ui->buttonTextLineEdit->text()); + + ui->checkedCheckBox->setEnabled(m_button->isCheckable()); +} + +void FlatButtonSettingsEditor::selectColor() +{ + QColorDialog dialog; + if (dialog.exec()) { + QColor color = dialog.selectedColor(); + QString senderName = sender()->objectName(); + if ("foregroundColorToolButton" == senderName) { + m_button->setForegroundColor(color); + ui->foregroundColorLineEdit->setText(color.name(QColor::HexRgb)); + } else if ("backgroundColorToolButton" == senderName) { + m_button->setBackgroundColor(color); + ui->backgroundColorLineEdit->setText(color.name(QColor::HexRgb)); + } else if ("overlayColorToolButton" == senderName) { + m_button->setOverlayColor(color); + ui->overlayColorLineEdit->setText(color.name(QColor::HexRgb)); + } else if ("disabledFgColorToolButton" == senderName) { + m_button->setDisabledForegroundColor(color); + ui->disableFgColorLineEdit->setText(color.name(QColor::HexRgb)); + } else if ("disabledBgColorToolButton" == senderName) { + m_button->setDisabledBackgroundColor(color); + ui->disabledBgColorLineEdit->setText(color.name(QColor::HexRgb)); + } + } + setupForm(); +} + +void FlatButtonSettingsEditor::applyDefaultPreset() +{ + m_button->setRole(Material::Default); + m_button->setRippleStyle(Material::PositionedRipple); + m_button->setIconPlacement(Material::LeftIcon); + m_button->setOverlayStyle(Material::GrayOverlay); + m_button->setBackgroundMode(Qt::TransparentMode); + m_button->setCornerRadius(3); + m_button->setBaseOpacity(0.13); + m_button->setFontSize(10); + m_button->setUseThemeColors(true); + m_button->setHaloVisible(true); + m_button->setCheckable(false); + m_button->setEnabled(true); + m_button->applyPreset(Material::FlatPreset); + setupForm(); +} + +void FlatButtonSettingsEditor::applyCheckablePreset() +{ + m_button->setRole(Material::Default); + m_button->setRippleStyle(Material::PositionedRipple); + m_button->setIconPlacement(Material::LeftIcon); + m_button->setOverlayStyle(Material::GrayOverlay); + m_button->setBackgroundMode(Qt::TransparentMode); + m_button->setCornerRadius(3); + m_button->setBaseOpacity(0.13); + m_button->setFontSize(10); + m_button->setUseThemeColors(true); + m_button->setHaloVisible(true); + m_button->setCheckable(true); + m_button->setEnabled(true); + m_button->applyPreset(Material::CheckablePreset); + setupForm(); +} + +void FlatButtonSettingsEditor::init() +{ + QVBoxLayout *layout = new QVBoxLayout; + setLayout(layout); + + QWidget *widget = new QWidget; + layout->addWidget(widget); + + QWidget *canvas = new QWidget; + canvas->setStyleSheet("QWidget { background: white; }"); + layout->addWidget(canvas); + + ui->setupUi(widget); + layout->setContentsMargins(20, 20, 20, 20); + + m_button->setFixedWidth(300); + + layout = new QVBoxLayout; + canvas->setLayout(layout); + layout->addWidget(m_button); + layout->setAlignment(m_button, Qt::AlignCenter); + + setupForm(); + + connect(ui->disabledCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateWidget())); + connect(ui->checkableCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateWidget())); + connect(ui->checkedCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateWidget())); + connect(ui->showHaloCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateWidget())); + connect(ui->iconCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateWidget())); + connect(ui->transparentCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateWidget())); + connect(ui->buttonRoleComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateWidget())); + connect(ui->rippleStyleComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateWidget())); + connect(ui->hoverStyleComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateWidget())); + connect(ui->iconPlacementComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateWidget())); + connect(ui->cornerRadiusSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateWidget())); + connect(ui->overlayOpacityDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(updateWidget())); + connect(ui->iconSizeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateWidget())); + connect(ui->fontSizeDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(updateWidget())); + connect(ui->buttonTextLineEdit, SIGNAL(textChanged(QString)), this, SLOT(updateWidget())); + connect(ui->useThemeColorsCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateWidget())); + connect(ui->foregroundColorToolButton, SIGNAL(clicked(bool)), this, SLOT(selectColor())); + connect(ui->backgroundColorToolButton, SIGNAL(clicked(bool)), this, SLOT(selectColor())); + connect(ui->disabledFgColorToolButton, SIGNAL(clicked(bool)), this, SLOT(selectColor())); + connect(ui->disabledBgColorToolButton, SIGNAL(clicked(bool)), this, SLOT(selectColor())); + connect(ui->overlayColorToolButton, SIGNAL(clicked(bool)), this, SLOT(selectColor())); + connect(ui->cornerRadiusSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateWidget())); + connect(ui->overlayOpacityDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(updateWidget())); + connect(ui->iconSizeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateWidget())); + connect(ui->fontSizeDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(updateWidget())); + connect(ui->buttonTextLineEdit, SIGNAL(textChanged(QString)), this, SLOT(updateWidget())); + connect(ui->defaultPresetPushButton, SIGNAL(pressed()), this, SLOT(applyDefaultPreset())); + connect(ui->checkablePresetPushButton, SIGNAL(pressed()), this, SLOT(applyCheckablePreset())); + connect(m_button, SIGNAL(toggled(bool)), this, SLOT(setupForm())); + + ui->buttonRoleComboBox->setCurrentIndex(1); +} + diff --git a/examples/flatbuttonsettingseditor.h b/examples/flatbuttonsettingseditor.h new file mode 100644 index 0000000..0ec4fd2 --- /dev/null +++ b/examples/flatbuttonsettingseditor.h @@ -0,0 +1,35 @@ +#ifndef FLATBUTTONSETTINGSMANAGER_H +#define FLATBUTTONSETTINGSMANAGER_H + +#include +#include "ui_flatbuttonsettingsform.h" + +class QtMaterialFlatButton; + +class FlatButtonSettingsEditor : public QWidget +{ + Q_OBJECT + +public: + explicit FlatButtonSettingsEditor(QWidget *parent = 0); + ~FlatButtonSettingsEditor(); + +protected: + explicit FlatButtonSettingsEditor(QtMaterialFlatButton *button, QWidget *parent = 0); + + Ui::FlatButtonSettingsForm *const ui; + +protected slots: + void setupForm(); + void updateWidget(); + void selectColor(); + void applyDefaultPreset(); + void applyCheckablePreset(); + +private: + void init(); + + QtMaterialFlatButton *const m_button; +}; + +#endif // FLATBUTTONSETTINGSMANAGER_H diff --git a/examples/flatbuttonsettingsform.ui b/examples/flatbuttonsettingsform.ui new file mode 100644 index 0000000..c4df4ee --- /dev/null +++ b/examples/flatbuttonsettingsform.ui @@ -0,0 +1,439 @@ + + + FlatButtonSettingsForm + + + + 0 + 0 + 624 + 537 + + + + Form + + + + + 0 + 0 + 549 + 281 + + + + + + + + + + + Disabled + + + + + + + Checkable + + + + + + + Checked + + + + + + + Show halo + + + + + + + Transparent + + + + + + + Icon + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Vertical + + + + + + + + + Button role + + + + + + + + Default + + + + + Primary + + + + + Secondary + + + + + + + + Ripple style + + + + + + + + Centered + + + + + Positioned + + + + + No Ripple + + + + + + + + Hover style + + + + + + + + No Overlay + + + + + Tinted Overlay + + + + + Gray Overlay + + + + + + + + Icon placement + + + + + + + + Left + + + + + Right + + + + + + + + Corner radius + + + + + + + + + + Overlay opacity + + + + + + + 1.000000000000000 + + + 0.050000000000000 + + + + + + + Icon size + + + + + + + + + + Font size + + + + + + + + + + Button text + + + + + + + + + + + + Qt::Vertical + + + + + + + + + Use theme colors + + + + + + + + + Background color + + + + + + + + + false + + + + + + + ... + + + + + + + + + Foreground color + + + + + + + + + false + + + + + + + ... + + + + + + + + + Disabled bg color + + + + + + + Disabled fg color + + + + + + + Overlay color + + + + + + + + + false + + + + + + + ... + + + + + + + + + + + false + + + + + + + ... + + + + + + + + + + + false + + + + + + + ... + + + + + + + + + + + + + + + + + Apply default preset + + + + + + + Apply checkable preset + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + diff --git a/examples/mainwindow.cpp b/examples/mainwindow.cpp index 1bb7a35..f5a3227 100644 --- a/examples/mainwindow.cpp +++ b/examples/mainwindow.cpp @@ -5,6 +5,9 @@ #include "avatarsettingseditor.h" #include "badgesettingseditor.h" #include "checkboxsettingseditor.h" +#include "fabsettingseditor.h" +#include "raisedbuttonsettingseditor.h" +#include "flatbuttonsettingseditor.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) @@ -27,14 +30,23 @@ MainWindow::MainWindow(QWidget *parent) AvatarSettingsEditor *avatar = new AvatarSettingsEditor; BadgeSettingsEditor *badge = new BadgeSettingsEditor; CheckBoxSettingsEditor *checkbox = new CheckBoxSettingsEditor; + FloatingActionButtonSettingsEditor *fab = new FloatingActionButtonSettingsEditor; + RaisedButtonSettingsEditor *raisedButton = new RaisedButtonSettingsEditor; + FlatButtonSettingsEditor *flatButton = new FlatButtonSettingsEditor; stack->addWidget(avatar); stack->addWidget(badge); stack->addWidget(checkbox); + stack->addWidget(fab); + stack->addWidget(flatButton); + stack->addWidget(raisedButton); list->addItem("Avatar"); list->addItem("Badge"); list->addItem("Checkbox"); + list->addItem("Floating Action Button"); + list->addItem("Flat Button"); + list->addItem("Raised Button"); list->setCurrentRow(0); diff --git a/examples/raisedbuttonsettingseditor.cpp b/examples/raisedbuttonsettingseditor.cpp new file mode 100644 index 0000000..b747bbf --- /dev/null +++ b/examples/raisedbuttonsettingseditor.cpp @@ -0,0 +1,14 @@ +#include "raisedbuttonsettingseditor.h" +#include "qtmaterialraisedbutton.h" + +RaisedButtonSettingsEditor::RaisedButtonSettingsEditor(QWidget *parent) + : FlatButtonSettingsEditor(new QtMaterialRaisedButton("Rise up"), parent) +{ + ui->transparentCheckBox->setDisabled(true); + ui->defaultPresetPushButton->setDisabled(true); + ui->checkablePresetPushButton->setDisabled(true); +} + +RaisedButtonSettingsEditor::~RaisedButtonSettingsEditor() +{ +} diff --git a/examples/raisedbuttonsettingseditor.h b/examples/raisedbuttonsettingseditor.h new file mode 100644 index 0000000..250acd0 --- /dev/null +++ b/examples/raisedbuttonsettingseditor.h @@ -0,0 +1,15 @@ +#ifndef RAISEDBUTTONSETTINGSEDITOR_H +#define RAISEDBUTTONSETTINGSEDITOR_H + +#include "flatbuttonsettingseditor.h" + +class RaisedButtonSettingsEditor : public FlatButtonSettingsEditor +{ + Q_OBJECT + +public: + explicit RaisedButtonSettingsEditor(QWidget *parent = 0); + ~RaisedButtonSettingsEditor(); +}; + +#endif // RAISEDBUTTONSETTINGSEDITOR_H