Reimplement Badge component

This commit is contained in:
johanneshilden 2017-09-29 01:01:01 +03:00
parent 915f24747e
commit a669df832f
12 changed files with 775 additions and 7 deletions

View File

@ -3,13 +3,18 @@ CONFIG += staticlib
SOURCES = \
qtmaterialavatar.cpp \
lib/qtmaterialstyle.cpp \
lib/qtmaterialtheme.cpp
lib/qtmaterialtheme.cpp \
qtmaterialbadge.cpp \
lib/qtmaterialoverlaywidget.cpp
HEADERS = \
qtmaterialavatar_p.h \
qtmaterialavatar.h \
lib/qtmaterialstyle_p.h \
lib/qtmaterialstyle.h \
lib/qtmaterialtheme_p.h \
lib/qtmaterialtheme.h
lib/qtmaterialtheme.h \
qtmaterialbadge_p.h \
qtmaterialbadge.h \
lib/qtmaterialoverlaywidget.h
RESOURCES += \
resources.qrc

View File

@ -0,0 +1,72 @@
#include "lib/qtmaterialoverlaywidget.h"
#include <QEvent>
/*!
* \class QtMaterialOverlayWidget
* \internal
*/
QtMaterialOverlayWidget::QtMaterialOverlayWidget(QWidget *parent)
: QWidget(parent)
{
if (parent) {
parent->installEventFilter(this);
}
}
QtMaterialOverlayWidget::~QtMaterialOverlayWidget()
{
}
/*!
* \reimp
*/
bool QtMaterialOverlayWidget::event(QEvent *event)
{
if (!parent()) {
return QWidget::event(event);
}
switch (event->type())
{
case QEvent::ParentChange:
{
parent()->installEventFilter(this);
setGeometry(overlayGeometry());
break;
}
case QEvent::ParentAboutToChange:
{
parent()->removeEventFilter(this);
break;
}
default:
break;
}
return QWidget::event(event);
}
/*!
* \reimp
*/
bool QtMaterialOverlayWidget::eventFilter(QObject *obj, QEvent *event)
{
switch (event->type())
{
case QEvent::Move:
case QEvent::Resize:
setGeometry(overlayGeometry());
break;
default:
break;
}
return QWidget::eventFilter(obj, event);
}
QRect QtMaterialOverlayWidget::overlayGeometry() const
{
QWidget *widget = parentWidget();
if (!widget) {
return QRect();
}
return widget->rect();
}

View File

@ -0,0 +1,24 @@
#ifndef QTMATERIALOVERLAYWIDGET_H
#define QTMATERIALOVERLAYWIDGET_H
#include <QtWidgets/QWidget>
class QtMaterialOverlayWidget : public QWidget
{
Q_OBJECT
public:
explicit QtMaterialOverlayWidget(QWidget *parent = 0);
~QtMaterialOverlayWidget();
protected:
bool event(QEvent *event) Q_DECL_OVERRIDE;
bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE;
virtual QRect overlayGeometry() const;
private:
Q_DISABLE_COPY(QtMaterialOverlayWidget)
};
#endif // QTMATERIALOVERLAYWIDGET_H

View File

@ -0,0 +1,290 @@
#include "qtmaterialbadge.h"
#include "qtmaterialbadge_p.h"
#include <QPainter>
#include "lib/qtmaterialstyle.h"
/*!
* \class QtMaterialBadgePrivate
* \internal
*/
/*!
* \internal
*/
QtMaterialBadgePrivate::QtMaterialBadgePrivate(QtMaterialBadge *q)
: q_ptr(q)
{
}
/*!
* \internal
*/
QtMaterialBadgePrivate::~QtMaterialBadgePrivate()
{
}
/*!
* \internal
*/
void QtMaterialBadgePrivate::init()
{
Q_Q(QtMaterialBadge);
x = 0;
y = 0;
padding = 10;
useThemeColors = true;
q->setAttribute(Qt::WA_TransparentForMouseEvents);
QFont font(q->font());
font.setPointSizeF(10);
font.setStyleName("Bold");
q->setFont(font);
q->setText("+1");
}
/*!
* \class QtMaterialBadge
*/
QtMaterialBadge::QtMaterialBadge(QWidget *parent)
: QtMaterialOverlayWidget(parent),
d_ptr(new QtMaterialBadgePrivate(this))
{
d_func()->init();
}
QtMaterialBadge::QtMaterialBadge(const QIcon &icon, QWidget *parent)
: QtMaterialOverlayWidget(parent),
d_ptr(new QtMaterialBadgePrivate(this))
{
d_func()->init();
setIcon(icon);
}
QtMaterialBadge::QtMaterialBadge(const QString &text, QWidget *parent)
: QtMaterialOverlayWidget(parent),
d_ptr(new QtMaterialBadgePrivate(this))
{
d_func()->init();
setText(text);
}
QtMaterialBadge::~QtMaterialBadge()
{
}
void QtMaterialBadge::setUseThemeColors(bool value)
{
Q_D(QtMaterialBadge);
if (d->useThemeColors == value) {
return;
}
d->useThemeColors = value;
update();
}
bool QtMaterialBadge::useThemeColors() const
{
Q_D(const QtMaterialBadge);
return d->useThemeColors;
}
void QtMaterialBadge::setTextColor(const QColor &color)
{
Q_D(QtMaterialBadge);
d->textColor = color;
setUseThemeColors(false);
}
QColor QtMaterialBadge::textColor() const
{
Q_D(const QtMaterialBadge);
if (d->useThemeColors || !d->textColor.isValid()) {
return QtMaterialStyle::instance().themeColor("canvas");
} else {
return d->textColor;
}
}
void QtMaterialBadge::setBackgroundColor(const QColor &color)
{
Q_D(QtMaterialBadge);
d->backgroundColor = color;
setUseThemeColors(false);
}
QColor QtMaterialBadge::backgroundColor() const
{
Q_D(const QtMaterialBadge);
if (d->useThemeColors || !d->backgroundColor.isValid()) {
return QtMaterialStyle::instance().themeColor("accent1");
} else {
return d->backgroundColor;
}
}
void QtMaterialBadge::setRelativePosition(const QPointF &pos)
{
setRelativePosition(pos.x(), pos.y());
}
void QtMaterialBadge::setRelativePosition(qreal x, qreal y)
{
Q_D(QtMaterialBadge);
d->x = x;
d->y = y;
update();
}
QPointF QtMaterialBadge::relativePosition() const
{
Q_D(const QtMaterialBadge);
return QPointF(d->x, d->y);
}
void QtMaterialBadge::setRelativeXPosition(qreal x)
{
Q_D(QtMaterialBadge);
d->x = x;
update();
}
qreal QtMaterialBadge::relativeXPosition() const
{
Q_D(const QtMaterialBadge);
return d->x;
}
void QtMaterialBadge::setRelativeYPosition(qreal y)
{
Q_D(QtMaterialBadge);
d->y = y;
update();
}
qreal QtMaterialBadge::relativeYPosition() const
{
Q_D(const QtMaterialBadge);
return d->y;
}
/*!
* \reimp
*/
QSize QtMaterialBadge::sizeHint() const
{
const int s = getDiameter();
return QSize(s+4, s+4);
}
void QtMaterialBadge::setIcon(const QIcon &icon)
{
Q_D(QtMaterialBadge);
d->icon = icon;
update();
}
QIcon QtMaterialBadge::icon() const
{
Q_D(const QtMaterialBadge);
return d->icon;
}
void QtMaterialBadge::setText(const QString &text)
{
Q_D(QtMaterialBadge);
d->text = text;
if (!d->icon.isNull()) {
d->icon = QIcon();
}
d->size = fontMetrics().size(Qt::TextShowMnemonic, text);
update();
}
QString QtMaterialBadge::text() const
{
Q_D(const QtMaterialBadge);
return d->text;
}
/*!
* \reimp
*/
void QtMaterialBadge::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
Q_D(QtMaterialBadge);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.translate(d->x, d->y);
QBrush brush;
brush.setStyle(Qt::SolidPattern);
brush.setColor(isEnabled() ? backgroundColor()
: QtMaterialStyle::instance().themeColor("disabled"));
painter.setBrush(brush);
painter.setPen(Qt::NoPen);
const int s = getDiameter();
QRectF r(0, 0, s, s);
r.translate(QPointF((width()-s), (height()-s))/2);
if (d->icon.isNull())
{
painter.drawEllipse(r);
painter.setPen(textColor());
painter.setBrush(Qt::NoBrush);
painter.drawText(r.translated(0, -0.5), Qt::AlignCenter, d->text);
}
else
{
painter.drawEllipse(r);
QRectF q(0, 0, 16, 16);
q.moveCenter(r.center());
QPixmap pixmap = icon().pixmap(16, 16);
QPainter icon(&pixmap);
icon.setCompositionMode(QPainter::CompositionMode_SourceIn);
icon.fillRect(pixmap.rect(), textColor());
painter.drawPixmap(q.toRect(), pixmap);
}
}
int QtMaterialBadge::getDiameter() const
{
Q_D(const QtMaterialBadge);
if (d->icon.isNull()) {
return qMax(d->size.width(), d->size.height()) + d->padding;
} else {
return 24;
}
}

View File

@ -0,0 +1,61 @@
#ifndef QTMATERIALBADGE_H
#define QTMATERIALBADGE_H
#include "lib/qtmaterialoverlaywidget.h"
class QtMaterialBadgePrivate;
class QtMaterialBadge : public QtMaterialOverlayWidget
{
Q_OBJECT
Q_PROPERTY(QColor textColor WRITE setTextColor READ textColor)
Q_PROPERTY(QColor backgroundColor WRITE setBackgroundColor READ backgroundColor)
Q_PROPERTY(QPointF relativePosition WRITE setRelativePosition READ relativePosition)
public:
explicit QtMaterialBadge(QWidget *parent = 0);
explicit QtMaterialBadge(const QIcon &icon, QWidget *parent = 0);
explicit QtMaterialBadge(const QString &text, QWidget *parent = 0);
~QtMaterialBadge();
void setUseThemeColors(bool value);
bool useThemeColors() const;
void setTextColor(const QColor &color);
QColor textColor() const;
void setBackgroundColor(const QColor &color);
QColor backgroundColor() const;
void setRelativePosition(const QPointF &pos);
void setRelativePosition(qreal x, qreal y);
QPointF relativePosition() const;
void setRelativeXPosition(qreal x);
qreal relativeXPosition() const;
void setRelativeYPosition(qreal y);
qreal relativeYPosition() const;
QSize sizeHint() const Q_DECL_OVERRIDE;
void setIcon(const QIcon &icon);
QIcon icon() const;
void setText(const QString &text);
QString text() const;
protected:
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
int getDiameter() const;
const QScopedPointer<QtMaterialBadgePrivate> d_ptr;
private:
Q_DISABLE_COPY(QtMaterialBadge)
Q_DECLARE_PRIVATE(QtMaterialBadge)
};
#endif // QTMATERIALBADGE_H

View File

@ -0,0 +1,34 @@
#ifndef QTMATERIALBADGE_P_H
#define QTMATERIALBADGE_P_H
#include <QtGlobal>
#include <QSize>
#include <QIcon>
#include <QColor>
class QtMaterialBadge;
class QtMaterialBadgePrivate
{
Q_DISABLE_COPY(QtMaterialBadgePrivate)
Q_DECLARE_PUBLIC(QtMaterialBadge)
public:
QtMaterialBadgePrivate(QtMaterialBadge *q);
~QtMaterialBadgePrivate();
void init();
QtMaterialBadge *const q_ptr;
QString text;
QColor textColor;
QColor backgroundColor;
QSize size;
QIcon icon;
qreal x;
qreal y;
int padding;
bool useThemeColors;
};
#endif // QTMATERIALBADGE_P_H

View File

@ -1,6 +1,7 @@
#include "avatarsettingseditor.h"
#include <QColorDialog>
#include "qtmaterialavatar.h"
#include "lib/qtmaterialtheme.h"
AvatarSettingsEditor::AvatarSettingsEditor(QWidget *parent)
: QWidget(parent),
@ -75,7 +76,7 @@ void AvatarSettingsEditor::updateWidget()
m_avatar->setImage(QImage(":/images/assets/sikh.jpg"));
break;
case 2:
m_avatar->setIcon(QIcon(":/icons/icons/communication/svg/production/ic_message_24px.svg"));
m_avatar->setIcon(QIcon(QtMaterialTheme::icon("communication", "message")));
break;
default:
break;

View File

@ -0,0 +1,103 @@
#include "badgesettingseditor.h"
#include <QColorDialog>
#include "qtmaterialavatar.h"
#include "qtmaterialbadge.h"
BadgeSettingsEditor::BadgeSettingsEditor(QWidget *parent)
: QWidget(parent),
ui(new Ui::BadgeSettingsForm),
m_avatar(new QtMaterialAvatar(QImage(":/images/assets/sikh.jpg"))),
m_badge(new QtMaterialBadge)
{
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);
layout = new QVBoxLayout;
canvas->setLayout(layout);
layout->addWidget(m_avatar);
layout->setAlignment(m_avatar, Qt::AlignCenter);
m_avatar->setSize(60);
m_badge->setParent(m_avatar);
m_badge->setRelativePosition(18, 18);
m_badge->setText("3");
setupForm();
connect(ui->disabledCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateWidget()));
connect(ui->typeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateWidget()));
connect(ui->useThemeColorsCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateWidget()));
connect(ui->horizontalOffsetSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateWidget()));
connect(ui->verticalOffsetSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateWidget()));
connect(ui->backgroundColorToolButton, SIGNAL(pressed()), this, SLOT(selectColor()));
connect(ui->textColorToolButton, SIGNAL(pressed()), this, SLOT(selectColor()));
ui->verticalOffsetSpinBox->setRange(-40, 40);
ui->horizontalOffsetSpinBox->setRange(-40, 40);
}
BadgeSettingsEditor::~BadgeSettingsEditor()
{
delete ui;
}
void BadgeSettingsEditor::setupForm()
{
if (m_badge->icon().isNull()) {
ui->typeComboBox->setCurrentIndex(0);
} else {
ui->typeComboBox->setCurrentIndex(1);
}
ui->verticalOffsetSpinBox->setValue(m_badge->relativeYPosition());
ui->horizontalOffsetSpinBox->setValue(m_badge->relativeXPosition());
ui->disabledCheckBox->setChecked(!m_badge->isEnabled());
ui->useThemeColorsCheckBox->setChecked(m_badge->useThemeColors());
}
void BadgeSettingsEditor::updateWidget()
{
switch (ui->typeComboBox->currentIndex())
{
case 0:
m_badge->setText("3");
break;
case 1:
m_badge->setIcon(QIcon(QtMaterialTheme::icon("communication", "message")));
break;
default:
break;
}
m_badge->setRelativeYPosition(ui->verticalOffsetSpinBox->value());
m_badge->setRelativeXPosition(ui->horizontalOffsetSpinBox->value());
m_badge->setDisabled(ui->disabledCheckBox->isChecked());
m_badge->setUseThemeColors(ui->useThemeColorsCheckBox->isChecked());
}
void BadgeSettingsEditor::selectColor()
{
QColorDialog dialog;
if (dialog.exec()) {
QColor color = dialog.selectedColor();
QString senderName = sender()->objectName();
if ("textColorToolButton" == senderName) {
m_badge->setTextColor(color);
ui->textColorLineEdit->setText(color.name(QColor::HexRgb));
} else if ("backgroundColorToolButton" == senderName) {
m_badge->setBackgroundColor(color);
ui->backgroundColorLineEdit->setText(color.name(QColor::HexRgb));
}
}
setupForm();
}

View File

@ -0,0 +1,29 @@
#ifndef BADGESETTINGSEDITOR_H
#define BADGESETTINGSEDITOR_H
#include <QWidget>
#include "ui_badgesettingsform.h"
class QtMaterialAvatar;
class QtMaterialBadge;
class BadgeSettingsEditor : public QWidget
{
Q_OBJECT
public:
explicit BadgeSettingsEditor(QWidget *parent = 0);
~BadgeSettingsEditor();
protected slots:
void setupForm();
void updateWidget();
void selectColor();
private:
Ui::BadgeSettingsForm *const ui;
QtMaterialAvatar *const m_avatar;
QtMaterialBadge *const m_badge;
};
#endif // BADGESETTINGSEDITOR_H

View File

@ -0,0 +1,142 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BadgeSettingsForm</class>
<widget class="QWidget" name="BadgeSettingsForm">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QWidget" name="formLayoutWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>201</width>
<height>231</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="disabledLabel">
<property name="text">
<string>Disabled</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="disabledCheckBox"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="useThemeColorsLabel">
<property name="text">
<string>Use theme colors</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="useThemeColorsCheckBox"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="backgroundColorLabel">
<property name="text">
<string>Background color</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="textColorLabel">
<property name="text">
<string>Text color</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="horizontalOffsetLabel">
<property name="text">
<string>Horizontal offset</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="horizontalOffsetSpinBox"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="verticalOffsetLabel">
<property name="text">
<string>Vertical offset</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QSpinBox" name="verticalOffsetSpinBox"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="typeLabel">
<property name="text">
<string>Type</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="typeComboBox">
<item>
<property name="text">
<string>Text</string>
</property>
</item>
<item>
<property name="text">
<string>Icon</string>
</property>
</item>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="backgroundColorLineEdit">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="backgroundColorToolButton">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLineEdit" name="textColorLineEdit">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="textColorToolButton">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -2,9 +2,11 @@ QT += core gui widgets
TEMPLATE = app
SOURCES = mainwindow.cpp \
main.cpp \
avatarsettingseditor.cpp
avatarsettingseditor.cpp \
badgesettingseditor.cpp
HEADERS = mainwindow.h \
avatarsettingseditor.h
avatarsettingseditor.h \
badgesettingseditor.h
LIBS += ../components/libcomponents.a
INCLUDEPATH += ../components/
TARGET = ../examples-exe
@ -13,4 +15,5 @@ RESOURCES += \
examples.qrc
FORMS += \
avatarsettingsform.ui
avatarsettingsform.ui \
badgesettingsform.ui

View File

@ -1,11 +1,15 @@
#include "mainwindow.h"
#include <QtWidgets/QVBoxLayout>
#include "avatarsettingseditor.h"
#include "badgesettingseditor.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
AvatarSettingsEditor *editor = new AvatarSettingsEditor;
//AvatarSettingsEditor *editor = new AvatarSettingsEditor;
//setCentralWidget(editor);
BadgeSettingsEditor *editor = new BadgeSettingsEditor;
setCentralWidget(editor);
}