2017-04-06 02:06:42 +03:00
|
|
|
#include <QEventTransition>
|
|
|
|
#include <QFontDatabase>
|
|
|
|
#include <QIcon>
|
|
|
|
#include <QMouseEvent>
|
|
|
|
#include <QPainterPath>
|
|
|
|
#include <QResizeEvent>
|
|
|
|
#include <QSignalTransition>
|
|
|
|
|
|
|
|
#include "FlatButton.h"
|
|
|
|
#include "Ripple.h"
|
|
|
|
#include "RippleOverlay.h"
|
|
|
|
#include "ThemeManager.h"
|
|
|
|
|
2017-09-24 15:25:57 +03:00
|
|
|
// The ampersand is automatically set in QPushButton or QCheckbx
|
2017-10-01 12:11:33 +03:00
|
|
|
// by KDEPlatformTheme plugin in Qt5.
|
|
|
|
// [https://bugs.kde.org/show_bug.cgi?id=337491]
|
2017-09-24 15:25:57 +03:00
|
|
|
//
|
|
|
|
// A workaroud is to add
|
|
|
|
//
|
|
|
|
// [Development]
|
|
|
|
// AutoCheckAccelerators=false
|
|
|
|
//
|
|
|
|
// to ~/.config/kdeglobals
|
|
|
|
static QString
|
|
|
|
removeKDEAccelerators(QString text)
|
|
|
|
{
|
|
|
|
return text.remove(QChar('&'));
|
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::init()
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
ripple_overlay_ = new RippleOverlay(this);
|
|
|
|
state_machine_ = new FlatButtonStateMachine(this);
|
|
|
|
role_ = ui::Role::Default;
|
|
|
|
ripple_style_ = ui::RippleStyle::PositionedRipple;
|
|
|
|
icon_placement_ = ui::ButtonIconPlacement::LeftIcon;
|
|
|
|
overlay_style_ = ui::OverlayStyle::GrayOverlay;
|
|
|
|
bg_mode_ = Qt::TransparentMode;
|
|
|
|
fixed_ripple_radius_ = 64;
|
|
|
|
corner_radius_ = 3;
|
|
|
|
base_opacity_ = 0.13;
|
|
|
|
font_size_ = 10; // 10.5;
|
|
|
|
use_fixed_ripple_radius_ = false;
|
|
|
|
|
|
|
|
setStyle(&ThemeManager::instance());
|
|
|
|
setAttribute(Qt::WA_Hover);
|
|
|
|
setMouseTracking(true);
|
|
|
|
setCursor(QCursor(Qt::PointingHandCursor));
|
|
|
|
|
|
|
|
QPainterPath path;
|
|
|
|
path.addRoundedRect(rect(), corner_radius_, corner_radius_);
|
|
|
|
|
|
|
|
ripple_overlay_->setClipPath(path);
|
|
|
|
ripple_overlay_->setClipping(true);
|
|
|
|
|
|
|
|
state_machine_->setupProperties();
|
|
|
|
state_machine_->startAnimations();
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
FlatButton::FlatButton(QWidget *parent, ui::ButtonPreset preset)
|
2017-08-20 13:47:22 +03:00
|
|
|
: QPushButton(parent)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
init();
|
|
|
|
applyPreset(preset);
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
FlatButton::FlatButton(const QString &text, QWidget *parent, ui::ButtonPreset preset)
|
2017-08-20 13:47:22 +03:00
|
|
|
: QPushButton(text, parent)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
init();
|
|
|
|
applyPreset(preset);
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
FlatButton::FlatButton(const QString &text, ui::Role role, QWidget *parent, ui::ButtonPreset preset)
|
2017-08-20 13:47:22 +03:00
|
|
|
: QPushButton(text, parent)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
init();
|
|
|
|
applyPreset(preset);
|
|
|
|
setRole(role);
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-10-01 12:11:33 +03:00
|
|
|
FlatButton::~FlatButton() {}
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::applyPreset(ui::ButtonPreset preset)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
switch (preset) {
|
|
|
|
case ui::ButtonPreset::FlatPreset:
|
|
|
|
setOverlayStyle(ui::OverlayStyle::NoOverlay);
|
|
|
|
break;
|
|
|
|
case ui::ButtonPreset::CheckablePreset:
|
|
|
|
setOverlayStyle(ui::OverlayStyle::NoOverlay);
|
|
|
|
setCheckable(true);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::setRole(ui::Role role)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
role_ = role;
|
|
|
|
state_machine_->setupProperties();
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
ui::Role
|
|
|
|
FlatButton::role() const
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
return role_;
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::setForegroundColor(const QColor &color)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
foreground_color_ = color;
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
QColor
|
|
|
|
FlatButton::foregroundColor() const
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
if (!foreground_color_.isValid()) {
|
|
|
|
if (bg_mode_ == Qt::OpaqueMode) {
|
|
|
|
return ThemeManager::instance().themeColor("BrightWhite");
|
|
|
|
}
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
switch (role_) {
|
|
|
|
case ui::Role::Primary:
|
|
|
|
return ThemeManager::instance().themeColor("Blue");
|
|
|
|
case ui::Role::Secondary:
|
|
|
|
return ThemeManager::instance().themeColor("Gray");
|
|
|
|
case ui::Role::Default:
|
|
|
|
default:
|
|
|
|
return ThemeManager::instance().themeColor("Black");
|
|
|
|
}
|
|
|
|
}
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
return foreground_color_;
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::setBackgroundColor(const QColor &color)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
background_color_ = color;
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
QColor
|
|
|
|
FlatButton::backgroundColor() const
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
if (!background_color_.isValid()) {
|
|
|
|
switch (role_) {
|
|
|
|
case ui::Role::Primary:
|
|
|
|
return ThemeManager::instance().themeColor("Blue");
|
|
|
|
case ui::Role::Secondary:
|
|
|
|
return ThemeManager::instance().themeColor("Gray");
|
|
|
|
case ui::Role::Default:
|
|
|
|
default:
|
|
|
|
return ThemeManager::instance().themeColor("Black");
|
|
|
|
}
|
|
|
|
}
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
return background_color_;
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::setOverlayColor(const QColor &color)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
overlay_color_ = color;
|
|
|
|
setOverlayStyle(ui::OverlayStyle::TintedOverlay);
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
QColor
|
|
|
|
FlatButton::overlayColor() const
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
if (!overlay_color_.isValid()) {
|
|
|
|
return foregroundColor();
|
|
|
|
}
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
return overlay_color_;
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::setDisabledForegroundColor(const QColor &color)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
disabled_color_ = color;
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
QColor
|
|
|
|
FlatButton::disabledForegroundColor() const
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
if (!disabled_color_.isValid()) {
|
|
|
|
return ThemeManager::instance().themeColor("FadedWhite");
|
|
|
|
}
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
return disabled_color_;
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::setDisabledBackgroundColor(const QColor &color)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
disabled_background_color_ = color;
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
QColor
|
|
|
|
FlatButton::disabledBackgroundColor() const
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
if (!disabled_background_color_.isValid()) {
|
|
|
|
return ThemeManager::instance().themeColor("FadedWhite");
|
|
|
|
}
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
return disabled_background_color_;
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::setFontSize(qreal size)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
font_size_ = size;
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
QFont f(font());
|
|
|
|
f.setPixelSize(size);
|
|
|
|
setFont(f);
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
update();
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
qreal
|
|
|
|
FlatButton::fontSize() const
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
return font_size_;
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::setOverlayStyle(ui::OverlayStyle style)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
overlay_style_ = style;
|
|
|
|
update();
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
ui::OverlayStyle
|
|
|
|
FlatButton::overlayStyle() const
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
return overlay_style_;
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::setRippleStyle(ui::RippleStyle style)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
ripple_style_ = style;
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
ui::RippleStyle
|
|
|
|
FlatButton::rippleStyle() const
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
return ripple_style_;
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::setIconPlacement(ui::ButtonIconPlacement placement)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
icon_placement_ = placement;
|
|
|
|
update();
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
ui::ButtonIconPlacement
|
|
|
|
FlatButton::iconPlacement() const
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
return icon_placement_;
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::setCornerRadius(qreal radius)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
corner_radius_ = radius;
|
|
|
|
updateClipPath();
|
|
|
|
update();
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
qreal
|
|
|
|
FlatButton::cornerRadius() const
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
return corner_radius_;
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::setBackgroundMode(Qt::BGMode mode)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
bg_mode_ = mode;
|
|
|
|
state_machine_->setupProperties();
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
Qt::BGMode
|
|
|
|
FlatButton::backgroundMode() const
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
return bg_mode_;
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::setBaseOpacity(qreal opacity)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
base_opacity_ = opacity;
|
|
|
|
state_machine_->setupProperties();
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
qreal
|
|
|
|
FlatButton::baseOpacity() const
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
return base_opacity_;
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::setCheckable(bool value)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
state_machine_->updateCheckedStatus();
|
|
|
|
state_machine_->setCheckedOverlayProgress(0);
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
QPushButton::setCheckable(value);
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::setHasFixedRippleRadius(bool value)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
use_fixed_ripple_radius_ = value;
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
bool
|
|
|
|
FlatButton::hasFixedRippleRadius() const
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
return use_fixed_ripple_radius_;
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::setFixedRippleRadius(qreal radius)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
fixed_ripple_radius_ = radius;
|
|
|
|
setHasFixedRippleRadius(true);
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
QSize
|
|
|
|
FlatButton::sizeHint() const
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
ensurePolished();
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-24 15:25:57 +03:00
|
|
|
QSize label(fontMetrics().size(Qt::TextSingleLine, removeKDEAccelerators(text())));
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
int w = 20 + label.width();
|
|
|
|
int h = label.height();
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
if (!icon().isNull()) {
|
|
|
|
w += iconSize().width() + FlatButton::IconPadding;
|
|
|
|
h = qMax(h, iconSize().height());
|
|
|
|
}
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
return QSize(w, 20 + h);
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::checkStateSet()
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
state_machine_->updateCheckedStatus();
|
|
|
|
QPushButton::checkStateSet();
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::mousePressEvent(QMouseEvent *event)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
if (ui::RippleStyle::NoRipple != ripple_style_) {
|
|
|
|
QPoint pos;
|
|
|
|
qreal radiusEndValue;
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
if (ui::RippleStyle::CenteredRipple == ripple_style_) {
|
|
|
|
pos = rect().center();
|
|
|
|
} else {
|
|
|
|
pos = event->pos();
|
|
|
|
}
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
if (use_fixed_ripple_radius_) {
|
|
|
|
radiusEndValue = fixed_ripple_radius_;
|
|
|
|
} else {
|
|
|
|
radiusEndValue = static_cast<qreal>(width()) / 2;
|
|
|
|
}
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
Ripple *ripple = new Ripple(pos);
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
ripple->setRadiusEndValue(radiusEndValue);
|
|
|
|
ripple->setOpacityStartValue(0.35);
|
|
|
|
ripple->setColor(foregroundColor());
|
|
|
|
ripple->radiusAnimation()->setDuration(250);
|
|
|
|
ripple->opacityAnimation()->setDuration(250);
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
ripple_overlay_->addRipple(ripple);
|
|
|
|
}
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
QPushButton::mousePressEvent(event);
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::mouseReleaseEvent(QMouseEvent *event)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
QPushButton::mouseReleaseEvent(event);
|
|
|
|
state_machine_->updateCheckedStatus();
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::resizeEvent(QResizeEvent *event)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
QPushButton::resizeEvent(event);
|
|
|
|
updateClipPath();
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::paintEvent(QPaintEvent *event)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
Q_UNUSED(event)
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
QPainter painter(this);
|
|
|
|
painter.setRenderHint(QPainter::Antialiasing);
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
const qreal cr = corner_radius_;
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
if (cr > 0) {
|
|
|
|
QPainterPath path;
|
|
|
|
path.addRoundedRect(rect(), cr, cr);
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
painter.setClipPath(path);
|
|
|
|
painter.setClipping(true);
|
|
|
|
}
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
paintBackground(&painter);
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
painter.setOpacity(1);
|
|
|
|
painter.setClipping(false);
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
paintForeground(&painter);
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::paintBackground(QPainter *painter)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
const qreal overlayOpacity = state_machine_->overlayOpacity();
|
|
|
|
const qreal checkedProgress = state_machine_->checkedOverlayProgress();
|
|
|
|
|
|
|
|
if (Qt::OpaqueMode == bg_mode_) {
|
|
|
|
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 ((ui::OverlayStyle::NoOverlay != overlay_style_) && (overlayOpacity > 0)) {
|
|
|
|
if (ui::OverlayStyle::TintedOverlay == overlay_style_) {
|
|
|
|
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 == bg_mode_ ? 0.45 : 0.7;
|
|
|
|
brush.setColor(foregroundColor());
|
|
|
|
painter->setOpacity(q * checkedProgress);
|
|
|
|
painter->setBrush(brush);
|
|
|
|
QRect r(rect());
|
|
|
|
r.setHeight(static_cast<qreal>(r.height()) * checkedProgress);
|
|
|
|
painter->drawRect(r);
|
|
|
|
}
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#define COLOR_INTERPOLATE(CH) (1 - progress) * source.CH() + progress *dest.CH()
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::paintForeground(QPainter *painter)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
if (isEnabled()) {
|
|
|
|
painter->setPen(foregroundColor());
|
|
|
|
const qreal progress = state_machine_->checkedOverlayProgress();
|
|
|
|
|
|
|
|
if (isCheckable() && progress > 0) {
|
|
|
|
QColor source = foregroundColor();
|
|
|
|
QColor dest =
|
|
|
|
Qt::TransparentMode == bg_mode_ ? 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()) {
|
2017-09-24 15:25:57 +03:00
|
|
|
painter->drawText(rect(), Qt::AlignCenter, removeKDEAccelerators(text()));
|
2017-09-10 12:59:21 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-09-24 15:25:57 +03:00
|
|
|
QSize textSize(fontMetrics().size(Qt::TextSingleLine, removeKDEAccelerators(text())));
|
2017-09-10 12:59:21 +03:00
|
|
|
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 (ui::LeftIcon == icon_placement_) { */
|
|
|
|
/* textGeometry.translate(iw, 0); */
|
|
|
|
/* } else { */
|
|
|
|
/* iconGeometry.translate(textSize.width() + IconPadding, 0); */
|
|
|
|
/* } */
|
|
|
|
|
2017-09-24 15:25:57 +03:00
|
|
|
painter->drawText(textGeometry, Qt::AlignCenter, removeKDEAccelerators(text()));
|
2017-09-10 12:59:21 +03:00
|
|
|
|
|
|
|
QPixmap pixmap = icon().pixmap(iconSize());
|
|
|
|
QPainter icon(&pixmap);
|
|
|
|
icon.setCompositionMode(QPainter::CompositionMode_SourceIn);
|
|
|
|
icon.fillRect(pixmap.rect(), painter->pen().color());
|
|
|
|
painter->drawPixmap(iconGeometry, pixmap);
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButton::updateClipPath()
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
const qreal radius = corner_radius_;
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
QPainterPath path;
|
|
|
|
path.addRoundedRect(rect(), radius, radius);
|
|
|
|
ripple_overlay_->setClipPath(path);
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
FlatButtonStateMachine::FlatButtonStateMachine(FlatButton *parent)
|
2017-08-20 13:47:22 +03:00
|
|
|
: QStateMachine(parent)
|
|
|
|
, button_(parent)
|
|
|
|
, top_level_state_(new QState(QState::ParallelStates))
|
|
|
|
, config_state_(new QState(top_level_state_))
|
|
|
|
, checkable_state_(new QState(top_level_state_))
|
|
|
|
, checked_state_(new QState(checkable_state_))
|
|
|
|
, unchecked_state_(new QState(checkable_state_))
|
|
|
|
, neutral_state_(new QState(config_state_))
|
|
|
|
, neutral_focused_state_(new QState(config_state_))
|
|
|
|
, hovered_state_(new QState(config_state_))
|
|
|
|
, hovered_focused_state_(new QState(config_state_))
|
|
|
|
, pressed_state_(new QState(config_state_))
|
|
|
|
, overlay_opacity_(0)
|
|
|
|
, checked_overlay_progress_(parent->isChecked() ? 1 : 0)
|
|
|
|
, was_checked_(false)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
Q_ASSERT(parent);
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
parent->installEventFilter(this);
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
config_state_->setInitialState(neutral_state_);
|
|
|
|
addState(top_level_state_);
|
|
|
|
setInitialState(top_level_state_);
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
checkable_state_->setInitialState(parent->isChecked() ? checked_state_ : unchecked_state_);
|
|
|
|
QSignalTransition *transition;
|
|
|
|
QPropertyAnimation *animation;
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
transition = new QSignalTransition(this, SIGNAL(buttonChecked()));
|
|
|
|
transition->setTargetState(checked_state_);
|
|
|
|
unchecked_state_->addTransition(transition);
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
animation = new QPropertyAnimation(this, "checkedOverlayProgress", this);
|
|
|
|
animation->setDuration(200);
|
|
|
|
transition->addAnimation(animation);
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
transition = new QSignalTransition(this, SIGNAL(buttonUnchecked()));
|
|
|
|
transition->setTargetState(unchecked_state_);
|
|
|
|
checked_state_->addTransition(transition);
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
animation = new QPropertyAnimation(this, "checkedOverlayProgress", this);
|
|
|
|
animation->setDuration(200);
|
|
|
|
transition->addAnimation(animation);
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
addTransition(button_, QEvent::FocusIn, neutral_state_, neutral_focused_state_);
|
|
|
|
addTransition(button_, QEvent::FocusOut, neutral_focused_state_, neutral_state_);
|
|
|
|
addTransition(button_, QEvent::Enter, neutral_state_, hovered_state_);
|
|
|
|
addTransition(button_, QEvent::Leave, hovered_state_, neutral_state_);
|
|
|
|
addTransition(button_, QEvent::Enter, neutral_focused_state_, hovered_focused_state_);
|
|
|
|
addTransition(button_, QEvent::Leave, hovered_focused_state_, neutral_focused_state_);
|
|
|
|
addTransition(button_, QEvent::FocusIn, hovered_state_, hovered_focused_state_);
|
|
|
|
addTransition(button_, QEvent::FocusOut, hovered_focused_state_, hovered_state_);
|
|
|
|
addTransition(this, SIGNAL(buttonPressed()), hovered_state_, pressed_state_);
|
|
|
|
addTransition(button_, QEvent::Leave, pressed_state_, neutral_focused_state_);
|
|
|
|
addTransition(button_, QEvent::FocusOut, pressed_state_, hovered_state_);
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-10-01 12:11:33 +03:00
|
|
|
FlatButtonStateMachine::~FlatButtonStateMachine() {}
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButtonStateMachine::setOverlayOpacity(qreal opacity)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
overlay_opacity_ = opacity;
|
|
|
|
button_->update();
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButtonStateMachine::setCheckedOverlayProgress(qreal opacity)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
checked_overlay_progress_ = opacity;
|
|
|
|
button_->update();
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButtonStateMachine::startAnimations()
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
start();
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButtonStateMachine::setupProperties()
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
QColor overlayColor;
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
if (Qt::TransparentMode == button_->backgroundMode()) {
|
|
|
|
overlayColor = button_->backgroundColor();
|
|
|
|
} else {
|
|
|
|
overlayColor = button_->foregroundColor();
|
|
|
|
}
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
const qreal baseOpacity = button_->baseOpacity();
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
neutral_state_->assignProperty(this, "overlayOpacity", 0);
|
|
|
|
neutral_focused_state_->assignProperty(this, "overlayOpacity", 0);
|
|
|
|
hovered_state_->assignProperty(this, "overlayOpacity", baseOpacity);
|
|
|
|
hovered_focused_state_->assignProperty(this, "overlayOpacity", baseOpacity);
|
|
|
|
pressed_state_->assignProperty(this, "overlayOpacity", baseOpacity);
|
|
|
|
checked_state_->assignProperty(this, "checkedOverlayProgress", 1);
|
|
|
|
unchecked_state_->assignProperty(this, "checkedOverlayProgress", 0);
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
button_->update();
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
|
|
|
FlatButtonStateMachine::updateCheckedStatus()
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
const bool checked = button_->isChecked();
|
|
|
|
if (was_checked_ != checked) {
|
|
|
|
was_checked_ = checked;
|
|
|
|
if (checked) {
|
|
|
|
emit buttonChecked();
|
|
|
|
} else {
|
|
|
|
emit buttonUnchecked();
|
|
|
|
}
|
|
|
|
}
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
bool
|
|
|
|
FlatButtonStateMachine::eventFilter(QObject *watched, QEvent *event)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
if (QEvent::FocusIn == event->type()) {
|
|
|
|
QFocusEvent *focusEvent = static_cast<QFocusEvent *>(event);
|
|
|
|
if (focusEvent && Qt::MouseFocusReason == focusEvent->reason()) {
|
|
|
|
emit buttonPressed();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
return QStateMachine::eventFilter(watched, event);
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
2017-09-10 12:59:21 +03:00
|
|
|
FlatButtonStateMachine::addTransition(QObject *object,
|
|
|
|
const char *signal,
|
|
|
|
QState *fromState,
|
|
|
|
QState *toState)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
addTransition(new QSignalTransition(object, signal), fromState, toState);
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
2017-09-10 12:59:21 +03:00
|
|
|
FlatButtonStateMachine::addTransition(QObject *object,
|
|
|
|
QEvent::Type eventType,
|
|
|
|
QState *fromState,
|
|
|
|
QState *toState)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
addTransition(new QEventTransition(object, eventType), fromState, toState);
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|
|
|
|
|
2017-08-20 13:47:22 +03:00
|
|
|
void
|
2017-09-10 12:59:21 +03:00
|
|
|
FlatButtonStateMachine::addTransition(QAbstractTransition *transition,
|
|
|
|
QState *fromState,
|
|
|
|
QState *toState)
|
2017-04-06 02:06:42 +03:00
|
|
|
{
|
2017-09-10 12:59:21 +03:00
|
|
|
transition->setTargetState(toState);
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
QPropertyAnimation *animation;
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
animation = new QPropertyAnimation(this, "overlayOpacity", this);
|
|
|
|
animation->setDuration(150);
|
|
|
|
transition->addAnimation(animation);
|
2017-04-06 02:06:42 +03:00
|
|
|
|
2017-09-10 12:59:21 +03:00
|
|
|
fromState->addTransition(transition);
|
2017-04-06 02:06:42 +03:00
|
|
|
}
|